Skip to content

Commit

Permalink
Merge pull request #6700 from rhuanjl/gen_scope_slots
Browse files Browse the repository at this point in the history
Fix Errors in Generator Jit for SlotArray and CopyProp Restores
  • Loading branch information
ppenzin authored Apr 18, 2021
2 parents fb2fe44 + d9e818b commit 8917a7e
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 6 deletions.
4 changes: 2 additions & 2 deletions lib/Backend/LinearScan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5135,13 +5135,13 @@ void LinearScan::GeneratorBailIn::BuildBailInSymbolList(

if (unrestorableSymbols.TestAndClear(value->m_id))
{
if (this->NeedsReloadingSymWhenBailingIn(copyPropSym.Key()))
if (this->NeedsReloadingSymWhenBailingIn(copyPropSym.Value()))
{
BailInSymbol bailInSym(key->m_id /* fromByteCodeRegSlot */, value->m_id /* toBackendId */);
bailInSymbols->PrependNode(this->func->m_alloc, bailInSym);
}
}
else if (unrestorableSymbols.TestAndClear(key->m_id))
if (unrestorableSymbols.TestAndClear(key->m_id))
{
if (this->NeedsReloadingSymWhenBailingIn(copyPropSym.Key()))
{
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/ByteCode/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,7 @@ void ByteCodeGenerator::FinalizeRegisters(FuncInfo* funcInfo, Js::FunctionBody*
}
}

// NOTE: The FB expects the yield reg to be the final non-temp.
// NOTE: The FunctionBody expects the yield reg to be the final non-temp.
if (byteCodeFunction->IsCoroutine())
{
if (funcInfo->root->IsAsync())
Expand Down
13 changes: 13 additions & 0 deletions lib/Runtime/Library/JavascriptGenerator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
Expand Down Expand Up @@ -171,6 +172,18 @@ Var JavascriptGenerator::CallGenerator(Var data, ResumeYieldKind resumeKind)
JavascriptLibrary* library = scriptContext->GetLibrary();
Var result = nullptr;

if (this->frame)
{
// if the function already has a state it may be going to resume in the jit
// if so copy any innerScopes into registers jit can access
uint32 innerScopeCount = this->scriptFunction->GetFunctionBody()->GetInnerScopeCount();
for (uint32 i = 0; i < innerScopeCount; ++i)
{
Js::RegSlot reg = this->scriptFunction->GetFunctionBody()->GetFirstInnerScopeRegister() + i;
this->frame->SetNonVarReg(reg, this->frame->InnerScopeFromIndex(i));
}
}

SetResumeYieldProperties(data, resumeKind);

{
Expand Down
33 changes: 33 additions & 0 deletions test/es6/async-jit-bugs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

function main() {
const v2 = [13.37,13.37,13.37,13.37,13.37];
async function v4(v5,v6,v7,v8) {
const v10 = 0;
for (let v14 = 0; v14 < 8; v14++) {
v5["vEBD7ei78q"] = v14;
}
for (let v16 = 1; v16 < 1337; v16++) {
const v17 = v2.__proto__;
const v23 = [13.37,13.37,-2.2250738585072014e-308,13.37,13.37];
const v24 = v23.length;
const v25 = "-4294967296";
const v26 = 7;
function* v28(v29,v30,v31,...v32) {}
let v33 = -2.2250738585072014e-308;
const v34 = v28(v33,Object,Object);
const v35 = 13.37;
const v36 = 2384357829;
const v37 = await "-4294967296";
const v38 = --v33;
}
const v39 = 128;
print("pass")
}
v4("vEBD7ei78q");
}
main();
69 changes: 66 additions & 3 deletions test/es6/generator-jit-bugs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

let results = 0;
let test = 0;
// Simpler mini-test harness to avoid any complicating factors when testing these jit bugs
var results = 0;
var test = 0;
const verbose = WScript.Arguments[0] != "summary";

function check(actual, expected) {
Expand Down Expand Up @@ -77,7 +78,7 @@ check(gen3.next().value, 1);
check(gen3.next().value, 2);

// Test 4 - yield* iterator fails to be restored after Bail on No Profile
title("Bail on no profile losing yield* iterator")
title("Bail on no profile losing yield* iterator");
function* gf4() {
yield 0;
yield* [1,2,3];
Expand All @@ -90,4 +91,66 @@ check(gen4.next().value, 1);
check(gen4.next().value, 2);
check(gen4.next().value, 3);

// Test 5 - scope slots fail to load inside for-in loop
title("Load Scope Slots in presence of for-in");
function* gf5(v1) {
for(v0 in v1) {
yield undefined;
let v2 = {}
function v3() { v2;}
}
}

const gen5 = gf5([0, 1]);

check(gen5.next().value, undefined);
check(gen5.next().value, undefined);
check(gen5.next().value, undefined);
check(gen5.next().value, undefined);

// Test 6 - scope slots used in loop control have invalid values
title("Load Scope Slots used in loop control");
function* gf6 () {
for (let v1 = 0; v1 < 1000; ++v1) {
function foo() {v1;}
yield v1;
}
}

const gen6 = gf6();

check(gen6.next().value, 0);
check(gen6.next().value, 1);
check(gen6.next().value, 2);
check(gen6.next().value, 3);

// Test 7 - storing scoped slot from loop control in array
title("Load Scope Slots used in loop control and captured indirectly");
function* gf7(v1) {
for (const v2 in v1) {
yield v2;
const v4 = [v2];
function foo() { v4; }
}
}

const gen7 = gf7([0, 1, 2]);
check(gen7.next().value, 0);
check(gen7.next().value, 1);
check(gen7.next().value, 2);
check(gen7.next().value, undefined);

// Test 8 - copy prop'd sym is counted as two values - hits bookkeeping FailFast
title("Copy prop sym double counted in unrestorable symbols hits FailFast");
function* gf8() {
var v8 = 1.1;
yield* [];
yield {v8};
}

check(gf8().next().value.v8, 1.1);
check(gf8().next().value.v8, 1.1);
check(gf8().next().value.v8, 1.1);


print("pass");
21 changes: 21 additions & 0 deletions test/es6/rlexe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,27 @@
<tags>exclude_nonative, exclude_dynapogo</tags>
</default>
</test>
<test>
<default>
<files>async-jit-bugs.js</files>
<compile-flags>-JitES6Generators -args summary -endargs</compile-flags>
<tags>exclude_nonative</tags>
</default>
</test>
<test>
<default>
<files>async-jit-bugs.js</files>
<compile-flags>-JitES6Generators -off:simplejit -args summary -endargs</compile-flags>
<tags>exclude_nonative</tags>
</default>
</test>
<test>
<default>
<files>async-jit-bugs.js</files>
<compile-flags>-JitES6Generators -off:fulljit -args summary -endargs</compile-flags>
<tags>exclude_nonative, exclude_dynapogo</tags>
</default>
</test>
<test>
<default>
<files>proto_basic.js</files>
Expand Down

0 comments on commit 8917a7e

Please sign in to comment.