Skip to content

Commit f15f3c4

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 8df3f80 commit f15f3c4

30 files changed

+776
-484
lines changed

lib/Backend/Inline.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ uint Inline::FillInlineesDataArray(
497497
}
498498

499499
Js::FunctionBody *inlineeFunctionBody = inlineeJitTimeData->GetFunctionBody();
500-
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFunctionBody))
500+
if (inlineeFunctionBody && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFunctionBody))
501501
{
502502
const Js::FunctionCodeGenJitTimeData* rightInlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFunctionBody->GetFunctionInfo());
503503
const Js::FunctionCodeGenRuntimeData* rightInlineeRuntimeData = inlineeRuntimeData->GetRuntimeDataFromFunctionInfo(inlineeFunctionBody->GetFunctionInfo());
@@ -549,14 +549,15 @@ void Inline::FillInlineesDataArrayUsingFixedMethods(
549549
while (inlineeJitTimeData)
550550
{
551551
inlineeFuncBody = inlineeJitTimeData->GetFunctionBody();
552-
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFuncBody) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeFuncBody))
552+
if (inlineeFuncBody && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFuncBody) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeFuncBody))
553553
{
554554
const Js::FunctionCodeGenJitTimeData* jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());
555555
if (jitTimeData)
556556
{
557557
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
558558
{
559-
if (inlineeFuncBody == ((Js::JavascriptFunction*)(fixedFieldInfoArray[i].fieldValue))->GetFunctionBody())
559+
Js::ParseableFunctionInfo *info = ((Js::JavascriptFunction*)(fixedFieldInfoArray[i].fieldValue))->GetParseableFunctionInfo();
560+
if (info->IsFunctionBody() && inlineeFuncBody == info->GetFunctionBody())
560561
{
561562
inlineesDataArray[i].inlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());
562563
inlineesDataArray[i].inlineeRuntimeData = inlineeRuntimeData->GetRuntimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());

lib/Backend/Opnd.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3234,7 +3234,7 @@ Opnd::GetAddrDescription(__out_ecount(count) char16 *const description, const si
32343234

32353235
case IR::AddrOpndKindDynamicFunctionInfo:
32363236
DumpAddress(address, printToConsole, skipMaskedAddress);
3237-
DumpFunctionInfo(&buffer, &n, (Js::FunctionInfo *)address, printToConsole);
3237+
DumpFunctionInfo(&buffer, &n, ((Js::FunctionBody *)address)->GetFunctionInfo(), printToConsole);
32383238
break;
32393239

32403240
case IR::AddrOpndKindDynamicFunctionBody:

lib/Common/ConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ PHASE(All)
1010
PHASE(Parse)
1111
PHASE(RegexCompile)
1212
PHASE(DeferParse)
13+
PHASE(Redeferral)
1314
PHASE(DeferEventHandlers)
1415
PHASE(FunctionSourceInfoParse)
1516
PHASE(StringTemplateParse)

lib/Common/Memory/CustomHeap.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ Allocation* Heap::Alloc(size_t bytes, ushort pdataCount, ushort xdataSize, bool
243243
{
244244
page = AllocNewPage(bucket, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, isAllJITCodeInPreReservedRegion);
245245
}
246+
else if (!canAllocInPreReservedHeapPageSegment && isAnyJittedCode)
247+
{
248+
*isAllJITCodeInPreReservedRegion = false;
249+
}
246250

247251
// Out of memory
248252
if (page == nullptr)

lib/Parser/Parse.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4881,7 +4881,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
48814881
BOOL isDeferredFnc = IsDeferredFnc();
48824882
AnalysisAssert(isDeferredFnc || pnodeFnc);
48834883
isTopLevelDeferredFunc =
4884-
(!isDeferredFnc
4884+
(!fLambda
48854885
&& DeferredParse(pnodeFnc->sxFnc.functionId)
48864886
&& (!pnodeFnc->sxFnc.IsNested() || CONFIG_FLAG(DeferNested))
48874887
// Don't defer if this is a function expression not contained in a statement or other expression.
@@ -4892,6 +4892,9 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
48924892
&& !fModule
48934893
);
48944894

4895+
pnodeFnc->sxFnc.SetCanBeDeferred(isTopLevelDeferredFunc && !pnodeFnc->sxFnc.IsGenerator());
4896+
isTopLevelDeferredFunc = isTopLevelDeferredFunc && !isDeferredFnc;
4897+
48954898
if (!fLambda &&
48964899
!isDeferredFnc &&
48974900
!isLikelyIIFE &&
@@ -6364,6 +6367,11 @@ ParseNodePtr Parser::GenerateEmptyConstructor(bool extends)
63646367
pnodeFnc->sxFnc.deferredStub = nullptr;
63656368
pnodeFnc->sxFnc.funcInfo = nullptr;
63666369

6370+
// In order to (re-)defer the default constructor, we need to, for instance, track
6371+
// deferred class expression the way we track function expression, since we lose the part of the source
6372+
// that tells us which we have.
6373+
pnodeFnc->sxFnc.canBeDeferred = false;
6374+
63676375
#ifdef DBG
63686376
pnodeFnc->sxFnc.deferredParseNextFunctionId = *(this->m_nextFunctionId);
63696377
#endif
@@ -10306,6 +10314,7 @@ void Parser::ParseStmtList(ParseNodePtr *ppnodeList, ParseNodePtr **pppnodeLast,
1030610314
// i.e. smEnvironment == SM_OnFunctionCode
1030710315
Assert(m_currentNodeFunc != nullptr);
1030810316
m_currentNodeFunc->sxFnc.SetAsmjsMode();
10317+
m_currentNodeFunc->sxFnc.SetCanBeDeferred(false);
1030910318
m_InAsmMode = true;
1031010319

1031110320
CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(AsmJSFunctionCount, m_scriptContext);
@@ -10560,7 +10569,7 @@ void Parser::InitPids()
1056010569
wellKnownPropertyPids._star = m_phtbl->PidHashNameLen(_u("*"), sizeof("*") - 1);
1056110570
}
1056210571

10563-
void Parser::RestoreScopeInfo(Js::FunctionBody* functionBody)
10572+
void Parser::RestoreScopeInfo(Js::ParseableFunctionInfo* functionBody)
1056410573
{
1056510574
if (!functionBody)
1056610575
{
@@ -10616,7 +10625,7 @@ void Parser::RestoreScopeInfo(Js::FunctionBody* functionBody)
1061610625
scopeInfo->GetScopeInfo(this, nullptr, nullptr, scope);
1061710626
}
1061810627

10619-
void Parser::FinishScopeInfo(Js::FunctionBody *functionBody)
10628+
void Parser::FinishScopeInfo(Js::ParseableFunctionInfo *functionBody)
1062010629
{
1062110630
if (!functionBody)
1062210631
{

lib/Parser/Parse.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -967,8 +967,8 @@ class Parser
967967
void RemovePrevPidRef(IdentPtr pid, PidRefStack *lastRef);
968968
void SetPidRefsInScopeDynamic(IdentPtr pid, int blockId);
969969

970-
void RestoreScopeInfo(Js::FunctionBody* functionBody);
971-
void FinishScopeInfo(Js::FunctionBody* functionBody);
970+
void RestoreScopeInfo(Js::ParseableFunctionInfo* functionBody);
971+
void FinishScopeInfo(Js::ParseableFunctionInfo* functionBody);
972972

973973
BOOL PnodeLabelNoAST(IdentToken* pToken, LabelId* pLabelIdList);
974974
LabelId* CreateLabelId(IdentToken* pToken);

lib/Parser/ptree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ struct PnFnc
246246
#endif
247247
RestorePoint *pRestorePoint;
248248
DeferredFunctionStub *deferredStub;
249+
bool canBeDeferred;
249250

250251
static const int32 MaxStackClosureAST = 800000;
251252

@@ -316,6 +317,7 @@ struct PnFnc
316317
void SetUsesArguments(bool set = true) { SetFlags(kFunctionUsesArguments, set); }
317318
void SetIsDefaultModuleExport(bool set = true) { SetFlags(kFunctionIsDefaultModuleExport, set); }
318319
void SetNestedFuncEscapes(bool set = true) { nestedFuncEscapes = set; }
320+
void SetCanBeDeferred(bool set = true) { canBeDeferred = set; }
319321

320322
bool CallsEval() const { return HasFlags(kFunctionCallsEval); }
321323
bool ChildCallsEval() const { return HasFlags(kFunctionChildCallsEval); }
@@ -353,6 +355,7 @@ struct PnFnc
353355
bool UsesArguments() const { return HasFlags(kFunctionUsesArguments); }
354356
bool IsDefaultModuleExport() const { return HasFlags(kFunctionIsDefaultModuleExport); }
355357
bool NestedFuncEscapes() const { return nestedFuncEscapes; }
358+
bool CanBeDeferred() const { return canBeDeferred; }
356359

357360
size_t LengthInBytes()
358361
{

0 commit comments

Comments
 (0)