Skip to content

Commit c3055bc

Browse files
author
Kevin Smith
committed
Set hasBailedOutBitPtr correctly for nested finally blocks
JITed functions use a stack of bits to determine whether a bailout occured within a try-catch or try-finally block. When a bailout occurs within a finally, the corresponding entry in the bit stack has already been popped, but we still need to set the bit correctly for the containing try block, if one exists.
1 parent 17cddd6 commit c3055bc

File tree

5 files changed

+74
-18
lines changed

5 files changed

+74
-18
lines changed

lib/Backend/BailOut.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,14 +1193,7 @@ BailOutRecord::BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, Bail
11931193
BailOutReturnValue bailOutReturnValue;
11941194
Js::ScriptFunction * innerMostInlinee = nullptr;
11951195
BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, false, branchValue);
1196-
1197-
bool * hasBailedOutBitPtr = layout->functionObject->GetScriptContext()->GetThreadContext()->GetHasBailedOutBitPtr();
1198-
Assert(!bailOutRecord->ehBailoutData || hasBailedOutBitPtr ||
1199-
bailOutRecord->ehBailoutData->ht == Js::HandlerType::HT_Finally /* When we bailout from inlinee in non exception finally, we maynot see hasBailedOutBitPtr*/);
1200-
if (hasBailedOutBitPtr && bailOutRecord->ehBailoutData && bailOutRecord->ehBailoutData->ht != Js::HandlerType::HT_Finally)
1201-
{
1202-
*hasBailedOutBitPtr = true;
1203-
}
1196+
SetHasBailedOutBit(bailOutRecord, layout->functionObject->GetScriptContext());
12041197
Js::Var result = BailOutCommonNoCodeGen(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset, returnAddress, bailOutKind, branchValue,
12051198
registerSaves, &bailOutReturnValue);
12061199
ScheduleFunctionCodeGen(Js::VarTo<Js::ScriptFunction>(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, bailOutOffset, savedImplicitCallFlags, returnAddress);
@@ -1239,20 +1232,40 @@ BailOutRecord::BailOutFromLoopBodyInlinedCommon(Js::JavascriptCallStackLayout *
12391232
BailOutReturnValue bailOutReturnValue;
12401233
Js::ScriptFunction * innerMostInlinee = nullptr;
12411234
BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, true, branchValue);
1242-
bool * hasBailedOutBitPtr = layout->functionObject->GetScriptContext()->GetThreadContext()->GetHasBailedOutBitPtr();
1243-
Assert(!bailOutRecord->ehBailoutData || hasBailedOutBitPtr ||
1244-
bailOutRecord->ehBailoutData->ht == Js::HandlerType::HT_Finally /* When we bailout from inlinee in non exception finally, we maynot see hasBailedOutBitPtr*/);
1245-
if (hasBailedOutBitPtr && bailOutRecord->ehBailoutData)
1246-
{
1247-
*hasBailedOutBitPtr = true;
1248-
}
1249-
1235+
SetHasBailedOutBit(bailOutRecord, layout->functionObject->GetScriptContext());
12501236
uint32 result = BailOutFromLoopBodyHelper(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset,
12511237
bailOutKind, nullptr, registerSaves, &bailOutReturnValue);
12521238
ScheduleLoopBodyCodeGen(Js::VarTo<Js::ScriptFunction>(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind);
12531239
return result;
12541240
}
12551241

1242+
void
1243+
BailOutRecord::SetHasBailedOutBit(BailOutRecord const * bailOutRecord, Js::ScriptContext * scriptContext)
1244+
{
1245+
Js::EHBailoutData * ehBailoutData = bailOutRecord->ehBailoutData;
1246+
if (!ehBailoutData)
1247+
{
1248+
return;
1249+
}
1250+
1251+
// When a bailout occurs within a finally region, the hasBailedOutBitPtr associated with the
1252+
// try-catch-finally or try-finally has already been removed from the stack. In that case,
1253+
// we set the hasBailedOutBitPtr for the nearest enclosing try or catch region within the
1254+
// function.
1255+
while (ehBailoutData->ht == Js::HandlerType::HT_Finally)
1256+
{
1257+
if (!ehBailoutData->parent || ehBailoutData->parent->nestingDepth < 0)
1258+
{
1259+
return;
1260+
}
1261+
ehBailoutData = ehBailoutData->parent;
1262+
}
1263+
1264+
bool * hasBailedOutBitPtr = scriptContext->GetThreadContext()->GetHasBailedOutBitPtr();
1265+
Assert(hasBailedOutBitPtr);
1266+
*hasBailedOutBitPtr = true;
1267+
}
1268+
12561269
void
12571270
BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, BailOutRecord const *& currentBailOutRecord,
12581271
uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var * registerSaves, BailOutReturnValue * bailOutReturnValue, Js::ScriptFunction ** innerMostInlinee, bool isInLoopBody, Js::Var branchValue)
@@ -3041,4 +3054,3 @@ void GlobalBailOutRecordDataTable::AddOrUpdateRow(JitArenaAllocator *allocator,
30413054
rowToInsert->regSlot = regSlot;
30423055
*lastUpdatedRowIndex = length++;
30433056
}
3044-

lib/Backend/BailOut.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ class BailOutRecord
277277
static uint32 BailOutFromLoopBodyHelper(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
278278
uint32 bailOutOffset, IR::BailOutKind bailOutKind, Js::Var branchValue, Js::Var * registerSaves, BailOutReturnValue * returnValue = nullptr);
279279

280+
static void SetHasBailedOutBit(BailOutRecord const * bailOutRecord, Js::ScriptContext * scriptContext);
281+
280282
static void UpdatePolymorphicFieldAccess(Js::JavascriptFunction * function, BailOutRecord const * bailOutRecord);
281283

282284
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,

test/EH/hasBailedOutBug3.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,3 @@ test0();
3232
test0();
3333
test0();
3434
print("Passed\n");
35-

test/EH/hasBailedOutBug4.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var shouldBailout = false;
2+
var caught = false;
3+
4+
function test0() {
5+
function func0() {
6+
if (shouldBailout) {
7+
throw new Error('oops');
8+
}
9+
}
10+
11+
function func1() { func0() }
12+
function func2() { func1() }
13+
function func3() { shouldBailout ? obj0 : null }
14+
15+
var obj0 = { method0: func1 };
16+
var obj1 = { method0: func2 };
17+
18+
try {
19+
try {} finally { func3(); }
20+
} catch {
21+
caught = true;
22+
}
23+
24+
func2();
25+
}
26+
27+
// generate profile
28+
test0();
29+
test0();
30+
31+
// run code with bailouts enabled
32+
shouldBailout = true;
33+
try {
34+
test0();
35+
} catch {}
36+
if (!caught) {
37+
print('Passed');
38+
}

test/EH/rlexe.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@
194194
<files>hasBailedOutBug3.js</files>
195195
</default>
196196
</test>
197+
<test>
198+
<default>
199+
<files>hasBailedOutBug4.js</files>
200+
</default>
201+
</test>
197202
<test>
198203
<default>
199204
<files>StackOverflow.js</files>

0 commit comments

Comments
 (0)