Browse Source

Always use AsmJsDefault entrypoint instead of a wasm deferred parse entry point

Michael Ferris 7 years ago
parent
commit
26833effbb

+ 5 - 4
lib/Backend/NativeCodeGenerator.cpp

@@ -1567,8 +1567,7 @@ NativeCodeGenerator::GetCheckCodeGenFunction(Js::JavascriptMethod codeAddress)
     return nullptr;
     return nullptr;
 }
 }
 
 
-
-Js::Var
+Js::JavascriptMethod
 NativeCodeGenerator::CheckAsmJsCodeGen(Js::ScriptFunction * function)
 NativeCodeGenerator::CheckAsmJsCodeGen(Js::ScriptFunction * function)
 {
 {
     Assert(function);
     Assert(function);
@@ -1579,6 +1578,7 @@ NativeCodeGenerator::CheckAsmJsCodeGen(Js::ScriptFunction * function)
     Assert(scriptContext->GetThreadContext()->IsScriptActive());
     Assert(scriptContext->GetThreadContext()->IsScriptActive());
     Assert(scriptContext->GetThreadContext()->IsInScript());
     Assert(scriptContext->GetThreadContext()->IsInScript());
 
 
+    AssertOrFailFastMsg(!functionBody->IsWasmFunction() || functionBody->GetByteCodeCount() > 0, "Wasm function should be parsed by now");
     // Load the entry point here to validate it got changed afterwards
     // Load the entry point here to validate it got changed afterwards
 
 
     Js::FunctionEntryPointInfo* entryPoint = function->GetFunctionEntryPointInfo();
     Js::FunctionEntryPointInfo* entryPoint = function->GetFunctionEntryPointInfo();
@@ -1595,16 +1595,17 @@ NativeCodeGenerator::CheckAsmJsCodeGen(Js::ScriptFunction * function)
         {
         {
             Output::Print(_u("Codegen not done yet for function: %s, Entrypoint is CheckAsmJsCodeGenThunk\n"), function->GetFunctionBody()->GetDisplayName());
             Output::Print(_u("Codegen not done yet for function: %s, Entrypoint is CheckAsmJsCodeGenThunk\n"), function->GetFunctionBody()->GetDisplayName());
         }
         }
-        return reinterpret_cast<Js::Var>(functionBody->GetOriginalEntryPoint());
+        return functionBody->GetOriginalEntryPoint();
     }
     }
     if (PHASE_TRACE1(Js::AsmjsEntryPointInfoPhase))
     if (PHASE_TRACE1(Js::AsmjsEntryPointInfoPhase))
     {
     {
         Output::Print(_u("CodeGen Done for function: %s, Changing Entrypoint to Full JIT\n"), function->GetFunctionBody()->GetDisplayName());
         Output::Print(_u("CodeGen Done for function: %s, Changing Entrypoint to Full JIT\n"), function->GetFunctionBody()->GetDisplayName());
     }
     }
     // we will need to set the functionbody external and asmjs entrypoint to the fulljit entrypoint
     // we will need to set the functionbody external and asmjs entrypoint to the fulljit entrypoint
-    return reinterpret_cast<Js::Var>(CheckCodeGenDone(functionBody, entryPoint, function));
+    return CheckCodeGenDone(functionBody, entryPoint, function);
 }
 }
 
 
+
 Js::JavascriptMethod
 Js::JavascriptMethod
 NativeCodeGenerator::CheckCodeGen(Js::ScriptFunction * function)
 NativeCodeGenerator::CheckCodeGen(Js::ScriptFunction * function)
 {
 {

+ 1 - 1
lib/Backend/NativeCodeGenerator.h

@@ -59,7 +59,7 @@ public:
     static bool IsAsmJsCodeGenThunk(Js::JavascriptMethod codeAddress);
     static bool IsAsmJsCodeGenThunk(Js::JavascriptMethod codeAddress);
     static CheckCodeGenFunction GetCheckCodeGenFunction(Js::JavascriptMethod codeAddress);
     static CheckCodeGenFunction GetCheckCodeGenFunction(Js::JavascriptMethod codeAddress);
     static Js::JavascriptMethod CheckCodeGen(Js::ScriptFunction * function);
     static Js::JavascriptMethod CheckCodeGen(Js::ScriptFunction * function);
-    static Js::Var CheckAsmJsCodeGen(Js::ScriptFunction * function);
+    static Js::JavascriptMethod CheckAsmJsCodeGen(Js::ScriptFunction * function);
 
 
 public:
 public:
     static void Jit_TransitionFromSimpleJit(void *const framePointer);
     static void Jit_TransitionFromSimpleJit(void *const framePointer);

+ 2 - 5
lib/Backend/amd64/Thunks.asm

@@ -61,7 +61,7 @@ endif
 ;; NativeCodeGenerator::CheckAsmJsCodeGenThunk
 ;; NativeCodeGenerator::CheckAsmJsCodeGenThunk
 ;;============================================================================================================
 ;;============================================================================================================
 
 
-extrn ?CheckAsmJsCodeGen@NativeCodeGenerator@@SAPEAXPEAVScriptFunction@Js@@@Z : PROC
+extrn ?CheckAsmJsCodeGen@NativeCodeGenerator@@SAP6APEAXPEAVRecyclableObject@Js@@UCallInfo@3@ZZPEAVScriptFunction@3@@Z : PROC
 align 16
 align 16
 ?CheckAsmJsCodeGenThunk@NativeCodeGenerator@@SAPEAXPEAVRecyclableObject@Js@@UCallInfo@3@ZZ PROC FRAME
 ?CheckAsmJsCodeGenThunk@NativeCodeGenerator@@SAPEAXPEAVRecyclableObject@Js@@UCallInfo@3@ZZ PROC FRAME
         ;; save volatile registers
         ;; save volatile registers
@@ -83,14 +83,11 @@ align 16
         movups xmmword ptr [rsp + 40h], xmm2
         movups xmmword ptr [rsp + 40h], xmm2
         movups xmmword ptr [rsp + 50h], xmm3
         movups xmmword ptr [rsp + 50h], xmm3
 
 
+        call ?CheckAsmJsCodeGen@NativeCodeGenerator@@SAP6APEAXPEAVRecyclableObject@Js@@UCallInfo@3@ZZPEAVScriptFunction@3@@Z
 ifdef _CONTROL_FLOW_GUARD
 ifdef _CONTROL_FLOW_GUARD
-        call ?CheckAsmJsCodeGen@NativeCodeGenerator@@SAPEAXPEAVScriptFunction@Js@@@Z
-
         mov rcx, rax                            ; __guard_check_icall_fptr requires the call target in rcx.
         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
         call [__guard_check_icall_fptr]         ; verify that the call target is valid
         mov rax, rcx ; CFG is guaranteed not to mess up rcx
         mov rax, rcx ; CFG is guaranteed not to mess up rcx
-else
-        call ?CheckAsmJsCodeGen@NativeCodeGenerator@@SAPEAXPEAVScriptFunction@Js@@@Z
 endif
 endif
 
 
         ;EPILOGUE starts here
         ;EPILOGUE starts here

+ 0 - 4
lib/Common/BackendApi.h

@@ -7,11 +7,7 @@
 
 
 #if DYNAMIC_INTERPRETER_THUNK
 #if DYNAMIC_INTERPRETER_THUNK
 #define DefaultEntryThunk Js::InterpreterStackFrame::DelayDynamicInterpreterThunk
 #define DefaultEntryThunk Js::InterpreterStackFrame::DelayDynamicInterpreterThunk
-#if _M_X64
 #define AsmJsDefaultEntryThunk Js::InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk
 #define AsmJsDefaultEntryThunk Js::InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk
-#elif _M_IX86
-#define AsmJsDefaultEntryThunk Js::InterpreterStackFrame::DelayDynamicInterpreterThunk
-#endif
 #else
 #else
 #define DefaultEntryThunk Js::InterpreterStackFrame::InterpreterThunk
 #define DefaultEntryThunk Js::InterpreterStackFrame::InterpreterThunk
 #endif
 #endif

+ 2 - 21
lib/Runtime/Base/CrossSite.cpp

@@ -357,16 +357,7 @@ namespace Js
 #ifdef ENABLE_WASM
 #ifdef ENABLE_WASM
         if (WasmScriptFunction::Is(function))
         if (WasmScriptFunction::Is(function))
         {
         {
-            AsmJsFunctionInfo* asmInfo = funcInfo->GetFunctionBody()->GetAsmJsFunctionInfo();
-            Assert(asmInfo);
-            if (asmInfo->IsWasmDeferredParse())
-            {
-                entryPoint = WasmLibrary::WasmDeferredParseExternalThunk;
-            }
-            else
-            {
-                entryPoint = Js::AsmJsExternalEntryPoint;
-            }
+            entryPoint = Js::AsmJsExternalEntryPoint;
         } else
         } else
 #endif
 #endif
         if (funcInfo->HasBody())
         if (funcInfo->HasBody())
@@ -414,17 +405,7 @@ namespace Js
             if (funcInfo->GetFunctionProxy()->IsFunctionBody() &&
             if (funcInfo->GetFunctionProxy()->IsFunctionBody() &&
                 funcInfo->GetFunctionBody()->GetIsAsmJsFunction())
                 funcInfo->GetFunctionBody()->GetIsAsmJsFunction())
             {
             {
-#ifdef ENABLE_WASM
-                AsmJsFunctionInfo* asmInfo = funcInfo->GetFunctionBody()->GetAsmJsFunctionInfo();
-                if (asmInfo && asmInfo->IsWasmDeferredParse())
-                {
-                    entryPoint = WasmLibrary::WasmDeferredParseExternalThunk;
-                }
-                else
-#endif
-                {
-                    entryPoint = Js::AsmJsExternalEntryPoint;
-                }
+                entryPoint = Js::AsmJsExternalEntryPoint;
             }
             }
             else
             else
 #endif
 #endif

+ 24 - 11
lib/Runtime/Base/FunctionBody.cpp

@@ -3564,23 +3564,33 @@ namespace Js
         JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod;
         JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod;
         JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked();
         JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked();
 
 
+        FunctionBody* body = this->GetFunctionBody();
+        Unused(body); // in some configuration
+#ifdef ASMJS_PLAT
+        if (body->GetIsAsmJsFunction())
+        {
+#ifdef ENABLE_WASM
+            if (body->IsWasmFunction() && body->GetByteCodeCount() == 0)
+            {
+                // The only valid 2 entrypoints if the function hasn't been parsed
+                return directEntryPoint == AsmJsDefaultEntryThunk || directEntryPoint == WasmLibrary::WasmLazyTrapCallback;
+            }
+#endif
+            // Entrypoints valid only for asm.js/wasm
+            if (directEntryPoint == AsmJsDefaultEntryThunk || IsAsmJsCodeGenThunk(directEntryPoint))
+            {
+                return true;
+            }
+        }
+#endif
         // Check the direct entry point to see if it is codegen thunk
         // Check the direct entry point to see if it is codegen thunk
         // if it is not, the background codegen thread has updated both original entry point and direct entry point
         // if it is not, the background codegen thread has updated both original entry point and direct entry point
         // and they should still match, same as cases other then code gen
         // and they should still match, same as cases other then code gen
         return IsIntermediateCodeGenThunk(directEntryPoint) || originalEntryPoint == directEntryPoint
         return IsIntermediateCodeGenThunk(directEntryPoint) || originalEntryPoint == directEntryPoint
 #if ENABLE_PROFILE_INFO
 #if ENABLE_PROFILE_INFO
-            || (directEntryPoint == DynamicProfileInfo::EnsureDynamicProfileInfoThunk &&
-            this->IsFunctionBody() && this->GetFunctionBody()->IsNativeOriginalEntryPoint())
-#ifdef ENABLE_WASM
-            || (GetFunctionBody()->IsWasmFunction() &&
-                (directEntryPoint == WasmLibrary::WasmDeferredParseInternalThunk || directEntryPoint == WasmLibrary::WasmLazyTrapCallback))
+            || (directEntryPoint == DynamicProfileInfo::EnsureDynamicProfileInfoThunk && body->IsNativeOriginalEntryPoint())
 #endif
 #endif
-#ifdef ASMJS_PLAT
-            || (GetFunctionBody()->GetIsAsmJsFunction() && directEntryPoint == AsmJsDefaultEntryThunk)
-            || IsAsmJsCodeGenThunk(directEntryPoint)
-#endif
-#endif
-        ;
+            ;
     }
     }
 #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
 #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
     bool FunctionProxy::HasValidProfileEntryPoint() const
     bool FunctionProxy::HasValidProfileEntryPoint() const
@@ -3695,6 +3705,8 @@ namespace Js
 #if DYNAMIC_INTERPRETER_THUNK
 #if DYNAMIC_INTERPRETER_THUNK
     void FunctionBody::GenerateDynamicInterpreterThunk()
     void FunctionBody::GenerateDynamicInterpreterThunk()
     {
     {
+        AssertOrFailFastMsg(!m_isWasmFunction || GetByteCodeCount() > 0, "The wasm function should have been parsed before generating the dynamic interpreter thunk");
+
         if (this->m_dynamicInterpreterThunk == nullptr)
         if (this->m_dynamicInterpreterThunk == nullptr)
         {
         {
             // NOTE: Etw rundown thread may be reading this->dynamicInterpreterThunk concurrently. We don't need to synchronize
             // NOTE: Etw rundown thread may be reading this->dynamicInterpreterThunk concurrently. We don't need to synchronize
@@ -3746,6 +3758,7 @@ namespace Js
         this->EnsureDynamicProfileInfo();
         this->EnsureDynamicProfileInfo();
 
 
         Assert(HasValidEntryPoint());
         Assert(HasValidEntryPoint());
+        AssertMsg(!m_isWasmFunction || GetByteCodeCount() > 0, "Wasm function should be parsed by this point");
         if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetEntryPoint(entryPointInfo)))
         if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetEntryPoint(entryPointInfo)))
         {
         {
             // We are not doing code gen on this function, just change the entry point directly
             // We are not doing code gen on this function, just change the entry point directly

+ 3 - 6
lib/Runtime/Base/ScriptContext.cpp

@@ -3970,13 +3970,10 @@ namespace Js
             functionBody->ResetEntryPoint();
             functionBody->ResetEntryPoint();
             CurrentThunk = realThunk;
             CurrentThunk = realThunk;
 
 
-            bool isDeferred = functionBody->GetAsmJsFunctionInfo()->IsWasmDeferredParse();
+            Js::WasmLibrary::ResetFunctionBodyDefaultEntryPoint(functionBody);
             // Make sure the function and the function body are using the same entry point
             // Make sure the function and the function body are using the same entry point
-            scriptFunction->ChangeEntryPoint(functionBody->GetDefaultEntryPointInfo(), AsmJsDefaultEntryThunk);
-            WasmLibrary::SetWasmEntryPointToInterpreter(scriptFunction, isDeferred);
-            // Reset jit status for this function
-            functionBody->SetIsAsmJsFullJitScheduled(false);
-            Assert(functionBody->HasValidEntryPoint());
+            scriptFunction->ChangeEntryPoint(functionBody->GetDefaultEntryPointInfo(), functionBody->GetDefaultEntryPointInfo()->jsMethod);
+            Assert(scriptFunction->GetFunctionEntryPointInfo()->GetIsAsmJSFunction());
         }
         }
         else
         else
 #endif
 #endif

+ 2 - 3
lib/Runtime/Language/AsmJsTypes.h

@@ -993,10 +993,9 @@ namespace Js
         }
         }
 
 
         Wasm::WasmReaderInfo* GetWasmReaderInfo() const {return mWasmReaderInfo;}
         Wasm::WasmReaderInfo* GetWasmReaderInfo() const {return mWasmReaderInfo;}
-        void SetWasmReaderInfo(Wasm::WasmReaderInfo* reader) {mWasmReaderInfo = reader;}
+        void SetWasmReaderInfo(Wasm::WasmReaderInfo* reader) { Assert(reader);  mWasmReaderInfo = reader; }
         WebAssemblyModule* GetWebAssemblyModule() const { return mWasmModule; }
         WebAssemblyModule* GetWebAssemblyModule() const { return mWasmModule; }
-        void SetWebAssemblyModule(WebAssemblyModule * module) { mWasmModule= module; }
-        bool IsWasmDeferredParse() const { return mWasmReaderInfo != nullptr; }
+        void SetWebAssemblyModule(WebAssemblyModule * module) { mWasmModule = module; }
 #endif
 #endif
     };
     };
 };
 };

+ 61 - 22
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -1592,31 +1592,68 @@ namespace Js
 #endif
 #endif
 #endif
 #endif
 
 
+
 #if DYNAMIC_INTERPRETER_THUNK
 #if DYNAMIC_INTERPRETER_THUNK
 #ifdef _M_IX86
 #ifdef _M_IX86
+    __declspec(naked)
+        Var InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
+    {
+        __asm
+        {
+            push ebp;
+            mov ebp, esp;
+            push[esp + 8];    // push function object
+            call WasmLibrary::EnsureWasmEntrypoint;
+            test eax, eax;
+            jne skipThunk;
+
+            push[esp + 8];    // push function object
+            call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
+skipThunk:
+#ifdef _CONTROL_FLOW_GUARD
+            // verify that the call target is valid
+            push eax;
+            mov  ecx, eax;
+            call[__guard_check_icall_fptr];
+            pop eax;
+#endif
+
+            pop ebp;
+
+            jmp eax;
+        }
+    }
+
     __declspec(naked)
     __declspec(naked)
         Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
         Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
     {
     {
         __asm
         __asm
         {
         {
-            push ebp
-            mov ebp, esp
-            push[esp + 8]     // push function object
+            push ebp;
+            mov ebp, esp;
+            push[esp + 8];    // push function object
             call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
             call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
 
 
 #ifdef _CONTROL_FLOW_GUARD
 #ifdef _CONTROL_FLOW_GUARD
             // verify that the call target is valid
             // verify that the call target is valid
-            push eax
-                mov  ecx, eax
-                call[__guard_check_icall_fptr]
-                pop eax
+            push eax;
+            mov  ecx, eax;
+            call[__guard_check_icall_fptr];
+            pop eax;
 #endif
 #endif
 
 
-                pop ebp
+            pop ebp;
 
 
-                jmp eax
+            jmp eax;
         }
         }
     }
     }
+#elif !defined(_M_AMD64)
+    Var InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
+    {
+        // Asm.js only supported on x64 and x86
+        AssertOrFailFast(UNREACHED);
+        return nullptr;
+    }
 #endif
 #endif
 #endif
 #endif
 
 
@@ -1645,15 +1682,14 @@ namespace Js
 
 
     bool InterpreterStackFrame::IsDelayDynamicInterpreterThunk(JavascriptMethod entryPoint)
     bool InterpreterStackFrame::IsDelayDynamicInterpreterThunk(JavascriptMethod entryPoint)
     {
     {
-        return
+        return false
 #if DYNAMIC_INTERPRETER_THUNK
 #if DYNAMIC_INTERPRETER_THUNK
-#if _M_X64
-            entryPoint == InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk ||
+            || entryPoint == InterpreterStackFrame::DelayDynamicInterpreterThunk
+#ifdef ASMJS_PLAT
+            || entryPoint == InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk
 #endif
 #endif
-            entryPoint == InterpreterStackFrame::DelayDynamicInterpreterThunk;
-#else
-            false;
 #endif
 #endif
+            ;
     }
     }
 
 
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
@@ -3648,24 +3684,27 @@ namespace Js
         ScriptContext * scriptContext = function->GetScriptContext();
         ScriptContext * scriptContext = function->GetScriptContext();
         Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)function->GetEntryPointInfo();
         Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)function->GetEntryPointInfo();
         PROBE_STACK_CALL(scriptContext, function, alignedArgsSize + Js::Constants::MinStackDefault);
         PROBE_STACK_CALL(scriptContext, function, alignedArgsSize + Js::Constants::MinStackDefault);
+        // Calling the jsMethod might change the entrypoint, adding the variable here 
+        // will save the method on the stack helping debug what really got called
+        JavascriptMethod jsMethod = entrypointInfo->jsMethod;
 
 
         switch (asmInfo->GetReturnType().which())
         switch (asmInfo->GetReturnType().which())
         {
         {
         case AsmJsRetType::Void:
         case AsmJsRetType::Void:
-            JavascriptFunction::CallAsmJsFunction<int>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            JavascriptFunction::CallAsmJsFunction<int>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             break;
             break;
         case AsmJsRetType::Signed:
         case AsmJsRetType::Signed:
 
 
-            m_localIntSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<int>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            m_localIntSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<int>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             break;
             break;
         case AsmJsRetType::Int64:
         case AsmJsRetType::Int64:
-            m_localInt64Slots[returnReg] = JavascriptFunction::CallAsmJsFunction<int64>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            m_localInt64Slots[returnReg] = JavascriptFunction::CallAsmJsFunction<int64>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             break;
             break;
         case AsmJsRetType::Double:
         case AsmJsRetType::Double:
-            m_localDoubleSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<double>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            m_localDoubleSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<double>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             break;
             break;
         case AsmJsRetType::Float:
         case AsmJsRetType::Float:
-            m_localFloatSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<float>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            m_localFloatSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<float>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             break;
             break;
 #ifdef ENABLE_WASM_SIMD
 #ifdef ENABLE_WASM_SIMD
         case AsmJsRetType::Float32x4:
         case AsmJsRetType::Float32x4:
@@ -3682,10 +3721,10 @@ namespace Js
 #if _WIN32 //WASM.SIMD ToDo: Enable thunk for Xplat
 #if _WIN32 //WASM.SIMD ToDo: Enable thunk for Xplat
 #if _M_X64
 #if _M_X64
             X86SIMDValue simdVal;
             X86SIMDValue simdVal;
-            simdVal.m128_value = JavascriptFunction::CallAsmJsFunction<__m128>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            simdVal.m128_value = JavascriptFunction::CallAsmJsFunction<__m128>(function, jsMethod, m_outParams, alignedArgsSize, reg);
             m_localSimdSlots[returnReg] = X86SIMDValue::ToSIMDValue(simdVal);
             m_localSimdSlots[returnReg] = X86SIMDValue::ToSIMDValue(simdVal);
 #else
 #else
-            m_localSimdSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<AsmJsSIMDValue>(function, entrypointInfo->jsMethod, m_outParams, alignedArgsSize, reg);
+            m_localSimdSlots[returnReg] = JavascriptFunction::CallAsmJsFunction<AsmJsSIMDValue>(function, jsMethod, m_outParams, alignedArgsSize, reg);
 #endif
 #endif
 #endif
 #endif
             break;
             break;

+ 1 - 4
lib/Runtime/Language/InterpreterStackFrame.h

@@ -344,11 +344,7 @@ namespace Js
         template <typename T>
         template <typename T>
         static T AsmJsInterpreter(AsmJsCallStackLayout* layout);
         static T AsmJsInterpreter(AsmJsCallStackLayout* layout);
         static void * GetAsmJsInterpreterEntryPoint(AsmJsCallStackLayout* stack);
         static void * GetAsmJsInterpreterEntryPoint(AsmJsCallStackLayout* stack);
-
-        static Var AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);
-
         static __m128 AsmJsInterpreterSimdJs(AsmJsCallStackLayout* func);
         static __m128 AsmJsInterpreterSimdJs(AsmJsCallStackLayout* func);
-
 #endif
 #endif
 
 
 #ifdef ASMJS_PLAT
 #ifdef ASMJS_PLAT
@@ -357,6 +353,7 @@ namespace Js
 #endif
 #endif
 
 
 #if DYNAMIC_INTERPRETER_THUNK
 #if DYNAMIC_INTERPRETER_THUNK
+        static Var AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);
         static Var DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);
         static Var DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);
         _NOINLINE static Var InterpreterThunk(JavascriptCallStackLayout* layout);
         _NOINLINE static Var InterpreterThunk(JavascriptCallStackLayout* layout);
         _NOINLINE static Var StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);
         _NOINLINE static Var StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...);

+ 1 - 0
lib/Runtime/Language/WAsmjsUtils.cpp

@@ -6,6 +6,7 @@
 #include "RuntimeLanguagePch.h"
 #include "RuntimeLanguagePch.h"
 
 
 #if defined(ASMJS_PLAT) || defined(ENABLE_WASM)
 #if defined(ASMJS_PLAT) || defined(ENABLE_WASM)
+#include "InterpreterStackFrame.h"
 
 
 namespace WAsmJs
 namespace WAsmJs
 {
 {

+ 5 - 69
lib/Runtime/Language/amd64/amd64_Thunks.S

@@ -62,7 +62,12 @@ NESTED_ENTRY _ZN2Js21InterpreterStackFrame33AsmJsDelayDynamicInterpreterThunkEPN
         push r8
         push r8
         push r9
         push r9
 
 
+        call C_FUNC(_ZN2Js11WasmLibrary20EnsureWasmEntrypointEPNS_14ScriptFunctionE)
+        test rax, rax
+        jne skipThunk
+        mov rdi, [rbp-0x8]
         call C_FUNC(_ZN2Js21InterpreterStackFrame29EnsureDynamicInterpreterThunkEPNS_14ScriptFunctionE)
         call C_FUNC(_ZN2Js21InterpreterStackFrame29EnsureDynamicInterpreterThunkEPNS_14ScriptFunctionE)
+skipThunk:
 
 
         pop r9
         pop r9
         pop r8
         pop r8
@@ -270,73 +275,4 @@ NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfo
         ret
         ret
 NESTED_END _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
 NESTED_END _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
 
 
-
-//============================================================================================================
-// WasmLibrary::WasmDeferredParseExternalThunk
-//============================================================================================================
-
-// Var WasmLibrary::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
-.balign 16
-NESTED_ENTRY _ZN2Js11WasmLibrary30WasmDeferredParseExternalThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
-        push_nonvol_reg rbp             // push rbp and adjust CFA offset
-        lea  rbp, [rsp]
-
-        set_cfa_register rbp, (2*8)     // Set to compute CFA as: rbp + 16 (sizeof: [rbp] [ReturnAddress])
-
-        // save argument registers used by custom calling convention
-        push rdi
-        push rsi
-        push rdx
-        push rcx
-        push r8
-        push r9
-
-        mov rsi, 0
-        call C_FUNC(_ZN2Js11WasmLibrary27WasmDeferredParseEntryPointEPNS_19AsmJsScriptFunctionEi)
-
-        pop r9
-        pop r8
-        pop rcx
-        pop rdx
-        pop rsi
-        pop rdi
-
-        pop_nonvol_reg rbp
-        jmp rax
-NESTED_END _ZN2Js11WasmLibrary30WasmDeferredParseExternalThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
-
-//============================================================================================================
-// WasmLibrary::WasmDeferredParseInternalThunk
-//============================================================================================================
-
-// Var WasmLibrary::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
-.balign 16
-NESTED_ENTRY _ZN2Js11WasmLibrary30WasmDeferredParseInternalThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT, NoHandler
-        push_nonvol_reg rbp             // push rbp and adjust CFA offset
-        lea  rbp, [rsp]
-
-        set_cfa_register rbp, (2*8)     // Set to compute CFA as: rbp + 16 (sizeof: [rbp] [ReturnAddress])
-
-        // save argument registers used by custom calling convention
-        push rdi
-        push rsi
-        push rdx
-        push rcx
-        push r8
-        push r9
-
-        mov rsi, 1
-        call C_FUNC(_ZN2Js11WasmLibrary27WasmDeferredParseEntryPointEPNS_19AsmJsScriptFunctionEi)
-
-        pop r9
-        pop r8
-        pop rcx
-        pop rdx
-        pop rsi
-        pop rdi
-
-        pop_nonvol_reg rbp
-        jmp rax
-NESTED_END _ZN2Js11WasmLibrary30WasmDeferredParseInternalThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT
-
 #endif // _ENABLE_DYNAMIC_THUNKS
 #endif // _ENABLE_DYNAMIC_THUNKS

+ 10 - 102
lib/Runtime/Language/amd64/amd64_Thunks.asm

@@ -66,6 +66,7 @@ endif
 
 
 ;; JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(ScriptFunction * function)
 ;; JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(ScriptFunction * function)
 extrn ?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z : PROC
 extrn ?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z : PROC
+extrn ?EnsureWasmEntrypoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z : PROC
 
 
 ;; Var InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
 ;; Var InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
 align 16
 align 16
@@ -88,14 +89,20 @@ align 16
         movaps xmmword ptr [rsp + 30h], xmm1
         movaps xmmword ptr [rsp + 30h], xmm1
         movaps xmmword ptr [rsp + 40h], xmm2
         movaps xmmword ptr [rsp + 40h], xmm2
         movaps xmmword ptr [rsp + 50h], xmm3
         movaps xmmword ptr [rsp + 50h], xmm3
-ifdef _CONTROL_FLOW_GUARD
+
+        ;; Make sure the wasm function has the right entrypoint
+        call ?EnsureWasmEntrypoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z
+        test rax, rax
+        jne skipThunk
+        mov rcx, qword ptr [rsp + 70h]
+
         call ?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z
         call ?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z
+skipThunk:
 
 
+ifdef _CONTROL_FLOW_GUARD
         mov rcx, rax                            ; __guard_check_icall_fptr requires the call target in rcx.
         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
         call [__guard_check_icall_fptr]         ; verify that the call target is valid
         mov rax, rcx                            ;restore call target
         mov rax, rcx                            ;restore call target
-else
-        call ?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z
 endif
 endif
         ; restore potential floating point arguments from stack
         ; restore potential floating point arguments from stack
         movaps xmm1, xmmword ptr [rsp + 30h]
         movaps xmm1, xmmword ptr [rsp + 30h]
@@ -452,105 +459,6 @@ endif
 
 
 ?AsmJsExternalEntryPoint@Js@@YAPEAXPEAVRecyclableObject@1@UCallInfo@1@ZZ ENDP
 ?AsmJsExternalEntryPoint@Js@@YAPEAXPEAVRecyclableObject@1@UCallInfo@1@ZZ ENDP
 
 
-;;============================================================================================================
-;; WasmLibrary::WasmDeferredParseExternalThunk
-;;============================================================================================================
-
-;;  JavascriptMethod WasmLibrary::WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall);
-extrn ?WasmDeferredParseEntryPoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVAsmJsScriptFunction@2@H@Z : PROC
-
-;; Var WasmLibrary::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
-align 16
-?WasmDeferredParseExternalThunk@WasmLibrary@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
-        mov rdx, 0
-        call ?WasmDeferredParseEntryPoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVAsmJsScriptFunction@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
-
-        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@WasmLibrary@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ ENDP
-
-;;============================================================================================================
-
-;;============================================================================================================
-;; WasmLibrary::WasmDeferredParseInternalThunk
-;;============================================================================================================
-
-;;  JavascriptMethod WasmLibrary::WasmDeferredParseEntryPoint(AsmJsScriptFunction** funcPtr, int internalCall);
-extrn ?WasmDeferredParseEntryPoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVAsmJsScriptFunction@2@H@Z : PROC
-
-;; Var WasmLibrary::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
-align 16
-?WasmDeferredParseInternalThunk@WasmLibrary@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
-        mov rdx, 1
-        call ?WasmDeferredParseEntryPoint@WasmLibrary@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVAsmJsScriptFunction@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]
-
-        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@WasmLibrary@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ ENDP
-
 ;;============================================================================================================
 ;;============================================================================================================
 
 
 endif ;; _ENABLE_DYNAMIC_THUNKS
 endif ;; _ENABLE_DYNAMIC_THUNKS

+ 1 - 5
lib/Runtime/Library/ScriptFunction.cpp

@@ -222,11 +222,7 @@ using namespace Js;
             return;
             return;
         }
         }
 
 
-        bool isAsmJS = false;
-        if (HasFunctionBody())
-        {
-            isAsmJS = this->GetFunctionBody()->GetIsAsmjsMode();
-        }
+        bool isAsmJS = HasFunctionBody() && this->GetFunctionBody()->GetIsAsmjsMode();
 
 
         // ASMJS:- for asmjs we don't need to update the entry point here as it updates the types entry point
         // ASMJS:- for asmjs we don't need to update the entry point here as it updates the types entry point
         if (!isAsmJS)
         if (!isAsmJS)

+ 46 - 102
lib/Runtime/Library/WasmLibrary.cpp

@@ -11,7 +11,6 @@
 
 
 namespace Js
 namespace Js
 {
 {
-
     Var WasmLibrary::WasmLazyTrapCallback(RecyclableObject *callee, CallInfo, ...)
     Var WasmLibrary::WasmLazyTrapCallback(RecyclableObject *callee, CallInfo, ...)
     {
     {
         WasmScriptFunction* asmFunction = static_cast<WasmScriptFunction*>(callee);
         WasmScriptFunction* asmFunction = static_cast<WasmScriptFunction*>(callee);
@@ -22,128 +21,73 @@ namespace Js
         JavascriptExceptionOperators::Throw(error, scriptContext);
         JavascriptExceptionOperators::Throw(error, scriptContext);
     }
     }
 
 
-    void WasmLibrary::SetWasmEntryPointToInterpreter(Js::ScriptFunction* func, bool deferParse)
-    {
-        Assert(WasmScriptFunction::Is(func));
-        FunctionEntryPointInfo* entrypointInfo = (FunctionEntryPointInfo*)func->GetEntryPointInfo();
-        entrypointInfo->SetIsAsmJSFunction(true);
-
-        if (deferParse)
-        {
-            func->SetEntryPoint(WasmLibrary::WasmDeferredParseExternalThunk);
-            entrypointInfo->jsMethod = WasmLibrary::WasmDeferredParseInternalThunk;
-        }
-        else
-        {
-            func->SetEntryPoint(Js::AsmJsExternalEntryPoint);
-            entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
-        }
-    }
-
-#if _M_IX86
-    __declspec(naked)
-    Var WasmLibrary::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
-    {
-        __asm
-        {
-            push 0;
-            push [esp + 8];
-            call WasmLibrary::WasmDeferredParseEntryPoint
-#ifdef _CONTROL_FLOW_GUARD
-            // verify that the call target is valid
-            mov  ecx, eax
-            call[__guard_check_icall_fptr]
-            mov eax, ecx
-#endif
-            // 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 WasmLibrary::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
+    void WasmLibrary::ResetFunctionBodyDefaultEntryPoint(FunctionBody* body)
     {
     {
-        __asm
-        {
-            push 1;
-            push [esp + 8];
-            call WasmLibrary::WasmDeferredParseEntryPoint
-#ifdef _CONTROL_FLOW_GUARD
-            // verify that the call target is valid
-            mov  ecx, eax
-            call[__guard_check_icall_fptr]
-            mov eax, ecx
-#endif
-            // Although we don't restore ESP here on WinCE, this is fine because script profiler is not shipped for WinCE.
-            jmp eax
-        }
+        body->GetDefaultFunctionEntryPointInfo()->SetIsAsmJSFunction(true);
+        body->GetDefaultFunctionEntryPointInfo()->jsMethod = AsmJsDefaultEntryThunk;
+        body->SetOriginalEntryPoint(AsmJsDefaultEntryThunk);
+        // Reset jit status for this function
+        body->SetIsAsmJsFullJitScheduled(false);
+        Assert(body->HasValidEntryPoint());
     }
     }
-#elif defined(_M_X64)
-    // Do nothing: the implementation of WasmLibrary::WasmDeferredParseExternalThunk is declared (appropriately decorated) in
-    // Language\amd64\amd64_Thunks.asm.
-#endif // _M_IX86
-
 }
 }
 
 
 #endif // ENABLE_WASM
 #endif // ENABLE_WASM
 
 
-Js::JavascriptMethod Js::WasmLibrary::WasmDeferredParseEntryPoint(Js::AsmJsScriptFunction* func, int internalCall)
+Js::JavascriptMethod Js::WasmLibrary::EnsureWasmEntrypoint(Js::ScriptFunction* func)
 {
 {
 #ifdef ENABLE_WASM
 #ifdef ENABLE_WASM
-    FunctionBody* body = func->GetFunctionBody();
-    AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
-    ScriptContext* scriptContext = func->GetScriptContext();
-
-    Js::FunctionEntryPointInfo * entrypointInfo = (Js::FunctionEntryPointInfo*)func->GetEntryPointInfo();
-    Wasm::WasmReaderInfo* readerInfo = info->GetWasmReaderInfo();
-    if (readerInfo)
+    if (func->GetFunctionBody()->IsWasmFunction())
     {
     {
-        try
+        FunctionBody* body = func->GetFunctionBody();
+        AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
+        ScriptContext* scriptContext = func->GetScriptContext();
+
+        Js::FunctionEntryPointInfo * entrypointInfo = (Js::FunctionEntryPointInfo*)func->GetEntryPointInfo();
+        if (info->GetLazyError())
         {
         {
-            Wasm::WasmBytecodeGenerator::GenerateFunctionBytecode(scriptContext, readerInfo);
-            func->GetDynamicType()->SetEntryPoint(Js::AsmJsExternalEntryPoint);
-            entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
-            WAsmJs::JitFunctionIfReady(func);
+            // We might have parsed this in the past and there was an error
+            entrypointInfo->jsMethod = WasmLibrary::WasmLazyTrapCallback;
         }
         }
-        catch (Wasm::WasmCompilationException& ex)
+        else if (body->GetByteCodeCount() == 0)
         {
         {
-            AutoFreeExceptionMessage autoCleanExceptionMessage;
-            char16* exceptionMessage = WebAssemblyModule::FormatExceptionMessage(&ex, &autoCleanExceptionMessage, readerInfo->m_module, body);
+            Wasm::WasmReaderInfo* readerInfo = info->GetWasmReaderInfo();
+            AssertOrFailFast(readerInfo);
+            try
+            {
+                Wasm::WasmBytecodeGenerator::GenerateFunctionBytecode(scriptContext, readerInfo);
+                entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
+                WAsmJs::JitFunctionIfReady(func);
+            }
+            catch (Wasm::WasmCompilationException& ex)
+            {
+                AutoFreeExceptionMessage autoCleanExceptionMessage;
+                char16* exceptionMessage = WebAssemblyModule::FormatExceptionMessage(&ex, &autoCleanExceptionMessage, readerInfo->m_module, body);
 
 
-            JavascriptLibrary *library = scriptContext->GetLibrary();
-            JavascriptError *pError = library->CreateWebAssemblyCompileError();
-            JavascriptError::SetErrorMessage(pError, WASMERR_WasmCompileError, exceptionMessage, scriptContext);
+                JavascriptLibrary *library = scriptContext->GetLibrary();
+                JavascriptError *pError = library->CreateWebAssemblyCompileError();
+                JavascriptError::SetErrorMessage(pError, WASMERR_WasmCompileError, exceptionMessage, scriptContext);
 
 
-            func->GetDynamicType()->SetEntryPoint(WasmLazyTrapCallback);
-            entrypointInfo->jsMethod = WasmLazyTrapCallback;
-            info->SetLazyError(pError);
+                entrypointInfo->jsMethod = WasmLibrary::WasmLazyTrapCallback;
+                info->SetLazyError(pError);
+            }
         }
         }
-        info->SetWasmReaderInfo(nullptr);
-    }
-    else
-    {
-        // This can happen if another function had its type changed and then was parsed
-        // They still share the function body, so just change the entry point
-        Assert(body->GetByteCodeCount() > 0);
-        Js::JavascriptMethod externalEntryPoint = info->GetLazyError() ? WasmLazyTrapCallback : Js::AsmJsExternalEntryPoint;
-        func->GetDynamicType()->SetEntryPoint(externalEntryPoint);
-        if (body->GetIsAsmJsFullJitScheduled())
+        // The function has already been parsed, just fix up the entry point
+        else if (body->GetIsAsmJsFullJitScheduled())
         {
         {
             Js::FunctionEntryPointInfo* defaultEntryPoint = (Js::FunctionEntryPointInfo*)body->GetDefaultEntryPointInfo();
             Js::FunctionEntryPointInfo* defaultEntryPoint = (Js::FunctionEntryPointInfo*)body->GetDefaultEntryPointInfo();
             func->ChangeEntryPoint(defaultEntryPoint, defaultEntryPoint->jsMethod);
             func->ChangeEntryPoint(defaultEntryPoint, defaultEntryPoint->jsMethod);
         }
         }
-        else if (entrypointInfo->jsMethod == WasmLibrary::WasmDeferredParseInternalThunk)
+        else
         {
         {
-            // The entrypointInfo is still shared even if the type has been changed
-            // However, no sibling functions changed this entry point yet, so fix it
-            entrypointInfo->jsMethod = info->GetLazyError() ? WasmLazyTrapCallback : AsmJsDefaultEntryThunk;
+            entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
         }
         }
-    }
 
 
-    Assert(body->HasValidEntryPoint());
-    Js::JavascriptMethod entryPoint = internalCall ? entrypointInfo->jsMethod : func->GetDynamicType()->GetEntryPoint();
-    return entryPoint;
-#else
-    Js::Throw::InternalError();
+        Assert(body->HasValidEntryPoint());
+        Js::JavascriptMethod jsMethod = func->GetEntryPointInfo()->jsMethod;
+        // We are already in AsmJsDefaultEntryThunk so return null so it just keeps going
+        return jsMethod == AsmJsDefaultEntryThunk ? nullptr : jsMethod;
+    }
 #endif
 #endif
+    return nullptr;
 }
 }

+ 2 - 4
lib/Runtime/Library/WasmLibrary.h

@@ -9,12 +9,10 @@ namespace Js
     class WasmLibrary
     class WasmLibrary
     {
     {
     public:
     public:
-        static JavascriptMethod WasmDeferredParseEntryPoint(AsmJsScriptFunction* funcPtr, int internalCall);
-        static void SetWasmEntryPointToInterpreter(Js::ScriptFunction* func, bool deferParse);
+        static JavascriptMethod EnsureWasmEntrypoint(ScriptFunction* funcPtr);
+        static void ResetFunctionBodyDefaultEntryPoint(FunctionBody* body);
 #ifdef ENABLE_WASM
 #ifdef ENABLE_WASM
         static Var WasmLazyTrapCallback(RecyclableObject *callee, CallInfo, ...);
         static Var WasmLazyTrapCallback(RecyclableObject *callee, CallInfo, ...);
-        static Var WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...);
-        static Var WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...);
 #endif
 #endif
     };
     };
 }
 }

+ 10 - 21
lib/Runtime/Library/WebAssemblyInstance.cpp

@@ -191,31 +191,20 @@ void WebAssemblyInstance::CreateWasmFunctions(WebAssemblyModule * wasmModule, Sc
         funcObj->SetSignature(body->GetAsmJsFunctionInfo()->GetWasmSignature());
         funcObj->SetSignature(body->GetAsmJsFunctionInfo()->GetWasmSignature());
         funcObj->SetEnvironment(frameDisplay);
         funcObj->SetEnvironment(frameDisplay);
 
 
-        // Todo:: need to fix issue #2452 before we can do this,
-        // otherwise we'll change the type of the functions and cause multiple instance to not share jitted code
-        //Wasm::WasmSignature* sig = wasmFuncInfo->GetSignature();
-        //funcObj->SetPropertyWithAttributes(PropertyIds::length, JavascriptNumber::ToVar(sig->GetParamCount(), ctx), PropertyNone, nullptr);
-        //funcObj->SetPropertyWithAttributes(PropertyIds::name, JavascriptConversion::ToString(JavascriptNumber::ToVar(i, ctx), ctx), PropertyNone, nullptr);
+        Wasm::WasmSignature* sig = wasmFuncInfo->GetSignature();
+        funcObj->SetPropertyWithAttributes(PropertyIds::length, JavascriptNumber::ToVar(sig->GetParamCount(), ctx), PropertyNone, nullptr);
+        funcObj->SetPropertyWithAttributes(PropertyIds::name, JavascriptConversion::ToString(JavascriptNumber::ToVar(i, ctx), ctx), PropertyNone, nullptr);
 
 
         env->SetWasmFunction(i, funcObj);
         env->SetWasmFunction(i, funcObj);
 
 
-        if (PHASE_ENABLED(WasmDeferredPhase, body))
+        FunctionEntryPointInfo* entrypointInfo = (FunctionEntryPointInfo*)funcObj->GetEntryPointInfo();
+        AssertOrFailFast(entrypointInfo->GetIsAsmJSFunction());
+        AssertOrFailFast(!funcObj->IsCrossSiteObject());
+        funcObj->SetEntryPoint(Js::AsmJsExternalEntryPoint);
+        entrypointInfo->jsMethod = funcObj->GetFunctionInfo()->GetOriginalEntryPoint();
+        if (!PHASE_ENABLED(WasmDeferredPhase, body))
         {
         {
-            // if we still have WasmReaderInfo we haven't yet parsed
-            if (body->GetAsmJsFunctionInfo()->GetWasmReaderInfo())
-            {
-                WasmLibrary::SetWasmEntryPointToInterpreter(funcObj, true);
-            }
-        }
-        else
-        {
-            AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
-            if (info->GetWasmReaderInfo())
-            {
-                WasmLibrary::SetWasmEntryPointToInterpreter(funcObj, false);
-                WAsmJs::JitFunctionIfReady(funcObj);
-                info->SetWasmReaderInfo(nullptr);
-            }
+            WAsmJs::JitFunctionIfReady(funcObj);
         }
         }
     }
     }
 }
 }

+ 3 - 0
lib/WasmReader/WasmByteCodeGenerator.cpp

@@ -11,6 +11,7 @@
 #include "EmptyWasmByteCodeWriter.h"
 #include "EmptyWasmByteCodeWriter.h"
 #include "ByteCode/ByteCodeDumper.h"
 #include "ByteCode/ByteCodeDumper.h"
 #include "AsmJsByteCodeDumper.h"
 #include "AsmJsByteCodeDumper.h"
+#include "Language/InterpreterStackFrame.h"
 
 
 #if DBG_DUMP
 #if DBG_DUMP
 #define DebugPrintOp(op) if (DO_WASM_TRACE_BYTECODE) { PrintOpBegin(op); }
 #define DebugPrintOp(op) if (DO_WASM_TRACE_BYTECODE) { PrintOpBegin(op); }
@@ -429,6 +430,8 @@ void WasmModuleGenerator::GenerateFunctionHeader(uint32 index)
     readerInfo->m_funcInfo = wasmInfo;
     readerInfo->m_funcInfo = wasmInfo;
     readerInfo->m_module = m_module;
     readerInfo->m_module = m_module;
 
 
+    Js::WasmLibrary::ResetFunctionBodyDefaultEntryPoint(body);
+
     Js::AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
     Js::AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
     info->SetWasmReaderInfo(readerInfo);
     info->SetWasmReaderInfo(readerInfo);
     info->SetWebAssemblyModule(m_module);
     info->SetWebAssemblyModule(m_module);

+ 0 - 1
lib/WasmReader/WasmReaderInfo.h

@@ -17,6 +17,5 @@ struct WasmReaderInfo
 {
 {
     Field(WasmFunctionInfo*) m_funcInfo;
     Field(WasmFunctionInfo*) m_funcInfo;
     Field(Js::WebAssemblyModule*) m_module;
     Field(Js::WebAssemblyModule*) m_module;
-    Field(Js::Var) m_bufferSrc;
 };
 };
 }
 }

+ 4 - 4
test/WasmSpec/baselines/jsapi.baseline

@@ -1,5 +1,5 @@
 Harness Status: OK
 Harness Status: OK
-Found 104 tests: Pass = 87 Fail = 17
+Found 104 tests: Pass = 90 Fail = 14
 Pass 'WebAssembly' data property on global object  
 Pass 'WebAssembly' data property on global object  
 Pass 'WebAssembly' object  
 Pass 'WebAssembly' object  
 Pass 'WebAssembly.(Compile|Link|Runtime)Error' data property  
 Pass 'WebAssembly.(Compile|Link|Runtime)Error' data property  
@@ -23,7 +23,7 @@ Pass 'WebAssembly.Instance.prototype' object
 Pass 'WebAssembly.Instance' instance objects  
 Pass 'WebAssembly.Instance' instance objects  
 Pass 'WebAssembly.Instance.prototype.exports' accessor property  
 Pass 'WebAssembly.Instance.prototype.exports' accessor property  
 Pass exports object  
 Pass exports object  
-Fail Exported WebAssembly functions  assert_equals: expected 0 but got -1
+Pass Exported WebAssembly functions  
 Pass 'WebAssembly.Memory' data property  
 Pass 'WebAssembly.Memory' data property  
 Pass 'WebAssembly.Memory' constructor function  
 Pass 'WebAssembly.Memory' constructor function  
 Pass 'WebAssembly.Memory.prototype' data property  
 Pass 'WebAssembly.Memory.prototype' data property  
@@ -101,6 +101,6 @@ Pass unexpected failure in assertInstantiateSuccess
 Pass unexpected failure in assertInstantiateSuccess  
 Pass unexpected failure in assertInstantiateSuccess  
 Pass unexpected failure in assertInstantiateSuccess  
 Pass unexpected failure in assertInstantiateSuccess  
 Pass unexpected failure in assertInstantiateSuccess  
 Pass unexpected failure in assertInstantiateSuccess  
-Fail Exported values have cached JS objects  assert_equals: expected "0" but got ""
-Fail Tables export cached  assert_equals: expected "0" but got ""
+Pass Exported values have cached JS objects  
+Pass Tables export cached  
 Pass WebAssembly integers are converted to JavaScript as if by ToInt32  
 Pass WebAssembly integers are converted to JavaScript as if by ToInt32