1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <utility> 6 7 #include "src/compiler/pipeline.h" 8 #include "src/execution.h" 9 #include "src/handles.h" 10 #include "src/interpreter/bytecode-array-builder.h" 11 #include "src/interpreter/interpreter.h" 12 #include "src/parsing/parser.h" 13 #include "test/cctest/cctest.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace compiler { 18 19 #define SHARD_TEST_BY_2(x) \ 20 TEST(x##_0) { Test##x(0); } \ 21 TEST(x##_1) { Test##x(1); } 22 #define SHARD_TEST_BY_4(x) \ 23 TEST(x##_0) { Test##x(0); } \ 24 TEST(x##_1) { Test##x(1); } \ 25 TEST(x##_2) { Test##x(2); } \ 26 TEST(x##_3) { Test##x(3); } 27 28 static const char kFunctionName[] = "f"; 29 30 static const Token::Value kCompareOperators[] = { 31 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, 32 Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE, 33 Token::Value::GT, Token::Value::GTE}; 34 35 static const int SMI_MAX = (1 << 30) - 1; 36 static const int SMI_MIN = -(1 << 30); 37 38 static MaybeHandle<Object> CallFunction(Isolate* isolate, 39 Handle<JSFunction> function) { 40 return Execution::Call(isolate, function, 41 isolate->factory()->undefined_value(), 0, nullptr); 42 } 43 44 45 template <class... A> 46 static MaybeHandle<Object> CallFunction(Isolate* isolate, 47 Handle<JSFunction> function, 48 A... args) { 49 Handle<Object> argv[] = {args...}; 50 return Execution::Call(isolate, function, 51 isolate->factory()->undefined_value(), sizeof...(args), 52 argv); 53 } 54 55 56 template <class... A> 57 class BytecodeGraphCallable { 58 public: 59 BytecodeGraphCallable(Isolate* isolate, Handle<JSFunction> function) 60 : isolate_(isolate), function_(function) {} 61 virtual ~BytecodeGraphCallable() {} 62 63 MaybeHandle<Object> operator()(A... args) { 64 return CallFunction(isolate_, function_, args...); 65 } 66 67 private: 68 Isolate* isolate_; 69 Handle<JSFunction> function_; 70 }; 71 72 73 class BytecodeGraphTester { 74 public: 75 BytecodeGraphTester(Isolate* isolate, Zone* zone, const char* script, 76 const char* filter = kFunctionName) 77 : isolate_(isolate), zone_(zone), script_(script) { 78 i::FLAG_ignition = true; 79 i::FLAG_always_opt = false; 80 i::FLAG_allow_natives_syntax = true; 81 i::FLAG_loop_assignment_analysis = false; 82 // Ensure handler table is generated. 83 isolate->interpreter()->Initialize(); 84 } 85 virtual ~BytecodeGraphTester() {} 86 87 template <class... A> 88 BytecodeGraphCallable<A...> GetCallable( 89 const char* functionName = kFunctionName) { 90 return BytecodeGraphCallable<A...>(isolate_, GetFunction(functionName)); 91 } 92 93 Local<Message> CheckThrowsReturnMessage() { 94 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_)); 95 auto callable = GetCallable<>(); 96 MaybeHandle<Object> no_result = callable(); 97 CHECK(isolate_->has_pending_exception()); 98 CHECK(try_catch.HasCaught()); 99 CHECK(no_result.is_null()); 100 isolate_->OptionalRescheduleException(true); 101 CHECK(!try_catch.Message().IsEmpty()); 102 return try_catch.Message(); 103 } 104 105 static Handle<Object> NewObject(const char* script) { 106 return v8::Utils::OpenHandle(*CompileRun(script)); 107 } 108 109 private: 110 Isolate* isolate_; 111 Zone* zone_; 112 const char* script_; 113 114 Handle<JSFunction> GetFunction(const char* functionName) { 115 CompileRun(script_); 116 Local<Function> api_function = Local<Function>::Cast( 117 CcTest::global() 118 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(functionName)) 119 .ToLocalChecked()); 120 Handle<JSFunction> function = 121 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); 122 CHECK(function->shared()->HasBytecodeArray()); 123 124 // TODO(mstarzinger): We should be able to prime CompilationInfo without 125 // having to instantiate a ParseInfo first. Fix this! 126 ParseInfo parse_info(zone_, function); 127 128 CompilationInfo compilation_info(&parse_info, function); 129 compilation_info.SetOptimizing(); 130 compilation_info.MarkAsDeoptimizationEnabled(); 131 compilation_info.MarkAsOptimizeFromBytecode(); 132 Handle<Code> code = Pipeline::GenerateCodeForTesting(&compilation_info); 133 function->ReplaceCode(*code); 134 135 return function; 136 } 137 138 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphTester); 139 }; 140 141 142 #define SPACE() 143 144 #define REPEAT_2(SEP, ...) __VA_ARGS__ SEP() __VA_ARGS__ 145 #define REPEAT_4(SEP, ...) \ 146 REPEAT_2(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) 147 #define REPEAT_8(SEP, ...) \ 148 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_4(SEP, __VA_ARGS__) 149 #define REPEAT_16(SEP, ...) \ 150 REPEAT_8(SEP, __VA_ARGS__) SEP() REPEAT_8(SEP, __VA_ARGS__) 151 #define REPEAT_32(SEP, ...) \ 152 REPEAT_16(SEP, __VA_ARGS__) SEP() REPEAT_16(SEP, __VA_ARGS__) 153 #define REPEAT_64(SEP, ...) \ 154 REPEAT_32(SEP, __VA_ARGS__) SEP() REPEAT_32(SEP, __VA_ARGS__) 155 #define REPEAT_128(SEP, ...) \ 156 REPEAT_64(SEP, __VA_ARGS__) SEP() REPEAT_64(SEP, __VA_ARGS__) 157 #define REPEAT_256(SEP, ...) \ 158 REPEAT_128(SEP, __VA_ARGS__) SEP() REPEAT_128(SEP, __VA_ARGS__) 159 160 #define REPEAT_127(SEP, ...) \ 161 REPEAT_64(SEP, __VA_ARGS__) \ 162 SEP() \ 163 REPEAT_32(SEP, __VA_ARGS__) \ 164 SEP() \ 165 REPEAT_16(SEP, __VA_ARGS__) \ 166 SEP() \ 167 REPEAT_8(SEP, __VA_ARGS__) \ 168 SEP() \ 169 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) SEP() __VA_ARGS__ 170 171 172 template <int N, typename T = Handle<Object>> 173 struct ExpectedSnippet { 174 const char* code_snippet; 175 T return_value_and_parameters[N + 1]; 176 177 inline T return_value() const { return return_value_and_parameters[0]; } 178 179 inline T parameter(int i) const { 180 CHECK_GE(i, 0); 181 CHECK_LT(i, N); 182 return return_value_and_parameters[1 + i]; 183 } 184 }; 185 186 187 TEST(BytecodeGraphBuilderReturnStatements) { 188 HandleAndZoneScope scope; 189 Isolate* isolate = scope.main_isolate(); 190 Zone* zone = scope.main_zone(); 191 Factory* factory = isolate->factory(); 192 193 ExpectedSnippet<0> snippets[] = { 194 {"return;", {factory->undefined_value()}}, 195 {"return null;", {factory->null_value()}}, 196 {"return true;", {factory->true_value()}}, 197 {"return false;", {factory->false_value()}}, 198 {"return 0;", {factory->NewNumberFromInt(0)}}, 199 {"return +1;", {factory->NewNumberFromInt(1)}}, 200 {"return -1;", {factory->NewNumberFromInt(-1)}}, 201 {"return +127;", {factory->NewNumberFromInt(127)}}, 202 {"return -128;", {factory->NewNumberFromInt(-128)}}, 203 {"return 0.001;", {factory->NewNumber(0.001)}}, 204 {"return 3.7e-60;", {factory->NewNumber(3.7e-60)}}, 205 {"return -3.7e60;", {factory->NewNumber(-3.7e60)}}, 206 {"return '';", {factory->NewStringFromStaticChars("")}}, 207 {"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}}, 208 {"return NaN;", {factory->nan_value()}}}; 209 210 for (size_t i = 0; i < arraysize(snippets); i++) { 211 ScopedVector<char> script(1024); 212 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 213 snippets[i].code_snippet, kFunctionName); 214 215 BytecodeGraphTester tester(isolate, zone, script.start()); 216 auto callable = tester.GetCallable<>(); 217 Handle<Object> return_value = callable().ToHandleChecked(); 218 CHECK(return_value->SameValue(*snippets[i].return_value())); 219 } 220 } 221 222 223 TEST(BytecodeGraphBuilderPrimitiveExpressions) { 224 HandleAndZoneScope scope; 225 Isolate* isolate = scope.main_isolate(); 226 Zone* zone = scope.main_zone(); 227 Factory* factory = isolate->factory(); 228 229 ExpectedSnippet<0> snippets[] = { 230 {"return 1 + 1;", {factory->NewNumberFromInt(2)}}, 231 {"return 20 - 30;", {factory->NewNumberFromInt(-10)}}, 232 {"return 4 * 100;", {factory->NewNumberFromInt(400)}}, 233 {"return 100 / 5;", {factory->NewNumberFromInt(20)}}, 234 {"return 25 % 7;", {factory->NewNumberFromInt(4)}}, 235 }; 236 237 for (size_t i = 0; i < arraysize(snippets); i++) { 238 ScopedVector<char> script(1024); 239 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 240 snippets[i].code_snippet, kFunctionName); 241 242 BytecodeGraphTester tester(isolate, zone, script.start()); 243 auto callable = tester.GetCallable<>(); 244 Handle<Object> return_value = callable().ToHandleChecked(); 245 CHECK(return_value->SameValue(*snippets[i].return_value())); 246 } 247 } 248 249 250 TEST(BytecodeGraphBuilderTwoParameterTests) { 251 HandleAndZoneScope scope; 252 Isolate* isolate = scope.main_isolate(); 253 Zone* zone = scope.main_zone(); 254 Factory* factory = isolate->factory(); 255 256 ExpectedSnippet<2> snippets[] = { 257 // Integers 258 {"return p1 + p2;", 259 {factory->NewNumberFromInt(-70), factory->NewNumberFromInt(3), 260 factory->NewNumberFromInt(-73)}}, 261 {"return p1 + p2 + 3;", 262 {factory->NewNumberFromInt(1139044), factory->NewNumberFromInt(300), 263 factory->NewNumberFromInt(1138741)}}, 264 {"return p1 - p2;", 265 {factory->NewNumberFromInt(1100), factory->NewNumberFromInt(1000), 266 factory->NewNumberFromInt(-100)}}, 267 {"return p1 * p2;", 268 {factory->NewNumberFromInt(-100000), factory->NewNumberFromInt(1000), 269 factory->NewNumberFromInt(-100)}}, 270 {"return p1 / p2;", 271 {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(1000), 272 factory->NewNumberFromInt(-100)}}, 273 {"return p1 % p2;", 274 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(373), 275 factory->NewNumberFromInt(16)}}, 276 // Doubles 277 {"return p1 + p2;", 278 {factory->NewHeapNumber(9.999), factory->NewHeapNumber(3.333), 279 factory->NewHeapNumber(6.666)}}, 280 {"return p1 - p2;", 281 {factory->NewHeapNumber(-3.333), factory->NewHeapNumber(3.333), 282 factory->NewHeapNumber(6.666)}}, 283 {"return p1 * p2;", 284 {factory->NewHeapNumber(3.333 * 6.666), factory->NewHeapNumber(3.333), 285 factory->NewHeapNumber(6.666)}}, 286 {"return p1 / p2;", 287 {factory->NewHeapNumber(2.25), factory->NewHeapNumber(9), 288 factory->NewHeapNumber(4)}}, 289 // Strings 290 {"return p1 + p2;", 291 {factory->NewStringFromStaticChars("abcdef"), 292 factory->NewStringFromStaticChars("abc"), 293 factory->NewStringFromStaticChars("def")}}}; 294 295 for (size_t i = 0; i < arraysize(snippets); i++) { 296 ScopedVector<char> script(1024); 297 SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName, 298 snippets[i].code_snippet, kFunctionName); 299 300 BytecodeGraphTester tester(isolate, zone, script.start()); 301 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 302 Handle<Object> return_value = 303 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 304 .ToHandleChecked(); 305 CHECK(return_value->SameValue(*snippets[i].return_value())); 306 } 307 } 308 309 310 TEST(BytecodeGraphBuilderNamedLoad) { 311 HandleAndZoneScope scope; 312 Isolate* isolate = scope.main_isolate(); 313 Zone* zone = scope.main_zone(); 314 Factory* factory = isolate->factory(); 315 316 ExpectedSnippet<1> snippets[] = { 317 {"return p1.val;", 318 {factory->NewNumberFromInt(10), 319 BytecodeGraphTester::NewObject("({val : 10})")}}, 320 {"return p1[\"name\"];", 321 {factory->NewStringFromStaticChars("abc"), 322 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 323 {"'use strict'; return p1.val;", 324 {factory->NewNumberFromInt(10), 325 BytecodeGraphTester::NewObject("({val : 10 })")}}, 326 {"'use strict'; return p1[\"val\"];", 327 {factory->NewNumberFromInt(10), 328 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}}, 329 {"var b;\n" REPEAT_127(SPACE, " b = p1.name; ") " return p1.name;\n", 330 {factory->NewStringFromStaticChars("abc"), 331 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 332 {"'use strict'; var b;\n" 333 REPEAT_127(SPACE, " b = p1.name; ") 334 "return p1.name;\n", 335 {factory->NewStringFromStaticChars("abc"), 336 BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, 337 }; 338 339 for (size_t i = 0; i < arraysize(snippets); i++) { 340 ScopedVector<char> script(2048); 341 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 342 snippets[i].code_snippet, kFunctionName); 343 344 BytecodeGraphTester tester(isolate, zone, script.start()); 345 auto callable = tester.GetCallable<Handle<Object>>(); 346 Handle<Object> return_value = 347 callable(snippets[i].parameter(0)).ToHandleChecked(); 348 CHECK(return_value->SameValue(*snippets[i].return_value())); 349 } 350 } 351 352 353 TEST(BytecodeGraphBuilderKeyedLoad) { 354 HandleAndZoneScope scope; 355 Isolate* isolate = scope.main_isolate(); 356 Zone* zone = scope.main_zone(); 357 Factory* factory = isolate->factory(); 358 359 ExpectedSnippet<2> snippets[] = { 360 {"return p1[p2];", 361 {factory->NewNumberFromInt(10), 362 BytecodeGraphTester::NewObject("({val : 10})"), 363 factory->NewStringFromStaticChars("val")}}, 364 {"return p1[100];", 365 {factory->NewStringFromStaticChars("abc"), 366 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 367 factory->NewNumberFromInt(0)}}, 368 {"var b = 100; return p1[b];", 369 {factory->NewStringFromStaticChars("abc"), 370 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 371 factory->NewNumberFromInt(0)}}, 372 {"'use strict'; return p1[p2];", 373 {factory->NewNumberFromInt(10), 374 BytecodeGraphTester::NewObject("({val : 10 })"), 375 factory->NewStringFromStaticChars("val")}}, 376 {"'use strict'; return p1[100];", 377 {factory->NewNumberFromInt(10), 378 BytecodeGraphTester::NewObject("({100 : 10})"), 379 factory->NewNumberFromInt(0)}}, 380 {"'use strict'; var b = p2; return p1[b];", 381 {factory->NewStringFromStaticChars("abc"), 382 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 383 factory->NewNumberFromInt(100)}}, 384 {"var b;\n" REPEAT_127(SPACE, " b = p1[p2]; ") " return p1[p2];\n", 385 {factory->NewStringFromStaticChars("abc"), 386 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 387 factory->NewNumberFromInt(100)}}, 388 {"'use strict'; var b;\n" REPEAT_127(SPACE, 389 " b = p1[p2]; ") "return p1[p2];\n", 390 {factory->NewStringFromStaticChars("abc"), 391 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"), 392 factory->NewNumberFromInt(100)}}, 393 }; 394 395 for (size_t i = 0; i < arraysize(snippets); i++) { 396 ScopedVector<char> script(2048); 397 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, 398 snippets[i].code_snippet, kFunctionName); 399 400 BytecodeGraphTester tester(isolate, zone, script.start()); 401 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 402 Handle<Object> return_value = 403 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 404 .ToHandleChecked(); 405 CHECK(return_value->SameValue(*snippets[i].return_value())); 406 } 407 } 408 409 void TestBytecodeGraphBuilderNamedStore(size_t shard) { 410 HandleAndZoneScope scope; 411 Isolate* isolate = scope.main_isolate(); 412 Zone* zone = scope.main_zone(); 413 Factory* factory = isolate->factory(); 414 415 ExpectedSnippet<1> snippets[] = { 416 {"return p1.val = 20;", 417 {factory->NewNumberFromInt(20), 418 BytecodeGraphTester::NewObject("({val : 10})")}}, 419 {"p1.type = 'int'; return p1.type;", 420 {factory->NewStringFromStaticChars("int"), 421 BytecodeGraphTester::NewObject("({val : 10})")}}, 422 {"p1.name = 'def'; return p1[\"name\"];", 423 {factory->NewStringFromStaticChars("def"), 424 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 425 {"'use strict'; p1.val = 20; return p1.val;", 426 {factory->NewNumberFromInt(20), 427 BytecodeGraphTester::NewObject("({val : 10 })")}}, 428 {"'use strict'; return p1.type = 'int';", 429 {factory->NewStringFromStaticChars("int"), 430 BytecodeGraphTester::NewObject("({val : 10})")}}, 431 {"'use strict'; p1.val = 20; return p1[\"val\"];", 432 {factory->NewNumberFromInt(20), 433 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}}, 434 {"var b = 'abc';\n" REPEAT_127( 435 SPACE, " p1.name = b; ") " p1.name = 'def'; return p1.name;\n", 436 {factory->NewStringFromStaticChars("def"), 437 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 438 {"'use strict'; var b = 'def';\n" REPEAT_127( 439 SPACE, " p1.name = 'abc'; ") "p1.name = b; return p1.name;\n", 440 {factory->NewStringFromStaticChars("def"), 441 BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, 442 }; 443 444 for (size_t i = 0; i < arraysize(snippets); i++) { 445 if ((i % 2) != shard) continue; 446 ScopedVector<char> script(3072); 447 SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName, 448 snippets[i].code_snippet, kFunctionName); 449 450 BytecodeGraphTester tester(isolate, zone, script.start()); 451 auto callable = tester.GetCallable<Handle<Object>>(); 452 Handle<Object> return_value = 453 callable(snippets[i].parameter(0)).ToHandleChecked(); 454 CHECK(return_value->SameValue(*snippets[i].return_value())); 455 } 456 } 457 458 SHARD_TEST_BY_2(BytecodeGraphBuilderNamedStore) 459 460 void TestBytecodeGraphBuilderKeyedStore(size_t shard) { 461 HandleAndZoneScope scope; 462 Isolate* isolate = scope.main_isolate(); 463 Zone* zone = scope.main_zone(); 464 Factory* factory = isolate->factory(); 465 466 ExpectedSnippet<2> snippets[] = { 467 {"p1[p2] = 20; return p1[p2];", 468 {factory->NewNumberFromInt(20), 469 BytecodeGraphTester::NewObject("({val : 10})"), 470 factory->NewStringFromStaticChars("val")}}, 471 {"return p1[100] = 'def';", 472 {factory->NewStringFromStaticChars("def"), 473 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 474 factory->NewNumberFromInt(0)}}, 475 {"var b = 100; p1[b] = 'def'; return p1[b];", 476 {factory->NewStringFromStaticChars("def"), 477 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 478 factory->NewNumberFromInt(0)}}, 479 {"'use strict'; p1[p2] = 20; return p1[p2];", 480 {factory->NewNumberFromInt(20), 481 BytecodeGraphTester::NewObject("({val : 10 })"), 482 factory->NewStringFromStaticChars("val")}}, 483 {"'use strict'; return p1[100] = 20;", 484 {factory->NewNumberFromInt(20), 485 BytecodeGraphTester::NewObject("({100 : 10})"), 486 factory->NewNumberFromInt(0)}}, 487 {"'use strict'; var b = p2; p1[b] = 'def'; return p1[b];", 488 {factory->NewStringFromStaticChars("def"), 489 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 490 factory->NewNumberFromInt(100)}}, 491 {"var b;\n" REPEAT_127( 492 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n", 493 {factory->NewStringFromStaticChars("def"), 494 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 495 factory->NewNumberFromInt(100)}}, 496 {"'use strict'; var b;\n" REPEAT_127( 497 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n", 498 {factory->NewStringFromStaticChars("def"), 499 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"), 500 factory->NewNumberFromInt(100)}}, 501 }; 502 503 for (size_t i = 0; i < arraysize(snippets); i++) { 504 if ((i % 2) != shard) continue; 505 ScopedVector<char> script(2048); 506 SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", kFunctionName, 507 snippets[i].code_snippet, kFunctionName); 508 509 BytecodeGraphTester tester(isolate, zone, script.start()); 510 auto callable = tester.GetCallable<Handle<Object>>(); 511 Handle<Object> return_value = 512 callable(snippets[i].parameter(0)).ToHandleChecked(); 513 CHECK(return_value->SameValue(*snippets[i].return_value())); 514 } 515 } 516 517 SHARD_TEST_BY_2(BytecodeGraphBuilderKeyedStore) 518 519 TEST(BytecodeGraphBuilderPropertyCall) { 520 HandleAndZoneScope scope; 521 Isolate* isolate = scope.main_isolate(); 522 Zone* zone = scope.main_zone(); 523 Factory* factory = isolate->factory(); 524 525 ExpectedSnippet<1> snippets[] = { 526 {"return p1.func();", 527 {factory->NewNumberFromInt(25), 528 BytecodeGraphTester::NewObject("({func() { return 25; }})")}}, 529 {"return p1.func('abc');", 530 {factory->NewStringFromStaticChars("abc"), 531 BytecodeGraphTester::NewObject("({func(a) { return a; }})")}}, 532 {"return p1.func(1, 2, 3, 4, 5, 6, 7, 8);", 533 {factory->NewNumberFromInt(36), 534 BytecodeGraphTester::NewObject( 535 "({func(a, b, c, d, e, f, g, h) {\n" 536 " return a + b + c + d + e + f + g + h;}})")}}, 537 }; 538 539 for (size_t i = 0; i < arraysize(snippets); i++) { 540 ScopedVector<char> script(2048); 541 SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", kFunctionName, 542 snippets[i].code_snippet, kFunctionName); 543 544 BytecodeGraphTester tester(isolate, zone, script.start()); 545 auto callable = tester.GetCallable<Handle<Object>>(); 546 Handle<Object> return_value = 547 callable(snippets[i].parameter(0)).ToHandleChecked(); 548 CHECK(return_value->SameValue(*snippets[i].return_value())); 549 } 550 } 551 552 553 TEST(BytecodeGraphBuilderCallNew) { 554 HandleAndZoneScope scope; 555 Isolate* isolate = scope.main_isolate(); 556 Zone* zone = scope.main_zone(); 557 Factory* factory = isolate->factory(); 558 559 ExpectedSnippet<0> snippets[] = { 560 {"function counter() { this.count = 20; }\n" 561 "function f() {\n" 562 " var c = new counter();\n" 563 " return c.count;\n" 564 "}; f()", 565 {factory->NewNumberFromInt(20)}}, 566 {"function counter(arg0) { this.count = 17; this.x = arg0; }\n" 567 "function f() {\n" 568 " var c = new counter(6);\n" 569 " return c.count + c.x;\n" 570 "}; f()", 571 {factory->NewNumberFromInt(23)}}, 572 {"function counter(arg0, arg1) {\n" 573 " this.count = 17; this.x = arg0; this.y = arg1;\n" 574 "}\n" 575 "function f() {\n" 576 " var c = new counter(3, 5);\n" 577 " return c.count + c.x + c.y;\n" 578 "}; f()", 579 {factory->NewNumberFromInt(25)}}, 580 }; 581 582 for (size_t i = 0; i < arraysize(snippets); i++) { 583 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 584 auto callable = tester.GetCallable<>(); 585 Handle<Object> return_value = callable().ToHandleChecked(); 586 CHECK(return_value->SameValue(*snippets[i].return_value())); 587 } 588 } 589 590 591 TEST(BytecodeGraphBuilderCreateClosure) { 592 HandleAndZoneScope scope; 593 Isolate* isolate = scope.main_isolate(); 594 Zone* zone = scope.main_zone(); 595 Factory* factory = isolate->factory(); 596 597 ExpectedSnippet<0> snippets[] = { 598 {"function f() {\n" 599 " function counter() { this.count = 20; }\n" 600 " var c = new counter();\n" 601 " return c.count;\n" 602 "}; f()", 603 {factory->NewNumberFromInt(20)}}, 604 {"function f() {\n" 605 " function counter(arg0) { this.count = 17; this.x = arg0; }\n" 606 " var c = new counter(6);\n" 607 " return c.count + c.x;\n" 608 "}; f()", 609 {factory->NewNumberFromInt(23)}}, 610 {"function f() {\n" 611 " function counter(arg0, arg1) {\n" 612 " this.count = 17; this.x = arg0; this.y = arg1;\n" 613 " }\n" 614 " var c = new counter(3, 5);\n" 615 " return c.count + c.x + c.y;\n" 616 "}; f()", 617 {factory->NewNumberFromInt(25)}}, 618 }; 619 620 for (size_t i = 0; i < arraysize(snippets); i++) { 621 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 622 auto callable = tester.GetCallable<>(); 623 Handle<Object> return_value = callable().ToHandleChecked(); 624 CHECK(return_value->SameValue(*snippets[i].return_value())); 625 } 626 } 627 628 629 TEST(BytecodeGraphBuilderCallRuntime) { 630 HandleAndZoneScope scope; 631 Isolate* isolate = scope.main_isolate(); 632 Zone* zone = scope.main_zone(); 633 Factory* factory = isolate->factory(); 634 635 ExpectedSnippet<1> snippets[] = { 636 {"function f(arg0) { return %MaxSmi(); }\nf()", 637 {factory->NewNumberFromInt(Smi::kMaxValue), factory->undefined_value()}}, 638 {"function f(arg0) { return %IsArray(arg0) }\nf(undefined)", 639 {factory->true_value(), BytecodeGraphTester::NewObject("[1, 2, 3]")}}, 640 {"function f(arg0) { return %Add(arg0, 2) }\nf(1)", 641 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(3)}}, 642 {"function f(arg0) { return %spread_arguments(arg0).length }\nf([])", 643 {factory->NewNumberFromInt(3), 644 BytecodeGraphTester::NewObject("[1, 2, 3]")}}, 645 }; 646 647 for (size_t i = 0; i < arraysize(snippets); i++) { 648 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 649 auto callable = tester.GetCallable<Handle<Object>>(); 650 Handle<Object> return_value = 651 callable(snippets[i].parameter(0)).ToHandleChecked(); 652 CHECK(return_value->SameValue(*snippets[i].return_value())); 653 } 654 } 655 656 TEST(BytecodeGraphBuilderInvokeIntrinsic) { 657 HandleAndZoneScope scope; 658 Isolate* isolate = scope.main_isolate(); 659 Zone* zone = scope.main_zone(); 660 Factory* factory = isolate->factory(); 661 662 ExpectedSnippet<1> snippets[] = { 663 {"function f(arg0) { return %_IsJSReceiver(arg0); }\nf()", 664 {factory->false_value(), factory->NewNumberFromInt(1)}}, 665 {"function f(arg0) { return %_IsArray(arg0) }\nf(undefined)", 666 {factory->true_value(), BytecodeGraphTester::NewObject("[1, 2, 3]")}}, 667 }; 668 669 for (size_t i = 0; i < arraysize(snippets); i++) { 670 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 671 auto callable = tester.GetCallable<Handle<Object>>(); 672 Handle<Object> return_value = 673 callable(snippets[i].parameter(0)).ToHandleChecked(); 674 CHECK(return_value->SameValue(*snippets[i].return_value())); 675 } 676 } 677 678 void TestBytecodeGraphBuilderGlobals(size_t shard) { 679 HandleAndZoneScope scope; 680 Isolate* isolate = scope.main_isolate(); 681 Zone* zone = scope.main_zone(); 682 Factory* factory = isolate->factory(); 683 684 ExpectedSnippet<0> snippets[] = { 685 {"var global = 321;\n function f() { return global; };\n f();", 686 {factory->NewNumberFromInt(321)}}, 687 {"var global = 321;\n" 688 "function f() { global = 123; return global };\n f();", 689 {factory->NewNumberFromInt(123)}}, 690 {"var global = function() { return 'abc'};\n" 691 "function f() { return global(); };\n f();", 692 {factory->NewStringFromStaticChars("abc")}}, 693 {"var global = 456;\n" 694 "function f() { 'use strict'; return global; };\n f();", 695 {factory->NewNumberFromInt(456)}}, 696 {"var global = 987;\n" 697 "function f() { 'use strict'; global = 789; return global };\n f();", 698 {factory->NewNumberFromInt(789)}}, 699 {"var global = function() { return 'xyz'};\n" 700 "function f() { 'use strict'; return global(); };\n f();", 701 {factory->NewStringFromStaticChars("xyz")}}, 702 {"var global = 'abc'; var global_obj = {val:123};\n" 703 "function f() {\n" REPEAT_127( 704 SPACE, " var b = global_obj.name;\n") "return global; };\n f();\n", 705 {factory->NewStringFromStaticChars("abc")}}, 706 {"var global = 'abc'; var global_obj = {val:123};\n" 707 "function f() { 'use strict';\n" REPEAT_127( 708 SPACE, " var b = global_obj.name;\n") "global = 'xyz'; return " 709 "global };\n f();\n", 710 {factory->NewStringFromStaticChars("xyz")}}, 711 {"function f() { return typeof(undeclared_var); }\n; f();\n", 712 {factory->NewStringFromStaticChars("undefined")}}, 713 {"var defined_var = 10; function f() { return typeof(defined_var); }\n; " 714 "f();\n", 715 {factory->NewStringFromStaticChars("number")}}, 716 }; 717 718 for (size_t i = 0; i < arraysize(snippets); i++) { 719 if ((i % 2) != shard) continue; 720 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 721 auto callable = tester.GetCallable<>(); 722 Handle<Object> return_value = callable().ToHandleChecked(); 723 CHECK(return_value->SameValue(*snippets[i].return_value())); 724 } 725 } 726 727 SHARD_TEST_BY_2(BytecodeGraphBuilderGlobals) 728 729 TEST(BytecodeGraphBuilderToObject) { 730 // TODO(mythria): tests for ToObject. Needs ForIn. 731 } 732 733 734 TEST(BytecodeGraphBuilderToName) { 735 HandleAndZoneScope scope; 736 Isolate* isolate = scope.main_isolate(); 737 Zone* zone = scope.main_zone(); 738 Factory* factory = isolate->factory(); 739 740 ExpectedSnippet<0> snippets[] = { 741 {"var a = 'val'; var obj = {[a] : 10}; return obj.val;", 742 {factory->NewNumberFromInt(10)}}, 743 {"var a = 20; var obj = {[a] : 10}; return obj['20'];", 744 {factory->NewNumberFromInt(10)}}, 745 {"var a = 20; var obj = {[a] : 10}; return obj[20];", 746 {factory->NewNumberFromInt(10)}}, 747 {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];", 748 {factory->NewNumberFromInt(10)}}, 749 {"var a = {val:23}; var obj = {[a] : 10}; return obj['[object Object]'];", 750 {factory->NewNumberFromInt(10)}}, 751 {"var a = {toString : function() { return 'x'}};\n" 752 "var obj = {[a] : 10};\n" 753 "return obj.x;", 754 {factory->NewNumberFromInt(10)}}, 755 {"var a = {valueOf : function() { return 'x'}};\n" 756 "var obj = {[a] : 10};\n" 757 "return obj.x;", 758 {factory->undefined_value()}}, 759 {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n" 760 "var obj = {[a] : 10};\n" 761 "return obj.x;", 762 {factory->NewNumberFromInt(10)}}, 763 }; 764 765 for (size_t i = 0; i < arraysize(snippets); i++) { 766 ScopedVector<char> script(1024); 767 SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName, 768 snippets[i].code_snippet, kFunctionName); 769 770 BytecodeGraphTester tester(isolate, zone, script.start()); 771 auto callable = tester.GetCallable<>(); 772 Handle<Object> return_value = callable().ToHandleChecked(); 773 CHECK(return_value->SameValue(*snippets[i].return_value())); 774 } 775 } 776 777 778 TEST(BytecodeGraphBuilderLogicalNot) { 779 HandleAndZoneScope scope; 780 Isolate* isolate = scope.main_isolate(); 781 Zone* zone = scope.main_zone(); 782 Factory* factory = isolate->factory(); 783 784 ExpectedSnippet<1> snippets[] = { 785 {"return !p1;", 786 {factory->false_value(), 787 BytecodeGraphTester::NewObject("({val : 10})")}}, 788 {"return !p1;", {factory->true_value(), factory->NewNumberFromInt(0)}}, 789 {"return !p1;", {factory->true_value(), factory->undefined_value()}}, 790 {"return !p1;", {factory->false_value(), factory->NewNumberFromInt(10)}}, 791 {"return !p1;", {factory->false_value(), factory->true_value()}}, 792 {"return !p1;", 793 {factory->false_value(), factory->NewStringFromStaticChars("abc")}}, 794 }; 795 796 for (size_t i = 0; i < arraysize(snippets); i++) { 797 ScopedVector<char> script(1024); 798 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 799 snippets[i].code_snippet, kFunctionName); 800 801 BytecodeGraphTester tester(isolate, zone, script.start()); 802 auto callable = tester.GetCallable<Handle<Object>>(); 803 Handle<Object> return_value = 804 callable(snippets[i].parameter(0)).ToHandleChecked(); 805 CHECK(return_value->SameValue(*snippets[i].return_value())); 806 } 807 } 808 809 810 TEST(BytecodeGraphBuilderTypeOf) { 811 HandleAndZoneScope scope; 812 Isolate* isolate = scope.main_isolate(); 813 Zone* zone = scope.main_zone(); 814 Factory* factory = isolate->factory(); 815 816 ExpectedSnippet<1> snippets[] = { 817 {"return typeof p1;", 818 {factory->NewStringFromStaticChars("object"), 819 BytecodeGraphTester::NewObject("({val : 10})")}}, 820 {"return typeof p1;", 821 {factory->NewStringFromStaticChars("undefined"), 822 factory->undefined_value()}}, 823 {"return typeof p1;", 824 {factory->NewStringFromStaticChars("number"), 825 factory->NewNumberFromInt(10)}}, 826 {"return typeof p1;", 827 {factory->NewStringFromStaticChars("boolean"), factory->true_value()}}, 828 {"return typeof p1;", 829 {factory->NewStringFromStaticChars("string"), 830 factory->NewStringFromStaticChars("abc")}}, 831 }; 832 833 for (size_t i = 0; i < arraysize(snippets); i++) { 834 ScopedVector<char> script(1024); 835 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 836 snippets[i].code_snippet, kFunctionName); 837 838 BytecodeGraphTester tester(isolate, zone, script.start()); 839 auto callable = tester.GetCallable<Handle<Object>>(); 840 Handle<Object> return_value = 841 callable(snippets[i].parameter(0)).ToHandleChecked(); 842 CHECK(return_value->SameValue(*snippets[i].return_value())); 843 } 844 } 845 846 847 TEST(BytecodeGraphBuilderCountOperation) { 848 HandleAndZoneScope scope; 849 Isolate* isolate = scope.main_isolate(); 850 Zone* zone = scope.main_zone(); 851 Factory* factory = isolate->factory(); 852 853 ExpectedSnippet<1> snippets[] = { 854 {"return ++p1;", 855 {factory->NewNumberFromInt(11), factory->NewNumberFromInt(10)}}, 856 {"return p1++;", 857 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}}, 858 {"return p1++ + 10;", 859 {factory->NewHeapNumber(15.23), factory->NewHeapNumber(5.23)}}, 860 {"return 20 + ++p1;", 861 {factory->NewHeapNumber(27.23), factory->NewHeapNumber(6.23)}}, 862 {"return --p1;", 863 {factory->NewHeapNumber(9.8), factory->NewHeapNumber(10.8)}}, 864 {"return p1--;", 865 {factory->NewHeapNumber(10.8), factory->NewHeapNumber(10.8)}}, 866 {"return p1-- + 10;", 867 {factory->NewNumberFromInt(20), factory->NewNumberFromInt(10)}}, 868 {"return 20 + --p1;", 869 {factory->NewNumberFromInt(29), factory->NewNumberFromInt(10)}}, 870 {"return p1.val--;", 871 {factory->NewNumberFromInt(10), 872 BytecodeGraphTester::NewObject("({val : 10})")}}, 873 {"return ++p1['val'];", 874 {factory->NewNumberFromInt(11), 875 BytecodeGraphTester::NewObject("({val : 10})")}}, 876 {"return ++p1[1];", 877 {factory->NewNumberFromInt(11), 878 BytecodeGraphTester::NewObject("({1 : 10})")}}, 879 {" function inner() { return p1 } return --p1;", 880 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(10)}}, 881 {" function inner() { return p1 } return p1--;", 882 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}}, 883 {"return ++p1;", 884 {factory->nan_value(), factory->NewStringFromStaticChars("String")}}, 885 }; 886 887 for (size_t i = 0; i < arraysize(snippets); i++) { 888 ScopedVector<char> script(1024); 889 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 890 snippets[i].code_snippet, kFunctionName); 891 892 BytecodeGraphTester tester(isolate, zone, script.start()); 893 auto callable = tester.GetCallable<Handle<Object>>(); 894 Handle<Object> return_value = 895 callable(snippets[i].parameter(0)).ToHandleChecked(); 896 CHECK(return_value->SameValue(*snippets[i].return_value())); 897 } 898 } 899 900 901 TEST(BytecodeGraphBuilderDelete) { 902 HandleAndZoneScope scope; 903 Isolate* isolate = scope.main_isolate(); 904 Zone* zone = scope.main_zone(); 905 Factory* factory = isolate->factory(); 906 907 ExpectedSnippet<1> snippets[] = { 908 {"return delete p1.val;", 909 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 910 {"delete p1.val; return p1.val;", 911 {factory->undefined_value(), 912 BytecodeGraphTester::NewObject("({val : 10})")}}, 913 {"delete p1.name; return p1.val;", 914 {factory->NewNumberFromInt(10), 915 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, 916 {"'use strict'; return delete p1.val;", 917 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 918 {"'use strict'; delete p1.val; return p1.val;", 919 {factory->undefined_value(), 920 BytecodeGraphTester::NewObject("({val : 10})")}}, 921 {"'use strict'; delete p1.name; return p1.val;", 922 {factory->NewNumberFromInt(10), 923 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, 924 }; 925 926 for (size_t i = 0; i < arraysize(snippets); i++) { 927 ScopedVector<char> script(1024); 928 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 929 snippets[i].code_snippet, kFunctionName); 930 931 BytecodeGraphTester tester(isolate, zone, script.start()); 932 auto callable = tester.GetCallable<Handle<Object>>(); 933 Handle<Object> return_value = 934 callable(snippets[i].parameter(0)).ToHandleChecked(); 935 CHECK(return_value->SameValue(*snippets[i].return_value())); 936 } 937 } 938 939 940 TEST(BytecodeGraphBuilderDeleteGlobal) { 941 HandleAndZoneScope scope; 942 Isolate* isolate = scope.main_isolate(); 943 Zone* zone = scope.main_zone(); 944 Factory* factory = isolate->factory(); 945 946 ExpectedSnippet<0> snippets[] = { 947 {"var obj = {val : 10, type : 'int'};" 948 "function f() {return delete obj;};", 949 {factory->false_value()}}, 950 {"function f() {return delete this;};", {factory->true_value()}}, 951 {"var obj = {val : 10, type : 'int'};" 952 "function f() {return delete obj.val;};", 953 {factory->true_value()}}, 954 {"var obj = {val : 10, type : 'int'};" 955 "function f() {'use strict'; return delete obj.val;};", 956 {factory->true_value()}}, 957 {"var obj = {val : 10, type : 'int'};" 958 "function f() {delete obj.val; return obj.val;};", 959 {factory->undefined_value()}}, 960 {"var obj = {val : 10, type : 'int'};" 961 "function f() {'use strict'; delete obj.val; return obj.val;};", 962 {factory->undefined_value()}}, 963 {"var obj = {1 : 10, 2 : 20};" 964 "function f() { return delete obj[1]; };", 965 {factory->true_value()}}, 966 {"var obj = {1 : 10, 2 : 20};" 967 "function f() { 'use strict'; return delete obj[1];};", 968 {factory->true_value()}}, 969 {"obj = {1 : 10, 2 : 20};" 970 "function f() { delete obj[1]; return obj[2];};", 971 {factory->NewNumberFromInt(20)}}, 972 {"function f() {" 973 " var obj = {1 : 10, 2 : 20};" 974 " function inner() { return obj[1]; };" 975 " return delete obj[1];" 976 "}", 977 {factory->true_value()}}, 978 }; 979 980 for (size_t i = 0; i < arraysize(snippets); i++) { 981 ScopedVector<char> script(1024); 982 SNPrintF(script, "%s %s({});", snippets[i].code_snippet, kFunctionName); 983 984 BytecodeGraphTester tester(isolate, zone, script.start()); 985 auto callable = tester.GetCallable<>(); 986 Handle<Object> return_value = callable().ToHandleChecked(); 987 CHECK(return_value->SameValue(*snippets[i].return_value())); 988 } 989 } 990 991 992 TEST(BytecodeGraphBuilderDeleteLookupSlot) { 993 HandleAndZoneScope scope; 994 Isolate* isolate = scope.main_isolate(); 995 Zone* zone = scope.main_zone(); 996 Factory* factory = isolate->factory(); 997 998 // TODO(mythria): Add more tests when we have support for LdaLookupSlot. 999 const char* function_prologue = "var f;" 1000 "var x = 1;" 1001 "y = 10;" 1002 "var obj = {val:10};" 1003 "var z = 30;" 1004 "function f1() {" 1005 " var z = 20;" 1006 " eval(\"function t() {"; 1007 const char* function_epilogue = " }; f = t; t();\");" 1008 "}" 1009 "f1();"; 1010 1011 ExpectedSnippet<0> snippets[] = { 1012 {"return delete y;", {factory->true_value()}}, 1013 {"return delete z;", {factory->false_value()}}, 1014 }; 1015 1016 for (size_t i = 0; i < arraysize(snippets); i++) { 1017 ScopedVector<char> script(1024); 1018 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1019 function_epilogue); 1020 1021 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1022 auto callable = tester.GetCallable<>(); 1023 Handle<Object> return_value = callable().ToHandleChecked(); 1024 CHECK(return_value->SameValue(*snippets[i].return_value())); 1025 } 1026 } 1027 1028 1029 TEST(BytecodeGraphBuilderLookupSlot) { 1030 HandleAndZoneScope scope; 1031 Isolate* isolate = scope.main_isolate(); 1032 Zone* zone = scope.main_zone(); 1033 Factory* factory = isolate->factory(); 1034 1035 const char* function_prologue = "var f;" 1036 "var x = 12;" 1037 "y = 10;" 1038 "var obj = {val:3.1414};" 1039 "var z = 30;" 1040 "function f1() {" 1041 " var z = 20;" 1042 " eval(\"function t() {"; 1043 const char* function_epilogue = " }; f = t; t();\");" 1044 "}" 1045 "f1();"; 1046 1047 ExpectedSnippet<0> snippets[] = { 1048 {"return x;", {factory->NewNumber(12)}}, 1049 {"return obj.val;", {factory->NewNumber(3.1414)}}, 1050 {"return typeof x;", {factory->NewStringFromStaticChars("number")}}, 1051 {"return typeof dummy;", 1052 {factory->NewStringFromStaticChars("undefined")}}, 1053 {"x = 23; return x;", {factory->NewNumber(23)}}, 1054 {"'use strict'; obj.val = 23.456; return obj.val;", 1055 {factory->NewNumber(23.456)}}}; 1056 1057 for (size_t i = 0; i < arraysize(snippets); i++) { 1058 ScopedVector<char> script(1024); 1059 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1060 function_epilogue); 1061 1062 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1063 auto callable = tester.GetCallable<>(); 1064 Handle<Object> return_value = callable().ToHandleChecked(); 1065 CHECK(return_value->SameValue(*snippets[i].return_value())); 1066 } 1067 } 1068 1069 1070 TEST(BytecodeGraphBuilderLookupSlotWide) { 1071 HandleAndZoneScope scope; 1072 Isolate* isolate = scope.main_isolate(); 1073 Zone* zone = scope.main_zone(); 1074 Factory* factory = isolate->factory(); 1075 1076 const char* function_prologue = 1077 "var f;" 1078 "var x = 12;" 1079 "y = 10;" 1080 "var obj = {val:3.1414};" 1081 "var z = 30;" 1082 "function f1() {" 1083 " var z = 20;" 1084 " eval(\"function t() {"; 1085 const char* function_epilogue = 1086 " }; f = t; t();\");" 1087 "}" 1088 "f1();"; 1089 1090 ExpectedSnippet<0> snippets[] = { 1091 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x;", 1092 {factory->NewNumber(12)}}, 1093 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return typeof x;", 1094 {factory->NewStringFromStaticChars("number")}}, 1095 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x = 23;", 1096 {factory->NewNumber(23)}}, 1097 {"'use strict';" REPEAT_256(SPACE, "y = 2.3;") "return obj.val = 23.456;", 1098 {factory->NewNumber(23.456)}}}; 1099 1100 for (size_t i = 0; i < arraysize(snippets); i++) { 1101 ScopedVector<char> script(3072); 1102 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1103 function_epilogue); 1104 1105 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1106 auto callable = tester.GetCallable<>(); 1107 Handle<Object> return_value = callable().ToHandleChecked(); 1108 CHECK(return_value->SameValue(*snippets[i].return_value())); 1109 } 1110 } 1111 1112 1113 TEST(BytecodeGraphBuilderCallLookupSlot) { 1114 HandleAndZoneScope scope; 1115 Isolate* isolate = scope.main_isolate(); 1116 Zone* zone = scope.main_zone(); 1117 1118 ExpectedSnippet<0> snippets[] = { 1119 {"g = function(){ return 2 }; eval(''); return g();", 1120 {handle(Smi::FromInt(2), isolate)}}, 1121 {"g = function(){ return 2 }; eval('g = function() {return 3}');\n" 1122 "return g();", 1123 {handle(Smi::FromInt(3), isolate)}}, 1124 {"g = { x: function(){ return this.y }, y: 20 };\n" 1125 "eval('g = { x: g.x, y: 30 }');\n" 1126 "return g.x();", 1127 {handle(Smi::FromInt(30), isolate)}}, 1128 }; 1129 1130 for (size_t i = 0; i < arraysize(snippets); i++) { 1131 ScopedVector<char> script(1024); 1132 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1133 snippets[i].code_snippet, kFunctionName); 1134 BytecodeGraphTester tester(isolate, zone, script.start()); 1135 auto callable = tester.GetCallable<>(); 1136 Handle<Object> return_value = callable().ToHandleChecked(); 1137 CHECK(return_value->SameValue(*snippets[i].return_value())); 1138 } 1139 } 1140 1141 1142 TEST(BytecodeGraphBuilderEval) { 1143 HandleAndZoneScope scope; 1144 Isolate* isolate = scope.main_isolate(); 1145 Zone* zone = scope.main_zone(); 1146 Factory* factory = isolate->factory(); 1147 1148 ExpectedSnippet<0> snippets[] = { 1149 {"return eval('1;');", {handle(Smi::FromInt(1), isolate)}}, 1150 {"return eval('100 * 20;');", {handle(Smi::FromInt(2000), isolate)}}, 1151 {"var x = 10; return eval('x + 20;');", 1152 {handle(Smi::FromInt(30), isolate)}}, 1153 {"var x = 10; eval('x = 33;'); return x;", 1154 {handle(Smi::FromInt(33), isolate)}}, 1155 {"'use strict'; var x = 20; var z = 0;\n" 1156 "eval('var x = 33; z = x;'); return x + z;", 1157 {handle(Smi::FromInt(53), isolate)}}, 1158 {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;", 1159 {handle(Smi::FromInt(86), isolate)}}, 1160 {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x", 1161 {handle(Smi::FromInt(11), isolate)}}, 1162 {"var x = 10; eval('var x = 20;'); return x;", 1163 {handle(Smi::FromInt(20), isolate)}}, 1164 {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;", 1165 {handle(Smi::FromInt(1), isolate)}}, 1166 {"'use strict'; var x = 1; eval('var x = 2;'); return x;", 1167 {handle(Smi::FromInt(1), isolate)}}, 1168 {"var x = 10; eval('x + 20;'); return typeof x;", 1169 {factory->NewStringFromStaticChars("number")}}, 1170 {"eval('var y = 10;'); return typeof unallocated;", 1171 {factory->NewStringFromStaticChars("undefined")}}, 1172 {"'use strict'; eval('var y = 10;'); return typeof unallocated;", 1173 {factory->NewStringFromStaticChars("undefined")}}, 1174 {"eval('var x = 10;'); return typeof x;", 1175 {factory->NewStringFromStaticChars("number")}}, 1176 {"var x = {}; eval('var x = 10;'); return typeof x;", 1177 {factory->NewStringFromStaticChars("number")}}, 1178 {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;", 1179 {factory->NewStringFromStaticChars("object")}}, 1180 }; 1181 1182 for (size_t i = 0; i < arraysize(snippets); i++) { 1183 ScopedVector<char> script(1024); 1184 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1185 snippets[i].code_snippet, kFunctionName); 1186 BytecodeGraphTester tester(isolate, zone, script.start()); 1187 auto callable = tester.GetCallable<>(); 1188 Handle<Object> return_value = callable().ToHandleChecked(); 1189 CHECK(return_value->SameValue(*snippets[i].return_value())); 1190 } 1191 } 1192 1193 1194 TEST(BytecodeGraphBuilderEvalParams) { 1195 HandleAndZoneScope scope; 1196 Isolate* isolate = scope.main_isolate(); 1197 Zone* zone = scope.main_zone(); 1198 1199 ExpectedSnippet<1> snippets[] = { 1200 {"var x = 10; return eval('x + p1;');", 1201 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, 1202 {"var x = 10; eval('p1 = x;'); return p1;", 1203 {handle(Smi::FromInt(10), isolate), handle(Smi::FromInt(20), isolate)}}, 1204 {"var a = 10;" 1205 "function inner() { return eval('a + p1;');}" 1206 "return inner();", 1207 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, 1208 }; 1209 1210 for (size_t i = 0; i < arraysize(snippets); i++) { 1211 ScopedVector<char> script(1024); 1212 SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName, 1213 snippets[i].code_snippet, kFunctionName); 1214 BytecodeGraphTester tester(isolate, zone, script.start()); 1215 auto callable = tester.GetCallable<Handle<Object>>(); 1216 Handle<Object> return_value = 1217 callable(snippets[i].parameter(0)).ToHandleChecked(); 1218 CHECK(return_value->SameValue(*snippets[i].return_value())); 1219 } 1220 } 1221 1222 1223 TEST(BytecodeGraphBuilderEvalGlobal) { 1224 HandleAndZoneScope scope; 1225 Isolate* isolate = scope.main_isolate(); 1226 Zone* zone = scope.main_zone(); 1227 Factory* factory = isolate->factory(); 1228 1229 ExpectedSnippet<0> snippets[] = { 1230 {"function add_global() { eval('function f() { z = 33; }; f()'); };" 1231 "function f() { add_global(); return z; }; f();", 1232 {handle(Smi::FromInt(33), isolate)}}, 1233 {"function add_global() {\n" 1234 " eval('\"use strict\"; function f() { y = 33; };" 1235 " try { f() } catch(e) {}');\n" 1236 "}\n" 1237 "function f() { add_global(); return typeof y; } f();", 1238 {factory->NewStringFromStaticChars("undefined")}}, 1239 }; 1240 1241 for (size_t i = 0; i < arraysize(snippets); i++) { 1242 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 1243 auto callable = tester.GetCallable<>(); 1244 Handle<Object> return_value = callable().ToHandleChecked(); 1245 CHECK(return_value->SameValue(*snippets[i].return_value())); 1246 } 1247 } 1248 1249 1250 bool get_compare_result(Token::Value opcode, Handle<Object> lhs_value, 1251 Handle<Object> rhs_value) { 1252 switch (opcode) { 1253 case Token::Value::EQ: 1254 return Object::Equals(lhs_value, rhs_value).FromJust(); 1255 case Token::Value::NE: 1256 return !Object::Equals(lhs_value, rhs_value).FromJust(); 1257 case Token::Value::EQ_STRICT: 1258 return lhs_value->StrictEquals(*rhs_value); 1259 case Token::Value::NE_STRICT: 1260 return !lhs_value->StrictEquals(*rhs_value); 1261 case Token::Value::LT: 1262 return Object::LessThan(lhs_value, rhs_value).FromJust(); 1263 case Token::Value::LTE: 1264 return Object::LessThanOrEqual(lhs_value, rhs_value).FromJust(); 1265 case Token::Value::GT: 1266 return Object::GreaterThan(lhs_value, rhs_value).FromJust(); 1267 case Token::Value::GTE: 1268 return Object::GreaterThanOrEqual(lhs_value, rhs_value).FromJust(); 1269 default: 1270 UNREACHABLE(); 1271 return false; 1272 } 1273 } 1274 1275 1276 const char* get_code_snippet(Token::Value opcode) { 1277 switch (opcode) { 1278 case Token::Value::EQ: 1279 return "return p1 == p2;"; 1280 case Token::Value::NE: 1281 return "return p1 != p2;"; 1282 case Token::Value::EQ_STRICT: 1283 return "return p1 === p2;"; 1284 case Token::Value::NE_STRICT: 1285 return "return p1 !== p2;"; 1286 case Token::Value::LT: 1287 return "return p1 < p2;"; 1288 case Token::Value::LTE: 1289 return "return p1 <= p2;"; 1290 case Token::Value::GT: 1291 return "return p1 > p2;"; 1292 case Token::Value::GTE: 1293 return "return p1 >= p2;"; 1294 default: 1295 UNREACHABLE(); 1296 return ""; 1297 } 1298 } 1299 1300 1301 TEST(BytecodeGraphBuilderCompare) { 1302 HandleAndZoneScope scope; 1303 Isolate* isolate = scope.main_isolate(); 1304 Zone* zone = scope.main_zone(); 1305 Factory* factory = isolate->factory(); 1306 Handle<Object> lhs_values[] = { 1307 factory->NewNumberFromInt(10), factory->NewHeapNumber(3.45), 1308 factory->NewStringFromStaticChars("abc"), 1309 factory->NewNumberFromInt(SMI_MAX), factory->NewNumberFromInt(SMI_MIN)}; 1310 Handle<Object> rhs_values[] = {factory->NewNumberFromInt(10), 1311 factory->NewStringFromStaticChars("10"), 1312 factory->NewNumberFromInt(20), 1313 factory->NewStringFromStaticChars("abc"), 1314 factory->NewHeapNumber(3.45), 1315 factory->NewNumberFromInt(SMI_MAX), 1316 factory->NewNumberFromInt(SMI_MIN)}; 1317 1318 for (size_t i = 0; i < arraysize(kCompareOperators); i++) { 1319 ScopedVector<char> script(1024); 1320 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, 1321 get_code_snippet(kCompareOperators[i]), kFunctionName); 1322 1323 BytecodeGraphTester tester(isolate, zone, script.start()); 1324 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 1325 for (size_t j = 0; j < arraysize(lhs_values); j++) { 1326 for (size_t k = 0; k < arraysize(rhs_values); k++) { 1327 Handle<Object> return_value = 1328 callable(lhs_values[j], rhs_values[k]).ToHandleChecked(); 1329 bool result = get_compare_result(kCompareOperators[i], lhs_values[j], 1330 rhs_values[k]); 1331 CHECK(return_value->SameValue(*factory->ToBoolean(result))); 1332 } 1333 } 1334 } 1335 } 1336 1337 1338 TEST(BytecodeGraphBuilderTestIn) { 1339 HandleAndZoneScope scope; 1340 Isolate* isolate = scope.main_isolate(); 1341 Zone* zone = scope.main_zone(); 1342 Factory* factory = isolate->factory(); 1343 1344 ExpectedSnippet<2> snippets[] = { 1345 {"return p2 in p1;", 1346 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1347 factory->NewStringFromStaticChars("val")}}, 1348 {"return p2 in p1;", 1349 {factory->true_value(), BytecodeGraphTester::NewObject("[]"), 1350 factory->NewStringFromStaticChars("length")}}, 1351 {"return p2 in p1;", 1352 {factory->true_value(), BytecodeGraphTester::NewObject("[]"), 1353 factory->NewStringFromStaticChars("toString")}}, 1354 {"return p2 in p1;", 1355 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1356 factory->NewStringFromStaticChars("toString")}}, 1357 {"return p2 in p1;", 1358 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1359 factory->NewStringFromStaticChars("abc")}}, 1360 {"return p2 in p1;", 1361 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1362 factory->NewNumberFromInt(10)}}, 1363 {"return p2 in p1;", 1364 {factory->true_value(), BytecodeGraphTester::NewObject("({10 : 'val'})"), 1365 factory->NewNumberFromInt(10)}}, 1366 {"return p2 in p1;", 1367 {factory->false_value(), 1368 BytecodeGraphTester::NewObject("({10 : 'val'})"), 1369 factory->NewNumberFromInt(1)}}, 1370 }; 1371 1372 for (size_t i = 0; i < arraysize(snippets); i++) { 1373 ScopedVector<char> script(1024); 1374 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, 1375 snippets[i].code_snippet, kFunctionName); 1376 1377 BytecodeGraphTester tester(isolate, zone, script.start()); 1378 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 1379 Handle<Object> return_value = 1380 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 1381 .ToHandleChecked(); 1382 CHECK(return_value->SameValue(*snippets[i].return_value())); 1383 } 1384 } 1385 1386 1387 TEST(BytecodeGraphBuilderTestInstanceOf) { 1388 HandleAndZoneScope scope; 1389 Isolate* isolate = scope.main_isolate(); 1390 Zone* zone = scope.main_zone(); 1391 Factory* factory = isolate->factory(); 1392 1393 ExpectedSnippet<1> snippets[] = { 1394 {"return p1 instanceof Object;", 1395 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 1396 {"return p1 instanceof String;", 1397 {factory->false_value(), factory->NewStringFromStaticChars("string")}}, 1398 {"var cons = function() {};" 1399 "var obj = new cons();" 1400 "return obj instanceof cons;", 1401 {factory->true_value(), factory->undefined_value()}}, 1402 }; 1403 1404 for (size_t i = 0; i < arraysize(snippets); i++) { 1405 ScopedVector<char> script(1024); 1406 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 1407 snippets[i].code_snippet, kFunctionName); 1408 1409 BytecodeGraphTester tester(isolate, zone, script.start()); 1410 auto callable = tester.GetCallable<Handle<Object>>(); 1411 Handle<Object> return_value = 1412 callable(snippets[i].parameter(0)).ToHandleChecked(); 1413 CHECK(return_value->SameValue(*snippets[i].return_value())); 1414 } 1415 } 1416 1417 TEST(BytecodeGraphBuilderTryCatch) { 1418 HandleAndZoneScope scope; 1419 Isolate* isolate = scope.main_isolate(); 1420 Zone* zone = scope.main_zone(); 1421 1422 ExpectedSnippet<0> snippets[] = { 1423 {"var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;", 1424 {handle(Smi::FromInt(2), isolate)}}, 1425 {"var a; try { undef.x } catch(e) { a = 2 }; return a;", 1426 {handle(Smi::FromInt(2), isolate)}}, 1427 {"var a; try { throw 1 } catch(e) { a = e + 2 }; return a;", 1428 {handle(Smi::FromInt(3), isolate)}}, 1429 {"var a; try { throw 1 } catch(e) { a = e + 2 };" 1430 " try { throw a } catch(e) { a = e + 3 }; return a;", 1431 {handle(Smi::FromInt(6), isolate)}}, 1432 }; 1433 1434 for (size_t i = 0; i < arraysize(snippets); i++) { 1435 ScopedVector<char> script(1024); 1436 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1437 snippets[i].code_snippet, kFunctionName); 1438 1439 BytecodeGraphTester tester(isolate, zone, script.start()); 1440 auto callable = tester.GetCallable<>(); 1441 Handle<Object> return_value = callable().ToHandleChecked(); 1442 CHECK(return_value->SameValue(*snippets[i].return_value())); 1443 } 1444 } 1445 1446 TEST(BytecodeGraphBuilderTryFinally1) { 1447 HandleAndZoneScope scope; 1448 Isolate* isolate = scope.main_isolate(); 1449 Zone* zone = scope.main_zone(); 1450 1451 ExpectedSnippet<0> snippets[] = { 1452 {"var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;", 1453 {handle(Smi::FromInt(4), isolate)}}, 1454 {"var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;", 1455 {handle(Smi::FromInt(23), isolate)}}, 1456 {"var a = 1; try { a = 2; throw 23; } finally { return a; };", 1457 {handle(Smi::FromInt(2), isolate)}}, 1458 {"var a = 1; for (var i = 10; i < 20; i += 5) {" 1459 " try { a = 2; break; } finally { a = 3; }" 1460 "} return a + i;", 1461 {handle(Smi::FromInt(13), isolate)}}, 1462 {"var a = 1; for (var i = 10; i < 20; i += 5) {" 1463 " try { a = 2; continue; } finally { a = 3; }" 1464 "} return a + i;", 1465 {handle(Smi::FromInt(23), isolate)}}, 1466 {"var a = 1; try { a = 2;" 1467 " try { a = 3; throw 23; } finally { a = 4; }" 1468 "} catch(e) { a = a + e; } return a;", 1469 {handle(Smi::FromInt(27), isolate)}}, 1470 }; 1471 1472 for (size_t i = 0; i < arraysize(snippets); i++) { 1473 ScopedVector<char> script(1024); 1474 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1475 snippets[i].code_snippet, kFunctionName); 1476 1477 BytecodeGraphTester tester(isolate, zone, script.start()); 1478 auto callable = tester.GetCallable<>(); 1479 Handle<Object> return_value = callable().ToHandleChecked(); 1480 CHECK(return_value->SameValue(*snippets[i].return_value())); 1481 } 1482 } 1483 1484 TEST(BytecodeGraphBuilderTryFinally2) { 1485 HandleAndZoneScope scope; 1486 Isolate* isolate = scope.main_isolate(); 1487 Zone* zone = scope.main_zone(); 1488 1489 ExpectedSnippet<0, const char*> snippets[] = { 1490 {"var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;", 1491 {"Uncaught 23"}}, 1492 {"var a = 1; try { a = 2; throw 23; } finally { throw 42; };", 1493 {"Uncaught 42"}}, 1494 }; 1495 1496 for (size_t i = 0; i < arraysize(snippets); i++) { 1497 ScopedVector<char> script(1024); 1498 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1499 snippets[i].code_snippet, kFunctionName); 1500 1501 BytecodeGraphTester tester(isolate, zone, script.start()); 1502 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); 1503 v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); 1504 CHECK( 1505 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) 1506 .FromJust()); 1507 } 1508 } 1509 1510 TEST(BytecodeGraphBuilderThrow) { 1511 HandleAndZoneScope scope; 1512 Isolate* isolate = scope.main_isolate(); 1513 Zone* zone = scope.main_zone(); 1514 1515 // TODO(mythria): Add more tests when real try-catch and deoptimization 1516 // information are supported. 1517 ExpectedSnippet<0, const char*> snippets[] = { 1518 {"throw undefined;", {"Uncaught undefined"}}, 1519 {"throw 1;", {"Uncaught 1"}}, 1520 {"throw 'Error';", {"Uncaught Error"}}, 1521 {"throw 'Error1'; throw 'Error2'", {"Uncaught Error1"}}, 1522 {"var a = true; if (a) { throw 'Error'; }", {"Uncaught Error"}}, 1523 }; 1524 1525 for (size_t i = 0; i < arraysize(snippets); i++) { 1526 ScopedVector<char> script(1024); 1527 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1528 snippets[i].code_snippet, kFunctionName); 1529 1530 BytecodeGraphTester tester(isolate, zone, script.start()); 1531 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); 1532 v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); 1533 CHECK( 1534 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) 1535 .FromJust()); 1536 } 1537 } 1538 1539 1540 TEST(BytecodeGraphBuilderContext) { 1541 HandleAndZoneScope scope; 1542 Isolate* isolate = scope.main_isolate(); 1543 Zone* zone = scope.main_zone(); 1544 Factory* factory = isolate->factory(); 1545 1546 ExpectedSnippet<0> snippets[] = { 1547 {"var x = 'outer';" 1548 "function f() {" 1549 " 'use strict';" 1550 " {" 1551 " let x = 'inner';" 1552 " (function() {x});" 1553 " }" 1554 "return(x);" 1555 "}" 1556 "f();", 1557 {factory->NewStringFromStaticChars("outer")}}, 1558 {"var x = 'outer';" 1559 "function f() {" 1560 " 'use strict';" 1561 " {" 1562 " let x = 'inner ';" 1563 " var innerFunc = function() {return x};" 1564 " }" 1565 "return(innerFunc() + x);" 1566 "}" 1567 "f();", 1568 {factory->NewStringFromStaticChars("inner outer")}}, 1569 {"var x = 'outer';" 1570 "function f() {" 1571 " 'use strict';" 1572 " {" 1573 " let x = 'inner ';" 1574 " var innerFunc = function() {return x;};" 1575 " {" 1576 " let x = 'innermost ';" 1577 " var innerMostFunc = function() {return x + innerFunc();};" 1578 " }" 1579 " x = 'inner_changed ';" 1580 " }" 1581 " return(innerMostFunc() + x);" 1582 "}" 1583 "f();", 1584 {factory->NewStringFromStaticChars("innermost inner_changed outer")}}, 1585 }; 1586 1587 for (size_t i = 0; i < arraysize(snippets); i++) { 1588 ScopedVector<char> script(1024); 1589 SNPrintF(script, "%s", snippets[i].code_snippet); 1590 1591 BytecodeGraphTester tester(isolate, zone, script.start(), "f"); 1592 auto callable = tester.GetCallable<>("f"); 1593 Handle<Object> return_value = callable().ToHandleChecked(); 1594 CHECK(return_value->SameValue(*snippets[i].return_value())); 1595 } 1596 } 1597 1598 1599 TEST(BytecodeGraphBuilderLoadContext) { 1600 HandleAndZoneScope scope; 1601 Isolate* isolate = scope.main_isolate(); 1602 Zone* zone = scope.main_zone(); 1603 Factory* factory = isolate->factory(); 1604 1605 ExpectedSnippet<1> snippets[] = { 1606 {"function Outer() {" 1607 " var outerVar = 2;" 1608 " function Inner(innerArg) {" 1609 " this.innerFunc = function () {" 1610 " return outerVar * innerArg;" 1611 " };" 1612 " };" 1613 " this.getInnerFunc = function GetInner() {" 1614 " return new Inner(3).innerFunc;" 1615 " }" 1616 "}" 1617 "var f = new Outer().getInnerFunc();" 1618 "f();", 1619 {factory->NewNumberFromInt(6), factory->undefined_value()}}, 1620 {"function Outer() {" 1621 " var outerVar = 2;" 1622 " function Inner(innerArg) {" 1623 " this.innerFunc = function () {" 1624 " outerVar = innerArg; return outerVar;" 1625 " };" 1626 " };" 1627 " this.getInnerFunc = function GetInner() {" 1628 " return new Inner(10).innerFunc;" 1629 " }" 1630 "}" 1631 "var f = new Outer().getInnerFunc();" 1632 "f();", 1633 {factory->NewNumberFromInt(10), factory->undefined_value()}}, 1634 {"function testOuter(outerArg) {" 1635 " this.testinnerFunc = function testInner(innerArg) {" 1636 " return innerArg + outerArg;" 1637 " }" 1638 "}" 1639 "var f = new testOuter(10).testinnerFunc;" 1640 "f(0);", 1641 {factory->NewNumberFromInt(14), factory->NewNumberFromInt(4)}}, 1642 {"function testOuter(outerArg) {" 1643 " var outerVar = outerArg * 2;" 1644 " this.testinnerFunc = function testInner(innerArg) {" 1645 " outerVar = outerVar + innerArg; return outerVar;" 1646 " }" 1647 "}" 1648 "var f = new testOuter(10).testinnerFunc;" 1649 "f(0);", 1650 {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}}; 1651 1652 for (size_t i = 0; i < arraysize(snippets); i++) { 1653 ScopedVector<char> script(1024); 1654 SNPrintF(script, "%s", snippets[i].code_snippet); 1655 1656 BytecodeGraphTester tester(isolate, zone, script.start(), "*"); 1657 auto callable = tester.GetCallable<Handle<Object>>("f"); 1658 Handle<Object> return_value = 1659 callable(snippets[i].parameter(0)).ToHandleChecked(); 1660 CHECK(return_value->SameValue(*snippets[i].return_value())); 1661 } 1662 } 1663 1664 1665 TEST(BytecodeGraphBuilderCreateArgumentsNoParameters) { 1666 HandleAndZoneScope scope; 1667 Isolate* isolate = scope.main_isolate(); 1668 Zone* zone = scope.main_zone(); 1669 Factory* factory = isolate->factory(); 1670 1671 ExpectedSnippet<0> snippets[] = { 1672 {"function f() {return arguments[0];}", {factory->undefined_value()}}, 1673 {"function f(a) {return arguments[0];}", {factory->undefined_value()}}, 1674 {"function f() {'use strict'; return arguments[0];}", 1675 {factory->undefined_value()}}, 1676 {"function f(a) {'use strict'; return arguments[0];}", 1677 {factory->undefined_value()}}, 1678 {"function f(...restArgs) {return restArgs[0];}", 1679 {factory->undefined_value()}}, 1680 {"function f(a, ...restArgs) {return restArgs[0];}", 1681 {factory->undefined_value()}}, 1682 }; 1683 1684 for (size_t i = 0; i < arraysize(snippets); i++) { 1685 ScopedVector<char> script(1024); 1686 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); 1687 1688 BytecodeGraphTester tester(isolate, zone, script.start()); 1689 auto callable = tester.GetCallable<>(); 1690 Handle<Object> return_value = callable().ToHandleChecked(); 1691 CHECK(return_value->SameValue(*snippets[i].return_value())); 1692 } 1693 } 1694 1695 1696 TEST(BytecodeGraphBuilderCreateArguments) { 1697 HandleAndZoneScope scope; 1698 Isolate* isolate = scope.main_isolate(); 1699 Zone* zone = scope.main_zone(); 1700 Factory* factory = isolate->factory(); 1701 1702 ExpectedSnippet<3> snippets[] = { 1703 {"function f(a, b, c) {return arguments[0];}", 1704 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), 1705 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1706 {"function f(a, b, c) {return arguments[3];}", 1707 {factory->undefined_value(), factory->NewNumberFromInt(1), 1708 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1709 {"function f(a, b, c) { b = c; return arguments[1];}", 1710 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1711 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1712 {"function f(a, b, c) {'use strict'; return arguments[0];}", 1713 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), 1714 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1715 {"function f(a, b, c) {'use strict'; return arguments[3];}", 1716 {factory->undefined_value(), factory->NewNumberFromInt(1), 1717 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1718 {"function f(a, b, c) {'use strict'; b = c; return arguments[1];}", 1719 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1), 1720 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1721 {"function inline_func(a, b) { return arguments[0] }" 1722 "function f(a, b, c) {return inline_func(b, c) + arguments[0];}", 1723 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1724 factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, 1725 }; 1726 1727 for (size_t i = 0; i < arraysize(snippets); i++) { 1728 ScopedVector<char> script(1024); 1729 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); 1730 1731 BytecodeGraphTester tester(isolate, zone, script.start()); 1732 auto callable = 1733 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); 1734 Handle<Object> return_value = 1735 callable(snippets[i].parameter(0), snippets[i].parameter(1), 1736 snippets[i].parameter(2)) 1737 .ToHandleChecked(); 1738 CHECK(return_value->SameValue(*snippets[i].return_value())); 1739 } 1740 } 1741 1742 TEST(BytecodeGraphBuilderCreateRestArguments) { 1743 HandleAndZoneScope scope; 1744 Isolate* isolate = scope.main_isolate(); 1745 Zone* zone = scope.main_zone(); 1746 Factory* factory = isolate->factory(); 1747 1748 ExpectedSnippet<3> snippets[] = { 1749 {"function f(...restArgs) {return restArgs[0];}", 1750 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), 1751 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1752 {"function f(a, b, ...restArgs) {return restArgs[0];}", 1753 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1754 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1755 {"function f(a, b, ...restArgs) {return arguments[2];}", 1756 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1757 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1758 {"function f(a, ...restArgs) { return restArgs[2];}", 1759 {factory->undefined_value(), factory->NewNumberFromInt(1), 1760 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1761 {"function f(a, ...restArgs) { return arguments[0] + restArgs[1];}", 1762 {factory->NewNumberFromInt(4), factory->NewNumberFromInt(1), 1763 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1764 {"function inline_func(a, ...restArgs) { return restArgs[0] }" 1765 "function f(a, b, c) {return inline_func(b, c) + arguments[0];}", 1766 {factory->NewNumberFromInt(31), factory->NewNumberFromInt(1), 1767 factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, 1768 }; 1769 1770 for (size_t i = 0; i < arraysize(snippets); i++) { 1771 ScopedVector<char> script(1024); 1772 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); 1773 1774 BytecodeGraphTester tester(isolate, zone, script.start()); 1775 auto callable = 1776 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); 1777 Handle<Object> return_value = 1778 callable(snippets[i].parameter(0), snippets[i].parameter(1), 1779 snippets[i].parameter(2)) 1780 .ToHandleChecked(); 1781 CHECK(return_value->SameValue(*snippets[i].return_value())); 1782 } 1783 } 1784 1785 TEST(BytecodeGraphBuilderRegExpLiterals) { 1786 HandleAndZoneScope scope; 1787 Isolate* isolate = scope.main_isolate(); 1788 Zone* zone = scope.main_zone(); 1789 Factory* factory = isolate->factory(); 1790 1791 ExpectedSnippet<0> snippets[] = { 1792 {"return /abd/.exec('cccabbdd');", {factory->null_value()}}, 1793 {"return /ab+d/.exec('cccabbdd')[0];", 1794 {factory->NewStringFromStaticChars("abbd")}}, 1795 {"var a = 3.1414;" 1796 REPEAT_256(SPACE, "a = 3.1414;") 1797 "return /ab+d/.exec('cccabbdd')[0];", 1798 {factory->NewStringFromStaticChars("abbd")}}, 1799 {"return /ab+d/.exec('cccabbdd')[1];", {factory->undefined_value()}}, 1800 {"return /AbC/i.exec('ssaBC')[0];", 1801 {factory->NewStringFromStaticChars("aBC")}}, 1802 {"return 'ssaBC'.match(/AbC/i)[0];", 1803 {factory->NewStringFromStaticChars("aBC")}}, 1804 {"return 'ssaBCtAbC'.match(/(AbC)/gi)[1];", 1805 {factory->NewStringFromStaticChars("AbC")}}, 1806 }; 1807 1808 for (size_t i = 0; i < arraysize(snippets); i++) { 1809 ScopedVector<char> script(4096); 1810 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1811 snippets[i].code_snippet, kFunctionName); 1812 1813 BytecodeGraphTester tester(isolate, zone, script.start()); 1814 auto callable = tester.GetCallable<>(); 1815 Handle<Object> return_value = callable().ToHandleChecked(); 1816 CHECK(return_value->SameValue(*snippets[i].return_value())); 1817 } 1818 } 1819 1820 1821 TEST(BytecodeGraphBuilderArrayLiterals) { 1822 HandleAndZoneScope scope; 1823 Isolate* isolate = scope.main_isolate(); 1824 Zone* zone = scope.main_zone(); 1825 Factory* factory = isolate->factory(); 1826 1827 ExpectedSnippet<0> snippets[] = { 1828 {"return [][0];", {factory->undefined_value()}}, 1829 {"return [1, 3, 2][1];", {factory->NewNumberFromInt(3)}}, 1830 {"var a;" REPEAT_256(SPACE, "a = 9.87;") "return [1, 3, 2][1];", 1831 {factory->NewNumberFromInt(3)}}, 1832 {"return ['a', 'b', 'c'][2];", {factory->NewStringFromStaticChars("c")}}, 1833 {"var a = 100; return [a, a++, a + 2, a + 3][2];", 1834 {factory->NewNumberFromInt(103)}}, 1835 {"var a = 100; return [a, ++a, a + 2, a + 3][1];", 1836 {factory->NewNumberFromInt(101)}}, 1837 {"var a = 9.2;" 1838 REPEAT_256(SPACE, "a = 9.34;") 1839 "return [a, ++a, a + 2, a + 3][2];", 1840 {factory->NewHeapNumber(12.34)}}, 1841 {"return [[1, 2, 3], ['a', 'b', 'c']][1][0];", 1842 {factory->NewStringFromStaticChars("a")}}, 1843 {"var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];", 1844 {factory->NewStringFromStaticChars("test")}}, 1845 {"var t = 't'; return [[t, t + 'est'], [1 + t]][1][0];", 1846 {factory->NewStringFromStaticChars("1t")}}}; 1847 1848 for (size_t i = 0; i < arraysize(snippets); i++) { 1849 ScopedVector<char> script(4096); 1850 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1851 snippets[i].code_snippet, kFunctionName); 1852 1853 BytecodeGraphTester tester(isolate, zone, script.start()); 1854 auto callable = tester.GetCallable<>(); 1855 Handle<Object> return_value = callable().ToHandleChecked(); 1856 CHECK(return_value->SameValue(*snippets[i].return_value())); 1857 } 1858 } 1859 1860 1861 TEST(BytecodeGraphBuilderObjectLiterals) { 1862 HandleAndZoneScope scope; 1863 Isolate* isolate = scope.main_isolate(); 1864 Zone* zone = scope.main_zone(); 1865 Factory* factory = isolate->factory(); 1866 1867 ExpectedSnippet<0> snippets[] = { 1868 {"return { }.name;", {factory->undefined_value()}}, 1869 {"return { name: 'string', val: 9.2 }.name;", 1870 {factory->NewStringFromStaticChars("string")}}, 1871 {"var a;\n" 1872 REPEAT_256(SPACE, "a = 1.23;\n") 1873 "return { name: 'string', val: 9.2 }.name;", 1874 {factory->NewStringFromStaticChars("string")}}, 1875 {"return { name: 'string', val: 9.2 }['name'];", 1876 {factory->NewStringFromStaticChars("string")}}, 1877 {"var a = 15; return { name: 'string', val: a }.val;", 1878 {factory->NewNumberFromInt(15)}}, 1879 {"var a;" 1880 REPEAT_256(SPACE, "a = 1.23;") 1881 "return { name: 'string', val: a }.val;", 1882 {factory->NewHeapNumber(1.23)}}, 1883 {"var a = 15; var b = 'val'; return { name: 'string', val: a }[b];", 1884 {factory->NewNumberFromInt(15)}}, 1885 {"var a = 5; return { val: a, val: a + 1 }.val;", 1886 {factory->NewNumberFromInt(6)}}, 1887 {"return { func: function() { return 'test' } }.func();", 1888 {factory->NewStringFromStaticChars("test")}}, 1889 {"return { func(a) { return a + 'st'; } }.func('te');", 1890 {factory->NewStringFromStaticChars("test")}}, 1891 {"return { get a() { return 22; } }.a;", {factory->NewNumberFromInt(22)}}, 1892 {"var a = { get b() { return this.x + 't'; },\n" 1893 " set b(val) { this.x = val + 's' } };\n" 1894 "a.b = 'te';\n" 1895 "return a.b;", 1896 {factory->NewStringFromStaticChars("test")}}, 1897 {"var a = 123; return { 1: a }[1];", {factory->NewNumberFromInt(123)}}, 1898 {"return Object.getPrototypeOf({ __proto__: null });", 1899 {factory->null_value()}}, 1900 {"var a = 'test'; return { [a]: 1 }.test;", 1901 {factory->NewNumberFromInt(1)}}, 1902 {"var a = 'test'; return { b: a, [a]: a + 'ing' }['test']", 1903 {factory->NewStringFromStaticChars("testing")}}, 1904 {"var a = 'proto_str';\n" 1905 "var b = { [a]: 1, __proto__: { var : a } };\n" 1906 "return Object.getPrototypeOf(b).var", 1907 {factory->NewStringFromStaticChars("proto_str")}}, 1908 {"var n = 'name';\n" 1909 "return { [n]: 'val', get a() { return 987 } }['a'];", 1910 {factory->NewNumberFromInt(987)}}, 1911 }; 1912 1913 for (size_t i = 0; i < arraysize(snippets); i++) { 1914 ScopedVector<char> script(4096); 1915 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1916 snippets[i].code_snippet, kFunctionName); 1917 BytecodeGraphTester tester(isolate, zone, script.start()); 1918 auto callable = tester.GetCallable<>(); 1919 Handle<Object> return_value = callable().ToHandleChecked(); 1920 CHECK(return_value->SameValue(*snippets[i].return_value())); 1921 } 1922 } 1923 1924 1925 TEST(BytecodeGraphBuilderIf) { 1926 HandleAndZoneScope scope; 1927 Isolate* isolate = scope.main_isolate(); 1928 Zone* zone = scope.main_zone(); 1929 Factory* factory = isolate->factory(); 1930 1931 ExpectedSnippet<1> snippets[] = { 1932 {"if (p1 > 1) return 1;\n" 1933 "return -1;", 1934 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1935 {"if (p1 > 1) return 1;\n" 1936 "return -1;", 1937 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}}, 1938 {"if (p1 > 1) { return 1; } else { return -1; }", 1939 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1940 {"if (p1 > 1) { return 1; } else { return -1; }", 1941 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}}, 1942 {"if (p1 > 50) {\n" 1943 " return 1;\n" 1944 "} else if (p1 < 10) {\n" 1945 " return 10;\n" 1946 "} else {\n" 1947 " return -10;\n" 1948 "}", 1949 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(51)}}, 1950 {"if (p1 > 50) {\n" 1951 " return 1;\n" 1952 "} else if (p1 < 10) {\n" 1953 " return 10;\n" 1954 "} else {\n" 1955 " return 100;\n" 1956 "}", 1957 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}}, 1958 {"if (p1 > 50) {\n" 1959 " return 1;\n" 1960 "} else if (p1 < 10) {\n" 1961 " return 10;\n" 1962 "} else {\n" 1963 " return 100;\n" 1964 "}", 1965 {factory->NewNumberFromInt(100), factory->NewNumberFromInt(10)}}, 1966 {"if (p1 >= 0) {\n" 1967 " if (p1 > 10) { return 2; } else { return 1; }\n" 1968 "} else {\n" 1969 " if (p1 < -10) { return -2; } else { return -1; }\n" 1970 "}", 1971 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(100)}}, 1972 {"if (p1 >= 0) {\n" 1973 " if (p1 > 10) { return 2; } else { return 1; }\n" 1974 "} else {\n" 1975 " if (p1 < -10) { return -2; } else { return -1; }\n" 1976 "}", 1977 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(10)}}, 1978 {"if (p1 >= 0) {\n" 1979 " if (p1 > 10) { return 2; } else { return 1; }\n" 1980 "} else {\n" 1981 " if (p1 < -10) { return -2; } else { return -1; }\n" 1982 "}", 1983 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(-11)}}, 1984 {"if (p1 >= 0) {\n" 1985 " if (p1 > 10) { return 2; } else { return 1; }\n" 1986 "} else {\n" 1987 " if (p1 < -10) { return -2; } else { return -1; }\n" 1988 "}", 1989 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-10)}}, 1990 {"var b = 20, c;" 1991 "if (p1 >= 0) {\n" 1992 " if (b > 0) { c = 2; } else { c = 3; }\n" 1993 "} else {\n" 1994 " if (b < -10) { c = -2; } else { c = -1; }\n" 1995 "}" 1996 "return c;", 1997 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-1)}}, 1998 {"var b = 20, c = 10;" 1999 "if (p1 >= 0) {\n" 2000 " if (b < 0) { c = 2; }\n" 2001 "} else {\n" 2002 " if (b < -10) { c = -2; } else { c = -1; }\n" 2003 "}" 2004 "return c;", 2005 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(1)}}, 2006 {"var x = 2, a = 10, b = 20, c, d;" 2007 "x = 0;" 2008 "if (a) {\n" 2009 " b = x;" 2010 " if (b > 0) { c = 2; } else { c = 3; }\n" 2011 " x = 4; d = 2;" 2012 "} else {\n" 2013 " d = 3;\n" 2014 "}" 2015 "x = d;" 2016 "function f1() {x}" 2017 "return x + c;", 2018 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(-1)}}, 2019 }; 2020 2021 for (size_t i = 0; i < arraysize(snippets); i++) { 2022 ScopedVector<char> script(2048); 2023 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 2024 snippets[i].code_snippet, kFunctionName); 2025 2026 BytecodeGraphTester tester(isolate, zone, script.start()); 2027 auto callable = tester.GetCallable<Handle<Object>>(); 2028 Handle<Object> return_value = 2029 callable(snippets[i].parameter(0)).ToHandleChecked(); 2030 CHECK(return_value->SameValue(*snippets[i].return_value())); 2031 } 2032 } 2033 2034 2035 TEST(BytecodeGraphBuilderConditionalOperator) { 2036 HandleAndZoneScope scope; 2037 Isolate* isolate = scope.main_isolate(); 2038 Zone* zone = scope.main_zone(); 2039 Factory* factory = isolate->factory(); 2040 2041 ExpectedSnippet<1> snippets[] = { 2042 {"return (p1 > 1) ? 1 : -1;", 2043 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 2044 {"return (p1 > 1) ? 1 : -1;", 2045 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0)}}, 2046 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);", 2047 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(2)}}, 2048 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);", 2049 {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(20)}}, 2050 }; 2051 2052 for (size_t i = 0; i < arraysize(snippets); i++) { 2053 ScopedVector<char> script(2048); 2054 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 2055 snippets[i].code_snippet, kFunctionName); 2056 2057 BytecodeGraphTester tester(isolate, zone, script.start()); 2058 auto callable = tester.GetCallable<Handle<Object>>(); 2059 Handle<Object> return_value = 2060 callable(snippets[i].parameter(0)).ToHandleChecked(); 2061 CHECK(return_value->SameValue(*snippets[i].return_value())); 2062 } 2063 } 2064 2065 2066 TEST(BytecodeGraphBuilderSwitch) { 2067 HandleAndZoneScope scope; 2068 Isolate* isolate = scope.main_isolate(); 2069 Zone* zone = scope.main_zone(); 2070 Factory* factory = isolate->factory(); 2071 2072 const char* switch_code = 2073 "switch (p1) {\n" 2074 " case 1: return 0;\n" 2075 " case 2: return 1;\n" 2076 " case 3:\n" 2077 " case 4: return 2;\n" 2078 " case 9: break;\n" 2079 " default: return 3;\n" 2080 "}\n" 2081 "return 9;"; 2082 2083 ExpectedSnippet<1> snippets[] = { 2084 {switch_code, 2085 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(1)}}, 2086 {switch_code, 2087 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 2088 {switch_code, 2089 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 2090 {switch_code, 2091 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}}, 2092 {switch_code, 2093 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(9)}}, 2094 {switch_code, 2095 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}}, 2096 {switch_code, 2097 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(6)}}, 2098 }; 2099 2100 for (size_t i = 0; i < arraysize(snippets); i++) { 2101 ScopedVector<char> script(2048); 2102 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 2103 snippets[i].code_snippet, kFunctionName); 2104 2105 BytecodeGraphTester tester(isolate, zone, script.start()); 2106 auto callable = tester.GetCallable<Handle<Object>>(); 2107 Handle<Object> return_value = 2108 callable(snippets[i].parameter(0)).ToHandleChecked(); 2109 CHECK(return_value->SameValue(*snippets[i].return_value())); 2110 } 2111 } 2112 2113 TEST(BytecodeGraphBuilderSwitchMerge) { 2114 HandleAndZoneScope scope; 2115 Isolate* isolate = scope.main_isolate(); 2116 Zone* zone = scope.main_zone(); 2117 Factory* factory = isolate->factory(); 2118 2119 const char* switch_code = 2120 "var x = 10;" 2121 "switch (p1) {\n" 2122 " case 1: x = 0;\n" 2123 " case 2: x = 1;\n" 2124 " case 3:\n" 2125 " case 4: x = 2; break;\n" 2126 " case 5: x = 3;\n" 2127 " case 9: break;\n" 2128 " default: x = 4;\n" 2129 "}\n" 2130 "return x;"; 2131 2132 ExpectedSnippet<1> snippets[] = { 2133 {switch_code, 2134 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1)}}, 2135 {switch_code, 2136 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(2)}}, 2137 {switch_code, 2138 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 2139 {switch_code, 2140 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}}, 2141 {switch_code, 2142 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}}, 2143 {switch_code, 2144 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}}, 2145 {switch_code, 2146 {factory->NewNumberFromInt(4), factory->NewNumberFromInt(6)}}, 2147 }; 2148 2149 for (size_t i = 0; i < arraysize(snippets); i++) { 2150 ScopedVector<char> script(2048); 2151 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 2152 snippets[i].code_snippet, kFunctionName); 2153 2154 BytecodeGraphTester tester(isolate, zone, script.start()); 2155 auto callable = tester.GetCallable<Handle<Object>>(); 2156 Handle<Object> return_value = 2157 callable(snippets[i].parameter(0)).ToHandleChecked(); 2158 CHECK(return_value->SameValue(*snippets[i].return_value())); 2159 } 2160 } 2161 2162 TEST(BytecodeGraphBuilderNestedSwitch) { 2163 HandleAndZoneScope scope; 2164 Isolate* isolate = scope.main_isolate(); 2165 Zone* zone = scope.main_zone(); 2166 Factory* factory = isolate->factory(); 2167 2168 const char* switch_code = 2169 "switch (p1) {\n" 2170 " case 0: {" 2171 " switch (p2) { case 0: return 0; case 1: return 1; case 2: break; }\n" 2172 " return -1;" 2173 " }\n" 2174 " case 1: {" 2175 " switch (p2) { case 0: return 2; case 1: return 3; }\n" 2176 " }\n" 2177 " case 2: break;" 2178 " }\n" 2179 "return -2;"; 2180 2181 ExpectedSnippet<2> snippets[] = { 2182 {switch_code, 2183 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(0), 2184 factory->NewNumberFromInt(0)}}, 2185 {switch_code, 2186 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(0), 2187 factory->NewNumberFromInt(1)}}, 2188 {switch_code, 2189 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0), 2190 factory->NewNumberFromInt(2)}}, 2191 {switch_code, 2192 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0), 2193 factory->NewNumberFromInt(3)}}, 2194 {switch_code, 2195 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1), 2196 factory->NewNumberFromInt(0)}}, 2197 {switch_code, 2198 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 2199 factory->NewNumberFromInt(1)}}, 2200 {switch_code, 2201 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(1), 2202 factory->NewNumberFromInt(2)}}, 2203 {switch_code, 2204 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(2), 2205 factory->NewNumberFromInt(0)}}, 2206 }; 2207 2208 for (size_t i = 0; i < arraysize(snippets); i++) { 2209 ScopedVector<char> script(2048); 2210 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0, 0);", kFunctionName, 2211 snippets[i].code_snippet, kFunctionName); 2212 2213 BytecodeGraphTester tester(isolate, zone, script.start()); 2214 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 2215 Handle<Object> return_value = 2216 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 2217 .ToHandleChecked(); 2218 CHECK(return_value->SameValue(*snippets[i].return_value())); 2219 } 2220 } 2221 2222 2223 TEST(BytecodeGraphBuilderBreakableBlocks) { 2224 HandleAndZoneScope scope; 2225 Isolate* isolate = scope.main_isolate(); 2226 Zone* zone = scope.main_zone(); 2227 Factory* factory = isolate->factory(); 2228 2229 ExpectedSnippet<0> snippets[] = { 2230 {"var x = 0;\n" 2231 "my_heart: {\n" 2232 " x = x + 1;\n" 2233 " break my_heart;\n" 2234 " x = x + 2;\n" 2235 "}\n" 2236 "return x;\n", 2237 {factory->NewNumberFromInt(1)}}, 2238 {"var sum = 0;\n" 2239 "outta_here: {\n" 2240 " for (var x = 0; x < 10; ++x) {\n" 2241 " for (var y = 0; y < 3; ++y) {\n" 2242 " ++sum;\n" 2243 " if (x + y == 12) { break outta_here; }\n" 2244 " }\n" 2245 " }\n" 2246 "}\n" 2247 "return sum;", 2248 {factory->NewNumber(30)}}, 2249 }; 2250 2251 for (size_t i = 0; i < arraysize(snippets); i++) { 2252 ScopedVector<char> script(1024); 2253 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2254 snippets[i].code_snippet, kFunctionName); 2255 2256 BytecodeGraphTester tester(isolate, zone, script.start()); 2257 auto callable = tester.GetCallable<>(); 2258 Handle<Object> return_value = callable().ToHandleChecked(); 2259 CHECK(return_value->SameValue(*snippets[i].return_value())); 2260 } 2261 } 2262 2263 2264 TEST(BytecodeGraphBuilderWhile) { 2265 HandleAndZoneScope scope; 2266 Isolate* isolate = scope.main_isolate(); 2267 Zone* zone = scope.main_zone(); 2268 Factory* factory = isolate->factory(); 2269 2270 ExpectedSnippet<0> snippets[] = { 2271 {"var x = 1; while (x < 1) { x *= 100; } return x;", 2272 {factory->NewNumberFromInt(1)}}, 2273 {"var x = 1, y = 0; while (x < 7) { y += x * x; x += 1; } return y;", 2274 {factory->NewNumberFromInt(91)}}, 2275 {"var x = 1; while (true) { x += 1; if (x == 10) break; } return x;", 2276 {factory->NewNumberFromInt(10)}}, 2277 {"var x = 1; while (false) { x += 1; } return x;", 2278 {factory->NewNumberFromInt(1)}}, 2279 {"var x = 0;\n" 2280 "while (true) {\n" 2281 " while (x < 10) {\n" 2282 " x = x * x + 1;\n" 2283 " }" 2284 " x += 1;\n" 2285 " break;\n" 2286 "}\n" 2287 "return x;", 2288 {factory->NewNumberFromInt(27)}}, 2289 {"var x = 1, y = 0;\n" 2290 "while (x < 7) {\n" 2291 " x += 1;\n" 2292 " if (x == 2) continue;\n" 2293 " if (x == 3) continue;\n" 2294 " y += x * x;\n" 2295 " if (x == 4) break;\n" 2296 "}\n" 2297 "return y;", 2298 {factory->NewNumberFromInt(16)}}}; 2299 2300 for (size_t i = 0; i < arraysize(snippets); i++) { 2301 ScopedVector<char> script(1024); 2302 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2303 snippets[i].code_snippet, kFunctionName); 2304 2305 BytecodeGraphTester tester(isolate, zone, script.start()); 2306 auto callable = tester.GetCallable<>(); 2307 Handle<Object> return_value = callable().ToHandleChecked(); 2308 CHECK(return_value->SameValue(*snippets[i].return_value())); 2309 } 2310 } 2311 2312 2313 TEST(BytecodeGraphBuilderDo) { 2314 HandleAndZoneScope scope; 2315 Isolate* isolate = scope.main_isolate(); 2316 Zone* zone = scope.main_zone(); 2317 Factory* factory = isolate->factory(); 2318 2319 ExpectedSnippet<0> snippets[] = { 2320 {"var x = 1; do { x *= 100; } while (x < 100); return x;", 2321 {factory->NewNumberFromInt(100)}}, 2322 {"var x = 1; do { x = x * x + 1; } while (x < 7) return x;", 2323 {factory->NewNumberFromInt(26)}}, 2324 {"var x = 1; do { x += 1; } while (false); return x;", 2325 {factory->NewNumberFromInt(2)}}, 2326 {"var x = 1, y = 0;\n" 2327 "do {\n" 2328 " x += 1;\n" 2329 " if (x == 2) continue;\n" 2330 " if (x == 3) continue;\n" 2331 " y += x * x;\n" 2332 " if (x == 4) break;\n" 2333 "} while (x < 7);\n" 2334 "return y;", 2335 {factory->NewNumberFromInt(16)}}}; 2336 2337 for (size_t i = 0; i < arraysize(snippets); i++) { 2338 ScopedVector<char> script(1024); 2339 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2340 snippets[i].code_snippet, kFunctionName); 2341 2342 BytecodeGraphTester tester(isolate, zone, script.start()); 2343 auto callable = tester.GetCallable<>(); 2344 Handle<Object> return_value = callable().ToHandleChecked(); 2345 CHECK(return_value->SameValue(*snippets[i].return_value())); 2346 } 2347 } 2348 2349 2350 TEST(BytecodeGraphBuilderFor) { 2351 HandleAndZoneScope scope; 2352 Isolate* isolate = scope.main_isolate(); 2353 Zone* zone = scope.main_zone(); 2354 Factory* factory = isolate->factory(); 2355 2356 ExpectedSnippet<0> snippets[] = { 2357 {"for (var x = 0;; x = 2 * x + 1) { if (x > 10) return x; }", 2358 {factory->NewNumberFromInt(15)}}, 2359 {"for (var x = 0; true; x = 2 * x + 1) { if (x > 100) return x; }", 2360 {factory->NewNumberFromInt(127)}}, 2361 {"for (var x = 0; false; x = 2 * x + 1) { if (x > 100) return x; } " 2362 "return 0;", 2363 {factory->NewNumberFromInt(0)}}, 2364 {"for (var x = 0; x < 200; x = 2 * x + 1) { x = x; } return x;", 2365 {factory->NewNumberFromInt(255)}}, 2366 {"for (var x = 0; x < 200; x = 2 * x + 1) {} return x;", 2367 {factory->NewNumberFromInt(255)}}, 2368 {"var sum = 0;\n" 2369 "for (var x = 0; x < 200; x += 1) {\n" 2370 " if (x % 2) continue;\n" 2371 " if (sum > 10) break;\n" 2372 " sum += x;\n" 2373 "}\n" 2374 "return sum;", 2375 {factory->NewNumberFromInt(12)}}, 2376 {"var sum = 0;\n" 2377 "for (var w = 0; w < 2; w++) {\n" 2378 " for (var x = 0; x < 200; x += 1) {\n" 2379 " if (x % 2) continue;\n" 2380 " if (x > 4) break;\n" 2381 " sum += x + w;\n" 2382 " }\n" 2383 "}\n" 2384 "return sum;", 2385 {factory->NewNumberFromInt(15)}}, 2386 {"var sum = 0;\n" 2387 "for (var w = 0; w < 2; w++) {\n" 2388 " if (w == 1) break;\n" 2389 " for (var x = 0; x < 200; x += 1) {\n" 2390 " if (x % 2) continue;\n" 2391 " if (x > 4) break;\n" 2392 " sum += x + w;\n" 2393 " }\n" 2394 "}\n" 2395 "return sum;", 2396 {factory->NewNumberFromInt(6)}}, 2397 {"var sum = 0;\n" 2398 "for (var w = 0; w < 3; w++) {\n" 2399 " if (w == 1) continue;\n" 2400 " for (var x = 0; x < 200; x += 1) {\n" 2401 " if (x % 2) continue;\n" 2402 " if (x > 4) break;\n" 2403 " sum += x + w;\n" 2404 " }\n" 2405 "}\n" 2406 "return sum;", 2407 {factory->NewNumberFromInt(18)}}, 2408 {"var sum = 0;\n" 2409 "for (var x = 1; x < 10; x += 2) {\n" 2410 " for (var y = x; y < x + 2; y++) {\n" 2411 " sum += y * y;\n" 2412 " }\n" 2413 "}\n" 2414 "return sum;", 2415 {factory->NewNumberFromInt(385)}}, 2416 }; 2417 2418 for (size_t i = 0; i < arraysize(snippets); i++) { 2419 ScopedVector<char> script(1024); 2420 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2421 snippets[i].code_snippet, kFunctionName); 2422 2423 BytecodeGraphTester tester(isolate, zone, script.start()); 2424 auto callable = tester.GetCallable<>(); 2425 Handle<Object> return_value = callable().ToHandleChecked(); 2426 CHECK(return_value->SameValue(*snippets[i].return_value())); 2427 } 2428 } 2429 2430 2431 TEST(BytecodeGraphBuilderForIn) { 2432 HandleAndZoneScope scope; 2433 Isolate* isolate = scope.main_isolate(); 2434 Zone* zone = scope.main_zone(); 2435 Factory* factory = isolate->factory(); 2436 ExpectedSnippet<0> snippets[] = { 2437 {"var sum = 0;\n" 2438 "var empty = null;\n" 2439 "for (var x in empty) { sum++; }\n" 2440 "return sum;", 2441 {factory->NewNumberFromInt(0)}}, 2442 {"var sum = 100;\n" 2443 "var empty = 1;\n" 2444 "for (var x in empty) { sum++; }\n" 2445 "return sum;", 2446 {factory->NewNumberFromInt(100)}}, 2447 {"for (var x in [ 10, 20, 30 ]) {}\n" 2448 "return 2;", 2449 {factory->NewNumberFromInt(2)}}, 2450 {"var last = 0;\n" 2451 "for (var x in [ 10, 20, 30 ]) {\n" 2452 " last = x;\n" 2453 "}\n" 2454 "return +last;", 2455 {factory->NewNumberFromInt(2)}}, 2456 {"var first = -1;\n" 2457 "for (var x in [ 10, 20, 30 ]) {\n" 2458 " first = +x;\n" 2459 " if (first > 0) break;\n" 2460 "}\n" 2461 "return first;", 2462 {factory->NewNumberFromInt(1)}}, 2463 {"var first = -1;\n" 2464 "for (var x in [ 10, 20, 30 ]) {\n" 2465 " if (first >= 0) continue;\n" 2466 " first = x;\n" 2467 "}\n" 2468 "return +first;", 2469 {factory->NewNumberFromInt(0)}}, 2470 {"var sum = 0;\n" 2471 "for (var x in [ 10, 20, 30 ]) {\n" 2472 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n" 2473 " sum += 1;\n" 2474 " }\n" 2475 "}\n" 2476 "return sum;", 2477 {factory->NewNumberFromInt(21)}}, 2478 {"var sum = 0;\n" 2479 "for (var x in [ 10, 20, 30 ]) {\n" 2480 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n" 2481 " if (sum == 7) break;\n" 2482 " if (sum == 6) continue;\n" 2483 " sum += 1;\n" 2484 " }\n" 2485 "}\n" 2486 "return sum;", 2487 {factory->NewNumberFromInt(6)}}, 2488 }; 2489 2490 for (size_t i = 0; i < arraysize(snippets); i++) { 2491 ScopedVector<char> script(1024); 2492 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2493 snippets[i].code_snippet, kFunctionName); 2494 2495 BytecodeGraphTester tester(isolate, zone, script.start()); 2496 auto callable = tester.GetCallable<>(); 2497 Handle<Object> return_value = callable().ToHandleChecked(); 2498 CHECK(return_value->SameValue(*snippets[i].return_value())); 2499 } 2500 } 2501 2502 2503 TEST(BytecodeGraphBuilderForOf) { 2504 HandleAndZoneScope scope; 2505 Isolate* isolate = scope.main_isolate(); 2506 Zone* zone = scope.main_zone(); 2507 Factory* factory = isolate->factory(); 2508 ExpectedSnippet<0> snippets[] = { 2509 {" var r = 0;\n" 2510 " for (var a of [0,6,7,9]) { r += a; }\n" 2511 " return r;\n", 2512 {handle(Smi::FromInt(22), isolate)}}, 2513 {" var r = '';\n" 2514 " for (var a of 'foobar') { r = a + r; }\n" 2515 " return r;\n", 2516 {factory->NewStringFromStaticChars("raboof")}}, 2517 {" var a = [1, 2, 3];\n" 2518 " a.name = 4;\n" 2519 " var r = 0;\n" 2520 " for (var x of a) { r += x; }\n" 2521 " return r;\n", 2522 {handle(Smi::FromInt(6), isolate)}}, 2523 {" var r = '';\n" 2524 " var data = [1, 2, 3]; \n" 2525 " for (a of data) { delete data[0]; r += a; } return r;", 2526 {factory->NewStringFromStaticChars("123")}}, 2527 {" var r = '';\n" 2528 " var data = [1, 2, 3]; \n" 2529 " for (a of data) { delete data[2]; r += a; } return r;", 2530 {factory->NewStringFromStaticChars("12undefined")}}, 2531 {" var r = '';\n" 2532 " var data = [1, 2, 3]; \n" 2533 " for (a of data) { delete data; r += a; } return r;", 2534 {factory->NewStringFromStaticChars("123")}}, 2535 {" var r = '';\n" 2536 " var input = 'foobar';\n" 2537 " for (var a of input) {\n" 2538 " if (a == 'b') break;\n" 2539 " r += a;\n" 2540 " }\n" 2541 " return r;\n", 2542 {factory->NewStringFromStaticChars("foo")}}, 2543 {" var r = '';\n" 2544 " var input = 'foobar';\n" 2545 " for (var a of input) {\n" 2546 " if (a == 'b') continue;\n" 2547 " r += a;\n" 2548 " }\n" 2549 " return r;\n", 2550 {factory->NewStringFromStaticChars("fooar")}}, 2551 {" var r = '';\n" 2552 " var data = [1, 2, 3, 4]; \n" 2553 " for (a of data) { data[2] = 567; r += a; }\n" 2554 " return r;\n", 2555 {factory->NewStringFromStaticChars("125674")}}, 2556 {" var r = '';\n" 2557 " var data = [1, 2, 3, 4]; \n" 2558 " for (a of data) { data[4] = 567; r += a; }\n" 2559 " return r;\n", 2560 {factory->NewStringFromStaticChars("1234567")}}, 2561 {" var r = '';\n" 2562 " var data = [1, 2, 3, 4]; \n" 2563 " for (a of data) { data[5] = 567; r += a; }\n" 2564 " return r;\n", 2565 {factory->NewStringFromStaticChars("1234undefined567")}}, 2566 {" var r = '';\n" 2567 " var obj = new Object();\n" 2568 " obj[Symbol.iterator] = function() { return {\n" 2569 " index: 3,\n" 2570 " data: ['a', 'b', 'c', 'd']," 2571 " next: function() {" 2572 " return {" 2573 " done: this.index == -1,\n" 2574 " value: this.index < 0 ? undefined : this.data[this.index--]\n" 2575 " }\n" 2576 " }\n" 2577 " }}\n" 2578 " for (a of obj) { r += a }\n" 2579 " return r;\n", 2580 {factory->NewStringFromStaticChars("dcba")}}, 2581 }; 2582 2583 for (size_t i = 0; i < arraysize(snippets); i++) { 2584 ScopedVector<char> script(1024); 2585 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2586 snippets[i].code_snippet, kFunctionName); 2587 2588 BytecodeGraphTester tester(isolate, zone, script.start()); 2589 auto callable = tester.GetCallable<>(); 2590 Handle<Object> return_value = callable().ToHandleChecked(); 2591 CHECK(return_value->SameValue(*snippets[i].return_value())); 2592 } 2593 } 2594 2595 void TestJumpWithConstantsAndWideConstants(size_t shard) { 2596 const int kStep = 46; 2597 int start = static_cast<int>(7 + 17 * shard); 2598 for (int constants = start; constants < 300; constants += kStep) { 2599 std::stringstream filler_os; 2600 // Generate a string that consumes constant pool entries and 2601 // spread out branch distances in script below. 2602 for (int i = 0; i < constants; i++) { 2603 filler_os << "var x_ = 'x_" << i << "';\n"; 2604 } 2605 std::string filler(filler_os.str()); 2606 2607 std::stringstream script_os; 2608 script_os << "function " << kFunctionName << "(a) {\n"; 2609 script_os << " " << filler; 2610 script_os << " for (var i = a; i < 2; i++) {\n"; 2611 script_os << " " << filler; 2612 script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n"; 2613 script_os << " else if (i == a) { " << filler << "i = 12; break; }\n"; 2614 script_os << " else { " << filler << " }\n"; 2615 script_os << " }\n"; 2616 script_os << " return i;\n"; 2617 script_os << "}\n"; 2618 script_os << kFunctionName << "(0);\n"; 2619 std::string script(script_os.str()); 2620 2621 HandleAndZoneScope scope; 2622 auto isolate = scope.main_isolate(); 2623 auto factory = isolate->factory(); 2624 auto zone = scope.main_zone(); 2625 BytecodeGraphTester tester(isolate, zone, script.c_str()); 2626 auto callable = tester.GetCallable<Handle<Object>>(); 2627 for (int a = 0; a < 3; a++) { 2628 Handle<Object> return_val = 2629 callable(factory->NewNumberFromInt(a)).ToHandleChecked(); 2630 static const int results[] = {11, 12, 2}; 2631 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]); 2632 } 2633 } 2634 } 2635 2636 SHARD_TEST_BY_4(JumpWithConstantsAndWideConstants) 2637 2638 TEST(BytecodeGraphBuilderDoExpressions) { 2639 bool old_flag = FLAG_harmony_do_expressions; 2640 FLAG_harmony_do_expressions = true; 2641 HandleAndZoneScope scope; 2642 Isolate* isolate = scope.main_isolate(); 2643 Zone* zone = scope.main_zone(); 2644 Factory* factory = isolate->factory(); 2645 ExpectedSnippet<0> snippets[] = { 2646 {"var a = do {}; return a;", {factory->undefined_value()}}, 2647 {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, 2648 {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, 2649 {"var a = do { var x = 100; x++; }; return a;", 2650 {handle(Smi::FromInt(100), isolate)}}, 2651 {"var i = 0; for (; i < 5;) { i = do { if (i == 3) { break; }; i + 1; }};" 2652 "return i;", 2653 {handle(Smi::FromInt(3), isolate)}}, 2654 }; 2655 2656 for (size_t i = 0; i < arraysize(snippets); i++) { 2657 ScopedVector<char> script(1024); 2658 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2659 snippets[i].code_snippet, kFunctionName); 2660 2661 BytecodeGraphTester tester(isolate, zone, script.start()); 2662 auto callable = tester.GetCallable<>(); 2663 Handle<Object> return_value = callable().ToHandleChecked(); 2664 CHECK(return_value->SameValue(*snippets[i].return_value())); 2665 } 2666 2667 FLAG_harmony_do_expressions = old_flag; 2668 } 2669 2670 TEST(BytecodeGraphBuilderWithStatement) { 2671 HandleAndZoneScope scope; 2672 Isolate* isolate = scope.main_isolate(); 2673 Zone* zone = scope.main_zone(); 2674 2675 ExpectedSnippet<0> snippets[] = { 2676 {"with({x:42}) return x;", {handle(Smi::FromInt(42), isolate)}}, 2677 {"with({}) { var y = 10; return y;}", 2678 {handle(Smi::FromInt(10), isolate)}}, 2679 {"var y = {x:42};" 2680 " function inner() {" 2681 " var x = 20;" 2682 " with(y) return x;" 2683 "}" 2684 "return inner();", 2685 {handle(Smi::FromInt(42), isolate)}}, 2686 {"var y = {x:42};" 2687 " function inner(o) {" 2688 " var x = 20;" 2689 " with(o) return x;" 2690 "}" 2691 "return inner(y);", 2692 {handle(Smi::FromInt(42), isolate)}}, 2693 }; 2694 2695 for (size_t i = 0; i < arraysize(snippets); i++) { 2696 ScopedVector<char> script(1024); 2697 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2698 snippets[i].code_snippet, kFunctionName); 2699 2700 BytecodeGraphTester tester(isolate, zone, script.start()); 2701 auto callable = tester.GetCallable<>(); 2702 Handle<Object> return_value = callable().ToHandleChecked(); 2703 CHECK(return_value->SameValue(*snippets[i].return_value())); 2704 } 2705 } 2706 2707 TEST(BytecodeGraphBuilderConstDeclaration) { 2708 HandleAndZoneScope scope; 2709 Isolate* isolate = scope.main_isolate(); 2710 Zone* zone = scope.main_zone(); 2711 Factory* factory = isolate->factory(); 2712 2713 ExpectedSnippet<0> snippets[] = { 2714 {"const x = 3; return x;", {handle(Smi::FromInt(3), isolate)}}, 2715 {"let x = 10; x = x + 20; return x;", 2716 {handle(Smi::FromInt(30), isolate)}}, 2717 {"let x = 10; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, 2718 {"let x; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, 2719 {"let x; return x;", {factory->undefined_value()}}, 2720 {"var x = 10; { let x = 30; } return x;", 2721 {handle(Smi::FromInt(10), isolate)}}, 2722 {"let x = 10; { let x = 20; } return x;", 2723 {handle(Smi::FromInt(10), isolate)}}, 2724 {"var x = 10; eval('let x = 20;'); return x;", 2725 {handle(Smi::FromInt(10), isolate)}}, 2726 {"var x = 10; eval('const x = 20;'); return x;", 2727 {handle(Smi::FromInt(10), isolate)}}, 2728 {"var x = 10; { const x = 20; } return x;", 2729 {handle(Smi::FromInt(10), isolate)}}, 2730 {"var x = 10; { const x = 20; return x;} return -1;", 2731 {handle(Smi::FromInt(20), isolate)}}, 2732 {"var a = 10;\n" 2733 "for (var i = 0; i < 10; ++i) {\n" 2734 " const x = i;\n" // const declarations are block scoped. 2735 " a = a + x;\n" 2736 "}\n" 2737 "return a;\n", 2738 {handle(Smi::FromInt(55), isolate)}}, 2739 }; 2740 2741 // Tests for sloppy mode. 2742 for (size_t i = 0; i < arraysize(snippets); i++) { 2743 ScopedVector<char> script(1024); 2744 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2745 snippets[i].code_snippet, kFunctionName); 2746 2747 BytecodeGraphTester tester(isolate, zone, script.start()); 2748 auto callable = tester.GetCallable<>(); 2749 Handle<Object> return_value = callable().ToHandleChecked(); 2750 CHECK(return_value->SameValue(*snippets[i].return_value())); 2751 } 2752 2753 // Tests for strict mode. 2754 for (size_t i = 0; i < arraysize(snippets); i++) { 2755 ScopedVector<char> script(1024); 2756 SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, 2757 snippets[i].code_snippet, kFunctionName); 2758 2759 BytecodeGraphTester tester(isolate, zone, script.start()); 2760 auto callable = tester.GetCallable<>(); 2761 Handle<Object> return_value = callable().ToHandleChecked(); 2762 CHECK(return_value->SameValue(*snippets[i].return_value())); 2763 } 2764 } 2765 2766 TEST(BytecodeGraphBuilderConstDeclarationLookupSlots) { 2767 HandleAndZoneScope scope; 2768 Isolate* isolate = scope.main_isolate(); 2769 Zone* zone = scope.main_zone(); 2770 Factory* factory = isolate->factory(); 2771 2772 ExpectedSnippet<0> snippets[] = { 2773 {"const x = 3; function f1() {return x;}; return x;", 2774 {handle(Smi::FromInt(3), isolate)}}, 2775 {"let x = 10; x = x + 20; function f1() {return x;}; return x;", 2776 {handle(Smi::FromInt(30), isolate)}}, 2777 {"let x; x = 20; function f1() {return x;}; return x;", 2778 {handle(Smi::FromInt(20), isolate)}}, 2779 {"let x; function f1() {return x;}; return x;", 2780 {factory->undefined_value()}}, 2781 }; 2782 2783 // Tests for sloppy mode. 2784 for (size_t i = 0; i < arraysize(snippets); i++) { 2785 ScopedVector<char> script(1024); 2786 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2787 snippets[i].code_snippet, kFunctionName); 2788 2789 BytecodeGraphTester tester(isolate, zone, script.start()); 2790 auto callable = tester.GetCallable<>(); 2791 Handle<Object> return_value = callable().ToHandleChecked(); 2792 CHECK(return_value->SameValue(*snippets[i].return_value())); 2793 } 2794 2795 // Tests for strict mode. 2796 for (size_t i = 0; i < arraysize(snippets); i++) { 2797 ScopedVector<char> script(1024); 2798 SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, 2799 snippets[i].code_snippet, kFunctionName); 2800 2801 BytecodeGraphTester tester(isolate, zone, script.start()); 2802 auto callable = tester.GetCallable<>(); 2803 Handle<Object> return_value = callable().ToHandleChecked(); 2804 CHECK(return_value->SameValue(*snippets[i].return_value())); 2805 } 2806 } 2807 2808 TEST(BytecodeGraphBuilderConstInLookupContextChain) { 2809 HandleAndZoneScope scope; 2810 Isolate* isolate = scope.main_isolate(); 2811 Zone* zone = scope.main_zone(); 2812 2813 const char* prologue = 2814 "function OuterMost() {\n" 2815 " const outerConst = 10;\n" 2816 " let outerLet = 20;\n" 2817 " function Outer() {\n" 2818 " function Inner() {\n" 2819 " this.innerFunc = function() { "; 2820 const char* epilogue = 2821 " }\n" 2822 " }\n" 2823 " this.getInnerFunc =" 2824 " function() {return new Inner().innerFunc;}\n" 2825 " }\n" 2826 " this.getOuterFunc =" 2827 " function() {return new Outer().getInnerFunc();}" 2828 "}\n" 2829 "var f = new OuterMost().getOuterFunc();\n" 2830 "f();\n"; 2831 2832 // Tests for let / constant. 2833 ExpectedSnippet<0> const_decl[] = { 2834 {"return outerConst;", {handle(Smi::FromInt(10), isolate)}}, 2835 {"return outerLet;", {handle(Smi::FromInt(20), isolate)}}, 2836 {"outerLet = 30; return outerLet;", {handle(Smi::FromInt(30), isolate)}}, 2837 {"var outerLet = 40; return outerLet;", 2838 {handle(Smi::FromInt(40), isolate)}}, 2839 {"var outerConst = 50; return outerConst;", 2840 {handle(Smi::FromInt(50), isolate)}}, 2841 {"try { outerConst = 30 } catch(e) { return -1; }", 2842 {handle(Smi::FromInt(-1), isolate)}}}; 2843 2844 for (size_t i = 0; i < arraysize(const_decl); i++) { 2845 ScopedVector<char> script(1024); 2846 SNPrintF(script, "%s %s %s", prologue, const_decl[i].code_snippet, 2847 epilogue); 2848 2849 BytecodeGraphTester tester(isolate, zone, script.start(), "*"); 2850 auto callable = tester.GetCallable<>(); 2851 Handle<Object> return_value = callable().ToHandleChecked(); 2852 CHECK(return_value->SameValue(*const_decl[i].return_value())); 2853 } 2854 } 2855 2856 TEST(BytecodeGraphBuilderIllegalConstDeclaration) { 2857 HandleAndZoneScope scope; 2858 Isolate* isolate = scope.main_isolate(); 2859 Zone* zone = scope.main_zone(); 2860 2861 ExpectedSnippet<0, const char*> illegal_const_decl[] = { 2862 {"const x = x = 10 + 3; return x;", 2863 {"Uncaught ReferenceError: x is not defined"}}, 2864 {"const x = 10; x = 20; return x;", 2865 {"Uncaught TypeError: Assignment to constant variable."}}, 2866 {"const x = 10; { x = 20; } return x;", 2867 {"Uncaught TypeError: Assignment to constant variable."}}, 2868 {"const x = 10; eval('x = 20;'); return x;", 2869 {"Uncaught TypeError: Assignment to constant variable."}}, 2870 {"let x = x + 10; return x;", 2871 {"Uncaught ReferenceError: x is not defined"}}, 2872 {"'use strict'; (function f1() { f1 = 123; })() ", 2873 {"Uncaught TypeError: Assignment to constant variable."}}, 2874 }; 2875 2876 // Tests for sloppy mode. 2877 for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { 2878 ScopedVector<char> script(1024); 2879 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2880 illegal_const_decl[i].code_snippet, kFunctionName); 2881 2882 BytecodeGraphTester tester(isolate, zone, script.start()); 2883 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); 2884 v8::Local<v8::String> expected_string = 2885 v8_str(illegal_const_decl[i].return_value()); 2886 CHECK( 2887 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) 2888 .FromJust()); 2889 } 2890 2891 // Tests for strict mode. 2892 for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { 2893 ScopedVector<char> script(1024); 2894 SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, 2895 illegal_const_decl[i].code_snippet, kFunctionName); 2896 2897 BytecodeGraphTester tester(isolate, zone, script.start()); 2898 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); 2899 v8::Local<v8::String> expected_string = 2900 v8_str(illegal_const_decl[i].return_value()); 2901 CHECK( 2902 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) 2903 .FromJust()); 2904 } 2905 } 2906 2907 TEST(BytecodeGraphBuilderDebuggerStatement) { 2908 FLAG_expose_debug_as = "debug"; 2909 HandleAndZoneScope scope; 2910 Isolate* isolate = scope.main_isolate(); 2911 Zone* zone = scope.main_zone(); 2912 2913 ExpectedSnippet<0> snippet = { 2914 "var Debug = debug.Debug;" 2915 "var count = 0;" 2916 "function f() {" 2917 " debugger;" 2918 "}" 2919 "function listener(event) {" 2920 " if (event == Debug.DebugEvent.Break) count++;" 2921 "}" 2922 "Debug.setListener(listener);" 2923 "f();" 2924 "Debug.setListener(null);" 2925 "return count;", 2926 {handle(Smi::FromInt(1), isolate)}}; 2927 2928 ScopedVector<char> script(1024); 2929 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2930 snippet.code_snippet, kFunctionName); 2931 2932 BytecodeGraphTester tester(isolate, zone, script.start()); 2933 auto callable = tester.GetCallable<>(); 2934 Handle<Object> return_value = callable().ToHandleChecked(); 2935 CHECK(return_value->SameValue(*snippet.return_value())); 2936 } 2937 2938 } // namespace compiler 2939 } // namespace internal 2940 } // namespace v8 2941