From 0769d15ebadcbe89ef498b73b228fa3a01481eb7 Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Wed, 29 Jun 2016 15:47:53 -0700 Subject: [PATCH 1/6] Wasm: Added instrumentation for -profile Made some Wasm tracing available in test build Update basic.wast to latest syntax (haven't update the baseline, because I am unsure what it is supposed to do) --- lib/Common/ConfigFlagsList.h | 8 ++- lib/Runtime/Base/ScriptContext.cpp | 3 + lib/Runtime/Base/ScriptContext.h | 32 +++++++++ .../Language/InterpreterStackFrame.cpp | 7 +- lib/WasmReader/WasmBinaryReader.cpp | 16 +++-- lib/WasmReader/WasmByteCodeGenerator.cpp | 28 ++++---- lib/WasmReader/WasmReader.h | 2 +- test/wasm/basic.js | 4 +- test/wasm/basic.wasm | Bin 131 -> 257 bytes test/wasm/basic.wast | 66 +++++++++--------- 10 files changed, 108 insertions(+), 58 deletions(-) diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index 399eaa17af9..d85bb840dc1 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -31,10 +31,12 @@ PHASE(All) PHASE(Speculation) PHASE(GatherCodeGenData) PHASE(Wasm) - PHASE(WasmSection) - PHASE(WasmReader) PHASE(WasmBytecode) - PHASE(WasmLEB128) + PHASE(WasmParser) + PHASE(WasmReader) + PHASE(WasmSection) + PHASE(WasmLEB128) + PHASE(WasmFunctionBody) PHASE(WasmLazyTrap) PHASE(Asmjs) PHASE(AsmjsTmpRegisterAllocation) diff --git a/lib/Runtime/Base/ScriptContext.cpp b/lib/Runtime/Base/ScriptContext.cpp index 127e16b4c15..6f0762e88e7 100644 --- a/lib/Runtime/Base/ScriptContext.cpp +++ b/lib/Runtime/Base/ScriptContext.cpp @@ -2020,6 +2020,9 @@ if (!sourceList) pSrcInfo = this->cache->noContextGlobalSourceInfo; } + AutoProfilingPhase wasmPhase(this, Js::WasmPhase); + Unused(wasmPhase); + Assert(!this->threadContext->IsScriptActive()); Assert(pse != nullptr); Wasm::WasmBytecodeGenerator *bytecodeGen = nullptr; diff --git a/lib/Runtime/Base/ScriptContext.h b/lib/Runtime/Base/ScriptContext.h index 9a1fa58aa20..267f11e023f 100644 --- a/lib/Runtime/Base/ScriptContext.h +++ b/lib/Runtime/Base/ScriptContext.h @@ -1761,8 +1761,40 @@ namespace Js return functionBody; } + + class AutoProfilingPhase + { + public: + AutoProfilingPhase(ScriptContext* scriptcontext, Js::Phase phase) : scriptcontext(scriptcontext), phase(phase), isPhaseComplete(false) + { + #ifdef PROFILE_EXEC + scriptcontext->ProfileBegin(phase); + #endif + } + + ~AutoProfilingPhase() + { + if(!this->isPhaseComplete) + { + EndProfile(); + } + } + + void EndProfile() + { + this->isPhaseComplete = true; +#ifdef PROFILE_EXEC + scriptcontext->ProfileEnd(phase); +#endif + } + private: + ScriptContext* scriptcontext; + Js::Phase phase; + bool isPhaseComplete; + }; } + #define BEGIN_TEMP_ALLOCATOR(allocator, scriptContext, name) \ Js::TempArenaAllocatorObject *temp##allocator = scriptContext->GetTemporaryAllocator(name); \ ArenaAllocator * allocator = temp##allocator->GetAllocator(); diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp index 0175c4e75d7..d01b86c269b 100644 --- a/lib/Runtime/Language/InterpreterStackFrame.cpp +++ b/lib/Runtime/Language/InterpreterStackFrame.cpp @@ -2965,16 +2965,21 @@ namespace Js uint homingAreaSize = 0; #endif -#if DBG_DUMP +#if ENABLE_DEBUG_CONFIG_OPTIONS const bool tracingFunc = PHASE_TRACE(AsmjsFunctionEntryPhase, functionBody); if (tracingFunc) { +#if DBG_DUMP if (AsmJsCallDepth) { Output::Print(_u("%*c"), AsmJsCallDepth, ' '); } Output::Print(_u("Executing function %s("), functionBody->GetDisplayName()); ++AsmJsCallDepth; +#else + Output::Print(_u("%s()\n"), functionBody->GetDisplayName()); + Output::Flush(); +#endif } #endif uintptr_t argAddress = (uintptr_t)m_inParams; diff --git a/lib/WasmReader/WasmBinaryReader.cpp b/lib/WasmReader/WasmBinaryReader.cpp index a6bbee153bc..2c469ab25ea 100644 --- a/lib/WasmReader/WasmBinaryReader.cpp +++ b/lib/WasmReader/WasmBinaryReader.cpp @@ -202,7 +202,7 @@ WasmBinaryReader::ReadSectionHeader() } } -#if DBG +#if ENABLE_DEBUG_CONFIG_OPTIONS Assert(idSize < 64); char16 buf[64]; size_t convertedChars = 0; @@ -278,6 +278,7 @@ WasmBinaryReader::ReadFunctionBodies(FunctionBodyCallback callback, void* callba UINT32 entryCount = LEB128(len); m_funcState.count += len; + TRACE_WASM_DECODER(_u("Function body header: index = %u, size = %u"), i, m_funcState.size); // locals for (UINT32 j = 0; j < entryCount; j++) @@ -285,13 +286,17 @@ WasmBinaryReader::ReadFunctionBodies(FunctionBodyCallback callback, void* callba UINT32 count = LEB128(len); m_funcState.count += len; Wasm::WasmTypes::WasmType type = ReadWasmType(len); - if (type == Wasm::WasmTypes::Void) + if (!Wasm::WasmTypes::IsLocalType(type)) { ThrowDecodingError(_u("Invalid local type")); } m_funcState.count += len; m_funcInfo->AddLocal(type, count); - TRACE_WASM_DECODER(_u("Function body header: type = %u, count = %u"), type, count); + switch (type) + { +#define WASM_LOCALTYPE(token, name) case Wasm::WasmTypes::token: TRACE_WASM_DECODER(_u("Local: type = " #name## ", count = %u"), type, count); break; +#include "WasmKeywords.h" + } } bool errorOccurred = !callback(i, callbackdata) || m_funcState.count != m_funcState.size; if (errorOccurred) @@ -706,10 +711,7 @@ void WasmBinaryReader::ReadIndirectFunctionTable() { ThrowDecodingError(_u("Indirect function index %u is out of bound (max %u)"), functionIndex, m_moduleInfo->GetFunctionCount()); } - if (PHASE_TRACE1(Js::WasmReaderPhase)) - { - Output::Print(_u("%u, "), functionIndex); - } + TRACE_WASM_DECODER(_u("%u, "), functionIndex); m_moduleInfo->SetIndirectFunction(functionIndex, i); } TRACE_WASM_DECODER(_u("]"), entries); diff --git a/lib/WasmReader/WasmByteCodeGenerator.cpp b/lib/WasmReader/WasmByteCodeGenerator.cpp index 147d5523ef4..67a28dd26c1 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.cpp +++ b/lib/WasmReader/WasmByteCodeGenerator.cpp @@ -42,6 +42,9 @@ typedef void(*AfterSectionCallback)(WasmBytecodeGenerator*); WasmModule * WasmBytecodeGenerator::GenerateModule() { + Js::AutoProfilingPhase parserProfiler(m_scriptContext, Js::WasmParserPhase); + Unused(parserProfiler); + // TODO: can this be in a better place? m_sourceInfo->EnsureInitialized(0); m_sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized(); @@ -138,6 +141,9 @@ WasmBytecodeGenerator::GenerateModule() WasmFunction * WasmBytecodeGenerator::GenerateFunction() { + Js::AutoProfilingPhase bytecodeProfiler(m_scriptContext, Js::WasmBytecodePhase); + Unused(bytecodeProfiler); + WasmFunctionInfo* wasmInfo = m_reader.m_currentNode.func.info; TRACE_WASM_DECODER(_u("GenerateFunction %u \n"), wasmInfo->GetNumber()); @@ -219,6 +225,9 @@ WasmBytecodeGenerator::GenerateFunction() m_funcInfo->SetExitLabel(m_writer.DefineLabel()); EnregisterLocals(); + Js::AutoProfilingPhase functionProfiler(m_scriptContext, Js::WasmFunctionBodyPhase); + Unused(functionProfiler); + WasmOp op = wnLIMIT; EmitInfo exprInfo; EnterEvalStackScope(); @@ -1352,18 +1361,13 @@ WasmBytecodeGenerator::PushLabel(Js::ByteCodeLabel label, bool addBlockYieldInfo if (addBlockYieldInfo) { info.yieldInfo = Anew(&m_alloc, BlockYieldInfo); - for (int type = WasmTypes::Void + 1; type < WasmTypes::Limit; ++type) - { - try - { - info.yieldInfo->yieldLocs[type] = GetRegisterSpace((WasmTypes::WasmType)type)->AcquireTmpRegister(); - } - catch (WasmCompilationException) - { - // This might be a NYI type - info.yieldInfo->yieldLocs[type] = Js::Constants::NoRegister; - } - } + info.yieldInfo->yieldLocs[WasmTypes::I32] = GetRegisterSpace(WasmTypes::I32)->AcquireTmpRegister(); + info.yieldInfo->yieldLocs[WasmTypes::I64] = Js::Constants::NoRegister; // NYI + info.yieldInfo->yieldLocs[WasmTypes::F32] = GetRegisterSpace(WasmTypes::F32)->AcquireTmpRegister(); + info.yieldInfo->yieldLocs[WasmTypes::F64] = GetRegisterSpace(WasmTypes::F64)->AcquireTmpRegister(); + + // Make sure we don't forget to add new types here + CompileAssert(WasmTypes::Limit == 5); } m_blockInfos.Push(info); } diff --git a/lib/WasmReader/WasmReader.h b/lib/WasmReader/WasmReader.h index e6d2e494897..c5ab9dea54b 100644 --- a/lib/WasmReader/WasmReader.h +++ b/lib/WasmReader/WasmReader.h @@ -9,7 +9,7 @@ #include "Runtime.h" #ifdef ENABLE_WASM -#if DBG +#if ENABLE_DEBUG_CONFIG_OPTIONS #define TRACE_WASM(condition, ...) \ if (condition)\ {\ diff --git a/test/wasm/basic.js b/test/wasm/basic.js index 3f41d94e007..47540762c6e 100644 --- a/test/wasm/basic.js +++ b/test/wasm/basic.js @@ -3,11 +3,11 @@ // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- -var a = WScript.LoadWasmFile('basic.wast', {foo: function(a){print(a); return 2;}}); +var a = Wasm.instantiateModule(readbuffer('basic.wasm'), {test: {foo: function(a){print(a); return 2;}}}); print(a.exports.a(11)); print(a.exports.a(11)); var b = 0; -var c = new Int32Array(a.memory); +var c = new Int32Array(a.exports.memory); for(var i=0; i<10000; i++) { b+= c[i]; diff --git a/test/wasm/basic.wasm b/test/wasm/basic.wasm index daad5c30c8432961e9977f66bf422aae4d7b85bd..d1bb887fd5f295beadae644bc841d5e7cbd1dd2d 100644 GIT binary patch literal 257 zcmYj}I}XAy5JYDkJK-XAklIGa|a~q0FD%i#0ZQ8Jq0JArR4w|kTn7cH?#Zv zc2FLhJ^&dmd)E^dM3(rab+h+}&?l0?9Ya!i->FXRCe*%71W1K)y>oF&8`t>5Mct;i zDW&cl&m=dLa^tt|K|(=`F5MX=dZNe6#6U}%W59_az@skyxMZ#t{7+xez+lCeLGiH- o8MmTJV8G(1P0wtX-Us0%asU7T literal 131 zcmaKk!3}^g3 Date: Tue, 5 Jul 2016 01:26:03 -0700 Subject: [PATCH 2/6] Implement deferred parsing for Wasm functions. Added new class WasmModuleGenerator which reads only what is necessary to create the wasm module. Then WasmBytecodeGenerator only generates the bytecode for the function bodies. Added thunks for x64/x86 for deferred parsing entry points. Simplified logic for LazyTraps --- lib/Common/ConfigFlagsList.h | 1 + lib/Runtime/Base/CrossSite.cpp | 9 +- lib/Runtime/Base/ScriptContext.cpp | 136 +++- lib/Runtime/Base/ScriptContext.h | 6 + lib/Runtime/Language/AsmJsTypes.h | 13 +- lib/Runtime/Language/amd64/amd64_Thunks.asm | 107 ++++ lib/WasmReader/ModuleInfo.cpp | 35 +- lib/WasmReader/ModuleInfo.h | 14 +- lib/WasmReader/WasmBinaryReader.cpp | 177 +++--- lib/WasmReader/WasmBinaryReader.h | 46 +- lib/WasmReader/WasmByteCodeGenerator.cpp | 661 ++++++++++---------- lib/WasmReader/WasmByteCodeGenerator.h | 53 +- lib/WasmReader/WasmFunctionInfo.cpp | 79 +-- lib/WasmReader/WasmFunctionInfo.h | 23 +- lib/WasmReader/WasmParseTree.h | 6 - 15 files changed, 731 insertions(+), 635 deletions(-) diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index d85bb840dc1..ec0470592a5 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -38,6 +38,7 @@ PHASE(All) PHASE(WasmLEB128) PHASE(WasmFunctionBody) PHASE(WasmLazyTrap) + PHASE(WasmDeferred) PHASE(Asmjs) PHASE(AsmjsTmpRegisterAllocation) PHASE(AsmjsEncoder) diff --git a/lib/Runtime/Base/CrossSite.cpp b/lib/Runtime/Base/CrossSite.cpp index 83b7bc4d951..bdfb45d2b4d 100644 --- a/lib/Runtime/Base/CrossSite.cpp +++ b/lib/Runtime/Base/CrossSite.cpp @@ -309,7 +309,14 @@ namespace Js if (funcInfo->GetFunctionProxy()->IsFunctionBody() && funcInfo->GetFunctionBody()->GetIsAsmJsFunction()) { - entryPoint = Js::AsmJsExternalEntryPoint; + if (((AsmJsFunctionInfo*)funcInfo)->IsWasmDeferredParse()) + { + entryPoint = ScriptContext::WasmDeferredParseExternalThunk; + } + else + { + entryPoint = Js::AsmJsExternalEntryPoint; + } } else #endif diff --git a/lib/Runtime/Base/ScriptContext.cpp b/lib/Runtime/Base/ScriptContext.cpp index 6f0762e88e7..68d9e66461d 100644 --- a/lib/Runtime/Base/ScriptContext.cpp +++ b/lib/Runtime/Base/ScriptContext.cpp @@ -1835,6 +1835,44 @@ if (!sourceList) } } + void WasmFunctionGenerateBytecode(AsmJsScriptFunction* func, bool propagateError) + { + FunctionBody* body = func->GetFunctionBody(); + AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo(); + ScriptContext* scriptContext = func->GetScriptContext(); + + Js::FunctionEntryPointInfo * entypointInfo = (Js::FunctionEntryPointInfo*)func->GetEntryPointInfo(); + Wasm::WasmReaderInfo* readerInfo = info->GetWasmReaderInfo(); + info->SetWasmReaderInfo(nullptr); + try + { + Wasm::WasmBytecodeGenerator::GenerateFunctionBytecode(scriptContext, body, readerInfo); + func->GetDynamicType()->SetEntryPoint(Js::AsmJsExternalEntryPoint); + entypointInfo->jsMethod = AsmJsDefaultEntryThunk; + // Do MTJRC/MAIC:0 check +#if ENABLE_DEBUG_CONFIG_OPTIONS + if (CONFIG_FLAG(ForceNative) || CONFIG_FLAG(MaxAsmJsInterpreterRunCount) == 0) + { + GenerateFunction(scriptContext->GetNativeCodeGenerator(), func->GetFunctionBody(), func); + } +#endif + } + catch (Wasm::WasmCompilationException ex) + { + if (propagateError) + { + throw; + } + Js::JavascriptLibrary *library = scriptContext->GetLibrary(); + Js::JavascriptError *pError = library->CreateError(); + Js::JavascriptError::SetErrorMessage(pError, JSERR_WasmCompileError, ex.ReleaseErrorMessage(), scriptContext); + + func->GetDynamicType()->SetEntryPoint(WasmLazyTrapCallback); + entypointInfo->jsMethod = WasmLazyTrapCallback; + func->SetLazyError(pError); + } + } + void WasmLoadFunctions(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* moduleMemoryPtr, Var* exportObj, Var* localModuleFunctions, bool* hasAnyLazyTraps) { FrameDisplay * frameDisplay = RecyclerNewPlus(ctx->GetRecycler(), sizeof(void*), FrameDisplay, 1); @@ -1845,35 +1883,22 @@ if (!sourceList) for (uint i = 0; i < wasmModule->funcCount; ++i) { AsmJsScriptFunction * funcObj = ctx->GetLibrary()->CreateAsmJsScriptFunction(functionArray[i]->body); - funcObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint); funcObj->SetModuleMemory(moduleMemoryPtr); FunctionEntryPointInfo * entypointInfo = (FunctionEntryPointInfo*)funcObj->GetEntryPointInfo(); entypointInfo->SetIsAsmJSFunction(true); - entypointInfo->jsMethod = AsmJsDefaultEntryThunk; entypointInfo->SetModuleAddress((uintptr_t)moduleMemoryPtr); funcObj->SetEnvironment(frameDisplay); localModuleFunctions[i] = funcObj; - - if (wasmModule->lazyTraps && wasmModule->lazyTraps[i]) + + if (PHASE_ON(WasmDeferredPhase, funcObj->GetFunctionBody())) { - Assert(PHASE_ON1(WasmLazyTrapPhase)); - *hasAnyLazyTraps = true; - JavascriptLibrary *library = ctx->GetLibrary(); - JavascriptError *pError = library->CreateError(); - JavascriptError::SetErrorMessage(pError, JSERR_WasmCompileError, wasmModule->lazyTraps[i]->ReleaseErrorMessage(), ctx); - - funcObj->GetDynamicType()->SetEntryPoint(WasmLazyTrapCallback); - entypointInfo->jsMethod = WasmLazyTrapCallback; - funcObj->SetLazyError(pError); - continue; + funcObj->GetDynamicType()->SetEntryPoint(ScriptContext::WasmDeferredParseExternalThunk); + entypointInfo->jsMethod = ScriptContext::WasmDeferredParseInternalThunk; } - // Do MTJRC/MAIC:0 check -#if ENABLE_DEBUG_CONFIG_OPTIONS - if (CONFIG_FLAG(ForceNative) || CONFIG_FLAG(MaxAsmJsInterpreterRunCount) == 0) + else { - GenerateFunction(ctx->GetNativeCodeGenerator(), funcObj->GetFunctionBody(), funcObj); + WasmFunctionGenerateBytecode(funcObj, !PHASE_ON(WasmLazyTrapPhase, funcObj->GetFunctionBody())); } -#endif } } @@ -1996,8 +2021,7 @@ if (!sourceList) uint funcIndex = wasmModule->info->GetIndirectFunctionIndex(i); if (funcIndex >= wasmModule->info->GetFunctionCount()) { - // TODO: michhol give error messages - Js::Throw::InternalError(); + throw Wasm::WasmCompilationException(_u("Invalid function index %U for indirect function table"), funcIndex); } Wasm::WasmFunctionInfo * indirFunc = wasmModule->info->GetFunSig(funcIndex); uint sigId = indirFunc->GetSignature()->GetSignatureId(); @@ -2011,6 +2035,72 @@ if (!sourceList) } } +#if _M_IX86 + __declspec(naked) + Var ScriptContext::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...) + { + // Register functions + __asm + { + push ebp + mov ebp, esp + lea eax, [esp + 8] + push 0 + push eax + call ScriptContext::WasmDeferredParseEntryPoint +#ifdef _CONTROL_FLOW_GUARD + // verify that the call target is valid + mov ecx, eax + call[__guard_check_icall_fptr] + mov eax, ecx +#endif + pop ebp + // Although we don't restore ESP here on WinCE, this is fine because script profiler is not shipped for WinCE. + jmp eax + } + } + + __declspec(naked) + Var ScriptContext::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...) + { + // Register functions + __asm + { + push ebp + mov ebp, esp + lea eax, [esp + 8] + push 1 + push eax + call ScriptContext::WasmDeferredParseEntryPoint +#ifdef _CONTROL_FLOW_GUARD + // verify that the call target is valid + mov ecx, eax + call[__guard_check_icall_fptr] + mov eax, ecx +#endif + pop ebp + // Although we don't restore ESP here on WinCE, this is fine because script profiler is not shipped for WinCE. + jmp eax + } + } +#elif defined(_M_X64) + // Do nothing: the implementation of ScriptContext::WasmDeferredParseExternalThunk is declared (appropriately decorated) in + // Language\amd64\amd64_Thunks.asm. +#endif + + JavascriptMethod ScriptContext::WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall) + { + AsmJsScriptFunction* func = *funcPtr; + + WasmFunctionGenerateBytecode(func, false); + Js::FunctionEntryPointInfo * entypointInfo = (Js::FunctionEntryPointInfo*)func->GetEntryPointInfo(); + if (internalCall) + { + return entypointInfo->jsMethod; + } + return func->GetDynamicType()->GetEntryPoint(); + } + char16* lastWasmExceptionMessage = nullptr; Var ScriptContext::LoadWasmScript(const char16* script, SRCINFO const * pSrcInfo, CompileScriptException * pse, bool isExpression, bool disableDeferredParse, bool isForNativeCode, Utf8SourceInfo** ppSourceInfo, const bool isBinary, const uint lengthBytes, const char16 *rootDisplayName, Js::Var ffi, Js::Var* start) @@ -2025,7 +2115,7 @@ if (!sourceList) Assert(!this->threadContext->IsScriptActive()); Assert(pse != nullptr); - Wasm::WasmBytecodeGenerator *bytecodeGen = nullptr; + Wasm::WasmModuleGenerator *bytecodeGen = nullptr; Js::Var exportObj = nullptr; try { @@ -2040,7 +2130,7 @@ if (!sourceList) } *ppSourceInfo = Utf8SourceInfo::New(this, (LPCUTF8)script, lengthBytes / sizeof(char16), lengthBytes, pSrcInfo, false); - bytecodeGen = HeapNew(Wasm::WasmBytecodeGenerator, this, *ppSourceInfo, (byte*)script, lengthBytes); + bytecodeGen = HeapNew(Wasm::WasmModuleGenerator, this, *ppSourceInfo, (byte*)script, lengthBytes); wasmModule = bytecodeGen->GenerateModule(); Var* moduleMemoryPtr = RecyclerNewArrayZ(GetRecycler(), Var, wasmModule->memSize); diff --git a/lib/Runtime/Base/ScriptContext.h b/lib/Runtime/Base/ScriptContext.h index 267f11e023f..96b50884861 100644 --- a/lib/Runtime/Base/ScriptContext.h +++ b/lib/Runtime/Base/ScriptContext.h @@ -1605,6 +1605,12 @@ namespace Js static JavascriptMethod ProfileModeDeferredParse(ScriptFunction **function); static Var ProfileModeDeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...); +#ifdef ENABLE_WASM + static JavascriptMethod WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall); + static Var WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...); + static Var WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...); +#endif + // Thunks for deferred deserialization of function bodies from the byte code cache static JavascriptMethod ProfileModeDeferredDeserialize(ScriptFunction* function); static Var ProfileModeDeferredDeserializeThunk(RecyclableObject* function, CallInfo callInfo, ...); diff --git a/lib/Runtime/Language/AsmJsTypes.h b/lib/Runtime/Language/AsmJsTypes.h index a1d0cd05f23..dd22f52bba0 100644 --- a/lib/Runtime/Language/AsmJsTypes.h +++ b/lib/Runtime/Language/AsmJsTypes.h @@ -24,6 +24,11 @@ #pragma once #ifndef TEMP_DISABLE_ASMJS +namespace Wasm +{ + struct WasmReaderInfo; +}; + namespace Js { typedef uint32 uint32_t; @@ -1016,6 +1021,7 @@ namespace Js int mSimdConstCount, mSimdVarCount, mSimdTmpCount, mSimdByteOffset; FunctionBody* asmJsModuleFunctionBody; + Wasm::WasmReaderInfo* mWasmReaderInfo; public: AsmJsFunctionInfo() : mArgCount(0), mIntConstCount(0), @@ -1042,7 +1048,8 @@ namespace Js mUsesHeapBuffer(false), mIsHeapBufferConst(false), mArgType(nullptr), - mArgSizes(nullptr) {} + mArgSizes(nullptr), + mWasmReaderInfo(nullptr) {} // the key is the bytecode address typedef JsUtil::BaseDictionary ByteCodeToTJMap; ByteCodeToTJMap* mbyteCodeTJMap; @@ -1137,7 +1144,9 @@ namespace Js // Normally, heap has min size of 0x10000, but if you use ChangeHeap, min heap size is increased to 0x1000000 return offset >= 0x1000000 || (IsHeapBufferConst() && offset >= 0x10000); } - + Wasm::WasmReaderInfo* GetWasmReaderInfo() const {return mWasmReaderInfo;} + void SetWasmReaderInfo(Wasm::WasmReaderInfo* reader) {mWasmReaderInfo = reader;} + bool IsWasmDeferredParse() const { return mWasmReaderInfo != nullptr; } }; // The asm.js spec recognizes this set of builtin SIMD functions. diff --git a/lib/Runtime/Language/amd64/amd64_Thunks.asm b/lib/Runtime/Language/amd64/amd64_Thunks.asm index ed7e4b54c8d..6d9fde9f925 100644 --- a/lib/Runtime/Language/amd64/amd64_Thunks.asm +++ b/lib/Runtime/Language/amd64/amd64_Thunks.asm @@ -447,6 +447,113 @@ endif ?AsmJsExternalEntryPoint@Js@@YAPEAXPEAVRecyclableObject@1@UCallInfo@1@ZZ ENDP +;;============================================================================================================ +;; ScriptContext::WasmDeferredParseExternalThunk +;;============================================================================================================ + +;; JavascriptMethod ScriptContext::WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall); +extrn ?WasmDeferredParseEntryPoint@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAPEAVAsmJsScriptFunction@2@H@Z : PROC + +;; Var ScriptContext::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...) +align 16 +?WasmDeferredParseExternalThunk@ScriptContext@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ PROC FRAME + ;; save volatile registers + mov qword ptr [rsp + 8h], rcx + mov qword ptr [rsp + 10h], rdx + mov qword ptr [rsp + 18h], r8 + mov qword ptr [rsp + 20h], r9 + + push rbp + .pushreg rbp + lea rbp, [rsp] + .setframe rbp, 0 + .endprolog + + sub rsp, 20h + lea rcx, [rsp + 30h] + mov rdx, 0 + call ?WasmDeferredParseEntryPoint@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAPEAVAsmJsScriptFunction@2@H@Z + +ifdef _CONTROL_FLOW_GUARD + mov rcx, rax ; __guard_check_icall_fptr requires the call target in rcx. + call [__guard_check_icall_fptr] ; verify that the call target is valid + mov rax, rcx ;restore call target +endif + add rsp, 20h + + lea rsp, [rbp] + pop rbp + + ;; restore volatile registers + mov rcx, qword ptr [rsp + 8h] + mov rdx, qword ptr [rsp + 10h] + mov r8, qword ptr [rsp + 18h] + mov r9, qword ptr [rsp + 20h] + + rex_jmp_reg rax +?WasmDeferredParseExternalThunk@ScriptContext@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ ENDP + +;;============================================================================================================ + +;;============================================================================================================ +;; ScriptContext::WasmDeferredParseInternalThunk +;;============================================================================================================ + +;; JavascriptMethod ScriptContext::WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall); +extrn ?WasmDeferredParseEntryPoint@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAPEAVAsmJsScriptFunction@2@H@Z : PROC + +;; Var ScriptContext::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...) +align 16 +?WasmDeferredParseInternalThunk@ScriptContext@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ PROC FRAME + ;; save volatile registers + mov qword ptr [rsp + 8h], rcx + mov qword ptr [rsp + 10h], rdx + mov qword ptr [rsp + 18h], r8 + mov qword ptr [rsp + 20h], r9 + + push rbp + .pushreg rbp + lea rbp, [rsp] + .setframe rbp, 0 + .endprolog + + sub rsp, 60h + + ; spill potential floating point arguments to stack + movaps xmmword ptr [rsp + 30h], xmm1 + movaps xmmword ptr [rsp + 40h], xmm2 + movaps xmmword ptr [rsp + 50h], xmm3 + + lea rcx, [rsp + 70h] + mov rdx, 1 + call ?WasmDeferredParseEntryPoint@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAPEAVAsmJsScriptFunction@2@H@Z + +ifdef _CONTROL_FLOW_GUARD + mov rcx, rax ; __guard_check_icall_fptr requires the call target in rcx. + call [__guard_check_icall_fptr] ; verify that the call target is valid + mov rax, rcx ;restore call target +endif + + ; restore potential floating point arguments from stack + movaps xmm1, xmmword ptr [rsp + 30h] + movaps xmm2, xmmword ptr [rsp + 40h] + movaps xmm3, xmmword ptr [rsp + 50h] + add rsp, 60h + + lea rsp, [rbp] + pop rbp + + ;; restore volatile registers + mov rcx, qword ptr [rsp + 8h] + mov rdx, qword ptr [rsp + 10h] + mov r8, qword ptr [rsp + 18h] + mov r9, qword ptr [rsp + 20h] + + rex_jmp_reg rax +?WasmDeferredParseInternalThunk@ScriptContext@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ ENDP + +;;============================================================================================================ + endif ;; _ENABLE_DYNAMIC_THUNKS ;;============================================================================================================ diff --git a/lib/WasmReader/ModuleInfo.cpp b/lib/WasmReader/ModuleInfo.cpp index db08ab7b316..7772097f500 100644 --- a/lib/WasmReader/ModuleInfo.cpp +++ b/lib/WasmReader/ModuleInfo.cpp @@ -13,17 +13,18 @@ namespace Wasm ModuleInfo::ModuleInfo(ArenaAllocator * alloc) : m_memory(), m_alloc(alloc), + m_funsigs(nullptr), m_funcCount(0), m_importCount(0), + m_indirectfuncs(nullptr), m_indirectFuncCount(0), + m_exports(nullptr), m_exportCount(0), m_datasegCount(0), + m_signatures(nullptr), + m_signaturesCount(0), m_startFunc(Js::Constants::UninitializedValue) { - m_signatures = Anew(m_alloc, WasmSignatureArray, m_alloc, 0); - m_indirectfuncs = nullptr; - m_funsigs = nullptr; - m_exports = nullptr; } bool @@ -53,32 +54,29 @@ ModuleInfo::GetMemory() const return &m_memory; } -uint32 -ModuleInfo::AddSignature(WasmSignature * signature) +void +ModuleInfo::SetSignature(uint32 index, WasmSignature * signature) { - uint32 id = m_signatures->Count(); - - signature->SetSignatureId(id); - m_signatures->Add(signature); - - return id; + Assert(index < GetSignatureCount()); + signature->SetSignatureId(index); + m_signatures[index] = signature; } WasmSignature * ModuleInfo::GetSignature(uint32 index) const { - if (index >= m_signatures->Count()) + if (index >= GetSignatureCount()) { return nullptr; } - return m_signatures->GetBuffer()[index]; + return m_signatures[index]; } uint32 ModuleInfo::GetSignatureCount() const { - return m_signatures->Count(); + return m_signaturesCount; } void @@ -250,6 +248,13 @@ ModuleInfo::GetStartFunction() const return m_startFunc; } +void ModuleInfo::SetSignatureCount(uint32 count) +{ + Assert(m_signaturesCount == 0 && m_signatures == nullptr); + m_signaturesCount = count; + m_signatures = AnewArray(m_alloc, WasmSignature*, count); +} + } // namespace Wasm #endif // ENABLE_WASM diff --git a/lib/WasmReader/ModuleInfo.h b/lib/WasmReader/ModuleInfo.h index b2719773fb2..e4ef15cfaf0 100644 --- a/lib/WasmReader/ModuleInfo.h +++ b/lib/WasmReader/ModuleInfo.h @@ -25,11 +25,11 @@ namespace Wasm bool InitializeMemory(uint32 minSize, uint32 maxSize, bool exported); - const Memory * GetMemory() const; - uint32 AddSignature(WasmSignature * signature); + void SetSignature(uint32 index, WasmSignature * signature); WasmSignature * GetSignature(uint32 index) const; + void SetSignatureCount(uint32 count); uint32 GetSignatureCount() const; void AllocateIndirectFunctions(uint32 entries); @@ -61,19 +61,17 @@ namespace Wasm void SetStartFunction(uint32 i); uint32 GetStartFunction() const; - private: - typedef JsUtil::GrowingArray WasmSignatureArray; - - WasmSignatureArray * m_signatures; + WasmSignature** m_signatures; uint32* m_indirectfuncs; WasmFunctionInfo** m_funsigs; WasmExport* m_exports; WasmImport* m_imports; WasmDataSegment** m_datasegs; - uint m_funcCount; + uint m_signaturesCount; uint m_indirectFuncCount; + uint m_funcCount; uint m_exportCount; uint32 m_importCount; uint32 m_datasegCount; @@ -87,7 +85,6 @@ namespace Wasm { WasmModule() : functions(nullptr), - lazyTraps(nullptr), memSize(0), indirFuncTableOffset(0), heapOffset(0), @@ -97,7 +94,6 @@ namespace Wasm { } WasmFunction** functions; - class WasmCompilationException** lazyTraps; ModuleInfo * info; uint heapOffset; uint funcOffset; diff --git a/lib/WasmReader/WasmBinaryReader.cpp b/lib/WasmReader/WasmBinaryReader.cpp index 2c469ab25ea..09d217586b1 100644 --- a/lib/WasmReader/WasmBinaryReader.cpp +++ b/lib/WasmReader/WasmBinaryReader.cpp @@ -49,22 +49,24 @@ Signature::Signature(ArenaAllocator *alloc, uint count, ...) } } // namespace WasmTypes -WasmBinaryReader::WasmBinaryReader(PageAllocator * alloc, byte* source, size_t length) : - m_alloc(_u("WasmBinaryDecoder"), alloc, Js::Throw::OutOfMemory), m_lastOp(WasmBinOp::wbLimit) +WasmBinaryReader::WasmBinaryReader(ArenaAllocator* alloc, byte* source, size_t length) : + m_alloc(alloc), + m_curFuncEnd(nullptr), + m_lastOp(WasmBinOp::wbLimit) { - m_moduleInfo = Anew(&m_alloc, ModuleInfo, &m_alloc); + m_moduleInfo = Anew(m_alloc, ModuleInfo, m_alloc); m_start = m_pc = source; m_end = source + length; m_currentSection.code = bSectInvalid; #if DBG_DUMP - m_ops = Anew(&m_alloc, OpSet, &m_alloc); + m_ops = Anew(m_alloc, OpSet, m_alloc); #endif } void WasmBinaryReader::InitializeReader() { - ModuleHeader(); + ValidateModuleHeader(); #if DBG_DUMP if (DO_WASM_TRACE_SECTION) { @@ -94,7 +96,6 @@ WasmBinaryReader::ThrowDecodingError(const char16* msg, ...) { va_list argptr; va_start(argptr, msg); - // We need to do a format twice (or concat the 2 strings) throw WasmCompilationException(msg, argptr); } @@ -252,12 +253,12 @@ WasmBinaryReader::PrintOps() } HeapDeleteArray(m_ops->Count(), ops); } + #endif bool -WasmBinaryReader::ReadFunctionBodies(FunctionBodyCallback callback, void* callbackdata) +WasmBinaryReader::ReadFunctionHeaders() { - Assert(callback != nullptr); uint32 len; uint32 entries = LEB128(len); if (entries != m_moduleInfo->GetFunctionCount()) @@ -267,60 +268,66 @@ WasmBinaryReader::ReadFunctionBodies(FunctionBodyCallback callback, void* callba for (uint32 i = 0; i < entries; ++i) { - m_funcInfo = m_moduleInfo->GetFunSig(i); - m_currentNode.func.info = m_funcInfo; + WasmFunctionInfo* funcInfo = m_moduleInfo->GetFunSig(i); - // Reset func state - m_funcState.count = 0; - m_funcState.size = LEB128(len); // function body size in bytes including AST - byte* end = m_pc + m_funcState.size; - CheckBytesLeft(m_funcState.size); + const uint32 funcSize = LEB128(len); + funcInfo->m_readerInfo.index = i; + funcInfo->m_readerInfo.size = funcSize; + funcInfo->m_readerInfo.startOffset = (m_pc - m_start); + CheckBytesLeft(funcSize); + TRACE_WASM_DECODER(_u("Function body header: index = %u, size = %u"), i, funcSize); + byte* end = m_pc + funcSize; + m_pc = end; + } + return m_pc == m_currentSection.end; +} - UINT32 entryCount = LEB128(len); - m_funcState.count += len; - TRACE_WASM_DECODER(_u("Function body header: index = %u, size = %u"), i, m_funcState.size); +void +WasmBinaryReader::SeekToFunctionBody(FunctionBodyReaderInfo readerInfo) +{ + if (readerInfo.startOffset >= (m_end - m_start)) + { + ThrowDecodingError(_u("Function byte offset out of bounds")); + } + // Seek to the function start and skip function header (count) + m_pc = m_start + readerInfo.startOffset; + m_funcState.size = readerInfo.size; + m_funcState.count = 0; + CheckBytesLeft(readerInfo.size); + m_curFuncEnd = m_pc + m_funcState.size; + + uint32 len = 0; + uint32 entryCount = LEB128(len); + m_funcState.count += len; - // locals - for (UINT32 j = 0; j < entryCount; j++) + WasmFunctionInfo* funcInfo = m_moduleInfo->GetFunSig(readerInfo.index); + if (!funcInfo) + { + ThrowDecodingError(_u("Invalid function index %u"), readerInfo.index); + } + // locals + for (uint32 j = 0; j < entryCount; j++) + { + uint32 count = LEB128(len); + m_funcState.count += len; + Wasm::WasmTypes::WasmType type = ReadWasmType(len); + if (!Wasm::WasmTypes::IsLocalType(type)) { - UINT32 count = LEB128(len); - m_funcState.count += len; - Wasm::WasmTypes::WasmType type = ReadWasmType(len); - if (!Wasm::WasmTypes::IsLocalType(type)) - { - ThrowDecodingError(_u("Invalid local type")); - } - m_funcState.count += len; - m_funcInfo->AddLocal(type, count); - switch (type) - { -#define WASM_LOCALTYPE(token, name) case Wasm::WasmTypes::token: TRACE_WASM_DECODER(_u("Local: type = " #name## ", count = %u"), type, count); break; -#include "WasmKeywords.h" - } + ThrowDecodingError(_u("Invalid local type")); } - bool errorOccurred = !callback(i, callbackdata) || m_funcState.count != m_funcState.size; - if (errorOccurred) + m_funcState.count += len; + funcInfo->AddLocal(type, count); + switch (type) { - if (!PHASE_ON1(Js::WasmLazyTrapPhase)) - { - ThrowDecodingError(_u("Error while processing function #%u"), i); - } - m_pc = end; +#define WASM_LOCALTYPE(token, name) case Wasm::WasmTypes::token: TRACE_WASM_DECODER(_u("Local: type = " #name## ", count = %u"), type, count); break; +#include "WasmKeywords.h" } } - return m_pc == m_currentSection.end; } -WasmOp -WasmBinaryReader::ReadFromBlock() +bool WasmBinaryReader::IsCurrentFunctionCompleted() const { - return GetWasmToken(ASTNode()); -} - -WasmOp -WasmBinaryReader::ReadFromCall() -{ - return GetWasmToken(ASTNode()); + return m_pc == m_curFuncEnd; } WasmOp @@ -419,7 +426,7 @@ WasmBinaryReader::ASTNode() } void -WasmBinaryReader::ModuleHeader() +WasmBinaryReader::ValidateModuleHeader() { uint32 magicNumber = ReadConst(); uint32 version = ReadConst(); @@ -516,7 +523,7 @@ WasmBinaryReader::BrTableNode() m_currentNode.brTable.numTargets = LEB128(len); m_funcState.count += len; - m_currentNode.brTable.targetTable = AnewArray(&m_alloc, UINT32, m_currentNode.brTable.numTargets); + m_currentNode.brTable.targetTable = AnewArray(m_alloc, UINT32, m_currentNode.brTable.numTargets); for (UINT32 i = 0; i < m_currentNode.brTable.numTargets; i++) { @@ -622,11 +629,12 @@ WasmBinaryReader::ReadSignatures() { UINT len = 0; const uint32 count = LEB128(len); + m_moduleInfo->SetSignatureCount(count); // signatures table for (UINT32 i = 0; i < count; i++) { TRACE_WASM_DECODER(_u("Signature #%u"), i); - WasmSignature * sig = Anew(&m_alloc, WasmSignature, &m_alloc); + WasmSignature * sig = Anew(m_alloc, WasmSignature, m_alloc); char form = ReadConst(); if (form != 0x40) @@ -653,7 +661,7 @@ WasmBinaryReader::ReadSignatures() type = ReadWasmType(len); sig->SetResultType(type); } - m_moduleInfo->AddSignature(sig); + m_moduleInfo->SetSignature(i, sig); } } @@ -671,7 +679,8 @@ WasmBinaryReader::ReadFunctionsSignatures() { ThrowDecodingError(_u("Function signature is out of bound")); } - WasmFunctionInfo* newFunction = Anew(&m_alloc, WasmFunctionInfo, &m_alloc); + + WasmFunctionInfo* newFunction = Anew(m_alloc, WasmFunctionInfo, m_alloc); WasmSignature* sig = m_moduleInfo->GetSignature(sigIndex); newFunction->SetSignature(sig); m_moduleInfo->SetFunSig(newFunction, iFunc); @@ -732,7 +741,7 @@ WasmBinaryReader::ReadDataSegments() TRACE_WASM_DECODER(L"Data Segment #%u", i); UINT32 offset = LEB128(len); UINT32 dataByteLen = LEB128(len); - WasmDataSegment *dseg = Anew(&m_alloc, WasmDataSegment, &m_alloc, offset, dataByteLen, m_pc); + WasmDataSegment *dseg = Anew(m_alloc, WasmDataSegment, m_alloc, offset, dataByteLen, m_pc); CheckBytesLeft(dataByteLen); m_pc += dataByteLen; m_moduleInfo->AddDataSeg(dseg, i); @@ -772,7 +781,20 @@ char16* WasmBinaryReader::ReadInlineName(uint32& length, uint32& nameLength) m_pc += nameLength; length += nameLength; - return CvtUtf8Str(&m_alloc, rawName, nameLength); + return CvtUtf8Str(rawName, nameLength); +} + +char16* WasmBinaryReader::CvtUtf8Str(LPUTF8 name, uint32 nameLen) +{ + utf8::DecodeOptions decodeOptions = utf8::doDefault; + charcount_t utf16Len = utf8::ByteIndexIntoCharacterIndex(name, nameLen, decodeOptions); + char16* contents = AnewArray(m_alloc, char16, utf16Len + 1); + if (contents == nullptr) + { + Js::Throw::OutOfMemory(); + } + utf8::DecodeIntoAndNullTerminate((char16*)contents, name, utf16Len, decodeOptions); + return contents; } void @@ -813,40 +835,6 @@ WasmBinaryReader::ReadStartFunction() // 2. Function should be void and nullary } -const char * -WasmBinaryReader::Name(UINT32 offset, UINT &length) -{ - BYTE* str = m_start + offset; - length = 0; - if (offset == 0) - { - return ""; - } - // validate string and get length - do - { - if (str >= m_end) - { - ThrowDecodingError(_u("Offset is out of range")); - } - length++; - } while (*str++); - - return (const char*)(m_start + offset); -} - -UINT -WasmBinaryReader::Offset() -{ - UINT len = 0; - UINT32 offset = LEB128(len); - if (offset > (UINT)(m_end - m_start)) - { - ThrowDecodingError(_u("Offset is out of range")); - } - return offset; -} - UINT WasmBinaryReader::LEB128(UINT &length, bool sgn) { @@ -931,10 +919,9 @@ void WasmBinaryReader::CheckBytesLeft(UINT bytesNeeded) { UINT bytesLeft = (UINT)(m_end - m_pc); - if ( bytesNeeded > bytesLeft) + if (bytesNeeded > bytesLeft) { - Output::Print(_u("Out of file: Needed: %d, Left: %d"), bytesNeeded, bytesLeft); - ThrowDecodingError(_u("Out of file.")); + ThrowDecodingError(_u("Out of file: Needed: %d, Left: %d"), bytesNeeded, bytesLeft); } } diff --git a/lib/WasmReader/WasmBinaryReader.h b/lib/WasmReader/WasmBinaryReader.h index 04abcb62e55..01c0a8e95a7 100644 --- a/lib/WasmReader/WasmBinaryReader.h +++ b/lib/WasmReader/WasmBinaryReader.h @@ -82,47 +82,30 @@ namespace Wasm static const unsigned int experimentalVersion = 0xb; - typedef bool(*FunctionBodyCallback)(uint32 index, void* data); - class WasmBinaryReader { public: - WasmBinaryReader(PageAllocator * alloc, byte* source, size_t length); + WasmBinaryReader(ArenaAllocator* alloc, byte* source, size_t length); static void Init(Js::ScriptContext *scriptContext); void InitializeReader(); bool ReadNextSection(SectionCode nextSection); // Fully read the section in the reader. Return true if the section fully read bool ProcessCurrentSection(); - bool ReadFunctionBodies(FunctionBodyCallback callback, void* callbackdata); - WasmOp ReadFromBlock(); - WasmOp ReadFromCall(); + bool ReadFunctionHeaders(); + void SeekToFunctionBody(FunctionBodyReaderInfo readerInfo); + bool IsCurrentFunctionCompleted() const; WasmOp ReadExpr(); WasmOp GetLastOp(); WasmBinOp GetLastBinOp() const { return m_lastOp; } #if DBG_DUMP void PrintOps(); #endif - // TODO: Move this to somewhere more appropriate and possible make m_alloc part of - // BaseWasmReader state. - char16* CvtUtf8Str(ArenaAllocator* m_alloc, LPUTF8 name, uint32 nameLen) - { - utf8::DecodeOptions decodeOptions = utf8::doDefault; - charcount_t utf16Len = utf8::ByteIndexIntoCharacterIndex(name, nameLen, decodeOptions); - char16* contents = AnewArray(m_alloc, char16, utf16Len + 1); - if (contents == nullptr) - { - Js::Throw::OutOfMemory(); - } - utf8::DecodeIntoAndNullTerminate((char16*)contents, name, utf16Len, decodeOptions); - return contents; - } WasmNode m_currentNode; ModuleInfo * m_moduleInfo; WasmModule * m_module; private: - WasmFunctionInfo * m_funcInfo; struct ReaderState { UINT32 count; // current entry @@ -133,7 +116,6 @@ namespace Wasm WasmOp GetWasmToken(WasmBinOp op); WasmBinOp ASTNode(); - void ModuleHeader(); void CallNode(); void CallIndirectNode(); void CallImportNode(); @@ -141,8 +123,10 @@ namespace Wasm void BrTableNode(); WasmOp MemNode(WasmBinOp op); void VarNode(); - template void ConstNode(); - // readers + + // Module readers + void ValidateModuleHeader(); + SectionHeader ReadSectionHeader(); void ReadMemorySection(); void ReadSignatures(); void ReadFunctionsSignatures(); @@ -151,17 +135,15 @@ namespace Wasm void ReadDataSegments(); void ReadImportEntries(); void ReadStartFunction(); - void ReadNamesSection(); + // Primitive reader + template void ConstNode(); + template T ReadConst(); char16* ReadInlineName(uint32& length, uint32& nameLength); - - const char* Name(UINT32 offset, UINT &length); - UINT32 Offset(); + char16* CvtUtf8Str(LPUTF8 name, uint32 nameLen); UINT LEB128(UINT &length, bool sgn = false); INT SLEB128(UINT &length); - template T ReadConst(); - SectionHeader ReadSectionHeader(); void CheckBytesLeft(UINT bytesNeeded); bool EndOfFunc(); @@ -169,9 +151,9 @@ namespace Wasm DECLSPEC_NORETURN void ThrowDecodingError(const char16* msg, ...); Wasm::WasmTypes::WasmType ReadWasmType(uint32& length); - ArenaAllocator m_alloc; + ArenaAllocator* m_alloc; uint m_funcNumber; - byte *m_start, *m_end, *m_pc; + byte *m_start, *m_end, *m_pc, *m_curFuncEnd; SectionHeader m_currentSection; WasmBinOp m_lastOp; ReaderState m_funcState; // func AST level diff --git a/lib/WasmReader/WasmByteCodeGenerator.cpp b/lib/WasmReader/WasmByteCodeGenerator.cpp index 67a28dd26c1..de3883e6d0c 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.cpp +++ b/lib/WasmReader/WasmByteCodeGenerator.cpp @@ -8,59 +8,101 @@ #ifdef ENABLE_WASM #if DBG_DUMP -#define DebugPrintOp(op) if (PHASE_TRACE(Js::WasmReaderPhase, m_currentFunc->body)) { PrintOpName(op); } +#define DebugPrintOp(op) if (PHASE_TRACE(Js::WasmReaderPhase, m_body)) { PrintOpName(op); } #else #define DebugPrintOp(op) #endif namespace Wasm { -WasmBytecodeGenerator::WasmBytecodeGenerator(Js::ScriptContext * scriptContext, Js::Utf8SourceInfo * sourceInfo, byte* binaryBuffer, uint binaryBufferLength) : - m_scriptContext(scriptContext), - m_sourceInfo(sourceInfo), - m_alloc(_u("WasmBytecodeGen"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory), - m_reader(scriptContext->GetThreadContext()->GetPageAllocator(), binaryBuffer, binaryBufferLength), - m_f32RegSlots(nullptr), - m_f64RegSlots(nullptr), - m_i32RegSlots(nullptr), - m_currentFunc(nullptr), - m_evalStack(&m_alloc), - m_blockInfos(&m_alloc) +#if DBG_DUMP + void + WasmBytecodeGenerator::PrintOpName(WasmOp op) const + { + switch (op) + { +#define WASM_KEYWORD(token, name) \ + case wn##token: \ + Output::Print(_u(#token ## "\r\n")); \ + break; +#include "WasmKeywords.h" + } + } +#endif + +/* static */ +Js::AsmJsRetType + WasmToAsmJs::GetAsmJsReturnType(WasmTypes::WasmType wasmType) { - m_writer.Create(); + switch (wasmType) + { + case WasmTypes::F32: + return Js::AsmJsRetType::Float; + case WasmTypes::F64: + return Js::AsmJsRetType::Double; + case WasmTypes::I32: + return Js::AsmJsRetType::Signed; + case WasmTypes::Void: + return Js::AsmJsRetType::Void; + case WasmTypes::I64: + throw WasmCompilationException(_u("I64 support NYI")); + default: + throw WasmCompilationException(_u("Unknown return type %u"), wasmType); + } +} - // TODO (michhol): try to make this more accurate? - const long astSize = 0; - m_writer.InitData(&m_alloc, astSize); +/* static */ +Js::AsmJsVarType + WasmToAsmJs::GetAsmJsVarType(WasmTypes::WasmType wasmType) +{ + Js::AsmJsVarType asmType = Js::AsmJsVarType::Int; + switch (wasmType) + { + case WasmTypes::F32: + return Js::AsmJsVarType::Float; + case WasmTypes::F64: + return Js::AsmJsVarType::Double; + case WasmTypes::I32: + return Js::AsmJsVarType::Int; + case WasmTypes::I64: + throw WasmCompilationException(_u("I64 support NYI")); + default: + throw WasmCompilationException(_u("Unknown var type %u"), wasmType); + } +} + +typedef bool(*SectionProcessFunc)(WasmModuleGenerator*); +typedef void(*AfterSectionCallback)(WasmModuleGenerator*); + +WasmModuleGenerator::WasmModuleGenerator(Js::ScriptContext * scriptContext, Js::Utf8SourceInfo * sourceInfo, byte* binaryBuffer, uint binaryBufferLength) : + m_sourceInfo(sourceInfo), + m_scriptContext(scriptContext), + m_alloc(scriptContext->GetThreadContext()->GetThreadAlloc()) +{ + m_reader = Anew(m_alloc, Binary::WasmBinaryReader, m_alloc, binaryBuffer, binaryBufferLength); // Initialize maps needed by binary reader Binary::WasmBinaryReader::Init(scriptContext); } -typedef bool(*SectionProcessFunc)(WasmBytecodeGenerator*); -typedef void(*AfterSectionCallback)(WasmBytecodeGenerator*); -WasmModule * -WasmBytecodeGenerator::GenerateModule() +Wasm::WasmModule* WasmModuleGenerator::GenerateModule() { - Js::AutoProfilingPhase parserProfiler(m_scriptContext, Js::WasmParserPhase); - Unused(parserProfiler); - // TODO: can this be in a better place? m_sourceInfo->EnsureInitialized(0); m_sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized(); - m_module = Anew(&m_alloc, WasmModule); - m_module->info = m_reader.m_moduleInfo; + m_module = Anew(m_alloc, WasmModule); + m_module->info = m_reader->m_moduleInfo; m_module->heapOffset = 0; m_module->importFuncOffset = m_module->heapOffset + 1; m_module->funcOffset = m_module->heapOffset + 1; - m_reader.InitializeReader(); - m_reader.m_module = m_module; + m_reader->InitializeReader(); + m_reader->m_module = m_module; - BVFixed* visitedSections = BVFixed::New(bSectLimit + 1, &m_alloc); + BVStatic visitedSections; - const auto readerProcess = [](WasmBytecodeGenerator* gen) { return gen->m_reader.ProcessCurrentSection(); }; + const auto readerProcess = [](WasmModuleGenerator* gen) { return gen->m_reader->ProcessCurrentSection(); }; // By default lest the reader process the section #define WASM_SECTION(name, id, flag, precedent) readerProcess, SectionProcessFunc sectionProcess[bSectLimit + 1] = { @@ -71,43 +113,42 @@ WasmBytecodeGenerator::GenerateModule() // Will callback regardless if the section is present or not AfterSectionCallback afterSectionCallback[bSectLimit + 1] = {}; - afterSectionCallback[bSectFunctionSignatures] = [](WasmBytecodeGenerator* gen) { + afterSectionCallback[bSectFunctionSignatures] = [](WasmModuleGenerator* gen) { gen->m_module->funcOffset = gen->m_module->importFuncOffset + gen->m_module->info->GetImportCount(); }; - afterSectionCallback[bSectIndirectFunctionTable] = [](WasmBytecodeGenerator* gen) { + afterSectionCallback[bSectIndirectFunctionTable] = [](WasmModuleGenerator* gen) { gen->m_module->indirFuncTableOffset = gen->m_module->funcOffset + gen->m_module->info->GetFunctionCount(); }; - sectionProcess[bSectFunctionBodies] = [](WasmBytecodeGenerator* gen) { - gen->m_module->funcCount = gen->m_module->info->GetFunctionCount(); - gen->m_module->functions = AnewArrayZ(&gen->m_alloc, WasmFunction*, gen->m_module->funcCount); - if (PHASE_ON1(Js::WasmLazyTrapPhase)) + sectionProcess[bSectFunctionBodies] = [](WasmModuleGenerator* gen) { + uint32 funcCount = gen->m_module->info->GetFunctionCount(); + gen->m_module->funcCount = funcCount; + gen->m_module->functions = AnewArrayZ(gen->m_alloc, WasmFunction*, funcCount); + if (!gen->m_reader->ReadFunctionHeaders()) { - gen->m_module->lazyTraps = AnewArrayZ(&gen->m_alloc, WasmCompilationException*, gen->m_module->funcCount); + return false; } - return gen->m_reader.ReadFunctionBodies([](uint32 index, void* g) { - WasmBytecodeGenerator* gen = (WasmBytecodeGenerator*)g; - if (index >= gen->m_module->funcCount) { - return false; - } - WasmFunction* fn = gen->GenerateFunction(); - gen->m_module->functions[index] = fn; - return true; - }, gen); + + for (uint32 i = 0; i < funcCount; ++i) + { + WasmFunction* fn = gen->GenerateFunctionHeader(i); + gen->m_module->functions[i] = fn; + } + return true; }; for (SectionCode sectionCode = (SectionCode)(bSectInvalid + 1); sectionCode < bSectLimit ; sectionCode = (SectionCode)(sectionCode + 1)) { SectionCode precedent = SectionInfo::All[sectionCode].precedent; - if (m_reader.ReadNextSection((SectionCode)sectionCode)) + if (m_reader->ReadNextSection((SectionCode)sectionCode)) { - if (precedent != bSectInvalid && !visitedSections->Test(precedent)) + if (precedent != bSectInvalid && !visitedSections.Test(precedent)) { throw WasmCompilationException(_u("%s section missing before %s"), SectionInfo::All[precedent].name, SectionInfo::All[sectionCode].name); } - visitedSections->Set(sectionCode); + visitedSections.Set(sectionCode); if (!sectionProcess[sectionCode](this)) { @@ -124,11 +165,11 @@ WasmBytecodeGenerator::GenerateModule() #if DBG_DUMP if (PHASE_TRACE1(Js::WasmReaderPhase)) { - m_reader.PrintOps(); + m_reader->PrintOps(); } #endif // If we see a FunctionSignatures section we need to see a FunctionBodies section - if (visitedSections->Test(bSectFunctionSignatures) && !visitedSections->Test(bSectFunctionBodies)) + if (visitedSections.Test(bSectFunctionSignatures) && !visitedSections.Test(bSectFunctionBodies)) { throw WasmCompilationException(_u("Missing required section: %s"), SectionInfo::All[bSectFunctionBodies].name); } @@ -138,24 +179,16 @@ WasmBytecodeGenerator::GenerateModule() return m_module; } -WasmFunction * -WasmBytecodeGenerator::GenerateFunction() +Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) { - Js::AutoProfilingPhase bytecodeProfiler(m_scriptContext, Js::WasmBytecodePhase); - Unused(bytecodeProfiler); - - WasmFunctionInfo* wasmInfo = m_reader.m_currentNode.func.info; - TRACE_WASM_DECODER(_u("GenerateFunction %u \n"), wasmInfo->GetNumber()); - - WasmRegisterSpace f32Space(ReservedRegisterCount); - WasmRegisterSpace f64Space(ReservedRegisterCount); - WasmRegisterSpace i32Space(ReservedRegisterCount); - - m_f32RegSlots = &f32Space; - m_f64RegSlots = &f64Space; - m_i32RegSlots = &i32Space; + TRACE_WASM_DECODER(_u("GenerateFunction %u \n"), index); + WasmFunctionInfo* wasmInfo = m_module->info->GetFunSig(index); + if (!wasmInfo) + { + throw WasmCompilationException(_u("Invalid function index %u"), index); + } - m_currentFunc = Anew(&m_alloc, WasmFunction); + WasmFunction* func = Anew(m_alloc, WasmFunction); char16* functionName = nullptr; int nameLength = 0; @@ -181,7 +214,7 @@ WasmBytecodeGenerator::GenerateFunction() nameLength = swprintf_s(functionName, 32, _u("wasm-function[%u]"), wasmInfo->GetNumber()); } - m_currentFunc->body = Js::FunctionBody::NewFromRecycler( + Js::FunctionBody* body = func->body = Js::FunctionBody::NewFromRecycler( m_scriptContext, functionName, nameLength, @@ -195,187 +228,210 @@ WasmBytecodeGenerator::GenerateFunction() #ifdef PERF_COUNTERS , false /* is function from deferred deserialized proxy */ #endif - ); + ); // TODO (michhol): numbering - m_currentFunc->body->SetSourceInfo(0); - m_currentFunc->body->AllocateAsmJsFunctionInfo(); - m_currentFunc->body->SetIsAsmJsFunction(true); - m_currentFunc->body->SetIsAsmjsMode(true); - m_currentFunc->body->SetIsWasmFunction(true); - m_currentFunc->body->GetAsmJsFunctionInfo()->SetIsHeapBufferConst(true); - m_funcInfo = wasmInfo; - m_currentFunc->wasmInfo = m_funcInfo; - m_nestedIfLevel = 0; - m_maxArgOutDepth = 0; + body->SetSourceInfo(0); + body->AllocateAsmJsFunctionInfo(); + body->SetIsAsmJsFunction(true); + body->SetIsAsmjsMode(true); + body->SetIsWasmFunction(true); + body->GetAsmJsFunctionInfo()->SetIsHeapBufferConst(true); + + WasmReaderInfo* readerInfo = Anew(m_alloc, WasmReaderInfo); + readerInfo->m_reader = m_reader; + readerInfo->m_funcInfo = wasmInfo; + readerInfo->m_module = m_module; + + Js::AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo(); + info->SetWasmReaderInfo(readerInfo); - Assert(m_evalStack.Empty()); - // The stack should always be empty when starting a new function, make sure by clearing it in case we missed something - m_evalStack.Clear(); + if (wasmInfo->GetParamCount() >= Js::Constants::InvalidArgSlot) + { + Js::Throw::OutOfMemory(); + } + Js::ArgSlot paramCount = (Js::ArgSlot)wasmInfo->GetParamCount(); + info->SetArgCount(paramCount); - // TODO: fix these bools - m_writer.Begin(m_currentFunc->body, &m_alloc, true, true, false); - try + Js::ArgSlot argSizeLength = max(paramCount, 3ui16); + info->SetArgSizeArrayLength(argSizeLength); + uint* argSizeArray = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), uint, argSizeLength); + info->SetArgsSizesArray(argSizeArray); + + if (m_module->memSize > 0) { - try + info->SetUsesHeapBuffer(true); + } + if (paramCount > 0) + { + body->SetHasImplicitArgIns(true); + body->SetInParamsCount(paramCount + 1); + body->SetReportedInParamsCount(paramCount + 1); + info->SetArgTypeArray(RecyclerNewArrayLeaf(m_scriptContext->GetRecycler(), Js::AsmJsVarType::Which, paramCount)); + } + Js::ArgSlot paramSize = 0; + for (Js::ArgSlot i = 0; i < paramCount; ++i) + { + WasmTypes::WasmType type = wasmInfo->GetParam(i); + info->SetArgType(WasmToAsmJs::GetAsmJsVarType(type), i); + uint16 size = 0; + switch (type) { - if (PHASE_OFF(Js::WasmBytecodePhase, m_currentFunc->body) && PHASE_ON1(Js::WasmLazyTrapPhase)) - { - throw WasmCompilationException(_u("Compilation skipped")); - } - m_funcInfo->SetExitLabel(m_writer.DefineLabel()); - EnregisterLocals(); + case WasmTypes::F32: + case WasmTypes::I32: + CompileAssert(sizeof(float) == sizeof(int32)); +#ifdef _M_X64 + // on x64, we always alloc (at least) 8 bytes per arguments + size = sizeof(void*); +#elif _M_IX86 + size = sizeof(int32); +#else + Assert(UNREACHED); +#endif + break; + case WasmTypes::F64: + case WasmTypes::I64: + CompileAssert(sizeof(double) == sizeof(int64)); + size = sizeof(int64); + break; + default: + Assume(UNREACHED); + } + argSizeArray[i] = size; + // REVIEW: reduce number of checked adds + paramSize = UInt16Math::Add(paramSize, size); + } + info->SetArgByteSize(paramSize); + info->SetReturnType(WasmToAsmJs::GetAsmJsReturnType(wasmInfo->GetResultType())); - Js::AutoProfilingPhase functionProfiler(m_scriptContext, Js::WasmFunctionBodyPhase); - Unused(functionProfiler); + return func; +} - WasmOp op = wnLIMIT; - EmitInfo exprInfo; - EnterEvalStackScope(); - while ((op = m_reader.ReadExpr()) != wnFUNC_END) - { - exprInfo = EmitExpr(op); - } - DebugPrintOp(op); - // Functions are like blocks. Emit implicit return of last stmt/expr, unless it is a return or end of file (sexpr). - Wasm::WasmTypes::WasmType returnType = m_funcInfo->GetSignature()->GetResultType(); +WasmBytecodeGenerator::WasmBytecodeGenerator(Js::ScriptContext* scriptContext, Js::FunctionBody* body, WasmReaderInfo* readerInfo) : + m_scriptContext(scriptContext), + m_alloc(_u("WasmBytecodeGen"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory), + m_evalStack(&m_alloc), + m_i32RegSlots(ReservedRegisterCount), + m_f32RegSlots(ReservedRegisterCount), + m_f64RegSlots(ReservedRegisterCount), + m_blockInfos(&m_alloc), + m_body(body) +{ + m_writer.Create(); + // Init reader to current func offset + m_reader = readerInfo->m_reader; + m_reader->SeekToFunctionBody(readerInfo->m_funcInfo->m_readerInfo); + m_funcInfo = readerInfo->m_funcInfo; + m_module = readerInfo->m_module; + + // Use binary size to estimate bytecode size + const long astSize = readerInfo->m_funcInfo->m_readerInfo.size; + m_writer.InitData(&m_alloc, astSize); +} - // If the last expression yielded a value, return it - if (exprInfo.type != WasmTypes::Unreachable) - { - if (exprInfo.type != returnType && returnType != Wasm::WasmTypes::Void) - { - throw WasmCompilationException(_u("Last expression return type mismatch return type")); - } - uint32 arity = 0; - if (returnType != Wasm::WasmTypes::Void) - { - arity = 1; - } - m_reader.m_currentNode.ret.arity = arity; - EmitReturnExpr(); - } - ExitEvalStackScope(); - } - catch (...) - { - m_writer.Reset(); - throw; - } - m_writer.MarkAsmJsLabel(m_funcInfo->GetExitLabel()); - m_writer.EmptyAsm(Js::OpCodeAsmJs::Ret); +void +WasmBytecodeGenerator::GenerateFunctionBytecode(Js::ScriptContext* scriptContext, Js::FunctionBody* body, WasmReaderInfo* readerinfo) +{ + WasmBytecodeGenerator generator(scriptContext, body, readerinfo); + generator.GenerateFunction(); + if (!generator.m_reader->IsCurrentFunctionCompleted()) + { + throw WasmCompilationException(_u("Invalid function format")); + } +} - m_writer.End(); -#if DBG_DUMP - if (PHASE_DUMP(Js::ByteCodePhase, m_currentFunc->body)) - { - Js::AsmJsByteCodeDumper::DumpBasic(m_currentFunc->body); - } -#endif +void +WasmBytecodeGenerator::GenerateFunction() +{ + if (PHASE_OFF(Js::WasmBytecodePhase, m_body)) + { + throw WasmCompilationException(_u("Compilation skipped")); + } + Js::AutoProfilingPhase functionProfiler(m_scriptContext, Js::WasmFunctionBodyPhase); + Unused(functionProfiler); - // TODO: refactor out to separate procedure - Js::AsmJsFunctionInfo * info = m_currentFunc->body->GetAsmJsFunctionInfo(); - if (m_funcInfo->GetParamCount() >= Js::Constants::InvalidArgSlot) - { - Js::Throw::OutOfMemory(); - } - Js::ArgSlot paramCount = (Js::ArgSlot)m_funcInfo->GetParamCount(); - info->SetArgCount(paramCount); + m_maxArgOutDepth = 0; - Js::ArgSlot argSizeLength = max(paramCount, 3ui16); - info->SetArgSizeArrayLength(argSizeLength); - uint* argSizeArray = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), uint, argSizeLength); - info->SetArgsSizesArray(argSizeArray); + // TODO: fix these bools + m_writer.Begin(m_body, &m_alloc, true, true, false); + try + { + m_funcInfo->SetExitLabel(m_writer.DefineLabel()); + EnregisterLocals(); - if (m_module->memSize > 0) + WasmOp op = wnLIMIT; + EmitInfo exprInfo; + EnterEvalStackScope(); + while ((op = m_reader->ReadExpr()) != wnFUNC_END) { - info->SetUsesHeapBuffer(true); + exprInfo = EmitExpr(op); } - if (paramCount > 0) - { - m_currentFunc->body->SetHasImplicitArgIns(true); - m_currentFunc->body->SetInParamsCount(paramCount + 1); - m_currentFunc->body->SetReportedInParamsCount(paramCount + 1); - info->SetArgTypeArray(RecyclerNewArrayLeaf(m_scriptContext->GetRecycler(), Js::AsmJsVarType::Which, paramCount)); - } - Js::ArgSlot paramSize = 0; - for (Js::ArgSlot i = 0; i < paramCount; ++i) + DebugPrintOp(op); + // Functions are like blocks. Emit implicit return of last stmt/expr, unless it is a return or end of file (sexpr). + Wasm::WasmTypes::WasmType returnType = m_funcInfo->GetSignature()->GetResultType(); + + // If the last expression yielded a value, return it + if (exprInfo.type != WasmTypes::Unreachable) { - WasmTypes::WasmType type = m_funcInfo->GetParam(i); - info->SetArgType(GetAsmJsVarType(type), i); - uint16 size = 0; - switch (type) + if (exprInfo.type != returnType && returnType != Wasm::WasmTypes::Void) { - case WasmTypes::F32: - case WasmTypes::I32: - CompileAssert(sizeof(float) == sizeof(int32)); -#ifdef _M_X64 - // on x64, we always alloc (at least) 8 bytes per arguments - size = sizeof(void*); -#elif _M_IX86 - size = sizeof(int32); -#else - Assert(UNREACHED); -#endif - break; - case WasmTypes::F64: - case WasmTypes::I64: - CompileAssert(sizeof(double) == sizeof(int64)); - size = sizeof(int64); - break; - default: - Assume(UNREACHED); + throw WasmCompilationException(_u("Last expression return type mismatch return type")); + } + uint32 arity = 0; + if (returnType != Wasm::WasmTypes::Void) + { + arity = 1; } - argSizeArray[i] = size; - // REVIEW: reduce number of checked adds - paramSize = UInt16Math::Add(paramSize, size); + m_reader->m_currentNode.ret.arity = arity; + EmitReturnExpr(); } - info->SetArgByteSize(paramSize); + ExitEvalStackScope(); + } + catch (...) + { + m_writer.Reset(); + throw; + } + m_writer.MarkAsmJsLabel(m_funcInfo->GetExitLabel()); + m_writer.EmptyAsm(Js::OpCodeAsmJs::Ret); - info->SetIntVarCount(m_i32RegSlots->GetVarCount()); - info->SetFloatVarCount(m_f32RegSlots->GetVarCount()); - info->SetDoubleVarCount(m_f64RegSlots->GetVarCount()); + m_writer.End(); - info->SetIntTmpCount(m_i32RegSlots->GetTmpCount()); - info->SetFloatTmpCount(m_f32RegSlots->GetTmpCount()); - info->SetDoubleTmpCount(m_f64RegSlots->GetTmpCount()); +#if DBG_DUMP + if (PHASE_DUMP(Js::ByteCodePhase, m_body)) + { + Js::AsmJsByteCodeDumper::DumpBasic(m_body); + } +#endif - info->SetIntConstCount(ReservedRegisterCount); - info->SetFloatConstCount(ReservedRegisterCount); - info->SetDoubleConstCount(ReservedRegisterCount); + Js::AsmJsFunctionInfo * info = m_body->GetAsmJsFunctionInfo(); + info->SetIntVarCount(m_i32RegSlots.GetVarCount()); + info->SetFloatVarCount(m_f32RegSlots.GetVarCount()); + info->SetDoubleVarCount(m_f64RegSlots.GetVarCount()); - int nbConst = - ((info->GetDoubleConstCount() + 1) * sizeof(double)) // space required - + (int)((info->GetFloatConstCount() + 1) * sizeof(float) + 0.5 /*ceil*/) - + (int)((info->GetIntConstCount() + 1) * sizeof(int) + 0.5/*ceil*/) // - + Js::AsmJsFunctionMemory::RequiredVarConstants; + info->SetIntTmpCount(m_i32RegSlots.GetTmpCount()); + info->SetFloatTmpCount(m_f32RegSlots.GetTmpCount()); + info->SetDoubleTmpCount(m_f64RegSlots.GetTmpCount()); - m_currentFunc->body->CheckAndSetConstantCount(nbConst); + info->SetIntConstCount(ReservedRegisterCount); + info->SetFloatConstCount(ReservedRegisterCount); + info->SetDoubleConstCount(ReservedRegisterCount); - info->SetReturnType(GetAsmJsReturnType(m_funcInfo->GetResultType())); + int nbConst = + ((info->GetDoubleConstCount() + 1) * sizeof(double)) // space required + + (int)((info->GetFloatConstCount() + 1) * sizeof(float) + 0.5 /*ceil*/) + + (int)((info->GetIntConstCount() + 1) * sizeof(int) + 0.5/*ceil*/) // + + Js::AsmJsFunctionMemory::RequiredVarConstants; - // REVIEW: overflow checks? - info->SetIntByteOffset(ReservedRegisterCount * sizeof(Js::Var)); - info->SetFloatByteOffset(info->GetIntByteOffset() + m_i32RegSlots->GetRegisterCount() * sizeof(int32)); - info->SetDoubleByteOffset(Math::Align(info->GetFloatByteOffset() + m_f32RegSlots->GetRegisterCount() * sizeof(float), sizeof(double))); + m_body->CheckAndSetConstantCount(nbConst); - m_currentFunc->body->SetOutParamMaxDepth(m_maxArgOutDepth); - m_currentFunc->body->SetVarCount(m_f32RegSlots->GetRegisterCount() + m_f64RegSlots->GetRegisterCount() + m_i32RegSlots->GetRegisterCount()); - } - catch (WasmCompilationException& ex) - { - if (!PHASE_ON1(Js::WasmLazyTrapPhase)) - { - throw WasmCompilationException(_u("function %s: %s"), functionName, ex.GetErrorMessage()); - } + // REVIEW: overflow checks? + info->SetIntByteOffset(ReservedRegisterCount * sizeof(Js::Var)); + info->SetFloatByteOffset(info->GetIntByteOffset() + m_i32RegSlots.GetRegisterCount() * sizeof(int32)); + info->SetDoubleByteOffset(Math::Align(info->GetFloatByteOffset() + m_f32RegSlots.GetRegisterCount() * sizeof(float), sizeof(double))); - // Since we will continue compilation for other functions, clear the eval stack - m_evalStack.Clear(); - Assert(m_module->lazyTraps != nullptr); - WasmCompilationException* lazyTrap = Anew(&m_alloc, WasmCompilationException, _u("(delayed) function %s: %s"), functionName, ex.GetErrorMessage()); - m_module->lazyTraps[wasmInfo->GetNumber()] = lazyTrap; - } - return m_currentFunc; + m_body->SetOutParamMaxDepth(m_maxArgOutDepth); + m_body->SetVarCount(m_f32RegSlots.GetRegisterCount() + m_f64RegSlots.GetRegisterCount() + m_i32RegSlots.GetRegisterCount()); } void @@ -415,21 +471,6 @@ WasmBytecodeGenerator::EnregisterLocals() } } -#if DBG_DUMP -void -WasmBytecodeGenerator::PrintOpName(WasmOp op) const -{ - switch (op) - { -#define WASM_KEYWORD(token, name) \ - case wn##token: \ - Output::Print(_u(#token ## "\r\n")); \ - break; -#include "WasmKeywords.h" - } -} -#endif - EmitInfo WasmBytecodeGenerator::EmitExpr(WasmOp op) { @@ -512,7 +553,7 @@ WasmBytecodeGenerator::EmitExpr(WasmOp op) break; #include "WasmKeywords.h" case wnNYI: - switch (m_reader.GetLastBinOp()) + switch (m_reader->GetLastBinOp()) { #define WASM_OPCODE(opname, opcode, token, sig) \ case opcode: \ @@ -532,12 +573,12 @@ WasmBytecodeGenerator::EmitExpr(WasmOp op) EmitInfo WasmBytecodeGenerator::EmitGetLocal() { - if (m_funcInfo->GetLocalCount() < m_reader.m_currentNode.var.num) + if (m_funcInfo->GetLocalCount() < m_reader->m_currentNode.var.num) { - throw WasmCompilationException(_u("%u is not a valid local"), m_reader.m_currentNode.var.num); + throw WasmCompilationException(_u("%u is not a valid local"), m_reader->m_currentNode.var.num); } - WasmLocal local = m_locals[m_reader.m_currentNode.var.num]; + WasmLocal local = m_locals[m_reader->m_currentNode.var.num]; Js::OpCodeAsmJs op = GetLoadOp(local.type); WasmRegisterSpace * regSpace = GetRegisterSpace(local.type); @@ -552,7 +593,7 @@ WasmBytecodeGenerator::EmitGetLocal() EmitInfo WasmBytecodeGenerator::EmitSetLocal() { - uint localNum = m_reader.m_currentNode.var.num; + uint localNum = m_reader->m_currentNode.var.num; if (localNum >= m_funcInfo->GetLocalCount()) { throw WasmCompilationException(_u("%u is not a valid local"), localNum); @@ -582,13 +623,13 @@ WasmBytecodeGenerator::EmitConst() switch (type) { case WasmTypes::F32: - m_writer.AsmFloat1Const1(Js::OpCodeAsmJs::Ld_FltConst, tmpReg, m_reader.m_currentNode.cnst.f32); + m_writer.AsmFloat1Const1(Js::OpCodeAsmJs::Ld_FltConst, tmpReg, m_reader->m_currentNode.cnst.f32); break; case WasmTypes::F64: - m_writer.AsmDouble1Const1(Js::OpCodeAsmJs::Ld_DbConst, tmpReg, m_reader.m_currentNode.cnst.f64); + m_writer.AsmDouble1Const1(Js::OpCodeAsmJs::Ld_DbConst, tmpReg, m_reader->m_currentNode.cnst.f64); break; case WasmTypes::I32: - m_writer.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, tmpReg, m_reader.m_currentNode.cnst.i32); + m_writer.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, tmpReg, m_reader->m_currentNode.cnst.i32); break; default: throw WasmCompilationException(_u("Unknown type %u"), type); @@ -603,7 +644,7 @@ WasmBytecodeGenerator::EmitBlockCommon() WasmOp op; EmitInfo blockInfo; EnterEvalStackScope(); - while ((op = m_reader.ReadFromBlock()) != wnEND && op != wnELSE) + while ((op = m_reader->ReadExpr()) != wnEND && op != wnELSE) { blockInfo = EmitExpr(op); } @@ -665,7 +706,7 @@ WasmBytecodeGenerator::EmitCall() switch (wasmOp) { case wnCALL: - funcNum = m_reader.m_currentNode.call.num; + funcNum = m_reader->m_currentNode.call.num; if (funcNum >= m_module->info->GetFunctionCount()) { throw WasmCompilationException(_u("Call is to unknown function")); @@ -674,7 +715,7 @@ WasmBytecodeGenerator::EmitCall() break; case wnCALL_IMPORT: { - funcNum = m_reader.m_currentNode.call.num; + funcNum = m_reader->m_currentNode.call.num; if (funcNum >= m_module->info->GetImportCount()) { throw WasmCompilationException(L"Call is to unknown function"); @@ -684,7 +725,7 @@ WasmBytecodeGenerator::EmitCall() break; } case wnCALL_INDIRECT: - signatureId = m_reader.m_currentNode.call.num; + signatureId = m_reader->m_currentNode.call.num; calleeSignature = m_module->info->GetSignature(signatureId); break; default: @@ -714,7 +755,7 @@ WasmBytecodeGenerator::EmitCall() m_writer.AsmStartCall(startCallOp, argSize); - if (calleeSignature->GetParamCount() != m_reader.m_currentNode.call.arity) + if (calleeSignature->GetParamCount() != m_reader->m_currentNode.call.arity) { throw WasmCompilationException(_u("Mismatch between call signature and arity")); } @@ -803,7 +844,7 @@ WasmBytecodeGenerator::EmitCall() callOp = Js::OpCodeAsmJs::I_Call; } - m_writer.AsmCall(callOp, 0, 0, args, GetAsmJsReturnType(calleeSignature->GetResultType())); + m_writer.AsmCall(callOp, 0, 0, args, WasmToAsmJs::GetAsmJsReturnType(calleeSignature->GetResultType())); // emit result coercion EmitInfo retInfo; @@ -814,15 +855,15 @@ WasmBytecodeGenerator::EmitCall() switch (retInfo.type) { case WasmTypes::F32: - retInfo.location = m_f32RegSlots->AcquireTmpRegister(); + retInfo.location = m_f32RegSlots.AcquireTmpRegister(); convertOp = wasmOp == wnCALL_IMPORT ? Js::OpCodeAsmJs::Conv_VTF : Js::OpCodeAsmJs::I_Conv_VTF; break; case WasmTypes::F64: - retInfo.location = m_f64RegSlots->AcquireTmpRegister(); + retInfo.location = m_f64RegSlots.AcquireTmpRegister(); convertOp = wasmOp == wnCALL_IMPORT ? Js::OpCodeAsmJs::Conv_VTD : Js::OpCodeAsmJs::I_Conv_VTD; break; case WasmTypes::I32: - retInfo.location = m_i32RegSlots->AcquireTmpRegister(); + retInfo.location = m_i32RegSlots.AcquireTmpRegister(); convertOp = wasmOp == wnCALL_IMPORT ? Js::OpCodeAsmJs::Conv_VTI : Js::OpCodeAsmJs::I_Conv_VTI; break; case WasmTypes::I64: @@ -848,14 +889,6 @@ WasmBytecodeGenerator::EmitCall() EmitInfo WasmBytecodeGenerator::EmitIfElseExpr() { - ++m_nestedIfLevel; - - if (m_nestedIfLevel == 0) - { - // overflow - Js::Throw::OutOfMemory(); - } - EmitInfo checkExpr = PopEvalStack(); if (checkExpr.type != WasmTypes::I32) @@ -869,7 +902,7 @@ WasmBytecodeGenerator::EmitIfElseExpr() m_writer.AsmBrReg1(Js::OpCodeAsmJs::BrFalse_Int, falseLabel, checkExpr.location); - m_i32RegSlots->ReleaseLocation(&checkExpr); + m_i32RegSlots.ReleaseLocation(&checkExpr); EmitInfo trueExpr = EmitBlock(); @@ -877,14 +910,14 @@ WasmBytecodeGenerator::EmitIfElseExpr() m_writer.MarkAsmJsLabel(falseLabel); - WasmOp op = m_reader.GetLastOp(); // wnEND or wnELSE + WasmOp op = m_reader->GetLastOp(); // wnEND or wnELSE EmitInfo retInfo; EmitInfo falseExpr; if (op == wnELSE) { falseExpr = EmitBlock(); // Read END - op = m_reader.GetLastOp(); + op = m_reader->GetLastOp(); } if (!WasmTypes::IsLocalType(trueExpr.type) || falseExpr.type != trueExpr.type) @@ -910,19 +943,16 @@ WasmBytecodeGenerator::EmitIfElseExpr() m_writer.MarkAsmJsLabel(endLabel); - Assert(m_nestedIfLevel > 0); - --m_nestedIfLevel; - return retInfo; } EmitInfo WasmBytecodeGenerator::EmitBrTable() { - const uint arity = m_reader.m_currentNode.brTable.arity; - const uint numTargets = m_reader.m_currentNode.brTable.numTargets; - const UINT* targetTable = m_reader.m_currentNode.brTable.targetTable; - const UINT defaultEntry = m_reader.m_currentNode.brTable.defaultTarget; + const uint arity = m_reader->m_currentNode.brTable.arity; + const uint numTargets = m_reader->m_currentNode.brTable.numTargets; + const UINT* targetTable = m_reader->m_currentNode.brTable.targetTable; + const UINT defaultEntry = m_reader->m_currentNode.brTable.defaultTarget; // Compile scrutinee EmitInfo scrutineeInfo = PopEvalStack(); @@ -1004,8 +1034,8 @@ template EmitInfo WasmBytecodeGenerator::EmitMemRead() { - const uint offset = m_reader.m_currentNode.mem.offset; - m_currentFunc->body->GetAsmJsFunctionInfo()->SetUsesHeapBuffer(true); + const uint offset = m_reader->m_currentNode.mem.offset; + m_body->GetAsmJsFunctionInfo()->SetUsesHeapBuffer(true); EmitInfo exprInfo = PopEvalStack(); @@ -1015,13 +1045,13 @@ WasmBytecodeGenerator::EmitMemRead() } if (offset != 0) { - Js::RegSlot tempReg = m_i32RegSlots->AcquireTmpRegister(); + Js::RegSlot tempReg = m_i32RegSlots.AcquireTmpRegister(); m_writer.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, tempReg, offset); m_writer.AsmReg3(Js::OpCodeAsmJs::Add_Int, exprInfo.location, exprInfo.location, tempReg); - m_i32RegSlots->ReleaseTmpRegister(tempReg); + m_i32RegSlots.ReleaseTmpRegister(tempReg); } - m_i32RegSlots->ReleaseLocation(&exprInfo); + m_i32RegSlots.ReleaseLocation(&exprInfo); Js::RegSlot resultReg = GetRegisterSpace(type)->AcquireTmpRegister(); m_writer.AsmTypedArr(Js::OpCodeAsmJs::LdArr, resultReg, exprInfo.location, GetViewType(wasmOp)); @@ -1033,8 +1063,8 @@ template EmitInfo WasmBytecodeGenerator::EmitMemStore() { - const uint offset = m_reader.m_currentNode.mem.offset; - m_currentFunc->body->GetAsmJsFunctionInfo()->SetUsesHeapBuffer(true); + const uint offset = m_reader->m_currentNode.mem.offset; + m_body->GetAsmJsFunctionInfo()->SetUsesHeapBuffer(true); // TODO (michhol): combine with MemRead EmitInfo rhsInfo = PopEvalStack(); @@ -1046,11 +1076,11 @@ WasmBytecodeGenerator::EmitMemStore() } if (offset != 0) { - Js::RegSlot indexReg = m_i32RegSlots->AcquireTmpRegister(); + Js::RegSlot indexReg = m_i32RegSlots.AcquireTmpRegister(); m_writer.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, indexReg, offset); m_writer.AsmReg3(Js::OpCodeAsmJs::Add_Int, exprInfo.location, exprInfo.location, indexReg); - m_i32RegSlots->ReleaseTmpRegister(indexReg); + m_i32RegSlots.ReleaseTmpRegister(indexReg); } if (rhsInfo.type != type) { @@ -1070,26 +1100,12 @@ WasmBytecodeGenerator::EmitMemStore() return EmitInfo(retLoc, type); } -template -Js::RegSlot -WasmBytecodeGenerator::GetConstReg(T constVal) -{ - Js::RegSlot location = m_funcInfo->GetConst(constVal); - if (location == Js::Constants::NoRegister) - { - WasmRegisterSpace * regSpace = GetRegisterSpace(m_reader.m_currentNode.type); - location = regSpace->AcquireConstRegister(); - m_funcInfo->AddConst(constVal, location); - } - return location; -} - EmitInfo WasmBytecodeGenerator::EmitReturnExpr() { if (m_funcInfo->GetResultType() == WasmTypes::Void) { - if (m_reader.m_currentNode.ret.arity != 0) + if (m_reader->m_currentNode.ret.arity != 0) { throw WasmCompilationException(_u("Nonzero arity for return op in void function")); } @@ -1098,7 +1114,7 @@ WasmBytecodeGenerator::EmitReturnExpr() } else { - if (m_reader.m_currentNode.ret.arity != 1) + if (m_reader->m_currentNode.ret.arity != 1) { throw WasmCompilationException(_u("Unexpected arity for return op")); } @@ -1172,8 +1188,8 @@ template EmitInfo WasmBytecodeGenerator::EmitBr() { - UINT depth = m_reader.m_currentNode.br.depth; - bool hasSubExpr = m_reader.m_currentNode.br.hasSubExpr; + UINT depth = m_reader->m_currentNode.br.depth; + bool hasSubExpr = m_reader->m_currentNode.br.hasSubExpr; EmitInfo conditionInfo; if (wasmOp == WasmOp::wnBR_IF) @@ -1202,54 +1218,13 @@ WasmBytecodeGenerator::EmitBr() { Assert(wasmOp == WasmOp::wnBR_IF); m_writer.AsmBrReg1(Js::OpCodeAsmJs::BrTrue_Int, target, conditionInfo.location); - m_i32RegSlots->ReleaseLocation(&conditionInfo); + m_i32RegSlots.ReleaseLocation(&conditionInfo); } ReleaseLocation(&info); return EmitInfo(WasmTypes::Unreachable); } -/* static */ -Js::AsmJsRetType -WasmBytecodeGenerator::GetAsmJsReturnType(WasmTypes::WasmType wasmType) -{ - switch (wasmType) - { - case WasmTypes::F32: - return Js::AsmJsRetType::Float; - case WasmTypes::F64: - return Js::AsmJsRetType::Double; - case WasmTypes::I32: - return Js::AsmJsRetType::Signed; - case WasmTypes::Void: - return Js::AsmJsRetType::Void; - case WasmTypes::I64: - throw WasmCompilationException(_u("I64 support NYI")); - default: - throw WasmCompilationException(_u("Unknown return type %u"), wasmType); - } -} - -/* static */ -Js::AsmJsVarType -WasmBytecodeGenerator::GetAsmJsVarType(WasmTypes::WasmType wasmType) -{ - Js::AsmJsVarType asmType = Js::AsmJsVarType::Int; - switch (wasmType) - { - case WasmTypes::F32: - return Js::AsmJsVarType::Float; - case WasmTypes::F64: - return Js::AsmJsVarType::Double; - case WasmTypes::I32: - return Js::AsmJsVarType::Int; - case WasmTypes::I64: - throw WasmCompilationException(_u("I64 support NYI")); - default: - throw WasmCompilationException(_u("Unknown var type %u"), wasmType); - } -} - /* static */ Js::OpCodeAsmJs WasmBytecodeGenerator::GetLoadOp(WasmTypes::WasmType wasmType) @@ -1418,16 +1393,16 @@ WasmBytecodeGenerator::GetLabel(uint relativeDepth) } WasmRegisterSpace * -WasmBytecodeGenerator::GetRegisterSpace(WasmTypes::WasmType type) const +WasmBytecodeGenerator::GetRegisterSpace(WasmTypes::WasmType type) { switch (type) { case WasmTypes::F32: - return m_f32RegSlots; + return &m_f32RegSlots; case WasmTypes::F64: - return m_f64RegSlots; + return &m_f64RegSlots; case WasmTypes::I32: - return m_i32RegSlots; + return &m_i32RegSlots; case WasmTypes::I64: throw WasmCompilationException(_u("I64 support NYI")); default: diff --git a/lib/WasmReader/WasmByteCodeGenerator.h b/lib/WasmReader/WasmByteCodeGenerator.h index 190b1dbdf4f..b4b6dc5ff5d 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.h +++ b/lib/WasmReader/WasmByteCodeGenerator.h @@ -39,6 +39,13 @@ namespace Wasm WasmTypes::WasmType type; }; + class WasmToAsmJs + { + public: + static Js::AsmJsRetType GetAsmJsReturnType(WasmTypes::WasmType wasmType); + static Js::AsmJsVarType GetAsmJsVarType(WasmTypes::WasmType wasmType); + }; + class WasmCompilationException { void FormatError(const char16* _msg, va_list arglist); @@ -81,6 +88,27 @@ namespace Wasm typedef JsUtil::BaseDictionary WasmExportDictionary; + struct WasmReaderInfo + { + Binary::WasmBinaryReader* m_reader; + WasmFunctionInfo* m_funcInfo; + WasmModule* m_module; + }; + + class WasmModuleGenerator + { + public: + WasmModuleGenerator(Js::ScriptContext * scriptContext, Js::Utf8SourceInfo * sourceInfo, byte* binaryBuffer, uint binaryBufferLength); + WasmModule * GenerateModule(); + WasmFunction * GenerateFunctionHeader(uint32 index); + private: + ArenaAllocator* m_alloc; + Js::Utf8SourceInfo * m_sourceInfo; + Js::ScriptContext * m_scriptContext; + Binary::WasmBinaryReader* m_reader; + WasmModule * m_module; + }; + class WasmBytecodeGenerator { public: @@ -95,11 +123,11 @@ namespace Wasm static const Js::RegSlot ScriptContextBufferRegister = 4; static const Js::RegSlot ReservedRegisterCount = 5; - WasmBytecodeGenerator(Js::ScriptContext * scriptContext, Js::Utf8SourceInfo * sourceInfo, byte* binaryBuffer, uint binaryBufferLength); - WasmModule * GenerateModule(); - WasmFunction * GenerateFunction(); + WasmBytecodeGenerator(Js::ScriptContext* scriptContext, Js::FunctionBody* body, WasmReaderInfo* readerinfo); + static void GenerateFunctionBytecode(Js::ScriptContext* scriptContext, Js::FunctionBody* body, WasmReaderInfo* readerinfo); private: + void GenerateFunction(); EmitInfo EmitExpr(WasmOp op); EmitInfo EmitBlock(); @@ -144,14 +172,9 @@ namespace Wasm BlockInfo GetBlockInfo(uint relativeDepth); Js::ByteCodeLabel GetLabel(uint relativeDepth); - template - Js::RegSlot GetConstReg(T constVal); - - static Js::AsmJsRetType GetAsmJsReturnType(WasmTypes::WasmType wasmType); - static Js::AsmJsVarType GetAsmJsVarType(WasmTypes::WasmType wasmType); static Js::ArrayBufferView::ViewType GetViewType(WasmOp op); static Js::OpCodeAsmJs GetLoadOp(WasmTypes::WasmType type); - WasmRegisterSpace * GetRegisterSpace(WasmTypes::WasmType type) const; + WasmRegisterSpace * GetRegisterSpace(WasmTypes::WasmType type); EmitInfo PopEvalStack(); void PushEvalStack(EmitInfo); @@ -163,21 +186,19 @@ namespace Wasm WasmLocal * m_locals; WasmFunctionInfo * m_funcInfo; - WasmFunction * m_currentFunc; + Js::FunctionBody * m_body; WasmModule * m_module; - uint m_nestedIfLevel; uint m_maxArgOutDepth; - Binary::WasmBinaryReader m_reader; + Binary::WasmBinaryReader* m_reader; Js::AsmJsByteCodeWriter m_writer; Js::ScriptContext * m_scriptContext; - Js::Utf8SourceInfo * m_sourceInfo; - WasmRegisterSpace * m_i32RegSlots; - WasmRegisterSpace * m_f32RegSlots; - WasmRegisterSpace * m_f64RegSlots; + WasmRegisterSpace m_i32RegSlots; + WasmRegisterSpace m_f32RegSlots; + WasmRegisterSpace m_f64RegSlots; JsUtil::Stack m_blockInfos; JsUtil::Stack m_evalStack; diff --git a/lib/WasmReader/WasmFunctionInfo.cpp b/lib/WasmReader/WasmFunctionInfo.cpp index ec52713f461..fc4536731ca 100644 --- a/lib/WasmReader/WasmFunctionInfo.cpp +++ b/lib/WasmReader/WasmFunctionInfo.cpp @@ -12,13 +12,8 @@ namespace Wasm WasmFunctionInfo::WasmFunctionInfo(ArenaAllocator * alloc) : m_alloc(alloc), - m_name(nullptr), - m_mod(nullptr) + m_name(nullptr) { - m_i32Consts = Anew(m_alloc, ConstMap, m_alloc); - m_i64Consts = Anew(m_alloc, ConstMap, m_alloc); - m_f32Consts = Anew(m_alloc, ConstMap, m_alloc); - m_f64Consts = Anew(m_alloc, ConstMap, m_alloc); m_locals = Anew(m_alloc, WasmTypeArray, m_alloc, 0); } @@ -31,38 +26,6 @@ WasmFunctionInfo::AddLocal(WasmTypes::WasmType type, uint count) } } -template<> -void -WasmFunctionInfo::AddConst(int32 constVal, Js::RegSlot reg) -{ - int result = m_i32Consts->Add(constVal, reg); - Assert(result != -1); // REVIEW: should always succeed (or at least throw OOM)? -} - -template<> -void -WasmFunctionInfo::AddConst(int64 constVal, Js::RegSlot reg) -{ - int result = m_i64Consts->Add(constVal, reg); - Assert(result != -1); -} - -template<> -void -WasmFunctionInfo::AddConst(float constVal, Js::RegSlot reg) -{ - int result = m_f32Consts->Add(constVal, reg); - Assert(result != -1); -} - -template<> -void -WasmFunctionInfo::AddConst(double constVal, Js::RegSlot reg) -{ - int result = m_f64Consts->Add(constVal, reg); - Assert(result != -1); -} - WasmTypes::WasmType WasmFunctionInfo::GetLocal(uint index) const { @@ -79,34 +42,6 @@ WasmFunctionInfo::GetParam(uint index) const return m_signature->GetParam(index); } -template<> -Js::RegSlot -WasmFunctionInfo::GetConst(int32 constVal) const -{ - return m_i32Consts->Lookup(constVal, Js::Constants::NoRegister); -} - -template<> -Js::RegSlot -WasmFunctionInfo::GetConst(int64 constVal) const -{ - return m_i64Consts->Lookup(constVal, Js::Constants::NoRegister); -} - -template<> -Js::RegSlot -WasmFunctionInfo::GetConst(float constVal) const -{ - return m_f32Consts->Lookup(constVal, Js::Constants::NoRegister); -} - -template<> -Js::RegSlot -WasmFunctionInfo::GetConst(double constVal) const -{ - return m_f64Consts->Lookup(constVal, Js::Constants::NoRegister); -} - WasmTypes::WasmType WasmFunctionInfo::GetResultType() const { @@ -137,18 +72,6 @@ WasmFunctionInfo::GetName() const return m_name; } -void -WasmFunctionInfo::SetModuleName(char16* name) -{ - m_mod = name; -} - -char16* -WasmFunctionInfo::GetModuleName() const -{ - return m_mod; -} - void WasmFunctionInfo::SetNumber(UINT32 number) { diff --git a/lib/WasmReader/WasmFunctionInfo.h b/lib/WasmReader/WasmFunctionInfo.h index 41666b82bf5..7b4aa653a90 100644 --- a/lib/WasmReader/WasmFunctionInfo.h +++ b/lib/WasmReader/WasmFunctionInfo.h @@ -7,17 +7,22 @@ namespace Wasm { + struct FunctionBodyReaderInfo + { + uint32 index; + uint32 size; + intptr_t startOffset; + }; + class WasmFunctionInfo { public: WasmFunctionInfo(ArenaAllocator * alloc); void AddLocal(WasmTypes::WasmType type, uint count = 1); - template void AddConst(T constVal, Js::RegSlot reg); WasmTypes::WasmType GetLocal(uint index) const; WasmTypes::WasmType GetParam(uint index) const; - template Js::RegSlot GetConst(T constVal) const; WasmTypes::WasmType GetResultType() const; uint32 GetLocalCount() const; @@ -25,8 +30,6 @@ namespace Wasm void SetName(char16* name); char16* GetName() const; - void SetModuleName(char16* name); - char16* GetModuleName() const; void SetNumber(UINT32 number); UINT32 GetNumber() const; @@ -39,23 +42,14 @@ namespace Wasm void SetLocalName(uint i, char16* n); char16* GetLocalName(uint i); + FunctionBodyReaderInfo m_readerInfo; private: - - // TODO: need custom comparator so -0 != 0 - template - using ConstMap = JsUtil::BaseDictionary; - ConstMap * m_i32Consts; - ConstMap * m_i64Consts; - ConstMap * m_f32Consts; - ConstMap * m_f64Consts; - WasmTypeArray * m_locals; ArenaAllocator * m_alloc; WasmSignature * m_signature; Js::ByteCodeLabel m_ExitLabel; char16* m_name; - char16* m_mod; // imported module UINT32 m_number; }; @@ -66,6 +60,5 @@ namespace Wasm { } Js::FunctionBody * body; - WasmFunctionInfo * wasmInfo; }; } // namespace Wasm diff --git a/lib/WasmReader/WasmParseTree.h b/lib/WasmReader/WasmParseTree.h index 72d82966475..8c443f3f840 100644 --- a/lib/WasmReader/WasmParseTree.h +++ b/lib/WasmReader/WasmParseTree.h @@ -30,11 +30,6 @@ namespace Wasm wnNYI }; - struct WasmFuncNode - { - WasmFunctionInfo * info; - }; - struct WasmConstLitNode { union @@ -94,7 +89,6 @@ namespace Wasm { WasmVarNode var; WasmConstLitNode cnst; - WasmFuncNode func; WasmBrNode br; WasmBrTableNode brTable; WasmMemOpNode mem; From d8cedc0f20063b90c1a81b42b04e3f3825d7c424 Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Tue, 19 Jul 2016 17:20:48 -0700 Subject: [PATCH 3/6] Do a recycler allocation instead of using the ThreadContext arena. Create a new ArenaAllocator on the WasmBinaryReader that has the same lifetime as the reader --- lib/WasmReader/WasmBinaryReader.cpp | 26 +++++++++---------- lib/WasmReader/WasmBinaryReader.h | 4 +-- lib/WasmReader/WasmByteCodeGenerator.cpp | 32 ++++++++++++------------ lib/WasmReader/WasmByteCodeGenerator.h | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/WasmReader/WasmBinaryReader.cpp b/lib/WasmReader/WasmBinaryReader.cpp index 09d217586b1..a1c65c14c55 100644 --- a/lib/WasmReader/WasmBinaryReader.cpp +++ b/lib/WasmReader/WasmBinaryReader.cpp @@ -12,7 +12,7 @@ namespace Wasm { namespace WasmTypes { - bool IsLocalType(WasmTypes::WasmType type) + bool IsLocalType(WasmTypes::WasmType type) { // Check if type in range ]Void,Limit[ return (uint)(type - 1) < (WasmTypes::Limit - 1); @@ -49,18 +49,18 @@ Signature::Signature(ArenaAllocator *alloc, uint count, ...) } } // namespace WasmTypes -WasmBinaryReader::WasmBinaryReader(ArenaAllocator* alloc, byte* source, size_t length) : - m_alloc(alloc), +WasmBinaryReader::WasmBinaryReader(Js::ScriptContext* scriptContext, byte* source, size_t length) : m_curFuncEnd(nullptr), - m_lastOp(WasmBinOp::wbLimit) + m_lastOp(WasmBinOp::wbLimit), + m_alloc(_u("WasmBytecodeGen"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory) { - m_moduleInfo = Anew(m_alloc, ModuleInfo, m_alloc); + m_moduleInfo = Anew(&m_alloc, ModuleInfo, &m_alloc); m_start = m_pc = source; m_end = source + length; m_currentSection.code = bSectInvalid; #if DBG_DUMP - m_ops = Anew(m_alloc, OpSet, m_alloc); + m_ops = Anew(&m_alloc, OpSet, &m_alloc); #endif } @@ -301,7 +301,7 @@ WasmBinaryReader::SeekToFunctionBody(FunctionBodyReaderInfo readerInfo) m_funcState.count += len; WasmFunctionInfo* funcInfo = m_moduleInfo->GetFunSig(readerInfo.index); - if (!funcInfo) + if (!funcInfo) { ThrowDecodingError(_u("Invalid function index %u"), readerInfo.index); } @@ -317,7 +317,7 @@ WasmBinaryReader::SeekToFunctionBody(FunctionBodyReaderInfo readerInfo) } m_funcState.count += len; funcInfo->AddLocal(type, count); - switch (type) + switch (type) { #define WASM_LOCALTYPE(token, name) case Wasm::WasmTypes::token: TRACE_WASM_DECODER(_u("Local: type = " #name## ", count = %u"), type, count); break; #include "WasmKeywords.h" @@ -523,7 +523,7 @@ WasmBinaryReader::BrTableNode() m_currentNode.brTable.numTargets = LEB128(len); m_funcState.count += len; - m_currentNode.brTable.targetTable = AnewArray(m_alloc, UINT32, m_currentNode.brTable.numTargets); + m_currentNode.brTable.targetTable = AnewArray(&m_alloc, UINT32, m_currentNode.brTable.numTargets); for (UINT32 i = 0; i < m_currentNode.brTable.numTargets; i++) { @@ -634,7 +634,7 @@ WasmBinaryReader::ReadSignatures() for (UINT32 i = 0; i < count; i++) { TRACE_WASM_DECODER(_u("Signature #%u"), i); - WasmSignature * sig = Anew(m_alloc, WasmSignature, m_alloc); + WasmSignature * sig = Anew(&m_alloc, WasmSignature, &m_alloc); char form = ReadConst(); if (form != 0x40) @@ -680,7 +680,7 @@ WasmBinaryReader::ReadFunctionsSignatures() ThrowDecodingError(_u("Function signature is out of bound")); } - WasmFunctionInfo* newFunction = Anew(m_alloc, WasmFunctionInfo, m_alloc); + WasmFunctionInfo* newFunction = Anew(&m_alloc, WasmFunctionInfo, &m_alloc); WasmSignature* sig = m_moduleInfo->GetSignature(sigIndex); newFunction->SetSignature(sig); m_moduleInfo->SetFunSig(newFunction, iFunc); @@ -741,7 +741,7 @@ WasmBinaryReader::ReadDataSegments() TRACE_WASM_DECODER(L"Data Segment #%u", i); UINT32 offset = LEB128(len); UINT32 dataByteLen = LEB128(len); - WasmDataSegment *dseg = Anew(m_alloc, WasmDataSegment, m_alloc, offset, dataByteLen, m_pc); + WasmDataSegment *dseg = Anew(&m_alloc, WasmDataSegment, &m_alloc, offset, dataByteLen, m_pc); CheckBytesLeft(dataByteLen); m_pc += dataByteLen; m_moduleInfo->AddDataSeg(dseg, i); @@ -788,7 +788,7 @@ char16* WasmBinaryReader::CvtUtf8Str(LPUTF8 name, uint32 nameLen) { utf8::DecodeOptions decodeOptions = utf8::doDefault; charcount_t utf16Len = utf8::ByteIndexIntoCharacterIndex(name, nameLen, decodeOptions); - char16* contents = AnewArray(m_alloc, char16, utf16Len + 1); + char16* contents = AnewArray(&m_alloc, char16, utf16Len + 1); if (contents == nullptr) { Js::Throw::OutOfMemory(); diff --git a/lib/WasmReader/WasmBinaryReader.h b/lib/WasmReader/WasmBinaryReader.h index 01c0a8e95a7..9df217a50b7 100644 --- a/lib/WasmReader/WasmBinaryReader.h +++ b/lib/WasmReader/WasmBinaryReader.h @@ -85,7 +85,7 @@ namespace Wasm class WasmBinaryReader { public: - WasmBinaryReader(ArenaAllocator* alloc, byte* source, size_t length); + WasmBinaryReader(Js::ScriptContext* scriptContext, byte* source, size_t length); static void Init(Js::ScriptContext *scriptContext); void InitializeReader(); @@ -151,7 +151,7 @@ namespace Wasm DECLSPEC_NORETURN void ThrowDecodingError(const char16* msg, ...); Wasm::WasmTypes::WasmType ReadWasmType(uint32& length); - ArenaAllocator* m_alloc; + ArenaAllocator m_alloc; uint m_funcNumber; byte *m_start, *m_end, *m_pc, *m_curFuncEnd; SectionHeader m_currentSection; diff --git a/lib/WasmReader/WasmByteCodeGenerator.cpp b/lib/WasmReader/WasmByteCodeGenerator.cpp index de3883e6d0c..863b05234b3 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.cpp +++ b/lib/WasmReader/WasmByteCodeGenerator.cpp @@ -77,9 +77,9 @@ typedef void(*AfterSectionCallback)(WasmModuleGenerator*); WasmModuleGenerator::WasmModuleGenerator(Js::ScriptContext * scriptContext, Js::Utf8SourceInfo * sourceInfo, byte* binaryBuffer, uint binaryBufferLength) : m_sourceInfo(sourceInfo), m_scriptContext(scriptContext), - m_alloc(scriptContext->GetThreadContext()->GetThreadAlloc()) + m_recycler(scriptContext->GetRecycler()) { - m_reader = Anew(m_alloc, Binary::WasmBinaryReader, m_alloc, binaryBuffer, binaryBufferLength); + m_reader = RecyclerNew(m_recycler, Binary::WasmBinaryReader, scriptContext, binaryBuffer, binaryBufferLength); // Initialize maps needed by binary reader Binary::WasmBinaryReader::Init(scriptContext); @@ -91,7 +91,7 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() m_sourceInfo->EnsureInitialized(0); m_sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized(); - m_module = Anew(m_alloc, WasmModule); + m_module = RecyclerNew(m_recycler, WasmModule); m_module->info = m_reader->m_moduleInfo; m_module->heapOffset = 0; m_module->importFuncOffset = m_module->heapOffset + 1; @@ -123,8 +123,8 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() sectionProcess[bSectFunctionBodies] = [](WasmModuleGenerator* gen) { uint32 funcCount = gen->m_module->info->GetFunctionCount(); gen->m_module->funcCount = funcCount; - gen->m_module->functions = AnewArrayZ(gen->m_alloc, WasmFunction*, funcCount); - if (!gen->m_reader->ReadFunctionHeaders()) + gen->m_module->functions = RecyclerNewArrayZ(gen->m_recycler, WasmFunction*, funcCount); + if (!gen->m_reader->ReadFunctionHeaders()) { return false; } @@ -188,7 +188,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) throw WasmCompilationException(_u("Invalid function index %u"), index); } - WasmFunction* func = Anew(m_alloc, WasmFunction); + WasmFunction* func = RecyclerNew(m_recycler, WasmFunction); char16* functionName = nullptr; int nameLength = 0; @@ -237,11 +237,11 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) body->SetIsWasmFunction(true); body->GetAsmJsFunctionInfo()->SetIsHeapBufferConst(true); - WasmReaderInfo* readerInfo = Anew(m_alloc, WasmReaderInfo); + WasmReaderInfo* readerInfo = RecyclerNew(m_recycler, WasmReaderInfo); readerInfo->m_reader = m_reader; readerInfo->m_funcInfo = wasmInfo; readerInfo->m_module = m_module; - + Js::AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo(); info->SetWasmReaderInfo(readerInfo); @@ -328,7 +328,7 @@ WasmBytecodeGenerator::WasmBytecodeGenerator(Js::ScriptContext* scriptContext, J m_writer.InitData(&m_alloc, astSize); } -void +void WasmBytecodeGenerator::GenerateFunctionBytecode(Js::ScriptContext* scriptContext, Js::FunctionBody* body, WasmReaderInfo* readerinfo) { WasmBytecodeGenerator generator(scriptContext, body, readerinfo); @@ -443,7 +443,7 @@ WasmBytecodeGenerator::EnregisterLocals() { WasmTypes::WasmType type = m_funcInfo->GetLocal(i); WasmRegisterSpace * regSpace = GetRegisterSpace(type); - if (regSpace == nullptr) + if (regSpace == nullptr) { throw WasmCompilationException(_u("Unable to find local register space")); } @@ -773,7 +773,7 @@ WasmBytecodeGenerator::EmitCall() switch (info.type) { case WasmTypes::F32: - if (wasmOp == wnCALL_IMPORT) + if (wasmOp == wnCALL_IMPORT) { throw WasmCompilationException(_u("External calls with float argument NYI")); } @@ -796,7 +796,7 @@ WasmBytecodeGenerator::EmitCall() throw WasmCompilationException(_u("Unknown argument type %u"), info.type); } argsBytesLeft -= wasmOp == wnCALL_IMPORT ? sizeof(Js::Var) : calleeSignature->GetParamSize(i); - if (argsBytesLeft < 0 || (argsBytesLeft % sizeof(Js::Var)) != 0) + if (argsBytesLeft < 0 || (argsBytesLeft % sizeof(Js::Var)) != 0) { throw WasmCompilationException(_u("Error while emitting call arguments")); } @@ -915,7 +915,7 @@ WasmBytecodeGenerator::EmitIfElseExpr() EmitInfo falseExpr; if (op == wnELSE) { - falseExpr = EmitBlock(); + falseExpr = EmitBlock(); // Read END op = m_reader->GetLastOp(); } @@ -963,7 +963,7 @@ WasmBytecodeGenerator::EmitBrTable() m_writer.AsmReg2(Js::OpCodeAsmJs::BeginSwitch_Int, scrutineeInfo.location, scrutineeInfo.location); EmitInfo yieldInfo; - if (arity == 1) + if (arity == 1) { yieldInfo = PopEvalStack(); } @@ -1319,7 +1319,7 @@ WasmBytecodeGenerator::PopLabel(Js::ByteCodeLabel labelValidation) yieldEmitInfo.location = yieldInfo->yieldLocs[yieldInfo->type]; yieldEmitInfo.type = yieldInfo->type; } - else + else { yieldEmitInfo.type = yieldInfo->type == WasmTypes::Limit ? WasmTypes::Unreachable : WasmTypes::Void; yieldEmitInfo.location = Js::Constants::NoRegister; @@ -1359,7 +1359,7 @@ WasmBytecodeGenerator::YieldToBlock(uint relativeDepth, EmitInfo expr) { return; } - + // If the type differs on any path, do not yield. // This will introduce some dead code on the first paths that tried to Yield a valid type if ( diff --git a/lib/WasmReader/WasmByteCodeGenerator.h b/lib/WasmReader/WasmByteCodeGenerator.h index b4b6dc5ff5d..659aad0fc46 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.h +++ b/lib/WasmReader/WasmByteCodeGenerator.h @@ -102,7 +102,7 @@ namespace Wasm WasmModule * GenerateModule(); WasmFunction * GenerateFunctionHeader(uint32 index); private: - ArenaAllocator* m_alloc; + Memory::Recycler* m_recycler; Js::Utf8SourceInfo * m_sourceInfo; Js::ScriptContext * m_scriptContext; Binary::WasmBinaryReader* m_reader; From 16925594dcfed3b5510a08675792477196fff83b Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Tue, 19 Jul 2016 19:01:17 -0700 Subject: [PATCH 4/6] Use RecyclerNewLeaf --- lib/WasmReader/WasmByteCodeGenerator.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/WasmReader/WasmByteCodeGenerator.cpp b/lib/WasmReader/WasmByteCodeGenerator.cpp index 863b05234b3..7a10a071d9d 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.cpp +++ b/lib/WasmReader/WasmByteCodeGenerator.cpp @@ -79,7 +79,7 @@ WasmModuleGenerator::WasmModuleGenerator(Js::ScriptContext * scriptContext, Js:: m_scriptContext(scriptContext), m_recycler(scriptContext->GetRecycler()) { - m_reader = RecyclerNew(m_recycler, Binary::WasmBinaryReader, scriptContext, binaryBuffer, binaryBufferLength); + m_reader = RecyclerNewLeaf(m_recycler, Binary::WasmBinaryReader, scriptContext, binaryBuffer, binaryBufferLength); // Initialize maps needed by binary reader Binary::WasmBinaryReader::Init(scriptContext); @@ -91,7 +91,7 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() m_sourceInfo->EnsureInitialized(0); m_sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized(); - m_module = RecyclerNew(m_recycler, WasmModule); + m_module = RecyclerNewLeaf(m_recycler, WasmModule); m_module->info = m_reader->m_moduleInfo; m_module->heapOffset = 0; m_module->importFuncOffset = m_module->heapOffset + 1; @@ -123,7 +123,7 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() sectionProcess[bSectFunctionBodies] = [](WasmModuleGenerator* gen) { uint32 funcCount = gen->m_module->info->GetFunctionCount(); gen->m_module->funcCount = funcCount; - gen->m_module->functions = RecyclerNewArrayZ(gen->m_recycler, WasmFunction*, funcCount); + gen->m_module->functions = RecyclerNewArrayLeafZ(gen->m_recycler, WasmFunction*, funcCount); if (!gen->m_reader->ReadFunctionHeaders()) { return false; @@ -188,7 +188,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) throw WasmCompilationException(_u("Invalid function index %u"), index); } - WasmFunction* func = RecyclerNew(m_recycler, WasmFunction); + WasmFunction* func = RecyclerNewLeaf(m_recycler, WasmFunction); char16* functionName = nullptr; int nameLength = 0; @@ -201,7 +201,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) if (funcIndex == wasmInfo->GetNumber()) { nameLength = funcExport->nameLength + 16; - functionName = RecyclerNewArrayZ(m_scriptContext->GetRecycler(), char16, nameLength); + functionName = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), char16, nameLength); nameLength = swprintf_s(functionName, nameLength, _u("%s[%u]"), funcExport->name, wasmInfo->GetNumber()); break; } @@ -210,7 +210,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) if (!functionName) { - functionName = RecyclerNewArrayZ(m_scriptContext->GetRecycler(), char16, 32); + functionName = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), char16, 32); nameLength = swprintf_s(functionName, 32, _u("wasm-function[%u]"), wasmInfo->GetNumber()); } @@ -237,7 +237,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) body->SetIsWasmFunction(true); body->GetAsmJsFunctionInfo()->SetIsHeapBufferConst(true); - WasmReaderInfo* readerInfo = RecyclerNew(m_recycler, WasmReaderInfo); + WasmReaderInfo* readerInfo = RecyclerNewLeaf(m_recycler, WasmReaderInfo); readerInfo->m_reader = m_reader; readerInfo->m_funcInfo = wasmInfo; readerInfo->m_module = m_module; @@ -254,7 +254,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) Js::ArgSlot argSizeLength = max(paramCount, 3ui16); info->SetArgSizeArrayLength(argSizeLength); - uint* argSizeArray = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), uint, argSizeLength); + uint* argSizeArray = RecyclerNewArrayLeafZ(m_recycler, uint, argSizeLength); info->SetArgsSizesArray(argSizeArray); if (m_module->memSize > 0) From 6430604accf4f3e9ab42ab8947bea4b99aa8670e Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Tue, 19 Jul 2016 19:07:31 -0700 Subject: [PATCH 5/6] Fix bug in CrossSite --- lib/Runtime/Base/CrossSite.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Runtime/Base/CrossSite.cpp b/lib/Runtime/Base/CrossSite.cpp index bdfb45d2b4d..adf2e814730 100644 --- a/lib/Runtime/Base/CrossSite.cpp +++ b/lib/Runtime/Base/CrossSite.cpp @@ -309,7 +309,8 @@ namespace Js if (funcInfo->GetFunctionProxy()->IsFunctionBody() && funcInfo->GetFunctionBody()->GetIsAsmJsFunction()) { - if (((AsmJsFunctionInfo*)funcInfo)->IsWasmDeferredParse()) + AsmJsFunctionInfo* asmInfo = funcInfo->GetFunctionBody()->GetAsmJsFunctionInfo(); + if (asmInfo && asmInfo->IsWasmDeferredParse()) { entryPoint = ScriptContext::WasmDeferredParseExternalThunk; } From 58f32dde3f66f55463f03a74f0dd1466bc564f34 Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Wed, 20 Jul 2016 15:42:06 -0700 Subject: [PATCH 6/6] Revert "Use RecyclerNewLeaf" This reverts commit 16925594dcfed3b5510a08675792477196fff83b. --- lib/WasmReader/WasmByteCodeGenerator.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/WasmReader/WasmByteCodeGenerator.cpp b/lib/WasmReader/WasmByteCodeGenerator.cpp index 7a10a071d9d..8463c316a4a 100644 --- a/lib/WasmReader/WasmByteCodeGenerator.cpp +++ b/lib/WasmReader/WasmByteCodeGenerator.cpp @@ -79,7 +79,7 @@ WasmModuleGenerator::WasmModuleGenerator(Js::ScriptContext * scriptContext, Js:: m_scriptContext(scriptContext), m_recycler(scriptContext->GetRecycler()) { - m_reader = RecyclerNewLeaf(m_recycler, Binary::WasmBinaryReader, scriptContext, binaryBuffer, binaryBufferLength); + m_reader = RecyclerNew(m_recycler, Binary::WasmBinaryReader, scriptContext, binaryBuffer, binaryBufferLength); // Initialize maps needed by binary reader Binary::WasmBinaryReader::Init(scriptContext); @@ -91,7 +91,7 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() m_sourceInfo->EnsureInitialized(0); m_sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized(); - m_module = RecyclerNewLeaf(m_recycler, WasmModule); + m_module = RecyclerNew(m_recycler, WasmModule); m_module->info = m_reader->m_moduleInfo; m_module->heapOffset = 0; m_module->importFuncOffset = m_module->heapOffset + 1; @@ -123,7 +123,7 @@ Wasm::WasmModule* WasmModuleGenerator::GenerateModule() sectionProcess[bSectFunctionBodies] = [](WasmModuleGenerator* gen) { uint32 funcCount = gen->m_module->info->GetFunctionCount(); gen->m_module->funcCount = funcCount; - gen->m_module->functions = RecyclerNewArrayLeafZ(gen->m_recycler, WasmFunction*, funcCount); + gen->m_module->functions = RecyclerNewArrayZ(gen->m_recycler, WasmFunction*, funcCount); if (!gen->m_reader->ReadFunctionHeaders()) { return false; @@ -188,7 +188,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) throw WasmCompilationException(_u("Invalid function index %u"), index); } - WasmFunction* func = RecyclerNewLeaf(m_recycler, WasmFunction); + WasmFunction* func = RecyclerNew(m_recycler, WasmFunction); char16* functionName = nullptr; int nameLength = 0; @@ -237,7 +237,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) body->SetIsWasmFunction(true); body->GetAsmJsFunctionInfo()->SetIsHeapBufferConst(true); - WasmReaderInfo* readerInfo = RecyclerNewLeaf(m_recycler, WasmReaderInfo); + WasmReaderInfo* readerInfo = RecyclerNew(m_recycler, WasmReaderInfo); readerInfo->m_reader = m_reader; readerInfo->m_funcInfo = wasmInfo; readerInfo->m_module = m_module; @@ -254,7 +254,7 @@ Wasm::WasmFunction * WasmModuleGenerator::GenerateFunctionHeader(uint32 index) Js::ArgSlot argSizeLength = max(paramCount, 3ui16); info->SetArgSizeArrayLength(argSizeLength); - uint* argSizeArray = RecyclerNewArrayLeafZ(m_recycler, uint, argSizeLength); + uint* argSizeArray = RecyclerNewArrayLeafZ(m_scriptContext->GetRecycler(), uint, argSizeLength); info->SetArgsSizesArray(argSizeArray); if (m_module->memSize > 0)