Skip to content

Commit ea45851

Browse files
committed
Redefer function bodies that are not currently being executed and are
eligible for deferred parsing (e.g., not arrow functions, not functions-in-block). This is experimental behavior, off by default. Define an 'on' mode in which all eligible functions are redeferred on GC, as well as a 'stress' mode in which all candidates are redeferred on each stack probe. This change is built on a previous PR that refactors the FunctionBody hierarchy to make it easier to toggle between deferred and fully-compiled states.
1 parent 2b0bbf5 commit ea45851

File tree

71 files changed

+2029
-1529
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2029
-1529
lines changed

lib/Backend/BailOut.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,7 +1763,7 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
17631763
bailOutRecordNotConst->bailOutCount++;
17641764

17651765
Js::FunctionEntryPointInfo *entryPointInfo = function->GetFunctionEntryPointInfo();
1766-
uint8 callsCount = entryPointInfo->callsCount;
1766+
uint32 callsCount = entryPointInfo->callsCount;
17671767
RejitReason rejitReason = RejitReason::None;
17681768
bool reThunk = false;
17691769

@@ -2320,11 +2320,7 @@ void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::S
23202320

23212321
entryPointInfo->totalJittedLoopIterations += entryPointInfo->jittedLoopIterationsSinceLastBailout;
23222322
entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
2323-
if (entryPointInfo->totalJittedLoopIterations > UINT8_MAX)
2324-
{
2325-
entryPointInfo->totalJittedLoopIterations = UINT8_MAX;
2326-
}
2327-
uint8 totalJittedLoopIterations = (uint8)entryPointInfo->totalJittedLoopIterations;
2323+
uint32 totalJittedLoopIterations = (uint8)entryPointInfo->totalJittedLoopIterations;
23282324
totalJittedLoopIterations = totalJittedLoopIterations <= Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() ? 0 : totalJittedLoopIterations - Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout();
23292325

23302326
CheckPreemptiveRejit(executeFunction, bailOutKind, bailOutRecordNotConst, totalJittedLoopIterations, interpreterFrame->GetCurrentLoopNum());
@@ -2608,7 +2604,7 @@ void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::S
26082604
}
26092605
}
26102606

2611-
void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber)
2607+
void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint32& callsOrIterationsCount, int loopNumber)
26122608
{
26132609
if (bailOutKind == IR::BailOutOnNoProfile && executeFunction->IncrementBailOnMisingProfileCount() > CONFIG_FLAG(BailOnNoProfileLimit))
26142610
{

lib/Backend/BailOut.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class BailOutRecord
255255

256256
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
257257
static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
258-
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
258+
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint32& callsOrIterationsCount, int loopNumber);
259259
void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, Js::InterpreterStackFrame * newInstance, Js::ScriptContext * scriptContext,
260260
bool fromLoopBody, Js::Var * registerSaves, BailOutReturnValue * returnValue, Js::Var* pArgumentsObject, Js::Var branchValue = nullptr, void* returnAddress = nullptr, bool useStartCall = true, void * argoutRestoreAddress = nullptr) const;
261261
void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, uint count, __in_ecount_opt(count) int * offsets, int argOutSlotId,

lib/Backend/FunctionJITTimeInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
3737

3838
jitData->inlineesBv = (BVFixedIDL*)codeGenData->inlineesBv;
3939

40-
if (codeGenData->GetFunctionInfo()->HasBody())
40+
if (codeGenData->GetFunctionInfo()->HasBody() && codeGenData->GetFunctionInfo()->GetFunctionProxy()->IsFunctionBody())
4141
{
4242
Assert(isInlinee == !!runtimeData);
4343
const Js::FunctionCodeGenRuntimeData * targetRuntimeData = nullptr;

lib/Backend/Inline.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,9 @@ uint Inline::FillInlineesDataArray(
524524
}
525525

526526
intptr_t inlineeFunctionInfoAddr = inlineeJitTimeData->GetFunctionInfoAddr();
527-
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData))
527+
#ifdef DBG
528+
if (inlineeJitTimeData->HasBody() && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData))
529+
#endif
528530
{
529531
const FunctionJITTimeInfo* rightInlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeFunctionInfoAddr);
530532

@@ -571,28 +573,31 @@ void Inline::FillInlineesDataArrayUsingFixedMethods(
571573
JITTimeFunctionBody* inlineeFuncBody = nullptr;
572574
while (inlineeJitTimeData)
573575
{
574-
inlineeFuncBody = inlineeJitTimeData->GetBody();
575-
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeJitTimeData))
576+
if (inlineeJitTimeData->HasBody())
576577
{
577-
const FunctionJITTimeInfo * jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
578-
if (jitTimeData)
578+
inlineeFuncBody = inlineeJitTimeData->GetBody();
579+
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeJitTimeData))
579580
{
580-
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
581+
const FunctionJITTimeInfo * jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
582+
if (jitTimeData)
581583
{
582-
if (inlineeJitTimeData->GetFunctionInfoAddr() == fixedFieldInfoArray[i].GetFuncInfoAddr())
584+
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
583585
{
584-
inlineesDataArray[i] = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
585-
break;
586+
if (inlineeJitTimeData->GetFunctionInfoAddr() == fixedFieldInfoArray[i].GetFuncInfoAddr())
587+
{
588+
inlineesDataArray[i] = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
589+
break;
590+
}
586591
}
587592
}
588-
}
589-
else
590-
{
593+
else
594+
{
591595
#if defined(DBG_DUMP) || defined(ENABLE_DEBUG_CONFIG_OPTIONS)
592-
char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
596+
char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
593597
#endif
594-
POLYMORPHIC_INLINE_TESTTRACE(_u("INLINING (Polymorphic): Missing jit time data skipped inlinee\tInlinee: %s (%s)\n"),
595-
inlineeFuncBody->GetDisplayName(), inlineeJitTimeData->GetDebugNumberSet(debugStringBuffer));
598+
POLYMORPHIC_INLINE_TESTTRACE(_u("INLINING (Polymorphic): Missing jit time data skipped inlinee\tInlinee: %s (%s)\n"),
599+
inlineeFuncBody->GetDisplayName(), inlineeJitTimeData->GetDebugNumberSet(debugStringBuffer));
600+
}
596601
}
597602
}
598603
inlineeJitTimeData = inlineeJitTimeData->GetNext();
@@ -1026,7 +1031,7 @@ Inline::InlinePolymorphicFunction(IR::Instr *callInstr, const FunctionJITTimeInf
10261031
IR::RegOpnd* functionObject = callInstr->GetSrc1()->AsRegOpnd();
10271032
dispatchStartLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::BrAddr_A, inlineeStartLabel,
10281033
IR::IndirOpnd::New(functionObject, Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, dispatchStartLabel->m_func),
1029-
IR::AddrOpnd::New(inlineesDataArray[i]->GetBody()->GetAddr(), IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
1034+
IR::AddrOpnd::New(inlineesDataArray[i]->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
10301035
}
10311036

10321037
CompletePolymorphicInlining(callInstr, returnValueOpnd, doneLabel, dispatchStartLabel, /*ldMethodFldInstr*/nullptr, IR::BailOutOnPolymorphicInlineFunction);
@@ -4063,14 +4068,14 @@ Inline::InsertJsFunctionCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr
40634068
}
40644069

40654070
void
4066-
Inline::InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
4071+
Inline::InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
40674072
{
40684073
// if (JavascriptFunction::FromVar(r1)->functionInfo != funcInfo) goto noInlineLabel
40694074
// BrNeq_I4 noInlineLabel, r1->functionInfo, funcInfo
4070-
IR::IndirOpnd* funcBody = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
4071-
IR::AddrOpnd* inlinedFuncBody = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionBody, callInstr->m_func);
4072-
bailoutInstr->SetSrc1(funcBody);
4073-
bailoutInstr->SetSrc2(inlinedFuncBody);
4075+
IR::IndirOpnd* opndFuncInfo = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
4076+
IR::AddrOpnd* inlinedFuncInfo = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionInfo, callInstr->m_func);
4077+
bailoutInstr->SetSrc1(opndFuncInfo);
4078+
bailoutInstr->SetSrc2(inlinedFuncInfo);
40744079

40754080
insertBeforeInstr->InsertBefore(bailoutInstr);
40764081
}
@@ -4108,7 +4113,7 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
41084113
InsertFunctionTypeIdCheck(callInstr, insertBeforeInstr, bailOutIfNotJsFunction);
41094114

41104115
// 3. Bailout if function body doesn't match funcInfo
4111-
InsertFunctionBodyCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);
4116+
InsertFunctionInfoCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);
41124117

41134118
return primaryBailOutInstr;
41144119
}

lib/Backend/Inline.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Inline
126126
void InsertObjectCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
127127
void InsertFunctionTypeIdCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
128128
void InsertJsFunctionCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind);
129-
void InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
129+
void InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
130130
void InsertFunctionObjectCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
131131

132132
void TryResetObjTypeSpecFldInfoOn(IR::PropertySymOpnd* propertySymOpnd);

lib/Backend/InliningDecider.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ uint InliningDecider::InlinePolymorphicCallSite(Js::FunctionBody *const inliner,
151151
AssertMsg(inlineeCount >= 2, "There are at least two polymorphic call site");
152152
break;
153153
}
154-
if (Inline(inliner, functionBodyArray[inlineeCount], isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
154+
if (Inline(inliner, functionBodyArray[inlineeCount]->GetFunctionInfo(), isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
155155
{
156156
canInlineArray[inlineeCount] = true;
157157
actualInlineeCount++;
@@ -272,7 +272,7 @@ Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::F
272272
#endif
273273

274274
this->bytecodeInlinedCount += inlinee->GetByteCodeCount();
275-
return inlinee;
275+
return inlinee->GetFunctionInfo();
276276
}
277277

278278
Js::OpCode builtInInlineCandidateOpCode;

0 commit comments

Comments
 (0)