diff options
Diffstat (limited to 'deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc')
-rw-r--r-- | deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc | 829 |
1 files changed, 737 insertions, 92 deletions
diff --git a/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc b/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc index 88555b7d57..9a038221a1 100644 --- a/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc +++ b/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc @@ -16,6 +16,14 @@ namespace v8 { namespace internal { namespace compiler { +#define SHARD_TEST_BY_2(x) \ + TEST(x##_0) { Test##x(0); } \ + TEST(x##_1) { Test##x(1); } +#define SHARD_TEST_BY_4(x) \ + TEST(x##_0) { Test##x(0); } \ + TEST(x##_1) { Test##x(1); } \ + TEST(x##_2) { Test##x(2); } \ + TEST(x##_3) { Test##x(3); } static const char kFunctionName[] = "f"; @@ -70,7 +78,7 @@ class BytecodeGraphTester { i::FLAG_ignition = true; i::FLAG_always_opt = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_ignition_fallback_on_eval_and_catch = false; + i::FLAG_loop_assignment_analysis = false; // Set ignition filter flag via SetFlagsFromString to avoid double-free // (or potential leak with StrDup() based on ownership confusion). ScopedVector<char> ignition_filter(64); @@ -119,13 +127,13 @@ class BytecodeGraphTester { Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); CHECK(function->shared()->HasBytecodeArray()); + // TODO(mstarzinger): We should be able to prime CompilationInfo without + // having to instantiate a ParseInfo first. Fix this! ParseInfo parse_info(zone_, function); CompilationInfo compilation_info(&parse_info); - compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>()); + compilation_info.SetOptimizing(); compilation_info.MarkAsDeoptimizationEnabled(); - // TODO(mythria): Remove this step once parse_info is not needed. - CHECK(Compiler::ParseAndAnalyze(&parse_info)); compiler::Pipeline pipeline(&compilation_info); Handle<Code> code = pipeline.GenerateCode(); function->ReplaceCode(*code); @@ -205,8 +213,7 @@ TEST(BytecodeGraphBuilderReturnStatements) { {"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}}, {"return NaN;", {factory->nan_value()}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -233,8 +240,7 @@ TEST(BytecodeGraphBuilderPrimitiveExpressions) { {"return 25 % 7;", {factory->NewNumberFromInt(4)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -292,8 +298,7 @@ TEST(BytecodeGraphBuilderTwoParameterTests) { factory->NewStringFromStaticChars("abc"), factory->NewStringFromStaticChars("def")}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -337,8 +342,7 @@ TEST(BytecodeGraphBuilderNamedLoad) { BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -394,8 +398,7 @@ TEST(BytecodeGraphBuilderKeyedLoad) { factory->NewNumberFromInt(100)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -409,8 +412,7 @@ TEST(BytecodeGraphBuilderKeyedLoad) { } } - -TEST(BytecodeGraphBuilderNamedStore) { +void TestBytecodeGraphBuilderNamedStore(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -445,8 +447,8 @@ TEST(BytecodeGraphBuilderNamedStore) { BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; ScopedVector<char> script(3072); SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -459,8 +461,9 @@ TEST(BytecodeGraphBuilderNamedStore) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderNamedStore) -TEST(BytecodeGraphBuilderKeyedStore) { +void TestBytecodeGraphBuilderKeyedStore(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -503,8 +506,8 @@ TEST(BytecodeGraphBuilderKeyedStore) { factory->NewNumberFromInt(100)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -517,6 +520,7 @@ TEST(BytecodeGraphBuilderKeyedStore) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderKeyedStore) TEST(BytecodeGraphBuilderPropertyCall) { HandleAndZoneScope scope; @@ -538,8 +542,7 @@ TEST(BytecodeGraphBuilderPropertyCall) { " return a + b + c + d + e + f + g + h;}})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -582,8 +585,7 @@ TEST(BytecodeGraphBuilderCallNew) { {factory->NewNumberFromInt(25)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -621,8 +623,7 @@ TEST(BytecodeGraphBuilderCreateClosure) { {factory->NewNumberFromInt(25)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -649,8 +650,7 @@ TEST(BytecodeGraphBuilderCallRuntime) { BytecodeGraphTester::NewObject("[1, 2, 3]")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<Handle<Object>>(); Handle<Object> return_value = @@ -659,8 +659,7 @@ TEST(BytecodeGraphBuilderCallRuntime) { } } - -TEST(BytecodeGraphBuilderGlobals) { +void TestBytecodeGraphBuilderGlobals(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -700,8 +699,8 @@ TEST(BytecodeGraphBuilderGlobals) { {factory->NewStringFromStaticChars("number")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -709,6 +708,7 @@ TEST(BytecodeGraphBuilderGlobals) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderGlobals) TEST(BytecodeGraphBuilderToObject) { // TODO(mythria): tests for ToObject. Needs ForIn. @@ -746,8 +746,7 @@ TEST(BytecodeGraphBuilderToName) { {factory->NewNumberFromInt(10)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -778,8 +777,7 @@ TEST(BytecodeGraphBuilderLogicalNot) { {factory->false_value(), factory->NewStringFromStaticChars("abc")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -816,8 +814,7 @@ TEST(BytecodeGraphBuilderTypeOf) { factory->NewStringFromStaticChars("abc")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -871,8 +868,7 @@ TEST(BytecodeGraphBuilderCountOperation) { {factory->nan_value(), factory->NewStringFromStaticChars("String")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -911,8 +907,7 @@ TEST(BytecodeGraphBuilderDelete) { BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -966,8 +961,7 @@ TEST(BytecodeGraphBuilderDeleteGlobal) { {factory->true_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s({});", snippets[i].code_snippet, kFunctionName); @@ -1003,8 +997,7 @@ TEST(BytecodeGraphBuilderDeleteLookupSlot) { {"return delete z;", {factory->false_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1045,8 +1038,7 @@ TEST(BytecodeGraphBuilderLookupSlot) { {"'use strict'; obj.val = 23.456; return obj.val;", {factory->NewNumber(23.456)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1089,8 +1081,7 @@ TEST(BytecodeGraphBuilderLookupSlotWide) { {"'use strict';" REPEAT_256(SPACE, "y = 2.3;") "return obj.val = 23.456;", {factory->NewNumber(23.456)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(3072); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1120,8 +1111,7 @@ TEST(BytecodeGraphBuilderCallLookupSlot) { {handle(Smi::FromInt(30), isolate)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1173,8 +1163,7 @@ TEST(BytecodeGraphBuilderEval) { {factory->NewStringFromStaticChars("object")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1202,8 +1191,7 @@ TEST(BytecodeGraphBuilderEvalParams) { {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1234,8 +1222,7 @@ TEST(BytecodeGraphBuilderEvalGlobal) { {factory->NewStringFromStaticChars("undefined")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -1366,8 +1353,7 @@ TEST(BytecodeGraphBuilderTestIn) { factory->NewNumberFromInt(1)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1399,8 +1385,7 @@ TEST(BytecodeGraphBuilderTestInstanceOf) { {factory->true_value(), factory->undefined_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1413,6 +1398,98 @@ TEST(BytecodeGraphBuilderTestInstanceOf) { } } +TEST(BytecodeGraphBuilderTryCatch) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;", + {handle(Smi::FromInt(2), isolate)}}, + {"var a; try { undef.x } catch(e) { a = 2 }; return a;", + {handle(Smi::FromInt(2), isolate)}}, + {"var a; try { throw 1 } catch(e) { a = e + 2 }; return a;", + {handle(Smi::FromInt(3), isolate)}}, + {"var a; try { throw 1 } catch(e) { a = e + 2 };" + " try { throw a } catch(e) { a = e + 3 }; return a;", + {handle(Smi::FromInt(6), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderTryFinally1) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;", + {handle(Smi::FromInt(4), isolate)}}, + {"var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;", + {handle(Smi::FromInt(23), isolate)}}, + {"var a = 1; try { a = 2; throw 23; } finally { return a; };", + {handle(Smi::FromInt(2), isolate)}}, + {"var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; break; } finally { a = 3; }" + "} return a + i;", + {handle(Smi::FromInt(13), isolate)}}, + {"var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; continue; } finally { a = 3; }" + "} return a + i;", + {handle(Smi::FromInt(23), isolate)}}, + {"var a = 1; try { a = 2;" + " try { a = 3; throw 23; } finally { a = 4; }" + "} catch(e) { a = a + e; } return a;", + {handle(Smi::FromInt(27), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderTryFinally2) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0, const char*> snippets[] = { + {"var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;", + {"Uncaught 23"}}, + {"var a = 1; try { a = 2; throw 23; } finally { throw 42; };", + {"Uncaught 42"}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } +} TEST(BytecodeGraphBuilderThrow) { HandleAndZoneScope scope; @@ -1426,15 +1503,14 @@ TEST(BytecodeGraphBuilderThrow) { {"throw 1;", {"Uncaught 1"}}, {"throw 'Error';", {"Uncaught Error"}}, {"throw 'Error1'; throw 'Error2'", {"Uncaught Error1"}}, - // TODO(mythria): Enable these tests when JumpIfTrue is supported. - // {"var a = true; if (a) { throw 'Error'; }", {"Error"}}, + {"var a = true; if (a) { throw 'Error'; }", {"Uncaught Error"}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, zone, script.start()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); @@ -1492,8 +1568,7 @@ TEST(BytecodeGraphBuilderContext) { {factory->NewStringFromStaticChars("innermost inner_changed outer")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s", snippets[i].code_snippet); @@ -1558,8 +1633,7 @@ TEST(BytecodeGraphBuilderLoadContext) { "f(0);", {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s", snippets[i].code_snippet); @@ -1585,10 +1659,13 @@ TEST(BytecodeGraphBuilderCreateArgumentsNoParameters) { {factory->undefined_value()}}, {"function f(a) {'use strict'; return arguments[0];}", {factory->undefined_value()}}, + {"function f(...restArgs) {return restArgs[0];}", + {factory->undefined_value()}}, + {"function f(a, ...restArgs) {return restArgs[0];}", + {factory->undefined_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1631,8 +1708,7 @@ TEST(BytecodeGraphBuilderCreateArguments) { factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1647,6 +1723,48 @@ TEST(BytecodeGraphBuilderCreateArguments) { } } +TEST(BytecodeGraphBuilderCreateRestArguments) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<3> snippets[] = { + {"function f(...restArgs) {return restArgs[0];}", + {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, b, ...restArgs) {return restArgs[0];}", + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, b, ...restArgs) {return arguments[2];}", + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, ...restArgs) { return restArgs[2];}", + {factory->undefined_value(), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, ...restArgs) { return arguments[0] + restArgs[1];}", + {factory->NewNumberFromInt(4), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function inline_func(a, ...restArgs) { return restArgs[0] }" + "function f(a, b, c) {return inline_func(b, c) + arguments[0];}", + {factory->NewNumberFromInt(31), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = + tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); + Handle<Object> return_value = + callable(snippets[i].parameter(0), snippets[i].parameter(1), + snippets[i].parameter(2)) + .ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} TEST(BytecodeGraphBuilderRegExpLiterals) { HandleAndZoneScope scope; @@ -1671,8 +1789,7 @@ TEST(BytecodeGraphBuilderRegExpLiterals) { {factory->NewStringFromStaticChars("AbC")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1712,8 +1829,7 @@ TEST(BytecodeGraphBuilderArrayLiterals) { {"var t = 't'; return [[t, t + 'est'], [1 + t]][1][0];", {factory->NewStringFromStaticChars("1t")}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1778,8 +1894,7 @@ TEST(BytecodeGraphBuilderObjectLiterals) { {factory->NewNumberFromInt(987)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1856,10 +1971,38 @@ TEST(BytecodeGraphBuilderIf) { " if (p1 < -10) { return -2; } else { return -1; }\n" "}", {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-10)}}, + {"var b = 20, c;" + "if (p1 >= 0) {\n" + " if (b > 0) { c = 2; } else { c = 3; }\n" + "} else {\n" + " if (b < -10) { c = -2; } else { c = -1; }\n" + "}" + "return c;", + {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-1)}}, + {"var b = 20, c = 10;" + "if (p1 >= 0) {\n" + " if (b < 0) { c = 2; }\n" + "} else {\n" + " if (b < -10) { c = -2; } else { c = -1; }\n" + "}" + "return c;", + {factory->NewNumberFromInt(10), factory->NewNumberFromInt(1)}}, + {"var x = 2, a = 10, b = 20, c, d;" + "x = 0;" + "if (a) {\n" + " b = x;" + " if (b > 0) { c = 2; } else { c = 3; }\n" + " x = 4; d = 2;" + "} else {\n" + " d = 3;\n" + "}" + "x = d;" + "function f1() {x}" + "return x + c;", + {factory->NewNumberFromInt(5), factory->NewNumberFromInt(-1)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1890,8 +2033,7 @@ TEST(BytecodeGraphBuilderConditionalOperator) { {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(20)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1952,6 +2094,54 @@ TEST(BytecodeGraphBuilderSwitch) { } } +TEST(BytecodeGraphBuilderSwitchMerge) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + const char* switch_code = + "var x = 10;" + "switch (p1) {\n" + " case 1: x = 0;\n" + " case 2: x = 1;\n" + " case 3:\n" + " case 4: x = 2; break;\n" + " case 5: x = 3;\n" + " case 9: break;\n" + " default: x = 4;\n" + "}\n" + "return x;"; + + ExpectedSnippet<1> snippets[] = { + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(2)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}}, + {switch_code, + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}}, + {switch_code, + {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}}, + {switch_code, + {factory->NewNumberFromInt(4), factory->NewNumberFromInt(6)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(2048); + SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<Handle<Object>>(); + Handle<Object> return_value = + callable(snippets[i].parameter(0)).ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} TEST(BytecodeGraphBuilderNestedSwitch) { HandleAndZoneScope scope; @@ -2294,12 +2484,102 @@ TEST(BytecodeGraphBuilderForIn) { } -TEST(JumpWithConstantsAndWideConstants) { +TEST(BytecodeGraphBuilderForOf) { HandleAndZoneScope scope; - auto isolate = scope.main_isolate(); - const int kStep = 19; - int start = 7; - for (int constants = start; constants < 256 + 3 * kStep; constants += kStep) { + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + ExpectedSnippet<0> snippets[] = { + {" var r = 0;\n" + " for (var a of [0,6,7,9]) { r += a; }\n" + " return r;\n", + {handle(Smi::FromInt(22), isolate)}}, + {" var r = '';\n" + " for (var a of 'foobar') { r = a + r; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("raboof")}}, + {" var a = [1, 2, 3];\n" + " a.name = 4;\n" + " var r = 0;\n" + " for (var x of a) { r += x; }\n" + " return r;\n", + {handle(Smi::FromInt(6), isolate)}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[0]; r += a; } return r;", + {factory->NewStringFromStaticChars("123")}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[2]; r += a; } return r;", + {factory->NewStringFromStaticChars("12undefined")}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data; r += a; } return r;", + {factory->NewStringFromStaticChars("123")}}, + {" var r = '';\n" + " var input = 'foobar';\n" + " for (var a of input) {\n" + " if (a == 'b') break;\n" + " r += a;\n" + " }\n" + " return r;\n", + {factory->NewStringFromStaticChars("foo")}}, + {" var r = '';\n" + " var input = 'foobar';\n" + " for (var a of input) {\n" + " if (a == 'b') continue;\n" + " r += a;\n" + " }\n" + " return r;\n", + {factory->NewStringFromStaticChars("fooar")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[2] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("125674")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[4] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("1234567")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[5] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("1234undefined567")}}, + {" var r = '';\n" + " var obj = new Object();\n" + " obj[Symbol.iterator] = function() { return {\n" + " index: 3,\n" + " data: ['a', 'b', 'c', 'd']," + " next: function() {" + " return {" + " done: this.index == -1,\n" + " value: this.index < 0 ? undefined : this.data[this.index--]\n" + " }\n" + " }\n" + " }}\n" + " for (a of obj) { r += a }\n" + " return r;\n", + {factory->NewStringFromStaticChars("dcba")}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +void TestJumpWithConstantsAndWideConstants(size_t shard) { + const int kStep = 46; + int start = static_cast<int>(7 + 17 * shard); + for (int constants = start; constants < 300; constants += kStep) { std::stringstream filler_os; // Generate a string that consumes constant pool entries and // spread out branch distances in script below. @@ -2321,11 +2601,14 @@ TEST(JumpWithConstantsAndWideConstants) { script_os << "}\n"; script_os << kFunctionName << "(0);\n"; std::string script(script_os.str()); + + HandleAndZoneScope scope; + auto isolate = scope.main_isolate(); auto factory = isolate->factory(); auto zone = scope.main_zone(); + BytecodeGraphTester tester(isolate, zone, script.c_str()); + auto callable = tester.GetCallable<Handle<Object>>(); for (int a = 0; a < 3; a++) { - BytecodeGraphTester tester(isolate, zone, script.c_str()); - auto callable = tester.GetCallable<Handle<Object>>(); Handle<Object> return_val = callable(factory->NewNumberFromInt(a)).ToHandleChecked(); static const int results[] = {11, 12, 2}; @@ -2334,6 +2617,368 @@ TEST(JumpWithConstantsAndWideConstants) { } } +SHARD_TEST_BY_4(JumpWithConstantsAndWideConstants) + +TEST(BytecodeGraphBuilderDoExpressions) { + bool old_flag = FLAG_harmony_do_expressions; + FLAG_harmony_do_expressions = true; + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + ExpectedSnippet<0> snippets[] = { + {"var a = do {}; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; x++; }; return a;", + {handle(Smi::FromInt(100), isolate)}}, + {"var i = 0; for (; i < 5;) { i = do { if (i == 3) { break; }; i + 1; }};" + "return i;", + {handle(Smi::FromInt(3), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + FLAG_harmony_do_expressions = old_flag; +} + +TEST(BytecodeGraphBuilderWithStatement) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"with({x:42}) return x;", {handle(Smi::FromInt(42), isolate)}}, + {"with({}) { var y = 10; return y;}", + {handle(Smi::FromInt(10), isolate)}}, + {"var y = {x:42};" + " function inner() {" + " var x = 20;" + " with(y) return x;" + "}" + "return inner();", + {handle(Smi::FromInt(42), isolate)}}, + {"var y = {x:42};" + " function inner(o) {" + " var x = 20;" + " with(o) return x;" + "}" + "return inner(y);", + {handle(Smi::FromInt(42), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstDeclaration) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<0> snippets[] = { + {"const x = 3; return x;", {handle(Smi::FromInt(3), isolate)}}, + {"let x = 10; x = x + 20; return x;", + {handle(Smi::FromInt(30), isolate)}}, + {"let x = 10; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, + {"let x; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, + {"let x; return x;", {factory->undefined_value()}}, + {"var x = 10; { let x = 30; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"let x = 10; { let x = 20; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; eval('let x = 20;'); return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; eval('const x = 20;'); return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; { const x = 20; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; { const x = 20; return x;} return -1;", + {handle(Smi::FromInt(20), isolate)}}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // const declarations are block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + {handle(Smi::FromInt(55), isolate)}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstDeclarationLookupSlots) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<0> snippets[] = { + {"const x = 3; function f1() {return x;}; return x;", + {handle(Smi::FromInt(3), isolate)}}, + {"let x = 10; x = x + 20; function f1() {return x;}; return x;", + {handle(Smi::FromInt(30), isolate)}}, + {"let x; x = 20; function f1() {return x;}; return x;", + {handle(Smi::FromInt(20), isolate)}}, + {"let x; function f1() {return x;}; return x;", + {factory->undefined_value()}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstInLookupContextChain) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + const char* prologue = + "function OuterMost() {\n" + " const outerConst = 10;\n" + " let outerLet = 20;\n" + " function Outer() {\n" + " function Inner() {\n" + " this.innerFunc = function() { "; + const char* epilogue = + " }\n" + " }\n" + " this.getInnerFunc =" + " function() {return new Inner().innerFunc;}\n" + " }\n" + " this.getOuterFunc =" + " function() {return new Outer().getInnerFunc();}" + "}\n" + "var f = new OuterMost().getOuterFunc();\n" + "f();\n"; + + // Tests for let / constant. + ExpectedSnippet<0> const_decl[] = { + {"return outerConst;", {handle(Smi::FromInt(10), isolate)}}, + {"return outerLet;", {handle(Smi::FromInt(20), isolate)}}, + {"outerLet = 30; return outerLet;", {handle(Smi::FromInt(30), isolate)}}, + {"var outerLet = 40; return outerLet;", + {handle(Smi::FromInt(40), isolate)}}, + {"var outerConst = 50; return outerConst;", + {handle(Smi::FromInt(50), isolate)}}, + {"try { outerConst = 30 } catch(e) { return -1; }", + {handle(Smi::FromInt(-1), isolate)}}}; + + for (size_t i = 0; i < arraysize(const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s %s %s", prologue, const_decl[i].code_snippet, + epilogue); + + BytecodeGraphTester tester(isolate, zone, script.start(), "*"); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].return_value())); + } + + // Tests for Legacy constant. + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + ExpectedSnippet<0> legacy_const_decl[] = { + {"return outerConst = 23;", {handle(Smi::FromInt(23), isolate)}}, + {"outerConst = 30; return outerConst;", + {handle(Smi::FromInt(10), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(legacy_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s %s %s", prologue, legacy_const_decl[i].code_snippet, + epilogue); + + BytecodeGraphTester tester(isolate, zone, script.start(), "*"); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*legacy_const_decl[i].return_value())); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + +TEST(BytecodeGraphBuilderIllegalConstDeclaration) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0, const char*> illegal_const_decl[] = { + {"const x = x = 10 + 3; return x;", + {"Uncaught ReferenceError: x is not defined"}}, + {"const x = 10; x = 20; return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"const x = 10; { x = 20; } return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"const x = 10; eval('x = 20;'); return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"let x = x + 10; return x;", + {"Uncaught ReferenceError: x is not defined"}}, + {"'use strict'; (function f1() { f1 = 123; })() ", + {"Uncaught TypeError: Assignment to constant variable."}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + illegal_const_decl[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = + v8_str(illegal_const_decl[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + illegal_const_decl[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = + v8_str(illegal_const_decl[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } +} + +TEST(BytecodeGraphBuilderLegacyConstDeclaration) { + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"const x = (x = 10) + 3; return x;", + {handle(Smi::FromInt(13), isolate)}}, + {"const x = 10; x = 20; return x;", {handle(Smi::FromInt(10), isolate)}}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // Legacy constants are not block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + {handle(Smi::FromInt(10), isolate)}}, + {"const x = 20; eval('x = 10;'); return x;", + {handle(Smi::FromInt(20), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + +TEST(BytecodeGraphBuilderDebuggerStatement) { + FLAG_expose_debug_as = "debug"; + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippet = { + "var Debug = debug.Debug;" + "var count = 0;" + "function f() {" + " debugger;" + "}" + "function listener(event) {" + " if (event == Debug.DebugEvent.Break) count++;" + "}" + "Debug.setListener(listener);" + "f();" + "Debug.setListener(null);" + "return count;", + {handle(Smi::FromInt(1), isolate)}}; + + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippet.code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippet.return_value())); +} + } // namespace compiler } // namespace internal } // namespace v8 |