Skip to content

Commit fcec8a1

Browse files
author
meg-gupta
committed
Fix BailOnNoProfile inside try functions in x86
There were multiple issues with having BailOnNoProfile for functions with try. 1. BailOnNoProfile for functions within try can make argouts orphaned. For orphaned argouts, we allocate space in locals area for bailouts. But when there is a try we expect all live out params at the top of the stack instead of the locals area. We cannot distinguish at Bailout time to read from the locals area or the top of the stack for out params, because all we depend upon to distinguish between the two are if the offsets are -ve or +ve. 2. To compute totalStackToBeRestored on return from EH bailout, we use totalOutParamCount. But with BailOnNoProfile, we need to remove the number of orphaned args and the number of dead out params from this number. 3 We compute startCallArgRestoreAdjustCounts in GlobOptBailOut which consist of offsets from top of the try c++ frame in case of nested calls. For nested calls, argouts for the outer call need to be restored from an offset of stack-adjustment-done-by-the-inner-call from esp. If the inner call consisted of orphaned args, this calculation is inaccurate. At this point we do not know how many orphaned args are present. We know if an arg is orphaned only during lowering. Similarly if the inner call consisted of dead out params, this calculation will be inaccurate. This change fixes the above issues. Fixes OS#14486384
1 parent cdf486f commit fcec8a1

File tree

5 files changed

+88
-38
lines changed

5 files changed

+88
-38
lines changed

lib/Backend/BailOut.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ BailOutInfo::NeedsStartCallAdjust(uint i, const IR::Instr * bailOutInstr) const
8383
}
8484

8585
void
86-
BailOutInfo::RecordStartCallInfo(uint i, uint argRestoreAdjustCount, IR::Instr *instr)
86+
BailOutInfo::RecordStartCallInfo(uint i, IR::Instr *instr)
8787
{
8888
Assert(i < this->startCallCount);
8989
Assert(this->startCallInfo);
@@ -92,7 +92,8 @@ BailOutInfo::RecordStartCallInfo(uint i, uint argRestoreAdjustCount, IR::Instr *
9292

9393
this->startCallInfo[i].instr = instr;
9494
this->startCallInfo[i].argCount = instr->GetArgOutCount(/*getInterpreterArgOutCount*/ true);
95-
this->startCallInfo[i].argRestoreAdjustCount = argRestoreAdjustCount;
95+
this->startCallInfo[i].argRestoreAdjustCount = 0;
96+
this->startCallInfo[i].isOrphanedCall = false;
9697
}
9798

9899
void
@@ -124,7 +125,7 @@ BailOutInfo::GetStartCallOutParamCount(uint i) const
124125
}
125126

126127
void
127-
BailOutInfo::RecordStartCallInfo(uint i, uint argRestoreAdjust, IR::Instr *instr)
128+
BailOutInfo::RecordStartCallInfo(uint i, IR::Instr *instr)
128129
{
129130
Assert(i < this->startCallCount);
130131
Assert(this->startCallInfo);
@@ -1028,6 +1029,7 @@ BailOutRecord::RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStac
10281029
bool fromLoopBody, Js::Var * registerSaves, Js::InterpreterStackFrame * newInstance, Js::Var* pArgumentsObject, void * argoutRestoreAddress) const
10291030
{
10301031
bool isLocal = offsets == nullptr;
1032+
10311033
if (isLocal == true)
10321034
{
10331035
globalBailOutRecordTable->IterateGlobalBailOutRecordTableRows(m_bailOutRecordId, [=](GlobalBailOutRecordDataRow *row) {
@@ -1071,7 +1073,15 @@ BailOutRecord::RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStac
10711073
this->IsOffsetNativeIntOrFloat(i, argOutSlotStart, &isFloat64, &isInt32,
10721074
&isSimd128F4, &isSimd128I4, &isSimd128I8, &isSimd128I16,
10731075
&isSimd128U4, &isSimd128U8, &isSimd128U16, &isSimd128B4, &isSimd128B8, &isSimd128B16);
1074-
1076+
#ifdef _M_IX86
1077+
if (this->argOutOffsetInfo->isOrphanedArgSlot->Test(argOutSlotStart + i))
1078+
{
1079+
RestoreValue(bailOutKind, layout, values, scriptContext, fromLoopBody, registerSaves, newInstance, pArgumentsObject,
1080+
nullptr, i, offset, /* isLocal */ true, isFloat64, isInt32, isSimd128F4, isSimd128I4, isSimd128I8,
1081+
isSimd128I16, isSimd128U4, isSimd128U8, isSimd128U16, isSimd128B4, isSimd128B8, isSimd128B16);
1082+
continue;
1083+
}
1084+
#endif
10751085
RestoreValue(bailOutKind, layout, values, scriptContext, fromLoopBody, registerSaves, newInstance, pArgumentsObject,
10761086
argoutRestoreAddress, i, offset, false, isFloat64, isInt32, isSimd128F4, isSimd128I4, isSimd128I8,
10771087
isSimd128I16, isSimd128U4, isSimd128U8, isSimd128U16, isSimd128B4, isSimd128B8, isSimd128B16);

lib/Backend/BailOut.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BailOutInfo
1818
IR::Instr * instr;
1919
uint argCount;
2020
uint argRestoreAdjustCount;
21+
bool isOrphanedCall;
2122
} StartCallInfo;
2223
#else
2324
typedef uint StartCallInfo;
@@ -55,7 +56,7 @@ class BailOutInfo
5556
void FinalizeOffsets(__in_ecount(count) int * offsets, uint count, Func *func, BVSparse<JitArenaAllocator> *bvInlinedArgSlot);
5657
#endif
5758

58-
void RecordStartCallInfo(uint i, uint argRestoreAdjustCount, IR::Instr *instr);
59+
void RecordStartCallInfo(uint i, IR::Instr *instr);
5960
uint GetStartCallOutParamCount(uint i) const;
6061
#ifdef _M_IX86
6162
bool NeedsStartCallAdjust(uint i, const IR::Instr * instr) const;
@@ -288,6 +289,9 @@ class BailOutRecord
288289
{
289290
BVFixed * argOutFloat64Syms; // Used for float-type-specialized ArgOut symbols. Index = [0 .. BailOutInfo::totalOutParamCount].
290291
BVFixed * argOutLosslessInt32Syms; // Used for int-type-specialized ArgOut symbols (which are native int and for bailout we need tagged ints).
292+
#ifdef _M_IX86
293+
BVFixed * isOrphanedArgSlot;
294+
#endif
291295
#ifdef ENABLE_SIMDJS
292296
// SIMD_JS
293297
BVFixed * argOutSimd128F4Syms;
@@ -310,6 +314,9 @@ class BailOutRecord
310314
{
311315
FixupNativeDataPointer(argOutFloat64Syms, chunkList);
312316
FixupNativeDataPointer(argOutLosslessInt32Syms, chunkList);
317+
#ifdef _M_IX86
318+
FixupNativeDataPointer(isOrphanedArgSlot, chunkList);
319+
#endif
313320
#ifdef ENABLE_SIMDJS
314321
FixupNativeDataPointer(argOutSimd128F4Syms, chunkList);
315322
FixupNativeDataPointer(argOutSimd128I4Syms, chunkList);

lib/Backend/GlobOptBailOut.cpp

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,6 @@ GlobOpt::FillBailOutInfo(BasicBlock *block, BailOutInfo * bailOutInfo)
952952
bailOutInfo->totalOutParamCount = totalOutParamCount;
953953
bailOutInfo->argOutSyms = JitAnewArrayZ(this->func->m_alloc, StackSym *, totalOutParamCount);
954954

955-
uint argRestoreAdjustCount = 0;
956955
FOREACH_SLISTBASE_ENTRY(IR::Opnd *, opnd, block->globOptData.callSequence)
957956
{
958957
if(opnd->GetStackSym()->HasArgSlotNum())
@@ -999,25 +998,6 @@ GlobOpt::FillBailOutInfo(BasicBlock *block, BailOutInfo * bailOutInfo)
999998

1000999
bailOutInfo->startCallFunc[startCallNumber] = sym->m_instrDef->m_func;
10011000
#ifdef _M_IX86
1002-
if (this->currentRegion && (this->currentRegion->GetType() == RegionTypeTry || this->currentRegion->GetType() == RegionTypeFinally))
1003-
{
1004-
// For a bailout in argument evaluation from an EH region, the esp is offset by the TryCatch helper's frame. So, the argouts are not actually pushed at the
1005-
// offsets stored in the bailout record, which are relative to ebp. Need to restore the argouts from the actual value of esp before calling the Bailout helper.
1006-
// For nested calls, argouts for the outer call need to be restored from an offset of stack-adjustment-done-by-the-inner-call from esp.
1007-
if (startCallNumber + 1 == bailOutInfo->startCallCount)
1008-
{
1009-
argRestoreAdjustCount = 0;
1010-
}
1011-
else
1012-
{
1013-
argRestoreAdjustCount = bailOutInfo->startCallInfo[startCallNumber + 1].argRestoreAdjustCount + bailOutInfo->startCallInfo[startCallNumber + 1].argCount;
1014-
if ((Math::Align<int32>(bailOutInfo->startCallInfo[startCallNumber + 1].argCount * MachPtr, MachStackAlignment) - (bailOutInfo->startCallInfo[startCallNumber + 1].argCount * MachPtr)) != 0)
1015-
{
1016-
argRestoreAdjustCount++;
1017-
}
1018-
}
1019-
}
1020-
10211001
if (sym->m_isInlinedArgSlot)
10221002
{
10231003
bailOutInfo->inlinedStartCall->Set(startCallNumber);
@@ -1027,10 +1007,9 @@ GlobOpt::FillBailOutInfo(BasicBlock *block, BailOutInfo * bailOutInfo)
10271007
Assert(totalOutParamCount >= argOutCount);
10281008
Assert(argOutCount >= currentArgOutCount);
10291009

1030-
bailOutInfo->RecordStartCallInfo(startCallNumber, argRestoreAdjustCount, sym->m_instrDef);
1010+
bailOutInfo->RecordStartCallInfo(startCallNumber, sym->m_instrDef);
10311011
totalOutParamCount -= argOutCount;
10321012
currentArgOutCount = 0;
1033-
10341013
}
10351014
}
10361015
NEXT_SLISTBASE_ENTRY;

lib/Backend/LinearScan.cpp

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,9 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
17401740
NativeCodeData::AllocatorNoFixup<BVFixed>* allocatorT = (NativeCodeData::AllocatorNoFixup<BVFixed>*)allocator;
17411741
BVFixed * argOutFloat64Syms = BVFixed::New(bailOutInfo->totalOutParamCount, allocatorT);
17421742
BVFixed * argOutLosslessInt32Syms = BVFixed::New(bailOutInfo->totalOutParamCount, allocatorT);
1743+
#ifdef _M_IX86
1744+
BVFixed * isOrphanedArgSlot = BVFixed::New(bailOutInfo->totalOutParamCount, allocatorT);
1745+
#endif
17431746
// SIMD_JS
17441747
BVFixed * argOutSimd128F4Syms = BVFixed::New(bailOutInfo->totalOutParamCount, allocatorT);
17451748
BVFixed * argOutSimd128I4Syms = BVFixed::New(bailOutInfo->totalOutParamCount, allocatorT);
@@ -1772,7 +1775,8 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
17721775
uint outParamCount = bailOutInfo->GetStartCallOutParamCount(i);
17731776
startCallOutParamCounts[i] = outParamCount;
17741777
#ifdef _M_IX86
1775-
startCallArgRestoreAdjustCounts[i] = bailOutInfo->startCallInfo[i].argRestoreAdjustCount;
1778+
uint orphanedArgCount = 0;
1779+
uint deadArgCount = 0;
17761780
// Only x86 has a progression of pushes of out args, with stack alignment.
17771781
bool fDoStackAdjust = false;
17781782
if (!bailOutInfo->inlinedStartCall->Test(i))
@@ -1833,6 +1837,7 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
18331837
currentBailOutRecord->argOutOffsetInfo->startCallIndex = i;
18341838
currentBailOutRecord->argOutOffsetInfo->startCallOutParamCounts = &startCallOutParamCounts[i];
18351839
#ifdef _M_IX86
1840+
currentBailOutRecord->argOutOffsetInfo->isOrphanedArgSlot = isOrphanedArgSlot;
18361841
currentBailOutRecord->startCallArgRestoreAdjustCounts = &startCallArgRestoreAdjustCounts[i];
18371842
#endif
18381843
currentBailOutRecord->argOutOffsetInfo->outParamOffsets = &outParamOffsets[outParamStart];
@@ -1842,13 +1847,13 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
18421847

18431848
#ifdef ENABLE_SIMDJS
18441849
// SIMD_JS
1845-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128F4Syms = argOutSimd128F4Syms;
1846-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I4Syms = argOutSimd128I4Syms ;
1847-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I8Syms = argOutSimd128I8Syms ;
1848-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I16Syms = argOutSimd128I16Syms ;
1849-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U4Syms = argOutSimd128U4Syms ;
1850-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U8Syms = argOutSimd128U8Syms ;
1851-
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U16Syms = argOutSimd128U16Syms ;
1850+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128F4Syms = argOutSimd128F4Syms;
1851+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I4Syms = argOutSimd128I4Syms;
1852+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I8Syms = argOutSimd128I8Syms;
1853+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128I16Syms = argOutSimd128I16Syms;
1854+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U4Syms = argOutSimd128U4Syms;
1855+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U8Syms = argOutSimd128U8Syms;
1856+
currentBailOutRecord->argOutOffsetInfo->argOutSimd128U16Syms = argOutSimd128U16Syms;
18521857
currentBailOutRecord->argOutOffsetInfo->argOutSimd128B4Syms = argOutSimd128U4Syms;
18531858
currentBailOutRecord->argOutOffsetInfo->argOutSimd128B8Syms = argOutSimd128U8Syms;
18541859
currentBailOutRecord->argOutOffsetInfo->argOutSimd128B16Syms = argOutSimd128U16Syms;
@@ -1866,6 +1871,11 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
18661871
StackSym * sym = bailOutInfo->argOutSyms[argOutSlot];
18671872
if (sym == nullptr)
18681873
{
1874+
#ifdef _M_IX86
1875+
#if DBG
1876+
deadArgCount++;
1877+
#endif
1878+
#endif
18691879
// This can happen when instr with bailout occurs before all ArgOuts for current call instr are processed.
18701880
continue;
18711881
}
@@ -2014,6 +2024,13 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
20142024
#else
20152025
// Stack offset are negative, includes the PUSH EBP and return address
20162026
outParamOffsets[outParamOffsetIndex] = sym->m_offset - (2 * MachPtr);
2027+
#endif
2028+
#ifdef _M_IX86
2029+
isOrphanedArgSlot->Set(outParamOffsetIndex);
2030+
bailOutInfo->startCallInfo[i].isOrphanedCall = true;
2031+
#if DBG
2032+
orphanedArgCount++;
2033+
#endif
20172034
#endif
20182035
}
20192036
#ifdef _M_IX86
@@ -2135,6 +2152,41 @@ LinearScan::FillBailOutRecord(IR::Instr * instr)
21352152
#endif
21362153
}
21372154
}
2155+
#ifdef _M_IX86
2156+
uint liveArgCount = bailOutInfo->startCallInfo[i /*startCallCount*/].argCount - orphanedArgCount - deadArgCount;
2157+
if (liveArgCount == 0)
2158+
{
2159+
bailOutInfo->startCallInfo[i].isOrphanedCall = true;
2160+
}
2161+
#endif
2162+
}
2163+
2164+
for (int i = startCallCount - 1; i >= 0; i--)
2165+
{
2166+
#ifdef _M_IX86
2167+
uint argRestoreAdjustCount = 0;
2168+
if (this->currentRegion && (this->currentRegion->GetType() == RegionTypeTry || this->currentRegion->GetType() == RegionTypeFinally))
2169+
{
2170+
// For a bailout in argument evaluation from an EH region, the esp is offset by the TryCatch helper's frame. So, the argouts are not actually pushed at the
2171+
// offsets stored in the bailout record, which are relative to ebp. Need to restore the argouts from the actual value of esp before calling the Bailout helper.
2172+
// For nested calls, argouts for the outer call need to be restored from an offset of stack-adjustment-done-by-the-inner-call from esp.
2173+
if ((unsigned)(i + 1) == bailOutInfo->startCallCount)
2174+
{
2175+
argRestoreAdjustCount = 0;
2176+
}
2177+
else
2178+
{
2179+
uint argCount = bailOutInfo->startCallInfo[i + 1].isOrphanedCall ? 0 : bailOutInfo->startCallInfo[i + 1].argCount;
2180+
argRestoreAdjustCount = bailOutInfo->startCallInfo[i + 1].argRestoreAdjustCount + argCount;
2181+
if ((Math::Align<int32>(argCount * MachPtr, MachStackAlignment) - (argCount * MachPtr)) != 0)
2182+
{
2183+
argRestoreAdjustCount++;
2184+
}
2185+
}
2186+
bailOutInfo->startCallInfo[i].argRestoreAdjustCount = argRestoreAdjustCount;
2187+
}
2188+
startCallArgRestoreAdjustCounts[i] = bailOutInfo->startCallInfo[i].argRestoreAdjustCount;
2189+
#endif
21382190
}
21392191
}
21402192
else

lib/Backend/Lower.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24982,19 +24982,21 @@ Lowerer::EmitEHBailoutStackRestore(IR::Instr * bailoutInstr)
2498224982

2498324983
#ifdef _M_IX86
2498424984
BailOutInfo * bailoutInfo = bailoutInstr->GetBailOutInfo();
24985+
uint totalLiveArgCount = 0;
2498524986
if (bailoutInfo->startCallCount != 0)
2498624987
{
2498724988
uint totalStackToBeRestored = 0;
2498824989
uint stackAlignmentAdjustment = 0;
2498924990
for (uint i = 0; i < bailoutInfo->startCallCount; i++)
2499024991
{
24991-
uint startCallOutParamCount = bailoutInfo->GetStartCallOutParamCount(i);
24992-
if ((Math::Align<int32>(startCallOutParamCount * MachPtr, MachStackAlignment) - (startCallOutParamCount * MachPtr)) != 0)
24992+
uint startCallLiveArgCount = bailoutInfo->startCallInfo[i].isOrphanedCall ? 0 : bailoutInfo->GetStartCallOutParamCount(i);
24993+
if ((Math::Align<int32>(startCallLiveArgCount * MachPtr, MachStackAlignment) - (startCallLiveArgCount * MachPtr)) != 0)
2499324994
{
2499424995
stackAlignmentAdjustment++;
2499524996
}
24997+
totalLiveArgCount += startCallLiveArgCount;
2499624998
}
24997-
totalStackToBeRestored = (bailoutInfo->totalOutParamCount + stackAlignmentAdjustment) * MachPtr;
24999+
totalStackToBeRestored = (totalLiveArgCount + stackAlignmentAdjustment) * MachPtr;
2499825000

2499925001
IR::RegOpnd * espOpnd = IR::RegOpnd::New(NULL, LowererMD::GetRegStackPointer(), TyMachReg, this->m_func);
2500025002
IR::Opnd * opnd = IR::IndirOpnd::New(espOpnd, totalStackToBeRestored, TyMachReg, this->m_func);

0 commit comments

Comments
 (0)