Skip to content

Commit 2aaad03

Browse files
committed
[MERGE #1975 @rajatd] A rejit/rethunk change
Merge pull request #1975 from rajatd:rejitrethunk If we are about to rejit a function body and the last rejit was caused by a bailout at the same bytecode offset as the current one, then its a fair assumption that if there is a newer entrypoint available, the problem that is causing the rejit would have been fixed in that entry point. So, rethunk to that entry point instead of rejitting. This specially helps with bailouts that don't disable an optimization on rejit but rely on updated profile info to fix the problem.
2 parents c7c6a06 + ea4e143 commit 2aaad03

File tree

6 files changed

+27
-8
lines changed

6 files changed

+27
-8
lines changed

lib/Backend/BailOut.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,7 @@ uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Imp
11501150
sizeof(registerSaves));
11511151

11521152
Js::Var result = BailOutCommonNoCodeGen(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutKind, branchValue, nullptr, bailOutReturnValue, argoutRestoreAddress);
1153-
ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), nullptr, bailOutRecord, bailOutKind, savedImplicitCallFlags, returnAddress);
1153+
ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), nullptr, bailOutRecord, bailOutKind, bailOutOffset, savedImplicitCallFlags, returnAddress);
11541154
return result;
11551155
}
11561156

@@ -1171,7 +1171,7 @@ BailOutRecord::BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, Bail
11711171
BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, false, branchValue);
11721172
Js::Var result = BailOutCommonNoCodeGen(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset, returnAddress, bailOutKind, branchValue,
11731173
registerSaves, &bailOutReturnValue);
1174-
ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, savedImplicitCallFlags, returnAddress);
1174+
ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, bailOutOffset, savedImplicitCallFlags, returnAddress);
11751175
return result;
11761176
}
11771177

@@ -1750,8 +1750,10 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
17501750
// code we avoid a rejit by checking if the offending optimization has been disabled in the default code and if so
17511751
// we "rethunk" the bailing out function rather that incurring a rejit.
17521752

1753+
// actualBailOutOffset - bail out offset in the function, inlinee or otherwise, that had the bailout.
1754+
17531755
void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee,
1754-
BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress)
1756+
BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, uint32 actualBailOutOffset, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress)
17551757
{
17561758
if (bailOutKind == IR::BailOnSimpleJitToFullJitLoopBody ||
17571759
bailOutKind == IR::BailOutForGeneratorYield ||
@@ -2216,18 +2218,21 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
22162218
rejitReason = RejitReason::Forced;
22172219
}
22182220

2219-
// REVIEW: Temporary fix for RS1. Disable Rejiting if it looks like it is not fixing the problem.
2220-
// For RS2, turn this into an assert and let's fix all these issues.
22212221
if (!reThunk && rejitReason != RejitReason::None)
22222222
{
2223-
if (executeFunction->GetDynamicProfileInfo()->GetRejitCount() >= 100)
2223+
Js::DynamicProfileInfo * profileInfo = executeFunction->GetAnyDynamicProfileInfo();
2224+
// REVIEW: Temporary fix for RS1. Disable Rejiting if it looks like it is not fixing the problem.
2225+
// For RS2, turn the rejitCount check into an assert and let's fix all these issues.
2226+
if (profileInfo->GetRejitCount() >= 100 ||
2227+
(profileInfo->GetBailOutOffsetForLastRejit() == actualBailOutOffset && function->IsNewEntryPointAvailable()))
22242228
{
22252229
reThunk = true;
22262230
rejitReason = RejitReason::None;
22272231
}
22282232
else
22292233
{
2230-
executeFunction->GetDynamicProfileInfo()->IncRejitCount();
2234+
profileInfo->IncRejitCount();
2235+
profileInfo->SetBailOutOffsetForLastRejit(actualBailOutOffset);
22312236
}
22322237
}
22332238

lib/Backend/BailOut.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ class BailOutRecord
253253

254254
static void UpdatePolymorphicFieldAccess(Js::JavascriptFunction * function, BailOutRecord const * bailOutRecord);
255255

256-
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
256+
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,
257+
uint32 actualBailOutOffset, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
257258
static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
258259
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
259260
void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, Js::InterpreterStackFrame * newInstance, Js::ScriptContext * scriptContext,

lib/Runtime/Language/DynamicProfileInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ namespace Js
189189
}
190190

191191
this->rejitCount = 0;
192+
this->bailOutOffsetForLastRejit = Js::Constants::NoByteCodeOffset;
192193
#if DBG
193194
for (ProfileId i = 0; i < functionBody->GetProfiledArrayCallSiteCount(); ++i)
194195
{

lib/Runtime/Language/DynamicProfileInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ namespace Js
517517

518518
uint32 m_recursiveInlineInfo; // Bit is set for each callsites where the function is called recursively
519519
uint32 polymorphicCacheState;
520+
uint32 bailOutOffsetForLastRejit;
520521
uint16 rejitCount;
521522
BYTE currentInlinerVersion; // Used to detect when inlining profile changes
522523
bool hasFunctionBody;
@@ -810,6 +811,8 @@ namespace Js
810811
static bool IsCallSiteNoInfo(Js::LocalFunctionId functionId) { return functionId == CallSiteNoInfo; }
811812
int IncRejitCount() { return this->rejitCount++; }
812813
int GetRejitCount() { return this->rejitCount; }
814+
void SetBailOutOffsetForLastRejit(uint32 offset) { this->bailOutOffsetForLastRejit = offset; }
815+
uint32 GetBailOutOffsetForLastRejit() { return this->bailOutOffsetForLastRejit; }
813816

814817
#if DBG_DUMP
815818
void Dump(FunctionBody* functionBody, ArenaAllocator * dynamicProfileInfoAllocator = nullptr);

lib/Runtime/Library/ScriptFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,14 @@ namespace Js
323323
return functionBody->GetOriginalEntryPoint();
324324
}
325325

326+
bool ScriptFunction::IsNewEntryPointAvailable()
327+
{
328+
Js::FunctionEntryPointInfo *const defaultEntryPointInfo = this->GetFunctionBody()->GetDefaultFunctionEntryPointInfo();
329+
JavascriptMethod defaultEntryPoint = this->GetFunctionBody()->GetDirectEntryPoint(defaultEntryPointInfo);
330+
331+
return this->GetEntryPoint() != defaultEntryPoint;
332+
}
333+
326334
Var ScriptFunction::GetSourceString() const
327335
{
328336
return this->GetFunctionProxy()->EnsureDeserialized()->GetCachedSourceString();

lib/Runtime/Library/ScriptFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ namespace Js
7272

7373
void ChangeEntryPoint(ProxyEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint);
7474
JavascriptMethod UpdateThunkEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint);
75+
bool IsNewEntryPointAvailable();
7576
JavascriptMethod UpdateUndeferredBody(FunctionBody* newFunctionInfo);
7677

7778
virtual ScriptFunctionType * DuplicateType() override;

0 commit comments

Comments
 (0)