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 Oct 30, 2016
1 parent b9a74ea commit 154d897
Show file tree
Hide file tree
Showing 71 changed files with 1,918 additions and 1,232 deletions.
10 changes: 3 additions & 7 deletions lib/Backend/BailOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
bailOutRecordNotConst->bailOutCount++;

Js::FunctionEntryPointInfo *entryPointInfo = function->GetFunctionEntryPointInfo();
uint8 callsCount = entryPointInfo->callsCount;
uint32 callsCount = entryPointInfo->callsCount;
RejitReason rejitReason = RejitReason::None;
bool reThunk = false;

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

entryPointInfo->totalJittedLoopIterations += entryPointInfo->jittedLoopIterationsSinceLastBailout;
entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
if (entryPointInfo->totalJittedLoopIterations > UINT8_MAX)
{
entryPointInfo->totalJittedLoopIterations = UINT8_MAX;
}
uint8 totalJittedLoopIterations = (uint8)entryPointInfo->totalJittedLoopIterations;
uint32 totalJittedLoopIterations = (uint8)entryPointInfo->totalJittedLoopIterations;
totalJittedLoopIterations = totalJittedLoopIterations <= Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() ? 0 : totalJittedLoopIterations - Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout();

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

void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber)
void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint32& callsOrIterationsCount, int loopNumber)
{
if (bailOutKind == IR::BailOutOnNoProfile && executeFunction->IncrementBailOnMisingProfileCount() > CONFIG_FLAG(BailOnNoProfileLimit))
{
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/BailOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class BailOutRecord

static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint32& callsOrIterationsCount, int loopNumber);
void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, Js::InterpreterStackFrame * newInstance, Js::ScriptContext * scriptContext,
bool fromLoopBody, Js::Var * registerSaves, BailOutReturnValue * returnValue, Js::Var* pArgumentsObject, Js::Var branchValue = nullptr, void* returnAddress = nullptr, bool useStartCall = true, void * argoutRestoreAddress = nullptr) const;
void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, uint count, __in_ecount_opt(count) int * offsets, int argOutSlotId,
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/FunctionJITTimeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ FunctionJITTimeInfo::BuildJITTimeData(

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

if (codeGenData->GetFunctionInfo()->HasBody())
if (codeGenData->GetFunctionInfo()->HasBody() && codeGenData->GetFunctionInfo()->GetFunctionProxy()->IsFunctionBody())
{
Assert(isInlinee == !!runtimeData);
const Js::FunctionCodeGenRuntimeData * targetRuntimeData = nullptr;
Expand Down
49 changes: 27 additions & 22 deletions lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,9 @@ uint Inline::FillInlineesDataArray(
}

intptr_t inlineeFunctionInfoAddr = inlineeJitTimeData->GetFunctionInfoAddr();
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData))
#ifdef DBG
if (inlineeJitTimeData->HasBody() && !PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData))
#endif
{
const FunctionJITTimeInfo* rightInlineeJitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeFunctionInfoAddr);

Expand Down Expand Up @@ -571,28 +573,31 @@ void Inline::FillInlineesDataArrayUsingFixedMethods(
JITTimeFunctionBody* inlineeFuncBody = nullptr;
while (inlineeJitTimeData)
{
inlineeFuncBody = inlineeJitTimeData->GetBody();
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeJitTimeData))
if (inlineeJitTimeData->HasBody())
{
const FunctionJITTimeInfo * jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
if (jitTimeData)
inlineeFuncBody = inlineeJitTimeData->GetBody();
if (!PHASE_OFF(Js::PolymorphicInlinePhase, inlineeJitTimeData) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, inlineeJitTimeData))
{
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
const FunctionJITTimeInfo * jitTimeData = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
if (jitTimeData)
{
if (inlineeJitTimeData->GetFunctionInfoAddr() == fixedFieldInfoArray[i].GetFuncInfoAddr())
for (uint16 i = 0; i < cachedFixedInlineeCount; i++)
{
inlineesDataArray[i] = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
break;
if (inlineeJitTimeData->GetFunctionInfoAddr() == fixedFieldInfoArray[i].GetFuncInfoAddr())
{
inlineesDataArray[i] = inlineeJitTimeData->GetJitTimeDataFromFunctionInfoAddr(inlineeJitTimeData->GetFunctionInfoAddr());
break;
}
}
}
}
else
{
else
{
#if defined(DBG_DUMP) || defined(ENABLE_DEBUG_CONFIG_OPTIONS)
char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
#endif
POLYMORPHIC_INLINE_TESTTRACE(_u("INLINING (Polymorphic): Missing jit time data skipped inlinee\tInlinee: %s (%s)\n"),
inlineeFuncBody->GetDisplayName(), inlineeJitTimeData->GetDebugNumberSet(debugStringBuffer));
POLYMORPHIC_INLINE_TESTTRACE(_u("INLINING (Polymorphic): Missing jit time data skipped inlinee\tInlinee: %s (%s)\n"),
inlineeFuncBody->GetDisplayName(), inlineeJitTimeData->GetDebugNumberSet(debugStringBuffer));
}
}
}
inlineeJitTimeData = inlineeJitTimeData->GetNext();
Expand Down Expand Up @@ -1026,7 +1031,7 @@ Inline::InlinePolymorphicFunction(IR::Instr *callInstr, const FunctionJITTimeInf
IR::RegOpnd* functionObject = callInstr->GetSrc1()->AsRegOpnd();
dispatchStartLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::BrAddr_A, inlineeStartLabel,
IR::IndirOpnd::New(functionObject, Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, dispatchStartLabel->m_func),
IR::AddrOpnd::New(inlineesDataArray[i]->GetBody()->GetAddr(), IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
IR::AddrOpnd::New(inlineesDataArray[i]->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
}

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

void
Inline::InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
Inline::InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
{
// if (JavascriptFunction::FromVar(r1)->functionInfo != funcInfo) goto noInlineLabel
// BrNeq_I4 noInlineLabel, r1->functionInfo, funcInfo
IR::IndirOpnd* funcBody = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
IR::AddrOpnd* inlinedFuncBody = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionBody, callInstr->m_func);
bailoutInstr->SetSrc1(funcBody);
bailoutInstr->SetSrc2(inlinedFuncBody);
IR::IndirOpnd* opndFuncInfo = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
IR::AddrOpnd* inlinedFuncInfo = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionInfo, callInstr->m_func);
bailoutInstr->SetSrc1(opndFuncInfo);
bailoutInstr->SetSrc2(inlinedFuncInfo);

insertBeforeInstr->InsertBefore(bailoutInstr);
}
Expand Down Expand Up @@ -4108,7 +4113,7 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
InsertFunctionTypeIdCheck(callInstr, insertBeforeInstr, bailOutIfNotJsFunction);

// 3. Bailout if function body doesn't match funcInfo
InsertFunctionBodyCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);
InsertFunctionInfoCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);

return primaryBailOutInstr;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/Inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Inline
void InsertObjectCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
void InsertFunctionTypeIdCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
void InsertJsFunctionCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind);
void InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
void InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
void InsertFunctionObjectCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);

void TryResetObjTypeSpecFldInfoOn(IR::PropertySymOpnd* propertySymOpnd);
Expand Down
4 changes: 2 additions & 2 deletions lib/Backend/InliningDecider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ uint InliningDecider::InlinePolymorphicCallSite(Js::FunctionBody *const inliner,
AssertMsg(inlineeCount >= 2, "There are at least two polymorphic call site");
break;
}
if (Inline(inliner, functionBodyArray[inlineeCount], isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
if (Inline(inliner, functionBodyArray[inlineeCount]->GetFunctionInfo(), isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
{
canInlineArray[inlineeCount] = true;
actualInlineeCount++;
Expand Down Expand Up @@ -272,7 +272,7 @@ Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::F
#endif

this->bytecodeInlinedCount += inlinee->GetByteCodeCount();
return inlinee;
return inlinee->GetFunctionInfo();
}

Js::OpCode builtInInlineCandidateOpCode;
Expand Down
Loading

0 comments on commit 154d897

Please sign in to comment.