Selaa lähdekoodia

Merge branch release/1.8 into mergeback_rs3_18

Jack Horton 8 vuotta sitten
vanhempi
sitoutus
b93fbc5489

+ 1 - 1
lib/Backend/BailOut.cpp

@@ -1614,7 +1614,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
     }
     if (isInlinee)
     {
-        newInstance->OrFlags(Js::InterpreterStackFrameFlags_FromInlineeCodeInEHBailOut);
+        newInstance->OrFlags(Js::InterpreterStackFrameFlags_FromBailOutInInlinee);
     }
 
     ThreadContext *threadContext = newInstance->GetScriptContext()->GetThreadContext();

+ 18 - 0
lib/Backend/Inline.cpp

@@ -2382,6 +2382,11 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo *
     // We may still decide not to inline.
     *pIsInlined = false;
 
+    if (argsCount == 0)
+    {
+        return callInstr;
+    }
+
     Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInForFuncInfo(applyData->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo());
     const FunctionJITTimeInfo * inlineeData = nullptr;
 
@@ -2476,6 +2481,10 @@ IR::Instr * Inline::InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::In
     IR::Instr * argumentsObjArgOut = nullptr;
     uint argOutCount = 0;
     this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &argumentsObjArgOut, argOutCount);
+    
+    Assert(implicitThisArgOut);
+    Assert(explicitThisArgOut);
+    Assert(argumentsObjArgOut);
 
     //      BailOnNotEqual  s4.var                  ---------------New additional BAILOUT if not stack args or actuals exceed 16 at runtime.
     //      Bailout: #004e (BailOutOnInlineFunction)
@@ -2567,6 +2576,10 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI
     uint argOutCount = 0;
     this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &arrayArgOut, argOutCount);
 
+    Assert(implicitThisArgOut);
+    Assert(explicitThisArgOut);
+    Assert(arrayArgOut);
+
     TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
 
     IR::Instr* builtInEndInstr = InsertInlineeBuiltInStartEndTags(callInstr, 3); // 3 args (implicit this + explicit this + array = 3)
@@ -2625,6 +2638,9 @@ IR::Instr * Inline::InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const
     uint argOutCount = 0;
     this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &dummyInstr, argOutCount);
 
+    Assert(implicitThisArgOut);
+    Assert(explicitThisArgOut);
+    
     TryFixedMethodAndPrepareInsertionPoint(callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
 
     InsertInlineeBuiltInStartEndTags(callInstr, 2); // 2 args (implicit this + explicit this)
@@ -2988,6 +3004,8 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co
     IR::Instr * dummyInstr2 = nullptr;
     this->GetArgInstrsForCallAndApply(callInstr, &argImplicitInstr, &dummyInstr1, &dummyInstr2, actualCount);
 
+    Assert(argImplicitInstr);
+
     IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2()->AsSymOpnd();
 
     TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);

+ 6 - 5
lib/Backend/JITTimeFunctionBody.cpp

@@ -21,17 +21,18 @@ JITTimeFunctionBody::InitializeJITFunctionData(
     Assert(functionBody != nullptr);
 
     // const table
-    jitBody->constCount = functionBody->GetConstantCount();
-    if (functionBody->GetConstantCount() > 0)
+    const Js::RegSlot numConstants = functionBody->GetConstantCount();
+    jitBody->constCount = numConstants;
+    if (numConstants > 0)
     {
         jitBody->constTable = (intptr_t *)PointerValue(functionBody->GetConstTable());
         if (!functionBody->GetIsAsmJsFunction())
         {
             jitBody->constTableContent = AnewStructZ(arena, ConstTableContentIDL);
-            jitBody->constTableContent->count = functionBody->GetConstantCount();
-            jitBody->constTableContent->content = AnewArrayZ(arena, RecyclableObjectIDL*, functionBody->GetConstantCount());
+            jitBody->constTableContent->count = numConstants;
+            jitBody->constTableContent->content = AnewArrayZ(arena, RecyclableObjectIDL*, numConstants);
 
-            for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < functionBody->GetConstantCount(); ++reg)
+            for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < numConstants; ++reg)
             {
                 Js::Var varConst = functionBody->GetConstantVar(reg);
                 Assert(varConst != nullptr);

+ 1 - 1
lib/Backend/arm/LowerMD.cpp

@@ -1711,7 +1711,7 @@ LowererMD::LowerTry(IR::Instr * tryInstr, IR::JnHelperMethod helperMethod)
     if (tryInstr->m_opcode == Js::OpCode::TryCatch || this->m_func->DoOptimizeTry())
     {
         // Arg 6 : hasBailedOutOffset
-        IR::Opnd * hasBailedOutOffset = IR::IntConstOpnd::New(this->m_func->m_hasBailedOutSym->m_offset, TyInt32, this->m_func);
+        IR::Opnd * hasBailedOutOffset = IR::IntConstOpnd::New(this->m_func->m_hasBailedOutSym->m_offset + tryInstr->m_func->GetInlineeArgumentStackSize(), TyInt32, this->m_func);
         this->LoadHelperArgument(tryAddr, hasBailedOutOffset);
     }
 

+ 15 - 1
lib/Backend/arm64/ARM64Encoder.h

@@ -3064,7 +3064,7 @@ EmitAddSubImmediateCommon(
     //
     // Otherwise fail.
     //
-
+    AssertMsg(false, "EmitAddSubImmediateCommon failed to emit");
     return 0;
 }
 
@@ -3092,6 +3092,8 @@ EmitAddImmediate64(
     if (LONG(Immediate) == Immediate) {
         return EmitAddSubImmediateCommon(Emitter, Dest, Src, LONG(Immediate), false, true, 0x80000000);
     }
+
+    AssertMsg(false, "EmitAddImmediate64 failed to emit");
     return 0;
 }
 
@@ -3119,6 +3121,8 @@ EmitAddsImmediate64(
     if (LONG(Immediate) == Immediate) {
         return EmitAddSubImmediateCommon(Emitter, Dest, Src, LONG(Immediate), true, true, 0x80000000);
     }
+
+    AssertMsg(false, "EmitAddsImmediate64 failed to emit");
     return 0;
 }
 
@@ -3146,6 +3150,8 @@ EmitSubImmediate64(
     if (-LONG(Immediate) == -LONG64(Immediate)) {
         return EmitAddSubImmediateCommon(Emitter, Dest, Src, -LONG(Immediate), false, false, 0x80000000);
     }
+
+    AssertMsg(false, "EmitSubImmediate64 failed to emit");
     return 0;
 }
 
@@ -3173,6 +3179,8 @@ EmitSubsImmediate64(
     if (-LONG(Immediate) == -LONG64(Immediate)) {
         return EmitAddSubImmediateCommon(Emitter, Dest, Src, -LONG(Immediate), true, false, 0x80000000);
     }
+
+    AssertMsg(false, "EmitSubsImmediate64 failed to emit");
     return 0;
 }
 
@@ -3255,6 +3263,8 @@ EmitLogicalImmediateCommon(
 
             return Emitter.EmitFourBytes(NotRegisterOpcode | (31 << 16) | (Src.RawRegister() << 5) | Dest.RawRegister());
         }
+
+        AssertMsg(false, "EmitLogicalImmediateCommon failed to emit");
         return 0;
     }
 
@@ -3540,6 +3550,7 @@ EmitLdrStrRegisterCommon(
     if (Index.ShiftType() != SHIFT_NONE && Index.ShiftCount() == AccessShift) {
         Amount = 1;
     } else if (Index.ShiftCount() != 0) {
+        AssertMsg(false, "EmitLdrStrRegisterCommon failed to emit");
         return 0;
     }
 
@@ -3747,6 +3758,7 @@ EmitLdrStrOffsetCommon(
         return Emitter.EmitFourBytes(OpcodeUnscaled | ((Offset & 0x1ff) << 12) | (Addr.RawRegister() << 5) | SrcDest.RawRegister());
     }
 
+    AssertMsg(false, "EmitLdrStrOffsetCommon failed to emit");
     return 0;
 }
 
@@ -4018,6 +4030,8 @@ EmitLdpStpOffsetCommon(
     if ((EncodeOffset << AccessShift) == Offset && EncodeOffset >= -0x40 && EncodeOffset <= 0x3f) {
         return Emitter.EmitFourBytes(Opcode | ((EncodeOffset & 0x7f) << 15) | (SrcDest2.RawRegister() << 10) | (Addr.RawRegister() << 5) | SrcDest1.RawRegister());
     }
+
+    AssertMsg(false, "EmitLdpStpOffsetCommon failed to emit");
     return 0;
 }
 

+ 18 - 7
lib/Backend/arm64/EncoderMD.cpp

@@ -313,11 +313,22 @@ int EncoderMD::EmitOp3RegisterOrImmediate(Arm64CodeEmitter &Emitter, IR::Instr*
     }
     else
     {
-        Assert(false);
+        AssertMsg(false, "EmitOp3RegisterOrImmediate failed to encode");
         return 0;
     }
 }
 
+template<typename _RegFunc32, typename _RegFunc64, typename _ImmFunc32, typename _ImmFunc64>
+int EncoderMD::EmitOp3RegisterOrImmediateExtendSP(Arm64CodeEmitter &Emitter, IR::Instr* instr, _RegFunc32 reg32, _RegFunc64 reg64, _ImmFunc32 imm32, _ImmFunc64 imm64)
+{
+    if (instr->GetSrc1()->AsRegOpnd()->GetReg() == RegSP)
+    {
+        return this->EmitOp3RegisterShifted(Emitter, instr, EXTEND_UXTX, 0, reg32, reg64);
+    }
+
+    return EmitOp3RegisterOrImmediate(Emitter, instr, reg32, reg64, imm32, imm64);
+}
+
 int EncoderMD::EmitPrefetch(Arm64CodeEmitter &Emitter, IR::Instr* instr, IR::Opnd* memOpnd)
 {
     Assert(memOpnd->IsIndirOpnd() || memOpnd->IsSymOpnd());
@@ -404,7 +415,7 @@ int EncoderMD::EmitLoadStorePair(Arm64CodeEmitter &Emitter, IR::Instr* instr, IR
     if (DecodeMemoryOpnd(memOpnd, baseReg, indexReg, indexScale, offset))
     {
         // Should never get here
-        Assert(false);
+        AssertMsg(false, "EmitLoadStorePair failed to encode");
         return 0;
     }
     else
@@ -636,7 +647,7 @@ int EncoderMD::EmitLoadStoreFp(Arm64CodeEmitter &Emitter, IR::Instr* instr, IR::
     if (DecodeMemoryOpnd(memOpnd, baseReg, indexReg, indexScale, offset))
     {
         // Should never get here
-        Assert(false);
+        AssertMsg(false, "EmitLoadStoreFp failed to encode");
         return 0;
     }
     else
@@ -660,7 +671,7 @@ int EncoderMD::EmitLoadStoreFpPair(Arm64CodeEmitter &Emitter, IR::Instr* instr,
     if (DecodeMemoryOpnd(memOpnd, baseReg, indexReg, indexScale, offset))
     {
         // Should never get here
-        Assert(false);
+        AssertMsg(false, "EmitLoadStoreFpPair failed to encode");
         return 0;
     }
     else
@@ -702,7 +713,7 @@ int EncoderMD::EmitConvertToInt(Arm64CodeEmitter &Emitter, IR::Instr* instr, _In
     }
     
     // Shouldn't get here
-    Assert(false);
+    AssertMsg(false, "EmitConvertToInt failed to encode");
     return 0;
 }
 
@@ -731,7 +742,7 @@ EncoderMD::GenerateEncoding(IR::Instr* instr, BYTE *pc)
         break;
 
     case Js::OpCode::ADDS:
-        bytes = this->EmitOp3RegisterOrImmediate(Emitter, instr, EmitAddsRegister, EmitAddsRegister64, EmitAddsImmediate, EmitAddsImmediate64);
+        bytes = this->EmitOp3RegisterOrImmediateExtendSP(Emitter, instr, EmitAddsRegister, EmitAddsRegister64, EmitAddsImmediate, EmitAddsImmediate64);
         break;
 
     case Js::OpCode::ADR:
@@ -1077,7 +1088,7 @@ EncoderMD::GenerateEncoding(IR::Instr* instr, BYTE *pc)
         break;
 
     case Js::OpCode::SUBS:
-        bytes = this->EmitOp3RegisterOrImmediate(Emitter, instr, EmitSubsRegister, EmitSubsRegister64, EmitSubsImmediate, EmitSubsImmediate64);
+        bytes = this->EmitOp3RegisterOrImmediateExtendSP(Emitter, instr, EmitSubsRegister, EmitSubsRegister64, EmitSubsImmediate, EmitSubsImmediate64);
         break;
 
     case Js::OpCode::SUB_LSL4:

+ 2 - 1
lib/Backend/arm64/EncoderMD.h

@@ -226,8 +226,9 @@ private:
     // General 3-operand instructions (ADD, AND, SUB, etc) follow a very standard pattern
     template<typename _RegFunc32, typename _RegFunc64> int EmitOp3Register(Arm64CodeEmitter &Emitter, IR::Instr* instr, _RegFunc32 reg32, _RegFunc64 reg64);
     template<typename _RegFunc32, typename _RegFunc64> int EmitOp3RegisterShifted(Arm64CodeEmitter &Emitter, IR::Instr* instr, SHIFT_EXTEND_TYPE shiftType, int shiftAmount, _RegFunc32 reg32, _RegFunc64 reg64);
-        template<typename _ImmFunc32, typename _ImmFunc64> int EmitOp3Immediate(Arm64CodeEmitter &Emitter, IR::Instr* instr, _ImmFunc32 imm32, _ImmFunc64 imm64);
+    template<typename _ImmFunc32, typename _ImmFunc64> int EmitOp3Immediate(Arm64CodeEmitter &Emitter, IR::Instr* instr, _ImmFunc32 imm32, _ImmFunc64 imm64);
     template<typename _RegFunc32, typename _RegFunc64, typename _ImmFunc32, typename _ImmFunc64> int EmitOp3RegisterOrImmediate(Arm64CodeEmitter &Emitter, IR::Instr* instr, _RegFunc32 reg32, _RegFunc64 reg64, _ImmFunc32 imm32, _ImmFunc64 imm64);
+    template<typename _RegFunc32, typename _RegFunc64, typename _ImmFunc32, typename _ImmFunc64> int EmitOp3RegisterOrImmediateExtendSP(Arm64CodeEmitter &Emitter, IR::Instr* instr, _RegFunc32 reg32, _RegFunc64 reg64, _ImmFunc32 imm32, _ImmFunc64 imm64);
 
     // Load/store operations
     int EmitPrefetch(Arm64CodeEmitter &Emitter, IR::Instr* instr, IR::Opnd* memOpnd);

+ 26 - 32
lib/Backend/arm64/LowerMD.cpp

@@ -443,44 +443,29 @@ LowererMD::GenerateFunctionObjectTest(IR::Instr * callInstr, IR::RegOpnd  *funct
 {
     AssertMsg(!m_func->IsJitInDebugMode() || continueAfterExLabel, "When jit is in debug mode, continueAfterExLabel must be provided otherwise continue after exception may cause AV.");
 
+    // Need check and error if we are calling a tagged int.
     if (!functionObjOpnd->IsNotTaggedValue())
     {
-        IR::Instr * insertBeforeInstr = callInstr;
-        // Need check and error if we are calling a tagged int.
-        if (!functionObjOpnd->IsTaggedInt())
+        IR::LabelInstr * helperLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
+        if (this->GenerateObjectTest(functionObjOpnd, callInstr, helperLabel))
         {
-            // TST functionObjOpnd, 1
-            IR::Instr * instr = IR::Instr::New(Js::OpCode::TST, this->m_func);
-            instr->SetSrc1(functionObjOpnd);
-            instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyMachReg, this->m_func));
-            callInstr->InsertBefore(instr);
-            LegalizeMD::LegalizeInstr(instr, false);
-
-            // BNE $helper
-            // B $callLabel
-
-            IR::LabelInstr * helperLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
-            instr = IR::BranchInstr::New(Js::OpCode::BNE, helperLabel, this->m_func);
-            callInstr->InsertBefore(instr);
 
             IR::LabelInstr * callLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, isHelper);
-            instr = IR::BranchInstr::New(Js::OpCode::B, callLabel, this->m_func);
+            IR::Instr * instr = IR::BranchInstr::New(Js::OpCode::B, callLabel, this->m_func);
             callInstr->InsertBefore(instr);
 
             callInstr->InsertBefore(helperLabel);
             callInstr->InsertBefore(callLabel);
 
-            insertBeforeInstr = callLabel;
-        }
-
-        this->m_lowerer->GenerateRuntimeError(insertBeforeInstr, JSERR_NeedFunction);
+            this->m_lowerer->GenerateRuntimeError(callLabel, JSERR_NeedFunction);
 
-        if (continueAfterExLabel)
-        {
-            // Under debugger the RuntimeError (exception) can be ignored, generate branch right after RunTimeError instr
-            // to jmp to a safe place (which would normally be debugger bailout check).
-            IR::BranchInstr* continueAfterEx = IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, continueAfterExLabel, this->m_func);
-            insertBeforeInstr->InsertBefore(continueAfterEx);
+            if (continueAfterExLabel)
+            {
+                // Under debugger the RuntimeError (exception) can be ignored, generate branch to jmp to safe place
+                // (which would normally be debugger bailout check).
+                IR::BranchInstr* continueAfterEx = IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, continueAfterExLabel, this->m_func);
+                callLabel->InsertBefore(continueAfterEx);
+            }
         }
     }
 }
@@ -1504,7 +1489,7 @@ LowererMD::LowerTry(IR::Instr * tryInstr, IR::JnHelperMethod helperMethod)
     if (tryInstr->m_opcode == Js::OpCode::TryCatch || this->m_func->DoOptimizeTry())
     {
         // Arg 6 : hasBailedOutOffset
-        IR::Opnd * hasBailedOutOffset = IR::IntConstOpnd::New(this->m_func->m_hasBailedOutSym->m_offset, TyInt32, this->m_func);
+        IR::Opnd * hasBailedOutOffset = IR::IntConstOpnd::New(this->m_func->m_hasBailedOutSym->m_offset + tryInstr->m_func->GetInlineeArgumentStackSize(), TyInt32, this->m_func);
         this->LoadHelperArgument(tryAddr, hasBailedOutOffset);
     }
 
@@ -2106,18 +2091,27 @@ LowererMD::ChangeToAssign(IR::Instr * instr, IRType destType)
     }
     else if (TySize[destType] > TySize[srcType] && (IRType_IsSignedInt(destType) || IRType_IsUnsignedInt(destType)))
     {
+        IR::Opnd *newSrcOpnd = src;
+
+        // If we have a indirect opnd and a scale we can't just change the source type, move the result to scratch reg and use that as src
+        if (newSrcOpnd->IsIndirOpnd() && newSrcOpnd->AsIndirOpnd()->GetScale() != 0)
+        {
+            newSrcOpnd = IR::RegOpnd::New(nullptr, SCRATCH_REG, srcType, instr->m_func);
+            Lowerer::InsertMove(newSrcOpnd, src, instr);
+            Assert(TySize[newSrcOpnd->GetType()] >= TySize[srcType]);
+        }
         // If we're moving between different lengths of registers, we need to use the
         // right operator - sign extend if the source is int, zero extend if uint.
         if (IRType_IsSignedInt(srcType))
         {
-            instr->ReplaceSrc1(src->UseWithNewType(IRType_EnsureSigned(destType), instr->m_func));
-            instr->SetSrc2(IR::IntConstOpnd::New(BITFIELD(0, (TySize[srcType] * MachBits) - 1), TyMachReg, instr->m_func, true));
+            instr->ReplaceSrc1(newSrcOpnd->UseWithNewType(IRType_EnsureSigned(destType), instr->m_func));
+            instr->SetSrc2(IR::IntConstOpnd::New(BITFIELD(0, TySize[srcType] * MachBits), TyMachReg, instr->m_func, true));
             instr->m_opcode = Js::OpCode::SBFX;
         }
         else if (IRType_IsUnsignedInt(srcType))
         {
-            instr->ReplaceSrc1(src->UseWithNewType(IRType_EnsureUnsigned(destType), instr->m_func));
-            instr->SetSrc2(IR::IntConstOpnd::New(BITFIELD(0, (TySize[srcType] * MachBits) - 1), TyMachReg, instr->m_func, true));
+            instr->ReplaceSrc1(newSrcOpnd->UseWithNewType(IRType_EnsureUnsigned(destType), instr->m_func));
+            instr->SetSrc2(IR::IntConstOpnd::New(BITFIELD(0, TySize[srcType] * MachBits), TyMachReg, instr->m_func, true));
             instr->m_opcode = Js::OpCode::UBFX;
         }
         else

+ 2 - 2
lib/Backend/arm64/Thunks.asm

@@ -40,11 +40,11 @@
     bl      |?CheckCodeGen@NativeCodeGenerator@@SAP6APEAXPEAVRecyclableObject@Js@@UCallInfo@3@ZZPEAVScriptFunction@3@@Z|  ; call  NativeCodeGenerator::CheckCodeGen
 
 #if defined(_CONTROL_FLOW_GUARD)
-    mov     x19, x0               ; save entryPoint in x19
+    mov     x15, x0               ; __guard_check_icall_fptr requires the call target in x15
     adrp    x17, __guard_check_icall_fptr
     ldr     x17, [x17, __guard_check_icall_fptr]
     blr     x17
-    mov     x17, x19              ; restore entryPoint in x17
+    mov     x17, x15              ; restore entryPoint in x17
 #else
     mov     x17, x0               ; back up entryPoint in x17
 #endif

+ 2 - 1
lib/Common/Memory/ArenaAllocator.cpp

@@ -588,9 +588,10 @@ Free(void * buffer, size_t byteSize)
 
         void **policy = &this->freeList;
 #if DBG
+        void *delayFreeList;
         if (needsDelayFreeList)
         {
-            void *delayFreeList = reinterpret_cast<FreeObject **>(this->freeList) + (MaxSmallObjectSize >> ObjectAlignmentBitShift);
+            delayFreeList = reinterpret_cast<FreeObject **>(this->freeList) + (MaxSmallObjectSize >> ObjectAlignmentBitShift);
             policy = &delayFreeList;
         }
 #endif

+ 45 - 42
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -1709,10 +1709,14 @@ namespace Js
     }
 #endif
 
+#if !defined(_M_ARM64)
     Var InterpreterStackFrame::StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
     {
         return InterpreterThunk((JavascriptCallStackLayout*)&function);
     }
+#else
+    // Language\arm64\arm64_Thunks.asm
+#endif
 #pragma optimize("", on)
 
     Var InterpreterStackFrame::InterpreterThunk(JavascriptCallStackLayout* layout)
@@ -1965,7 +1969,7 @@ namespace Js
         TTD::TTDExceptionFramePopper exceptionFramePopper;
         if(SHOULD_DO_TTD_STACK_STMT_OP(functionScriptContext))
         {
-            bool isInFinally = ((newInstance->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock) == Js::InterpreterStackFrameFlags_WithinFinallyBlock);
+            bool isInFinally = newInstance->TestFlags(Js::InterpreterStackFrameFlags_WithinFinallyBlock);
 
             threadContext->TTDExecutionInfo->PushCallEvent(function, args.Info.Count, args.Values, isInFinally);
             exceptionFramePopper.PushInfo(threadContext->TTDExecutionInfo, function);
@@ -2868,7 +2872,6 @@ namespace Js
 #else
         InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr);
 #endif
-
         newInstance->m_reader.Create(funcObj->GetFunctionBody());
         // now that we have set up the new frame, let's interpret it!
         funcObj->GetFunctionBody()->BeginExecution();
@@ -3285,11 +3288,11 @@ namespace Js
         } autoRestore(this);
 #endif
 
-        if (this->ehBailoutData && !(m_flags & InterpreterStackFrameFlags_FromInlineeCodeInEHBailOut))
+        if (this->ehBailoutData && !this->TestFlags(InterpreterStackFrameFlags_FromBailOutInInlinee))
         {
-            if ((m_flags & Js::InterpreterStackFrameFlags_FromBailOut) && !(m_flags & InterpreterStackFrameFlags_ProcessingBailOutFromEHCode))
+            if (this->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut) && !this->TestFlags(InterpreterStackFrameFlags_ProcessingBailOutFromEHCode))
             {
-                m_flags |= Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
+                this->OrFlags(Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode);
                 EHBailoutData * topLevelEHBailoutData = this->ehBailoutData;
                 while (topLevelEHBailoutData->parent->nestingDepth != -1)
                 {
@@ -3297,7 +3300,7 @@ namespace Js
                     topLevelEHBailoutData = topLevelEHBailoutData->parent;
                 }
                 ProcessTryHandlerBailout(topLevelEHBailoutData, this->ehBailoutData->nestingDepth);
-                m_flags &= ~Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
+                this->ClearFlags(Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode);
                 this->ehBailoutData = nullptr;
             }
         }
@@ -3364,7 +3367,7 @@ namespace Js
 #if ENABLE_PROFILE_INFO
         FunctionBody *const functionBody = GetFunctionBody();
         const ExecutionMode interpreterExecutionMode =
-            functionBody->GetInterpreterExecutionMode(!!(GetFlags() & InterpreterStackFrameFlags_FromBailOut));
+            functionBody->GetInterpreterExecutionMode(TestFlags(InterpreterStackFrameFlags_FromBailOut));
         if(interpreterExecutionMode == ExecutionMode::ProfilingInterpreter)
         {
 #if ENABLE_TTD
@@ -5021,9 +5024,9 @@ namespace Js
                 GetReg(playout->Element),
                 m_functionBody,
                 playout->profileId,
-                (m_flags & InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall) != 0));
+                this->TestFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall)));
 
-        m_flags &= ~InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall;
+        this->ClearFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall);
 
         threadContext->CheckAndResetImplicitCallAccessorFlag();
         threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
@@ -5058,7 +5061,7 @@ namespace Js
             element = JavascriptOperators::OP_GetElementI(instance, GetReg(playout->Element), GetScriptContext());
         }
 
-        m_flags &= ~InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall;
+        this->ClearFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall);
 
         threadContext->CheckAndResetImplicitCallAccessorFlag();
         threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
@@ -5098,7 +5101,7 @@ namespace Js
             JavascriptOperators::OP_SetElementI(instance, varIndex, value, GetScriptContext(), flags);
         }
 
-        m_flags &= ~InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall;
+        this->ClearFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall);
 
         threadContext->CheckAndResetImplicitCallAccessorFlag();
         threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
@@ -5121,9 +5124,9 @@ namespace Js
             m_functionBody,
             playout->profileId,
             flags,
-            (m_flags & InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall) != 0);
+            this->TestFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall));
 
-        m_flags &= ~InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall;
+        this->ClearFlags(InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall);
 
         threadContext->CheckAndResetImplicitCallAccessorFlag();
         threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
@@ -5861,7 +5864,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         Assert(!this->IsInCatchOrFinallyBlock());
 
         Js::LoopHeader *loopHeader = fn->GetLoopHeader(loopNumber);
-        loopHeader->isInTry = (this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
+        loopHeader->isInTry = this->TestFlags(Js::InterpreterStackFrameFlags_WithinTryBlock);
 
         Js::LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
 
@@ -6454,7 +6457,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
     void InterpreterStackFrame::OP_ChkNewCallFlag()
     {
-        if (!(this->m_callFlags & CallFlags_New))
+        if (!(this->m_callFlags & CallFlags_New) && !this->TestFlags(InterpreterStackFrameFlags_FromBailOutInInlinee))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew);
         }
@@ -6495,7 +6498,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         {
             this->nestedTryDepth++;
             // mark the stackFrame as 'in try block'
-            this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
+            this->OrFlags(InterpreterStackFrameFlags_WithinTryBlock);
 
             Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
 
@@ -6534,7 +6537,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         if (--this->nestedTryDepth == -1)
         {
             // unmark the stackFrame as 'in try block'
-            this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
+            this->ClearFlags(InterpreterStackFrameFlags_WithinTryBlock);
         }
 
         // Now that the stack is unwound, let's run the catch block.
@@ -6573,14 +6576,14 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
             this->nestedCatchDepth++;
             // mark the stackFrame as 'in catch block'
-            this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
+            this->OrFlags(InterpreterStackFrameFlags_WithinCatchBlock);
 
             this->ProcessCatch();
 
             if (--this->nestedCatchDepth == -1)
             {
                 // unmark the stackFrame as 'in catch block'
-                this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
+                this->ClearFlags(InterpreterStackFrameFlags_WithinCatchBlock);
             }
         }
     }
@@ -6637,7 +6640,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             {
                 this->nestedTryDepth++;
                 // mark the stackFrame as 'in try block'
-                this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
+                this->OrFlags(InterpreterStackFrameFlags_WithinTryBlock);
 
                 if (tryNestingDepth != 0)
                 {
@@ -6685,7 +6688,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         {
             this->nestedCatchDepth++;
             // mark the stackFrame as 'in catch block'
-            this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
+            this->OrFlags(InterpreterStackFrameFlags_WithinCatchBlock);
 
             if (tryNestingDepth != 0)
             {
@@ -6696,7 +6699,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             if (--this->nestedCatchDepth == -1)
             {
                 // unmark the stackFrame as 'in catch block'
-                this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
+                this->ClearFlags(InterpreterStackFrameFlags_WithinCatchBlock);
             }
             return;
         }
@@ -6705,7 +6708,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             Assert(ehBailoutData->ht == HandlerType::HT_Finally);
             this->nestedFinallyDepth++;
             // mark the stackFrame as 'in finally block'
-            this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
+            this->OrFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
             if (tryNestingDepth != 0)
             {
@@ -6720,7 +6723,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             if (--this->nestedFinallyDepth == -1)
             {
                 // unmark the stackFrame as 'in finally block'
-                this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
+                this->ClearFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
             }
 
             // Finally exited with LeaveNull, We don't throw for early returns
@@ -6739,7 +6742,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         if (--this->nestedTryDepth == -1)
         {
             // unmark the stackFrame as 'in try block'
-            this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
+            this->ClearFlags(InterpreterStackFrameFlags_WithinTryBlock);
         }
 
         // Now that the stack is unwound, let's run the catch block.
@@ -6779,14 +6782,14 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
                 this->nestedCatchDepth++;
                 // mark the stackFrame as 'in catch block'
-                this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
+                this->OrFlags(InterpreterStackFrameFlags_WithinCatchBlock);
 
                 this->ProcessCatch();
 
                 if (--this->nestedCatchDepth == -1)
                 {
                     // unmark the stackFrame as 'in catch block'
-                    this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
+                    this->ClearFlags(InterpreterStackFrameFlags_WithinCatchBlock);
                 }
             }
             else
@@ -6800,7 +6803,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
                 this->nestedFinallyDepth++;
                 // mark the stackFrame as 'in finally block'
-                this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
+                this->OrFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
                 LayoutSize layoutSize;
                 OpCode finallyOp = m_reader.ReadOp(layoutSize);
@@ -6820,7 +6823,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
                 if (--this->nestedFinallyDepth == -1)
                 {
                     // unmark the stackFrame as 'in finally block'
-                    this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
+                    this->ClearFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
                 }
                 if (finallyEndOffset == 0)
                 {
@@ -6840,7 +6843,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
                 this->nestedFinallyDepth++;
 
                 // mark the stackFrame as 'in finally block'
-                this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
+                this->OrFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
                 LayoutSize layoutSize;
                 OpCode finallyOp = m_reader.ReadOp(layoutSize);
@@ -6860,7 +6863,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
                 if (--this->nestedFinallyDepth == -1)
                 {
                     // unmark the stackFrame as 'in finally block'
-                    this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
+                    this->ClearFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
                 }
                 if (finallyEndOffset == 0)
                 {
@@ -6872,7 +6875,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
     void InterpreterStackFrame::TrySetRetOffset()
     {
-        Assert(this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
+        Assert(this->TestFlags(Js::InterpreterStackFrameFlags_WithinTryBlock));
         // It may happen that a JITted loop body returned the offset of RET. If the loop body was
         // called from a try, the interpreter "Process()" should also just return.
         if (this->retOffset != 0)
@@ -6883,8 +6886,8 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
     bool InterpreterStackFrame::IsInCatchOrFinallyBlock()
     {
-        return (this->m_flags & Js::InterpreterStackFrameFlags_WithinCatchBlock) ||
-               (this->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock);
+        return this->TestFlags(Js::InterpreterStackFrameFlags_WithinCatchBlock) ||
+               this->TestFlags(Js::InterpreterStackFrameFlags_WithinFinallyBlock);
     }
 
     void InterpreterStackFrame::OP_BeginBodyScope()
@@ -6911,7 +6914,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
     void InterpreterStackFrame::OP_ResumeCatch()
     {
-        this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
+        this->OrFlags(InterpreterStackFrameFlags_WithinCatchBlock);
 
 #ifdef ENABLE_SCRIPT_DEBUGGING
         if (this->IsInDebugMode())
@@ -6924,7 +6927,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             this->Process();
         }
 
-        this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
+        this->ClearFlags(InterpreterStackFrameFlags_WithinCatchBlock);
     }
 
     /// ---------------------------------------------------------------------------------------------------
@@ -6945,7 +6948,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
             this->nestedTryDepth++;
             // mark the stackFrame as 'in try block'
-            this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
+            this->OrFlags(InterpreterStackFrameFlags_WithinTryBlock);
 
             if (shouldCacheSP)
             {
@@ -6988,7 +6991,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         if (--this->nestedTryDepth == -1)
         {
             // unmark the stackFrame as 'in try block'
-            this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
+            this->ClearFlags(InterpreterStackFrameFlags_WithinTryBlock);
         }
 
         shouldCacheSP = !skipFinallyBlock;
@@ -7032,7 +7035,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
         RestoreSp();
         // mark the stackFrame as 'in finally block'
-        this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
+        this->OrFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
         LayoutSize layoutSize;
         OpCode finallyOp = m_reader.ReadOp(layoutSize);
@@ -7052,7 +7055,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
         if (--this->nestedFinallyDepth == -1)
         {
             // unmark the stackFrame as 'in finally block'
-            this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
+            this->ClearFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
         }
 
         bool endOfFinallyBlock = newOffset == 0;
@@ -7087,7 +7090,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
 
     void InterpreterStackFrame::OP_ResumeFinally(const byte* ip, Js::JumpOffset jumpOffset, RegSlot exceptionRegSlot, RegSlot offsetRegSlot)
     {
-        this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
+        this->OrFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
         int newOffset = 0;
 #ifdef ENABLE_SCRIPT_DEBUGGING
@@ -7101,7 +7104,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
             newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
         }
 
-        this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
+        this->ClearFlags(InterpreterStackFrameFlags_WithinFinallyBlock);
 
         bool endOfFinallyBlock = newOffset == 0;
         if (endOfFinallyBlock)

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

@@ -27,7 +27,7 @@ namespace Js
         InterpreterStackFrameFlags_FromBailOut = 8,
         InterpreterStackFrameFlags_ProcessingBailOutOnArrayAccessHelperCall = 0x10,
         InterpreterStackFrameFlags_ProcessingBailOutFromEHCode = 0x20,
-        InterpreterStackFrameFlags_FromInlineeCodeInEHBailOut = 0x40,
+        InterpreterStackFrameFlags_FromBailOutInInlinee = 0x40,
         InterpreterStackFrameFlags_All = 0xFFFF,
     };
 
@@ -289,6 +289,8 @@ namespace Js
         void SetArgumentsObject(Var args) { m_arguments = args; }
         UINT16 GetFlags() const { return m_flags; }
         void OrFlags(UINT16 addTo) { m_flags |= addTo; }
+        void ClearFlags(UINT16 flags) { m_flags &= ~flags; }
+        bool TestFlags(UINT16 flags) { return (m_flags & flags) != 0; }
         bool IsInCatchOrFinallyBlock();
         static bool IsDelayDynamicInterpreterThunk(JavascriptMethod entryPoint);
 

+ 3 - 3
lib/Runtime/Language/JavascriptStackWalker.cpp

@@ -540,7 +540,7 @@ namespace Js
 #endif
 
                 // We might've bailed out of an inlinee, so check if there were any inlinees.
-                if (this->interpreterFrame->GetFlags() & InterpreterStackFrameFlags_FromBailOut)
+                if (this->interpreterFrame->TestFlags(InterpreterStackFrameFlags_FromBailOut))
                 {
                     previousInterpreterFrameIsFromBailout = true;
 
@@ -907,7 +907,7 @@ namespace Js
         void * codeAddr = this->currentFrame.GetInstructionPointer();
         if (this->tempInterpreterFrame && codeAddr == this->tempInterpreterFrame->GetReturnAddress())
         {
-            bool isBailoutInterpreter = (this->tempInterpreterFrame->GetFlags() & Js::InterpreterStackFrameFlags_FromBailOut) != 0;
+            bool isBailoutInterpreter = this->tempInterpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut);
 
             // We need to skip over the first interpreter frame on the stack if it is the partially initialized frame
             // otherwise it is a real frame and we should continue.
@@ -940,7 +940,7 @@ namespace Js
                 // The return address of the interpreterFrame is the same as the entryPoint for a jitted loop body.
                 // This can only ever happen when we have bailed out from a function inlined in the loop body. We
                 // wouldn't have created a new interpreterFrame if the bailout were from the loop body itself.
-                Assert((this->interpreterFrame->GetFlags() & Js::InterpreterStackFrameFlags_FromBailOut) != 0);
+                Assert(this->interpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut));
                 InlinedFrameWalker tmpFrameWalker;
                 Assert(InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
                     true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/));

+ 24 - 1
lib/Runtime/Language/arm64/arm64_Thunks.asm

@@ -15,6 +15,8 @@
     EXPORT  |?EnsureDynamicProfileInfoThunk@DynamicProfileInfo@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ|
     ; Var ScriptContext::ProfileModeDeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...)
     EXPORT  |?ProfileModeDeferredParsingThunk@ScriptContext@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ|
+    ; Var InterpreterStackFrame::StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo)
+    EXPORT  |?StaticInterpreterThunk@InterpreterStackFrame@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ|
 
     ;JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(Js::ScriptFunction * function)
     IMPORT  |?EnsureDynamicInterpreterThunk@InterpreterStackFrame@Js@@CAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z|
@@ -24,7 +26,8 @@
     IMPORT  |?ProfileModeDeferredParse@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAPEAVScriptFunction@2@@Z|
     ;JavascriptMethod ScriptContext::ProfileModeDeferredDeserialize(ScriptFunction *function)
     IMPORT  |?ProfileModeDeferredDeserialize@ScriptContext@Js@@SAP6APEAXPEAVRecyclableObject@2@UCallInfo@2@ZZPEAVScriptFunction@2@@Z|
-
+    ;Var InterpreterStackFrame::InterpreterThunk(JavascriptCallStackLayout* layout)
+    IMPORT  |?InterpreterThunk@InterpreterStackFrame@Js@@SAPEAXPEAVJavascriptCallStackLayout@2@@Z|
     TEXTAREA
 
 ;;============================================================================================================
@@ -123,6 +126,26 @@
     EPILOG_RESTORE_REG_PAIR fp, lr, #80!
     EPILOG_NOP br x16             ; jump (tail call) to new entryPoint
 
+    NESTED_END
+
+;;============================================================================================================
+;; InterpreterStackFrame::StaticInterpreterThunk
+;;============================================================================================================
+    ;; Var InterpreterStackFrame::StaticInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
+    NESTED_ENTRY ?StaticInterpreterThunk@InterpreterStackFrame@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ
+
+    PROLOG_SAVE_REG_PAIR fp, lr, #-80!
+    stp   x0, x1, [sp, #16]
+    stp   x2, x3, [sp, #32]
+    stp   x4, x5, [sp, #48]
+    stp   x6, x7, [sp, #64]
+
+    add   x0, sp, #16
+    bl |?InterpreterThunk@InterpreterStackFrame@Js@@SAPEAXPEAVJavascriptCallStackLayout@2@@Z| ; call InterpreterStackFrame::InterpreterThunk
+    
+    EPILOG_RESTORE_REG_PAIR fp, lr, #80!
+    EPILOG_RETURN
+
     NESTED_END
 ;;============================================================================================================
     END

+ 1 - 0
lib/Runtime/Library/arm64/arm64_CallFunction.asm

@@ -54,6 +54,7 @@
     mov     x9, x3                              ; copy values pointer to x9
 
 #if _CONTROL_FLOW_GUARD
+    mov     x15, x4                             ; __guard_check_icall_fptr requires the call target in x15
     adrp    x16, __guard_check_icall_fptr       ;
     ldr     x16, [x16, __guard_check_icall_fptr]; fetch address of guard check handler
     blr     x16                                 ; call it