Skip to content

Commit 60fe018

Browse files
committed
[MERGE #1502 @akroshg] Fixing stack balance under generator/yield
Merge pull request #1502 from akroshg:fix1 We were caching and restoring the sp in the processtryfinally in order to balance the stack when we are in the middle of call. However in the case of generator we can yield out of the call. In that case we actually haven't finished the try part. So once we comeback after yield we don't need to cache the stack again. Introduced the flag to capture such state and fix the problem.
2 parents cd950a7 + 5cd9eed commit 60fe018

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

lib/Runtime/Language/InterpreterStackFrame.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ namespace Js
10841084
newInstance->m_flags = InterpreterStackFrameFlags_None;
10851085
newInstance->closureInitDone = false;
10861086
newInstance->isParamScopeDone = false;
1087+
newInstance->shouldCacheSP = true;
10871088
#if ENABLE_PROFILE_INFO
10881089
newInstance->switchProfileMode = false;
10891090
newInstance->isAutoProfiling = false;
@@ -6744,7 +6745,10 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
67446745
// mark the stackFrame as 'in try block'
67456746
this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
67466747

6747-
CacheSp();
6748+
if (shouldCacheSP)
6749+
{
6750+
CacheSp();
6751+
}
67486752

67496753
if (this->IsInDebugMode())
67506754
{
@@ -6772,10 +6776,10 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
67726776
this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
67736777
}
67746778

6779+
shouldCacheSP = !skipFinallyBlock;
6780+
67756781
if (skipFinallyBlock)
67766782
{
6777-
RestoreSp();
6778-
67796783
// A leave occurred due to a yield
67806784
return;
67816785
}

lib/Runtime/Language/InterpreterStackFrame.h

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

113113
bool closureInitDone : 1;
114114
bool isParamScopeDone : 1;
115+
bool shouldCacheSP : 1; // Helps in determining if we need to cache the sp in ProcessTryFinally
115116
#if ENABLE_PROFILE_INFO
116117
bool switchProfileMode : 1;
117118
bool isAutoProfiling : 1;

test/es6/iteratorclose.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,47 @@ var tests = [
10691069
});
10701070
}
10711071
},
1072+
{
1073+
name : "BugFix : yielding in the call expression under generator function",
1074+
body : function () {
1075+
var val = 0;
1076+
function bar(a, b, c) { val = b; }
1077+
function *foo(d) {
1078+
for (var k of [2, 3]) {
1079+
bar(1, d ? yield : d, k);
1080+
}
1081+
}
1082+
var iter = foo(true);
1083+
iter.next();
1084+
iter.next();
1085+
iter.next(10);
1086+
assert.areEqual(val, 10, "yielding in the call expression under for..of is working correctly");
1087+
}
1088+
},
1089+
{
1090+
name : "BugFix : yielding in the call expression under try catch",
1091+
body : function () {
1092+
var val = 0;
1093+
var counter = 0;
1094+
function bar(a, b, c) { val = b; }
1095+
function *foo(d) {
1096+
try {
1097+
try {
1098+
bar(1, d ? yield : d, 11);
1099+
} finally {
1100+
counter++;
1101+
}
1102+
} finally {
1103+
counter++;
1104+
}
1105+
}
1106+
var iter = foo(true);
1107+
iter.next();
1108+
iter.next(10);
1109+
assert.areEqual(val, 10, "yielding in the call expression under try/catch is working correctly");
1110+
assert.areEqual(counter, 2, "both finally called after yielding");
1111+
}
1112+
},
10721113
];
10731114

10741115
testRunner.runTests(tests, {

0 commit comments

Comments
 (0)