Skip to content

Commit

Permalink
Redefer function bodies that are not currently being executed and are
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pleath committed Sep 28, 2016
1 parent 8df3f80 commit f15f3c4
Show file tree
Hide file tree
Showing 30 changed files with 776 additions and 484 deletions.
7 changes: 4 additions & 3 deletions lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ uint Inline::FillInlineesDataArray(
}

Js::FunctionBody *inlineeFunctionBody = inlineeJitTimeData->GetFunctionBody();
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFunctionBody))
if (inlineeFunctionBody && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFunctionBody))
{
const Js::FunctionCodeGenJitTimeData* rightInlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFunctionBody->GetFunctionInfo());
const Js::FunctionCodeGenRuntimeData* rightInlineeRuntimeData = inlineeRuntimeData->GetRuntimeDataFromFunctionInfo(inlineeFunctionBody->GetFunctionInfo());
Expand Down Expand Up @@ -549,14 +549,15 @@ void Inline::FillInlineesDataArrayUsingFixedMethods(
while (inlineeJitTimeData)
{
inlineeFuncBody = inlineeJitTimeData->GetFunctionBody();
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFuncBody) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeFuncBody))
if (inlineeFuncBody && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeFuncBody) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeFuncBody))
{
const Js::FunctionCodeGenJitTimeData* jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());
if (jitTimeData)
{
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
{
if (inlineeFuncBody == ((Js::JavascriptFunction*)(fixedFieldInfoArray[i].fieldValue))->GetFunctionBody())
Js::ParseableFunctionInfo *info = ((Js::JavascriptFunction*)(fixedFieldInfoArray[i].fieldValue))->GetParseableFunctionInfo();
if (info->IsFunctionBody() && inlineeFuncBody == info->GetFunctionBody())
{
inlineesDataArray[i].inlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());
inlineesDataArray[i].inlineeRuntimeData = inlineeRuntimeData->GetRuntimeDataFromFunctionInfo(inlineeFuncBody->GetFunctionInfo());
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/Opnd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3234,7 +3234,7 @@ Opnd::GetAddrDescription(__out_ecount(count) char16 *const description, const si

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

case IR::AddrOpndKindDynamicFunctionBody:
Expand Down
1 change: 1 addition & 0 deletions lib/Common/ConfigFlagsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ PHASE(All)
PHASE(Parse)
PHASE(RegexCompile)
PHASE(DeferParse)
PHASE(Redeferral)
PHASE(DeferEventHandlers)
PHASE(FunctionSourceInfoParse)
PHASE(StringTemplateParse)
Expand Down
4 changes: 4 additions & 0 deletions lib/Common/Memory/CustomHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ Allocation* Heap::Alloc(size_t bytes, ushort pdataCount, ushort xdataSize, bool
{
page = AllocNewPage(bucket, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, isAllJITCodeInPreReservedRegion);
}
else if (!canAllocInPreReservedHeapPageSegment && isAnyJittedCode)
{
*isAllJITCodeInPreReservedRegion = false;
}

// Out of memory
if (page == nullptr)
Expand Down
15 changes: 12 additions & 3 deletions lib/Parser/Parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4881,7 +4881,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
BOOL isDeferredFnc = IsDeferredFnc();
AnalysisAssert(isDeferredFnc || pnodeFnc);
isTopLevelDeferredFunc =
(!isDeferredFnc
(!fLambda
&& DeferredParse(pnodeFnc->sxFnc.functionId)
&& (!pnodeFnc->sxFnc.IsNested() || CONFIG_FLAG(DeferNested))
// Don't defer if this is a function expression not contained in a statement or other expression.
Expand All @@ -4892,6 +4892,9 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
&& !fModule
);

pnodeFnc->sxFnc.SetCanBeDeferred(isTopLevelDeferredFunc && !pnodeFnc->sxFnc.IsGenerator());
isTopLevelDeferredFunc = isTopLevelDeferredFunc && !isDeferredFnc;

if (!fLambda &&
!isDeferredFnc &&
!isLikelyIIFE &&
Expand Down Expand Up @@ -6364,6 +6367,11 @@ ParseNodePtr Parser::GenerateEmptyConstructor(bool extends)
pnodeFnc->sxFnc.deferredStub = nullptr;
pnodeFnc->sxFnc.funcInfo = nullptr;

// In order to (re-)defer the default constructor, we need to, for instance, track
// deferred class expression the way we track function expression, since we lose the part of the source
// that tells us which we have.
pnodeFnc->sxFnc.canBeDeferred = false;

#ifdef DBG
pnodeFnc->sxFnc.deferredParseNextFunctionId = *(this->m_nextFunctionId);
#endif
Expand Down Expand Up @@ -10306,6 +10314,7 @@ void Parser::ParseStmtList(ParseNodePtr *ppnodeList, ParseNodePtr **pppnodeLast,
// i.e. smEnvironment == SM_OnFunctionCode
Assert(m_currentNodeFunc != nullptr);
m_currentNodeFunc->sxFnc.SetAsmjsMode();
m_currentNodeFunc->sxFnc.SetCanBeDeferred(false);
m_InAsmMode = true;

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

void Parser::RestoreScopeInfo(Js::FunctionBody* functionBody)
void Parser::RestoreScopeInfo(Js::ParseableFunctionInfo* functionBody)
{
if (!functionBody)
{
Expand Down Expand Up @@ -10616,7 +10625,7 @@ void Parser::RestoreScopeInfo(Js::FunctionBody* functionBody)
scopeInfo->GetScopeInfo(this, nullptr, nullptr, scope);
}

void Parser::FinishScopeInfo(Js::FunctionBody *functionBody)
void Parser::FinishScopeInfo(Js::ParseableFunctionInfo *functionBody)
{
if (!functionBody)
{
Expand Down
4 changes: 2 additions & 2 deletions lib/Parser/Parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -967,8 +967,8 @@ class Parser
void RemovePrevPidRef(IdentPtr pid, PidRefStack *lastRef);
void SetPidRefsInScopeDynamic(IdentPtr pid, int blockId);

void RestoreScopeInfo(Js::FunctionBody* functionBody);
void FinishScopeInfo(Js::FunctionBody* functionBody);
void RestoreScopeInfo(Js::ParseableFunctionInfo* functionBody);
void FinishScopeInfo(Js::ParseableFunctionInfo* functionBody);

BOOL PnodeLabelNoAST(IdentToken* pToken, LabelId* pLabelIdList);
LabelId* CreateLabelId(IdentToken* pToken);
Expand Down
3 changes: 3 additions & 0 deletions lib/Parser/ptree.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ struct PnFnc
#endif
RestorePoint *pRestorePoint;
DeferredFunctionStub *deferredStub;
bool canBeDeferred;

static const int32 MaxStackClosureAST = 800000;

Expand Down Expand Up @@ -316,6 +317,7 @@ struct PnFnc
void SetUsesArguments(bool set = true) { SetFlags(kFunctionUsesArguments, set); }
void SetIsDefaultModuleExport(bool set = true) { SetFlags(kFunctionIsDefaultModuleExport, set); }
void SetNestedFuncEscapes(bool set = true) { nestedFuncEscapes = set; }
void SetCanBeDeferred(bool set = true) { canBeDeferred = set; }

bool CallsEval() const { return HasFlags(kFunctionCallsEval); }
bool ChildCallsEval() const { return HasFlags(kFunctionChildCallsEval); }
Expand Down Expand Up @@ -353,6 +355,7 @@ struct PnFnc
bool UsesArguments() const { return HasFlags(kFunctionUsesArguments); }
bool IsDefaultModuleExport() const { return HasFlags(kFunctionIsDefaultModuleExport); }
bool NestedFuncEscapes() const { return nestedFuncEscapes; }
bool CanBeDeferred() const { return canBeDeferred; }

size_t LengthInBytes()
{
Expand Down
Loading

0 comments on commit f15f3c4

Please sign in to comment.