소스 검색

Merge pull request #6700 from rhuanjl/gen_scope_slots

Fix Errors in Generator Jit for SlotArray and CopyProp Restores
Petr Penzin 4 년 전
부모
커밋
8917a7e437

+ 2 - 2
lib/Backend/LinearScan.cpp

@@ -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()))
             {

+ 1 - 1
lib/Runtime/ByteCode/ByteCodeEmitter.cpp

@@ -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())

+ 13 - 0
lib/Runtime/Library/JavascriptGenerator.cpp

@@ -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"
@@ -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);
 
     {

+ 33 - 0
test/es6/async-jit-bugs.js

@@ -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();

+ 66 - 3
test/es6/generator-jit-bugs.js

@@ -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) {
@@ -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];
@@ -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 - 0
test/es6/rlexe.xml

@@ -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>