Przeglądaj źródła

JIT Generator (and Async func) loops (#6990)

* Disable JitES6Generators

* Jit Generator and async func LoopBodies

* Update Tests cases for Generator Jit
Richard 1 rok temu
rodzic
commit
615a614597

+ 7 - 3
lib/Backend/IRBuilder.cpp

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "Backend.h"
@@ -118,7 +118,7 @@ IRBuilder::DoBailOnNoProfile()
         return false;
     }
 
-    if (m_func->GetTopFunc()->GetJITFunctionBody()->IsCoroutine())
+    if (m_func->GetTopFunc()->GetJITFunctionBody()->IsCoroutine() && !m_func->IsLoopBody())
     {
         return false;
     }
@@ -441,7 +441,7 @@ IRBuilder::Build()
     // Note that for generators, we insert the bailout after the jump table to allow
     // the generator's execution to proceed before bailing out. Otherwise, we would always
     // bail to the beginning of the function in the interpreter, creating an infinite loop.
-    if (m_func->IsJitInDebugMode() && !this->m_func->GetJITFunctionBody()->IsCoroutine())
+    if (m_func->IsJitInDebugMode() && (!this->m_func->GetJITFunctionBody()->IsCoroutine() || this->IsLoopBody()))
     {
         this->InsertBailOutForDebugger(m_functionStartOffset, IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction | IR::BailOutStep, nullptr);
     }
@@ -1880,6 +1880,9 @@ IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::Re
         break;
 
     case Js::OpCode::Yield:
+        // Jitting Loop Bodies containing Yield is not possible, blocked at callsites of GenerateLoopBody
+        AssertMsg(!this->IsLoopBody(), "Attempting to JIT loop body containing Yield");
+
         instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
         this->AddInstr(instr, offset);
         IR::Instr* yieldInstr = instr->ConvertToBailOutInstr(instr, IR::BailOutForGeneratorYield);
@@ -7849,6 +7852,7 @@ IRBuilder::GeneratorJumpTable::GeneratorJumpTable(Func* func, IRBuilder* irBuild
 IR::Instr*
 IRBuilder::GeneratorJumpTable::BuildJumpTable()
 {
+    AssertMsg(!this->m_func->IsLoopBody(), "Coroutine Loop Bodies can be jitted but should follow a different path");
     if (!this->m_func->GetJITFunctionBody()->IsCoroutine())
     {
         return this->m_irBuilder->m_lastInstr;

+ 3 - 2
lib/Backend/Lower.cpp

@@ -5467,7 +5467,7 @@ Lowerer::LowerPrologEpilog()
     instr = m_func->m_exitInstr;
     AssertMsg(instr->IsExitInstr(), "Last instr isn't an ExitInstr...");
 
-    if (m_func->GetJITFunctionBody()->IsCoroutine())
+    if (m_func->GetJITFunctionBody()->IsCoroutine() && !m_func->IsLoopBody())
     {
         IR::LabelInstr* epilogueLabel = this->m_lowerGeneratorHelper.GetEpilogueForReturnStatements();
         this->m_lowerGeneratorHelper.InsertNullOutGeneratorFrameInEpilogue(epilogueLabel);
@@ -11527,6 +11527,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
 
             if (m_func->GetJITFunctionBody()->IsCoroutine())
             {
+                AssertMsg(!m_func->IsLoopBody(), "LoopBody Jit should not involve Rest params");
                 generatorArgsPtrOpnd = LoadGeneratorArgsPtr(instrArgIn);
             }
 
@@ -11544,7 +11545,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
     if (argIndex == 1)
     {
         // The "this" argument is not source-dependent and doesn't need to be checked.
-        if (m_func->GetJITFunctionBody()->IsCoroutine())
+        if (m_func->GetJITFunctionBody()->IsCoroutine() && !m_func->IsLoopBody())
         {
             generatorArgsPtrOpnd = LoadGeneratorArgsPtr(instrArgIn);
             ConvertArgOpndIfGeneratorFunction(instrArgIn, generatorArgsPtrOpnd);

+ 7 - 2
lib/Backend/NativeCodeGenerator.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "Backend.h"
@@ -246,8 +247,11 @@ NativeCodeGenerator::GenerateAllFunctions(Js::FunctionBody * fn)
             for (uint i = 0; i < fn->GetLoopCount(); i++)
             {
                 Js::LoopHeader * loopHeader = fn->GetLoopHeader(i);
-                Js::EntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
-                this->GenerateLoopBody(fn, loopHeader, entryPointInfo);
+                if (loopHeader->hasYield == false)
+                {
+                    Js::EntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
+                    this->GenerateLoopBody(fn, loopHeader, entryPointInfo);
+                }
             }
         }
         else
@@ -631,6 +635,7 @@ void NativeCodeGenerator::GenerateLoopBody(Js::FunctionBody * fn, Js::LoopHeader
     ASSERT_THREAD();
     Assert(fn->GetScriptContext()->GetNativeCodeGenerator() == this);
     Assert(entryPoint->jsMethod == nullptr);
+    Assert(!loopHeader->hasYield);
 
 #if DBG_DUMP
     if (PHASE_TRACE1(Js::JITLoopBodyPhase))

+ 3 - 3
lib/Common/ConfigFlagsList.h

@@ -675,12 +675,12 @@ PHASE(All)
 #define DEFAULT_CONFIG_ESNullishCoalescingOperator (true)
 #define DEFAULT_CONFIG_ESGlobalThis            (true)
 
-// Jitting generators has not been tested on ARM
-// enabled only for x86 and x64 for now
+// Jitting generator functions is not functional on ARM
+// Also still contains significant bugs on x86/x64 hence disabled
 #ifdef _M_ARM32_OR_ARM64
     #define DEFAULT_CONFIG_JitES6Generators            (false)
 #else
-    #define DEFAULT_CONFIG_JitES6Generators            (true)
+    #define DEFAULT_CONFIG_JitES6Generators            (false)
 #endif
 
 #ifdef COMPILE_DISABLE_ES6RegExPrototypeProperties

+ 5 - 2
lib/Runtime/Base/FunctionBody.h

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #pragma once
@@ -725,6 +726,7 @@ namespace Js
 #if ENABLE_NATIVE_CODEGEN
         Field(uint) rejitCount;
 #endif
+        Field(bool) hasYield;
         Field(bool) isNested;
         Field(bool) isInTry;
         Field(bool) isInTryFinally;
@@ -1153,8 +1155,9 @@ namespace Js
 
         bool IsJitLoopBodyPhaseEnabled() const
         {
-            // Consider: Allow JitLoopBody in generator functions for loops that do not yield.
-            return !PHASE_OFF(JITLoopBodyPhase, this) && !PHASE_OFF(FullJitPhase, this) && !this->IsCoroutine();
+            return !PHASE_OFF(JITLoopBodyPhase, this) && !PHASE_OFF(FullJitPhase, this) &&
+                (!this->IsCoroutine() || !CONFIG_FLAG(JitES6Generators) || this->IsModule());
+                // Jitting loop bodies is currently disabled when testing the Jitting of whole generator functions
         }
 
         bool IsJitLoopBodyPhaseForced() const

+ 2 - 1
lib/Runtime/ByteCode/AsmJsByteCodeWriter.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
@@ -632,7 +633,7 @@ namespace Js
         uint loopId = m_functionWrite->IncrLoopCount();
         Assert((uint)m_loopHeaders->Count() == loopId);
 
-        m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0));
+        m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0, false));
         m_loopNest++;
         Js::OpCodeAsmJs loopBodyOpcode = Js::OpCodeAsmJs::AsmJsLoopBodyStart;
         this->MarkAsmJsLabel(loopEntrance);

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

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeByteCodePch.h"
@@ -10477,6 +10477,9 @@ void EmitYieldAndResume(
 
     auto* writer = byteCodeGenerator->Writer();
 
+    // If in a loop mark it as containing Yield and hence not eligible for Jit loop body
+    writer->SetCurrentLoopHasYield();
+
     if (inputReg != funcInfo->yieldRegister)
         writer->Reg2(Js::OpCode::Ld_A, funcInfo->yieldRegister, inputReg);
 

+ 18 - 3
lib/Runtime/ByteCode/ByteCodeWriter.cpp

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeByteCodePch.h"
@@ -210,7 +210,7 @@ namespace Js
             }
         }
 
-        if (this->DoJitLoopBodies() &&
+        if (this->DoJitLoopBodies() && this->HasLoopWithoutYield() &&
             !(this->m_functionWrite->GetFunctionBody()->GetHasTry() && PHASE_OFF(Js::JITLoopBodyInTryCatchPhase, this->m_functionWrite)) &&
             !(this->m_functionWrite->GetFunctionBody()->GetHasFinally() && PHASE_OFF(Js::JITLoopBodyInTryFinallyPhase, this->m_functionWrite)))
         {
@@ -252,6 +252,7 @@ namespace Js
             loopHeader->startOffset = data.startOffset;
             loopHeader->endOffset = data.endOffset;
             loopHeader->isNested = data.isNested;
+            loopHeader->hasYield = data.hasYield;
         });
     }
 
@@ -3224,7 +3225,7 @@ StoreCommon:
         uint loopId = m_functionWrite->IncrLoopCount();
         Assert((uint)m_loopHeaders->Count() == loopId);
 
-        m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0));
+        m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0, false));
         m_loopNest++;
         m_functionWrite->SetHasNestedLoop(m_loopNest > 1);
 
@@ -3259,6 +3260,20 @@ StoreCommon:
         m_loopHeaders->Item(loopId).endOffset = m_byteCodeData.GetCurrentOffset();
     }
 
+    void ByteCodeWriter::SetCurrentLoopHasYield()
+    {
+        if (m_loopNest > 0)
+        {
+            for (int i = 0; i < m_loopHeaders->Count(); ++i)
+            {
+                if (m_loopHeaders->Item(i).endOffset == 0) // check for loops we're currently inside
+                {
+                    m_loopHeaders->Item(i).hasYield = true;
+                }
+            }
+        }
+    }
+
     void ByteCodeWriter::IncreaseByteCodeCount()
     {
         m_byteCodeCount++;

+ 15 - 2
lib/Runtime/ByteCode/ByteCodeWriter.h

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #pragma once
@@ -114,8 +114,9 @@ namespace Js
             uint startOffset;
             uint endOffset;
             bool isNested;
+            bool hasYield;
             LoopHeaderData() {}
-            LoopHeaderData(uint startOffset, uint endOffset, bool isNested) : startOffset(startOffset), endOffset(endOffset), isNested(isNested){}
+            LoopHeaderData(uint startOffset, uint endOffset, bool isNested, bool hasYield) : startOffset(startOffset), endOffset(endOffset), isNested(isNested), hasYield(hasYield){}
         };
 
         JsUtil::List<uint, ArenaAllocator> * m_labelOffsets;          // Label offsets, once defined
@@ -384,6 +385,18 @@ namespace Js
 
         uint EnterLoop(Js::ByteCodeLabel loopEntrance);
         void ExitLoop(uint loopId);
+        void SetCurrentLoopHasYield();
+        bool HasLoopWithoutYield()
+        {
+            for (int i = 0; i < m_loopHeaders->Count(); ++i)
+            {
+                if(!m_loopHeaders->Item(i).hasYield)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
 
         bool DoJitLoopBodies() const { return m_doJitLoopBodies; }
         bool DoInterruptProbes() const { return m_doInterruptProbe; }

+ 2 - 1
lib/Runtime/ByteCode/WasmByteCodeWriter.cpp

@@ -1,5 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeByteCodePch.h"
@@ -45,7 +46,7 @@ uint32 WasmByteCodeWriter::WasmLoopStart(ByteCodeLabel loopEntrance, __in_ecount
     uint loopId = m_functionWrite->IncrLoopCount();
     Assert((uint)m_loopHeaders->Count() == loopId);
 
-    m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0));
+    m_loopHeaders->Add(LoopHeaderData(m_byteCodeData.GetCurrentOffset(), 0, m_loopNest > 0, false));
     m_loopNest++;
     this->MarkAsmJsLabel(loopEntrance);
     MULTISIZE_LAYOUT_WRITE(WasmLoopStart, Js::OpCodeAsmJs::WasmLoopBodyStart, loopId, curRegs);

+ 3 - 3
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -1220,7 +1220,7 @@ namespace Js
             !(this->executeFunction->GetHasTry() && (PHASE_OFF((Js::JITLoopBodyInTryCatchPhase), this->executeFunction))) &&
             !(this->executeFunction->GetHasFinally() && (PHASE_OFF((Js::JITLoopBodyInTryFinallyPhase), this->executeFunction))) &&
             (this->executeFunction->ForceJITLoopBody() || this->executeFunction->IsJitLoopBodyPhaseEnabled()) &&
-            !this->executeFunction->IsInDebugMode();
+            !this->executeFunction->IsInDebugMode() && this->executeFunction->GetLoopHeaderArray() != nullptr;
 #endif
 
         // Pick a version of the LoopBodyStart OpCode handlers that is hardcoded to do loop body JIT and
@@ -6057,7 +6057,7 @@ skipThunk:
 
         Js::LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
 
-        if (fn->ForceJITLoopBody() && loopHeader->interpretCount == 0 &&
+        if (fn->ForceJITLoopBody() && loopHeader->interpretCount == 0 && loopHeader->hasYield == false &&
             (entryPointInfo != NULL && entryPointInfo->IsNotScheduled()))
         {
 #if ENABLE_PROFILE_INFO
@@ -6250,7 +6250,7 @@ skipThunk:
                 return nullptr;
             }
 
-            if (!fn->DoJITLoopBody())
+            if (!fn->DoJITLoopBody() || loopHeader->hasYield)
             {
                 return nullptr;
             }

+ 0 - 43
test/es6/rlexe.xml

@@ -132,48 +132,6 @@
       <tags>exclude_dynapogo</tags>
     </default>
   </test>
-  <test>
-    <default>
-      <files>generator-jit-bugs.js</files>
-      <compile-flags>-JitES6Generators -args summary -endargs</compile-flags>
-      <tags>exclude_nonative</tags>
-    </default>
-  </test>
-  <test>
-    <default>
-      <files>generator-jit-bugs.js</files>
-      <compile-flags>-JitES6Generators -off:simplejit -args summary -endargs</compile-flags>
-      <tags>exclude_nonative</tags>
-    </default>
-  </test>
-  <test>
-    <default>
-      <files>generator-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>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>
@@ -913,7 +871,6 @@
   <test>
     <default>
       <files>generators-functionality.js</files>
-      <!-- <compile-flags>-ES6Generators -JitES6Generators -args summary -endargs</compile-flags> -->
       <compile-flags>-ES6Generators -args summary -endargs</compile-flags>
       <tags>exclude_arm</tags>
     </default>

+ 1 - 1
test/es6/async-jit-bugs.js → test/es6GeneratorJit/async-jit-bugs.js

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 

+ 1 - 1
test/es6/generator-jit-bugs.js → test/es6GeneratorJit/generator-jit-bugs.js

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 

+ 20 - 0
test/es6GeneratorJit/jit-async-loop-body-2.baseline

@@ -0,0 +1,20 @@
+Beginning basicAsync
+basicAsync Loop 0 a = 80
+basicAsync Loop 0 arguments[0] = 80
+basicAsync Loop 0 a = 160
+basicAsync Loop 0 arguments[0] = 160
+Loop 3 completed
+Loop 4 k = 160
+Loop 4 k = 80
+Loop 4 k = 0
+Loop 4 completed
+Beginning basicAsync
+basicAsync Loop 0 a = 80
+basicAsync Loop 0 arguments[0] = 80
+basicAsync Loop 0 a = 160
+basicAsync Loop 0 arguments[0] = 160
+Loop 3 completed
+Loop 4 k = 160
+Loop 4 k = 80
+Loop 4 k = 0
+Loop 4 completed

+ 42 - 0
test/es6GeneratorJit/jit-async-loop-body.baseline

@@ -0,0 +1,42 @@
+Beginning basicAsync
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: basicAsync, loop:1---
+---EndBackEnd---
+basicAsync Loop 0 a = 80
+basicAsync Loop 0 arguments[0] = 80
+---BeginBackEnd: function: basicAsync, loop:0---
+---EndBackEnd---
+basicAsync Loop 0 a = 160
+basicAsync Loop 0 arguments[0] = 160
+Loop 3 completed
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+Loop 4 k = 160
+---BeginBackEnd: function: basicAsync, loop:4---
+---EndBackEnd---
+Loop 4 k = 80
+Loop 4 k = 0
+Loop 4 completed
+Beginning basicAsync
+basicAsync Loop 0 a = 80
+basicAsync Loop 0 arguments[0] = 80
+basicAsync Loop 0 a = 160
+basicAsync Loop 0 arguments[0] = 160
+Loop 3 completed
+---BeginBackEnd: function: Array.prototype.values---
+---EndBackEnd---
+---BeginBackEnd: function: Anonymous function---
+---EndBackEnd---
+---BeginBackEnd: function: Anonymous function---
+---EndBackEnd---
+Loop 4 k = 160
+Loop 4 k = 80
+Loop 4 k = 0
+Loop 4 completed

+ 42 - 0
test/es6GeneratorJit/jit-async-loop-body.js

@@ -0,0 +1,42 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+let bar = [];
+let j = 0;
+
+function printif (text, x, mod) {
+    if (x % mod == 0) {
+        print (text + x);
+    }
+}
+
+async function basicAsync(a, b) {
+    print("Beginning basicAsync")
+    await b;
+    var foo = [0.1, 0.2, 0.3, 0.4, 0];
+    while (a < 200) { // Loop 0 - should be jitted
+        foo[a] = Math.random();
+        printif(arguments.callee.name + " Loop 0 a = ", a, 80);
+        printif(arguments.callee.name + " Loop 0 arguments[0] = ", arguments[0], 80);
+        for (let k in foo) { bar[k] = a - k;} // Loop 1 - shuld be jitted
+        ++a;
+    }
+    while (true){ // Loop 2 - should not be jitted
+        for (j = 0; j < 100; ++j) { // Loop 3 - should not be jitted
+            await j;
+            foo[j] = j;
+        }
+        print("Loop 3 completed");
+        for (let k of bar) { // Loop 4 - should be jitted
+            printif("Loop 4 k = ", k, 80);
+            foo[0] = foo[1] + 1;
+        }
+        print("Loop 4 completed");
+        return j;
+    }
+}
+
+basicAsync(4, 3).then(x => basicAsync(3, 2));

+ 13 - 0
test/es6GeneratorJit/jit-gen-loop-body-2.baseline

@@ -0,0 +1,13 @@
+Beginning test of basicGenerator
+basicGenerator Loop 0 a = 40
+basicGenerator Loop 0 arguments[0] = 40
+basicGenerator Loop 0 a = 80
+basicGenerator Loop 0 arguments[0] = 80
+Loop 3 completed
+Loop 4 k = 80
+Loop 4 k = 40
+Loop 4 k = 0
+Loop 4 completed
+yielded value = 80
+yielded value = 40
+yielded value = 0

+ 35 - 0
test/es6GeneratorJit/jit-gen-loop-body.baseline

@@ -0,0 +1,35 @@
+Beginning test of basicGenerator
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: basicGenerator, loop:1---
+---EndBackEnd---
+basicGenerator Loop 0 a = 40
+basicGenerator Loop 0 arguments[0] = 40
+---BeginBackEnd: function: basicGenerator, loop:0---
+---EndBackEnd---
+basicGenerator Loop 0 a = 80
+basicGenerator Loop 0 arguments[0] = 80
+Loop 3 completed
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+Loop 4 k = 80
+---BeginBackEnd: function: basicGenerator, loop:4---
+---EndBackEnd---
+Loop 4 k = 40
+Loop 4 k = 0
+Loop 4 completed
+---BeginBackEnd: function: Array.prototype.values---
+---EndBackEnd---
+---BeginBackEnd: function: Anonymous function---
+---EndBackEnd---
+---BeginBackEnd: function: Anonymous function---
+---EndBackEnd---
+yielded value = 80
+yielded value = 40
+yielded value = 0

+ 48 - 0
test/es6GeneratorJit/jit-gen-loop-body.js

@@ -0,0 +1,48 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+let bar = [];
+let j = 0;
+
+function printif (text, x, mod) {
+    if (x % mod == 0) {
+        print (text + x);
+    }
+}
+
+function* basicGenerator(a, b) {
+    print("Beginning test of " + arguments.callee.name);
+    yield "yield 2nd param b =" + b;
+    var foo = [0.1, 0.2, 0.3, 0.4, 0];
+    while (a < 100) { // Loop 0 - should be jitted
+        foo[a] = Math.random();
+        printif(arguments.callee.name + " Loop 0 a = ", a, 40);
+        printif(arguments.callee.name + " Loop 0 arguments[0] = ", arguments[0], 40);
+        for (let k in foo) { bar[k] = a - k;} // Loop 1 - shuld be jitted
+        ++a;
+    }
+    while (true){ // Loop 2 - should not be jitted
+        for (j = 0; j < 100; ++j) { // Loop 3 - should not be jitted
+            if (j % 40 == 1)
+                yield j;
+
+           foo[j] = j;
+        }
+        print("Loop 3 completed");
+        for (let k of bar) { // Loop 4 - should be jitted
+            printif("Loop 4 k = ", k, 40);
+            foo[0] = foo[1] + 1;
+        }
+        print("Loop 4 completed");
+        yield* bar; // Loop 5 - should not be jitted
+        return j;
+    }
+}
+
+const gen = basicGenerator(5, 1);
+for (let x = gen.next(); !x.done; x = gen.next() ) {
+    printif("yielded value = ", x.value, 40);
+}

+ 11 - 0
test/es6GeneratorJit/jit-module-loop-body-2.baseline

@@ -0,0 +1,11 @@
+Loop 0 a = 40
+Loop 0 a = 80
+Loop 0 a = 120
+Loop 0 a = 160
+Loop 3 completed
+Loop 4 k = 160
+Loop 4 k = 120
+Loop 4 k = 80
+Loop 4 k = 40
+Loop 4 k = 0
+Loop 4 completed

+ 27 - 0
test/es6GeneratorJit/jit-module-loop-body.baseline

@@ -0,0 +1,27 @@
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: printif---
+---EndBackEnd---
+---BeginBackEnd: function: Module code, loop:1---
+---EndBackEnd---
+Loop 0 a = 40
+Loop 0 a = 80
+Loop 0 a = 120
+---BeginBackEnd: function: Module code, loop:0---
+---EndBackEnd---
+Loop 0 a = 160
+Loop 3 completed
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+---BeginBackEnd: function: value---
+---EndBackEnd---
+Loop 4 k = 160
+---BeginBackEnd: function: Module code, loop:4---
+---EndBackEnd---
+Loop 4 k = 120
+Loop 4 k = 80
+Loop 4 k = 40
+Loop 4 k = 0
+Loop 4 completed

+ 41 - 0
test/es6GeneratorJit/jit-module-loop-body.js

@@ -0,0 +1,41 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+let bar = [];
+let j = 0, a = 3, b = 2;
+
+function printif (text, x, mod) {
+    if (x % mod == 0) {
+        print (text + x);
+    }
+}
+
+
+await b;
+var foo = [0.1, 0.2, 0.3, 0.4, 0];
+while (a < 200) { // Loop 0 - should be jitted
+    foo[a] = Math.random();
+    printif("Loop 0 a = ", a, 40);
+    for (let k in foo) { bar[k] = a - k;} // Loop 1 - shuld be jitted
+        ++a;
+}
+while (true){ // Loop 2 - should not be jitted
+    for (j = 0; j < 100; ++j) { // Loop 3 - should not be jitted
+        await j;
+
+        foo[j] = j;
+    }
+    print("Loop 3 completed");
+    for (let k of bar) { // Loop 4 - should be jitted
+        printif("Loop 4 k = ", k, 40);
+        foo[0] = foo[1] + 1;
+    }
+    print("Loop 4 completed");
+    await j;
+    break;
+}
+
+

+ 52 - 0
test/es6GeneratorJit/newtest.js

@@ -0,0 +1,52 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+// 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) {
+    if (actual != expected)
+        throw new Error("Generator produced " + actual + " instead of " + expected);
+    if (verbose)
+        print('Result ' + ++results +  ' Generator correctly produced ' + actual);
+}
+
+function title (name) {
+    if (verbose) {
+        print("Beginning Test " + ++test + ": " + name);
+        results = 0;
+    }
+}
+
+
+// Test 1 - Construction after self-reference in loop control
+title("Construction after self-reference in loop control");
+
+function testOne()
+{
+	function* foo(a1,a2) {
+	
+		for (let i = a1; i < foo; i = i + a2)
+        {
+		    yield 0;
+		}
+
+		function bar() {}
+		var b = new bar();
+	}
+
+    foo().next()
+    return true;
+}
+
+
+for (var i = 0; i < 30 ;++i){
+    testOne();
+}
+
+print('pass')

+ 140 - 0
test/es6GeneratorJit/rlexe.xml

@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<regress-exe>
+  <test>
+    <default>
+      <files>generator-jit-bugs.js</files>
+      <compile-flags>-args summary -endargs</compile-flags>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>generator-jit-bugs.js</files>
+      <compile-flags>-JitES6Generators -args summary -endargs</compile-flags>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>generator-jit-bugs.js</files>
+      <compile-flags>-JitES6Generators -off:simplejit -args summary -endargs</compile-flags>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>generator-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>async-jit-bugs.js</files>
+      <compile-flags>-args summary -endargs</compile-flags>
+      <tags>exclude_nonative</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>async-jit-bugs.js</files>
+      <compile-flags>-off:fulljit -args summary -endargs</compile-flags>
+      <tags>exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+  <default>
+      <files>newTest.js</files>
+      <compile-flags>-args summary -endargs</compile-flags>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>newTest.js</files>
+      <compile-flags>-off:simplejit -args summary -endargs</compile-flags>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>newTest.js</files>
+      <compile-flags>-off:fulljit -args summary -endargs</compile-flags>
+      <tags>exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>newTest.js</files>
+      <compile-flags>-off:fulljit -args summary -endargs</compile-flags>
+      <tags>exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-gen-loop-body.js</files>
+      <compile-flags>-testtrace:Backend</compile-flags>
+      <baseline>jit-gen-loop-body.baseline</baseline>
+      <tags>exclude_test, exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-gen-loop-body.js</files>
+      <baseline>jit-gen-loop-body-2.baseline</baseline>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-async-loop-body.js</files>
+      <compile-flags>-testtrace:Backend</compile-flags>
+      <baseline>jit-async-loop-body.baseline</baseline>
+      <tags>exclude_test, exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-async-loop-body.js</files>
+      <baseline>jit-async-loop-body-2.baseline</baseline>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-module-loop-body.js</files>
+      <compile-flags>-testtrace:Backend -module</compile-flags>
+      <baseline>jit-module-loop-body.baseline</baseline>
+      <tags>exclude_test, exclude_nonative, exclude_dynapogo</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>jit-module-loop-body.js</files>
+      <compile-flags>-module</compile-flags>
+      <baseline>jit-module-loop-body-2.baseline</baseline>
+      <tags>exclude_nonative</tags>
+    </default>
+  </test>
+</regress-exe>

+ 6 - 0
test/rlexedirs.xml

@@ -262,6 +262,12 @@
     <files>es6</files>
   </default>
 </dir>
+<dir>
+  <default>
+    <files>es6GeneratorJit</files>
+    <tags>require_backend</tags>
+  </default>
+</dir>
 <dir>
   <default>
     <files>es6module</files>