From ede39dd801802fdecb36d23aca04ac85acbdeb3a Mon Sep 17 00:00:00 2001 From: rhuanjl Date: Tue, 23 Mar 2021 22:05:33 +0000 Subject: [PATCH] Enable Jitting Generators and Async Functions - exclude ARM which has not been tested - excludes code running with debugger attached (not tested) - excludes functions containing try/catch (not tested) - excludes Module globals (unlikely to benefit) - add tests for bugs fixed above --- lib/Common/ConfigFlagsList.h | 11 +++- lib/Runtime/Base/FunctionBody.cpp | 11 ++-- test/es6/generator-jit-bugs.js | 85 ++++++++++++++++++++++++++++--- test/es6/rlexe.xml | 16 +++++- 4 files changed, 109 insertions(+), 14 deletions(-) diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index b32993f8482..6581ad2a8fb 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -673,6 +673,15 @@ PHASE(All) #define DEFAULT_CONFIG_ESArrayFindFromLast (false) #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 +#ifdef _M_ARM32_OR_ARM64 + #define DEFAULT_CONFIG_JitES6Generators (false) +#else + #define DEFAULT_CONFIG_JitES6Generators (true) +#endif + #ifdef COMPILE_DISABLE_ES6RegExPrototypeProperties // If ES6RegExPrototypeProperties needs to be disabled by compile flag, DEFAULT_CONFIG_ES6RegExPrototypeProperties should be false #define DEFAULT_CONFIG_ES6RegExPrototypeProperties (false) @@ -1206,7 +1215,7 @@ FLAGR(Boolean, ESImportMeta, "Enable import.meta keyword", DEFAULT_CONFIG_ESImpo FLAGR(Boolean, ESGlobalThis, "Enable globalThis", DEFAULT_CONFIG_ESGlobalThis) // This flag to be removed once JITing generator functions is stable -FLAGNR(Boolean, JitES6Generators , "Enable JITing of ES6 generators", false) +FLAGNR(Boolean, JitES6Generators , "Enable JITing of ES6 generators", DEFAULT_CONFIG_JitES6Generators) FLAGNR(Boolean, FastLineColumnCalculation, "Enable fast calculation of line/column numbers from the source.", DEFAULT_CONFIG_FastLineColumnCalculation) FLAGR (String, Filename , "Jscript source file", nullptr) diff --git a/lib/Runtime/Base/FunctionBody.cpp b/lib/Runtime/Base/FunctionBody.cpp index 833e20c1843..5f625fc7be7 100644 --- a/lib/Runtime/Base/FunctionBody.cpp +++ b/lib/Runtime/Base/FunctionBody.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 "RuntimeBasePch.h" @@ -341,13 +342,13 @@ namespace Js bool FunctionBody::SkipAutoProfileForCoroutine() const { - return this->IsCoroutine() && CONFIG_ISENABLED(Js::JitES6GeneratorsFlag); + return this->IsCoroutine() && CONFIG_FLAG(JitES6Generators); } bool FunctionBody::IsGeneratorAndJitIsDisabled() const { - return this->IsCoroutine() && !(CONFIG_ISENABLED(Js::JitES6GeneratorsFlag) && !this->GetHasTry() && !this->IsInDebugMode() && !this->IsAsync()); + return this->IsCoroutine() && !(CONFIG_FLAG(JitES6Generators) && !this->GetHasTry() && !this->IsInDebugMode() && !this->IsModule()); } ScriptContext* EntryPointInfo::GetScriptContext() @@ -7151,8 +7152,7 @@ namespace Js !GetScriptContext()->IsScriptContextInDebugMode() && DoInterpreterProfile() && #pragma warning(suppress: 6235) // ( || ) is always a non-zero constant. - (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()) && - !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt + (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()); } bool FunctionBody::DoSimpleJitWithLock() const @@ -7166,8 +7166,7 @@ namespace Js !this->IsInDebugMode() && DoInterpreterProfileWithLock() && #pragma warning(suppress: 6235) // ( || ) is always a non-zero constant. - (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()) && - !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt + (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()); } bool FunctionBody::DoSimpleJitDynamicProfile() const diff --git a/test/es6/generator-jit-bugs.js b/test/es6/generator-jit-bugs.js index 676afe058d0..c3035de0834 100644 --- a/test/es6/generator-jit-bugs.js +++ b/test/es6/generator-jit-bugs.js @@ -1,20 +1,93 @@ //------------------------------------------------------------------------------------------------------- // 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. //------------------------------------------------------------------------------------------------------- +let results = 0; +let 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 - const that is unused/replaced with undefined -function* foo() { +title("const that is unused/replaced with undefined"); +function* gf1() { const temp2 = null; while (true) { yield temp2; } } -const gen = foo(); +const gen = gf1(); + +check(gen.next().value, null); +check(gen.next().value, null); +check(gen.next().value, null); + +// Test 2 - load for-in enumerator in nested for-in loop +title("load for-in enumerator in nested for-in loop"); +const arr = [0, 1, 2]; +function* gf2() { + for (let a in arr) { + for (let b in arr) { + yield a + b; + } + } +} + +const gen2 = gf2(); + +check(gen2.next().value, "00"); +check(gen2.next().value, "01"); +check(gen2.next().value, "02"); +check(gen2.next().value, "10"); +check(gen2.next().value, "11"); +check(gen2.next().value, "12"); +check(gen2.next().value, "20"); +check(gen2.next().value, "21"); +check(gen2.next().value, "22"); +check(gen2.next().value, undefined); + +// Test 3 - Bail on no profile losing loop control variable +title("Bail on no profile losing loop control variable"); +function* gf3() { + for (let i = 0; i < 3; ++i) { + yield i; + } +} + +const gen3 = gf3(); + +check(gen3.next().value, 0); +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") +function* gf4() { + yield 0; + yield* [1,2,3]; +} + +const gen4 = gf4(); -gen.next(); -gen.next(); -gen.next(); +check(gen4.next().value, 0); +check(gen4.next().value, 1); +check(gen4.next().value, 2); +check(gen4.next().value, 3); -print("Pass"); +print("pass"); diff --git a/test/es6/rlexe.xml b/test/es6/rlexe.xml index 0c465d79d6d..e079f4c46eb 100644 --- a/test/es6/rlexe.xml +++ b/test/es6/rlexe.xml @@ -135,10 +135,24 @@ generator-jit-bugs.js - -JitES6Generators + -JitES6Generators -args summary -endargs exclude_nonative + + + generator-jit-bugs.js + -JitES6Generators -off:simplejit -args summary -endargs + exclude_nonative + + + + + generator-jit-bugs.js + -JitES6Generators -off:fulljit -args summary -endargs + exclude_nonative, exclude_dynapogo + + proto_basic.js