Skip to content

Commit d5c6f59

Browse files
committed
Handle SlotArray loads in jitted generators
1 parent fb2fe44 commit d5c6f59

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1792,7 +1792,7 @@ void ByteCodeGenerator::FinalizeRegisters(FuncInfo* funcInfo, Js::FunctionBody*
17921792
}
17931793
}
17941794

1795-
// NOTE: The FB expects the yield reg to be the final non-temp.
1795+
// NOTE: The FunctionBody expects the yield reg to be the final non-temp.
17961796
if (byteCodeFunction->IsCoroutine())
17971797
{
17981798
if (funcInfo->root->IsAsync())

lib/Runtime/Library/JavascriptGenerator.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "RuntimeLibraryPch.h"
@@ -171,6 +172,18 @@ Var JavascriptGenerator::CallGenerator(Var data, ResumeYieldKind resumeKind)
171172
JavascriptLibrary* library = scriptContext->GetLibrary();
172173
Var result = nullptr;
173174

175+
if (this->frame)
176+
{
177+
// if the function already has a state it may be going to resume in the jit
178+
// if so copy any innerScopes into registers jit can access
179+
uint32 innerScopeCount = this->scriptFunction->GetFunctionBody()->GetInnerScopeCount();
180+
for (uint32 i = 0; i < innerScopeCount; ++i)
181+
{
182+
Js::RegSlot reg = this->scriptFunction->GetFunctionBody()->GetFirstInnerScopeRegister() + i;
183+
this->frame->SetNonVarReg(reg, this->frame->InnerScopeFromIndex(i));
184+
}
185+
}
186+
174187
SetResumeYieldProperties(data, resumeKind);
175188

176189
{

test/es6/generator-jit-bugs.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ check(gen3.next().value, 1);
7777
check(gen3.next().value, 2);
7878

7979
// Test 4 - yield* iterator fails to be restored after Bail on No Profile
80-
title("Bail on no profile losing yield* iterator")
80+
title("Bail on no profile losing yield* iterator");
8181
function* gf4() {
8282
yield 0;
8383
yield* [1,2,3];
@@ -90,4 +90,51 @@ check(gen4.next().value, 1);
9090
check(gen4.next().value, 2);
9191
check(gen4.next().value, 3);
9292

93+
title("Load Scope Slots in presence of for-in");
94+
function* gf5(v1) {
95+
for(v0 in v1) {
96+
yield undefined;
97+
let v2 = {}
98+
function v3() { v2;}
99+
}
100+
}
101+
102+
const gen5 = gf5([0, 1]);
103+
104+
check(gen5.next().value, undefined);
105+
check(gen5.next().value, undefined);
106+
check(gen5.next().value, undefined);
107+
check(gen5.next().value, undefined);
108+
109+
title("Load Scope Slots used in loop control");
110+
function* gf6 () {
111+
for (let v1 = 0; v1 < 1000; ++v1) {
112+
function foo() {v1;}
113+
yield v1;
114+
}
115+
}
116+
117+
const gen6 = gf6();
118+
119+
check(gen6.next().value, 0);
120+
check(gen6.next().value, 1);
121+
check(gen6.next().value, 2);
122+
check(gen6.next().value, 3);
123+
124+
title("Load Scope Slots used in loop control and captured indirectly");
125+
function* gf7(v1) {
126+
for (const v2 in v1) {
127+
yield v2;
128+
const v4 = [v2];
129+
function foo() { v4; }
130+
}
131+
}
132+
133+
const gen7 = gf7([0, 1, 2]);
134+
check(gen7.next().value, 0);
135+
check(gen7.next().value, 1);
136+
check(gen7.next().value, 2);
137+
check(gen7.next().value, undefined);
138+
139+
93140
print("pass");

0 commit comments

Comments
 (0)