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 20 static const char kFunctionName[] = "f"; 21 22 static const Token::Value kCompareOperators[] = { 23 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, 24 Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE, 25 Token::Value::GT, Token::Value::GTE}; 26 27 static const int SMI_MAX = (1 << 30) - 1; 28 static const int SMI_MIN = -(1 << 30); 29 30 static MaybeHandle<Object> CallFunction(Isolate* isolate, 31 Handle<JSFunction> function) { 32 return Execution::Call(isolate, function, 33 isolate->factory()->undefined_value(), 0, nullptr); 34 } 35 36 37 template <class... A> 38 static MaybeHandle<Object> CallFunction(Isolate* isolate, 39 Handle<JSFunction> function, 40 A... args) { 41 Handle<Object> argv[] = {args...}; 42 return Execution::Call(isolate, function, 43 isolate->factory()->undefined_value(), sizeof...(args), 44 argv); 45 } 46 47 48 template <class... A> 49 class BytecodeGraphCallable { 50 public: 51 BytecodeGraphCallable(Isolate* isolate, Handle<JSFunction> function) 52 : isolate_(isolate), function_(function) {} 53 virtual ~BytecodeGraphCallable() {} 54 55 MaybeHandle<Object> operator()(A... args) { 56 return CallFunction(isolate_, function_, args...); 57 } 58 59 private: 60 Isolate* isolate_; 61 Handle<JSFunction> function_; 62 }; 63 64 65 class BytecodeGraphTester { 66 public: 67 BytecodeGraphTester(Isolate* isolate, Zone* zone, const char* script, 68 const char* filter = kFunctionName) 69 : isolate_(isolate), zone_(zone), script_(script) { 70 i::FLAG_ignition = true; 71 i::FLAG_always_opt = false; 72 i::FLAG_allow_natives_syntax = true; 73 i::FLAG_ignition_fallback_on_eval_and_catch = false; 74 // Set ignition filter flag via SetFlagsFromString to avoid double-free 75 // (or potential leak with StrDup() based on ownership confusion). 76 ScopedVector<char> ignition_filter(64); 77 SNPrintF(ignition_filter, "--ignition-filter=%s", filter); 78 FlagList::SetFlagsFromString(ignition_filter.start(), 79 ignition_filter.length()); 80 // Ensure handler table is generated. 81 isolate->interpreter()->Initialize(); 82 } 83 virtual ~BytecodeGraphTester() {} 84 85 template <class... A> 86 BytecodeGraphCallable<A...> GetCallable( 87 const char* functionName = kFunctionName) { 88 return BytecodeGraphCallable<A...>(isolate_, GetFunction(functionName)); 89 } 90 91 Local<Message> CheckThrowsReturnMessage() { 92 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_)); 93 auto callable = GetCallable<>(); 94 MaybeHandle<Object> no_result = callable(); 95 CHECK(isolate_->has_pending_exception()); 96 CHECK(try_catch.HasCaught()); 97 CHECK(no_result.is_null()); 98 isolate_->OptionalRescheduleException(true); 99 CHECK(!try_catch.Message().IsEmpty()); 100 return try_catch.Message(); 101 } 102 103 static Handle<Object> NewObject(const char* script) { 104 return v8::Utils::OpenHandle(*CompileRun(script)); 105 } 106 107 private: 108 Isolate* isolate_; 109 Zone* zone_; 110 const char* script_; 111 112 Handle<JSFunction> GetFunction(const char* functionName) { 113 CompileRun(script_); 114 Local<Function> api_function = Local<Function>::Cast( 115 CcTest::global() 116 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(functionName)) 117 .ToLocalChecked()); 118 Handle<JSFunction> function = 119 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); 120 CHECK(function->shared()->HasBytecodeArray()); 121 122 ParseInfo parse_info(zone_, function); 123 124 CompilationInfo compilation_info(&parse_info); 125 compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>()); 126 compilation_info.MarkAsDeoptimizationEnabled(); 127 // TODO(mythria): Remove this step once parse_info is not needed. 128 CHECK(Compiler::ParseAndAnalyze(&parse_info)); 129 compiler::Pipeline pipeline(&compilation_info); 130 Handle<Code> code = pipeline.GenerateCode(); 131 function->ReplaceCode(*code); 132 133 return function; 134 } 135 136 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphTester); 137 }; 138 139 140 #define SPACE() 141 142 #define REPEAT_2(SEP, ...) __VA_ARGS__ SEP() __VA_ARGS__ 143 #define REPEAT_4(SEP, ...) \ 144 REPEAT_2(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) 145 #define REPEAT_8(SEP, ...) \ 146 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_4(SEP, __VA_ARGS__) 147 #define REPEAT_16(SEP, ...) \ 148 REPEAT_8(SEP, __VA_ARGS__) SEP() REPEAT_8(SEP, __VA_ARGS__) 149 #define REPEAT_32(SEP, ...) \ 150 REPEAT_16(SEP, __VA_ARGS__) SEP() REPEAT_16(SEP, __VA_ARGS__) 151 #define REPEAT_64(SEP, ...) \ 152 REPEAT_32(SEP, __VA_ARGS__) SEP() REPEAT_32(SEP, __VA_ARGS__) 153 #define REPEAT_128(SEP, ...) \ 154 REPEAT_64(SEP, __VA_ARGS__) SEP() REPEAT_64(SEP, __VA_ARGS__) 155 #define REPEAT_256(SEP, ...) \ 156 REPEAT_128(SEP, __VA_ARGS__) SEP() REPEAT_128(SEP, __VA_ARGS__) 157 158 #define REPEAT_127(SEP, ...) \ 159 REPEAT_64(SEP, __VA_ARGS__) \ 160 SEP() \ 161 REPEAT_32(SEP, __VA_ARGS__) \ 162 SEP() \ 163 REPEAT_16(SEP, __VA_ARGS__) \ 164 SEP() \ 165 REPEAT_8(SEP, __VA_ARGS__) \ 166 SEP() \ 167 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) SEP() __VA_ARGS__ 168 169 170 template <int N, typename T = Handle<Object>> 171 struct ExpectedSnippet { 172 const char* code_snippet; 173 T return_value_and_parameters[N + 1]; 174 175 inline T return_value() const { return return_value_and_parameters[0]; } 176 177 inline T parameter(int i) const { 178 CHECK_GE(i, 0); 179 CHECK_LT(i, N); 180 return return_value_and_parameters[1 + i]; 181 } 182 }; 183 184 185 TEST(BytecodeGraphBuilderReturnStatements) { 186 HandleAndZoneScope scope; 187 Isolate* isolate = scope.main_isolate(); 188 Zone* zone = scope.main_zone(); 189 Factory* factory = isolate->factory(); 190 191 ExpectedSnippet<0> snippets[] = { 192 {"return;", {factory->undefined_value()}}, 193 {"return null;", {factory->null_value()}}, 194 {"return true;", {factory->true_value()}}, 195 {"return false;", {factory->false_value()}}, 196 {"return 0;", {factory->NewNumberFromInt(0)}}, 197 {"return +1;", {factory->NewNumberFromInt(1)}}, 198 {"return -1;", {factory->NewNumberFromInt(-1)}}, 199 {"return +127;", {factory->NewNumberFromInt(127)}}, 200 {"return -128;", {factory->NewNumberFromInt(-128)}}, 201 {"return 0.001;", {factory->NewNumber(0.001)}}, 202 {"return 3.7e-60;", {factory->NewNumber(3.7e-60)}}, 203 {"return -3.7e60;", {factory->NewNumber(-3.7e60)}}, 204 {"return '';", {factory->NewStringFromStaticChars("")}}, 205 {"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}}, 206 {"return NaN;", {factory->nan_value()}}}; 207 208 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 209 for (size_t i = 0; i < num_snippets; i++) { 210 ScopedVector<char> script(1024); 211 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 212 snippets[i].code_snippet, kFunctionName); 213 214 BytecodeGraphTester tester(isolate, zone, script.start()); 215 auto callable = tester.GetCallable<>(); 216 Handle<Object> return_value = callable().ToHandleChecked(); 217 CHECK(return_value->SameValue(*snippets[i].return_value())); 218 } 219 } 220 221 222 TEST(BytecodeGraphBuilderPrimitiveExpressions) { 223 HandleAndZoneScope scope; 224 Isolate* isolate = scope.main_isolate(); 225 Zone* zone = scope.main_zone(); 226 Factory* factory = isolate->factory(); 227 228 ExpectedSnippet<0> snippets[] = { 229 {"return 1 + 1;", {factory->NewNumberFromInt(2)}}, 230 {"return 20 - 30;", {factory->NewNumberFromInt(-10)}}, 231 {"return 4 * 100;", {factory->NewNumberFromInt(400)}}, 232 {"return 100 / 5;", {factory->NewNumberFromInt(20)}}, 233 {"return 25 % 7;", {factory->NewNumberFromInt(4)}}, 234 }; 235 236 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 237 for (size_t i = 0; i < num_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 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 296 for (size_t i = 0; i < num_snippets; i++) { 297 ScopedVector<char> script(1024); 298 SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName, 299 snippets[i].code_snippet, kFunctionName); 300 301 BytecodeGraphTester tester(isolate, zone, script.start()); 302 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 303 Handle<Object> return_value = 304 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 305 .ToHandleChecked(); 306 CHECK(return_value->SameValue(*snippets[i].return_value())); 307 } 308 } 309 310 311 TEST(BytecodeGraphBuilderNamedLoad) { 312 HandleAndZoneScope scope; 313 Isolate* isolate = scope.main_isolate(); 314 Zone* zone = scope.main_zone(); 315 Factory* factory = isolate->factory(); 316 317 ExpectedSnippet<1> snippets[] = { 318 {"return p1.val;", 319 {factory->NewNumberFromInt(10), 320 BytecodeGraphTester::NewObject("({val : 10})")}}, 321 {"return p1[\"name\"];", 322 {factory->NewStringFromStaticChars("abc"), 323 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 324 {"'use strict'; return p1.val;", 325 {factory->NewNumberFromInt(10), 326 BytecodeGraphTester::NewObject("({val : 10 })")}}, 327 {"'use strict'; return p1[\"val\"];", 328 {factory->NewNumberFromInt(10), 329 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}}, 330 {"var b;\n" REPEAT_127(SPACE, " b = p1.name; ") " return p1.name;\n", 331 {factory->NewStringFromStaticChars("abc"), 332 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 333 {"'use strict'; var b;\n" 334 REPEAT_127(SPACE, " b = p1.name; ") 335 "return p1.name;\n", 336 {factory->NewStringFromStaticChars("abc"), 337 BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, 338 }; 339 340 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 341 for (size_t i = 0; i < num_snippets; i++) { 342 ScopedVector<char> script(2048); 343 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 344 snippets[i].code_snippet, kFunctionName); 345 346 BytecodeGraphTester tester(isolate, zone, script.start()); 347 auto callable = tester.GetCallable<Handle<Object>>(); 348 Handle<Object> return_value = 349 callable(snippets[i].parameter(0)).ToHandleChecked(); 350 CHECK(return_value->SameValue(*snippets[i].return_value())); 351 } 352 } 353 354 355 TEST(BytecodeGraphBuilderKeyedLoad) { 356 HandleAndZoneScope scope; 357 Isolate* isolate = scope.main_isolate(); 358 Zone* zone = scope.main_zone(); 359 Factory* factory = isolate->factory(); 360 361 ExpectedSnippet<2> snippets[] = { 362 {"return p1[p2];", 363 {factory->NewNumberFromInt(10), 364 BytecodeGraphTester::NewObject("({val : 10})"), 365 factory->NewStringFromStaticChars("val")}}, 366 {"return p1[100];", 367 {factory->NewStringFromStaticChars("abc"), 368 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 369 factory->NewNumberFromInt(0)}}, 370 {"var b = 100; return p1[b];", 371 {factory->NewStringFromStaticChars("abc"), 372 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 373 factory->NewNumberFromInt(0)}}, 374 {"'use strict'; return p1[p2];", 375 {factory->NewNumberFromInt(10), 376 BytecodeGraphTester::NewObject("({val : 10 })"), 377 factory->NewStringFromStaticChars("val")}}, 378 {"'use strict'; return p1[100];", 379 {factory->NewNumberFromInt(10), 380 BytecodeGraphTester::NewObject("({100 : 10})"), 381 factory->NewNumberFromInt(0)}}, 382 {"'use strict'; var b = p2; return p1[b];", 383 {factory->NewStringFromStaticChars("abc"), 384 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 385 factory->NewNumberFromInt(100)}}, 386 {"var b;\n" REPEAT_127(SPACE, " b = p1[p2]; ") " return p1[p2];\n", 387 {factory->NewStringFromStaticChars("abc"), 388 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 389 factory->NewNumberFromInt(100)}}, 390 {"'use strict'; var b;\n" REPEAT_127(SPACE, 391 " b = p1[p2]; ") "return p1[p2];\n", 392 {factory->NewStringFromStaticChars("abc"), 393 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"), 394 factory->NewNumberFromInt(100)}}, 395 }; 396 397 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 398 for (size_t i = 0; i < num_snippets; i++) { 399 ScopedVector<char> script(2048); 400 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, 401 snippets[i].code_snippet, kFunctionName); 402 403 BytecodeGraphTester tester(isolate, zone, script.start()); 404 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 405 Handle<Object> return_value = 406 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 407 .ToHandleChecked(); 408 CHECK(return_value->SameValue(*snippets[i].return_value())); 409 } 410 } 411 412 413 TEST(BytecodeGraphBuilderNamedStore) { 414 HandleAndZoneScope scope; 415 Isolate* isolate = scope.main_isolate(); 416 Zone* zone = scope.main_zone(); 417 Factory* factory = isolate->factory(); 418 419 ExpectedSnippet<1> snippets[] = { 420 {"return p1.val = 20;", 421 {factory->NewNumberFromInt(20), 422 BytecodeGraphTester::NewObject("({val : 10})")}}, 423 {"p1.type = 'int'; return p1.type;", 424 {factory->NewStringFromStaticChars("int"), 425 BytecodeGraphTester::NewObject("({val : 10})")}}, 426 {"p1.name = 'def'; return p1[\"name\"];", 427 {factory->NewStringFromStaticChars("def"), 428 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 429 {"'use strict'; p1.val = 20; return p1.val;", 430 {factory->NewNumberFromInt(20), 431 BytecodeGraphTester::NewObject("({val : 10 })")}}, 432 {"'use strict'; return p1.type = 'int';", 433 {factory->NewStringFromStaticChars("int"), 434 BytecodeGraphTester::NewObject("({val : 10})")}}, 435 {"'use strict'; p1.val = 20; return p1[\"val\"];", 436 {factory->NewNumberFromInt(20), 437 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}}, 438 {"var b = 'abc';\n" REPEAT_127( 439 SPACE, " p1.name = b; ") " p1.name = 'def'; return p1.name;\n", 440 {factory->NewStringFromStaticChars("def"), 441 BytecodeGraphTester::NewObject("({name : 'abc'})")}}, 442 {"'use strict'; var b = 'def';\n" REPEAT_127( 443 SPACE, " p1.name = 'abc'; ") "p1.name = b; return p1.name;\n", 444 {factory->NewStringFromStaticChars("def"), 445 BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, 446 }; 447 448 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 449 for (size_t i = 0; i < num_snippets; i++) { 450 ScopedVector<char> script(3072); 451 SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName, 452 snippets[i].code_snippet, kFunctionName); 453 454 BytecodeGraphTester tester(isolate, zone, script.start()); 455 auto callable = tester.GetCallable<Handle<Object>>(); 456 Handle<Object> return_value = 457 callable(snippets[i].parameter(0)).ToHandleChecked(); 458 CHECK(return_value->SameValue(*snippets[i].return_value())); 459 } 460 } 461 462 463 TEST(BytecodeGraphBuilderKeyedStore) { 464 HandleAndZoneScope scope; 465 Isolate* isolate = scope.main_isolate(); 466 Zone* zone = scope.main_zone(); 467 Factory* factory = isolate->factory(); 468 469 ExpectedSnippet<2> snippets[] = { 470 {"p1[p2] = 20; return p1[p2];", 471 {factory->NewNumberFromInt(20), 472 BytecodeGraphTester::NewObject("({val : 10})"), 473 factory->NewStringFromStaticChars("val")}}, 474 {"return p1[100] = 'def';", 475 {factory->NewStringFromStaticChars("def"), 476 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 477 factory->NewNumberFromInt(0)}}, 478 {"var b = 100; p1[b] = 'def'; return p1[b];", 479 {factory->NewStringFromStaticChars("def"), 480 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 481 factory->NewNumberFromInt(0)}}, 482 {"'use strict'; p1[p2] = 20; return p1[p2];", 483 {factory->NewNumberFromInt(20), 484 BytecodeGraphTester::NewObject("({val : 10 })"), 485 factory->NewStringFromStaticChars("val")}}, 486 {"'use strict'; return p1[100] = 20;", 487 {factory->NewNumberFromInt(20), 488 BytecodeGraphTester::NewObject("({100 : 10})"), 489 factory->NewNumberFromInt(0)}}, 490 {"'use strict'; var b = p2; p1[b] = 'def'; return p1[b];", 491 {factory->NewStringFromStaticChars("def"), 492 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 493 factory->NewNumberFromInt(100)}}, 494 {"var b;\n" REPEAT_127( 495 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n", 496 {factory->NewStringFromStaticChars("def"), 497 BytecodeGraphTester::NewObject("({100 : 'abc'})"), 498 factory->NewNumberFromInt(100)}}, 499 {"'use strict'; var b;\n" REPEAT_127( 500 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n", 501 {factory->NewStringFromStaticChars("def"), 502 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"), 503 factory->NewNumberFromInt(100)}}, 504 }; 505 506 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 507 for (size_t i = 0; i < num_snippets; i++) { 508 ScopedVector<char> script(2048); 509 SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", kFunctionName, 510 snippets[i].code_snippet, kFunctionName); 511 512 BytecodeGraphTester tester(isolate, zone, script.start()); 513 auto callable = tester.GetCallable<Handle<Object>>(); 514 Handle<Object> return_value = 515 callable(snippets[i].parameter(0)).ToHandleChecked(); 516 CHECK(return_value->SameValue(*snippets[i].return_value())); 517 } 518 } 519 520 521 TEST(BytecodeGraphBuilderPropertyCall) { 522 HandleAndZoneScope scope; 523 Isolate* isolate = scope.main_isolate(); 524 Zone* zone = scope.main_zone(); 525 Factory* factory = isolate->factory(); 526 527 ExpectedSnippet<1> snippets[] = { 528 {"return p1.func();", 529 {factory->NewNumberFromInt(25), 530 BytecodeGraphTester::NewObject("({func() { return 25; }})")}}, 531 {"return p1.func('abc');", 532 {factory->NewStringFromStaticChars("abc"), 533 BytecodeGraphTester::NewObject("({func(a) { return a; }})")}}, 534 {"return p1.func(1, 2, 3, 4, 5, 6, 7, 8);", 535 {factory->NewNumberFromInt(36), 536 BytecodeGraphTester::NewObject( 537 "({func(a, b, c, d, e, f, g, h) {\n" 538 " return a + b + c + d + e + f + g + h;}})")}}, 539 }; 540 541 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 542 for (size_t i = 0; i < num_snippets; i++) { 543 ScopedVector<char> script(2048); 544 SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", kFunctionName, 545 snippets[i].code_snippet, kFunctionName); 546 547 BytecodeGraphTester tester(isolate, zone, script.start()); 548 auto callable = tester.GetCallable<Handle<Object>>(); 549 Handle<Object> return_value = 550 callable(snippets[i].parameter(0)).ToHandleChecked(); 551 CHECK(return_value->SameValue(*snippets[i].return_value())); 552 } 553 } 554 555 556 TEST(BytecodeGraphBuilderCallNew) { 557 HandleAndZoneScope scope; 558 Isolate* isolate = scope.main_isolate(); 559 Zone* zone = scope.main_zone(); 560 Factory* factory = isolate->factory(); 561 562 ExpectedSnippet<0> snippets[] = { 563 {"function counter() { this.count = 20; }\n" 564 "function f() {\n" 565 " var c = new counter();\n" 566 " return c.count;\n" 567 "}; f()", 568 {factory->NewNumberFromInt(20)}}, 569 {"function counter(arg0) { this.count = 17; this.x = arg0; }\n" 570 "function f() {\n" 571 " var c = new counter(6);\n" 572 " return c.count + c.x;\n" 573 "}; f()", 574 {factory->NewNumberFromInt(23)}}, 575 {"function counter(arg0, arg1) {\n" 576 " this.count = 17; this.x = arg0; this.y = arg1;\n" 577 "}\n" 578 "function f() {\n" 579 " var c = new counter(3, 5);\n" 580 " return c.count + c.x + c.y;\n" 581 "}; f()", 582 {factory->NewNumberFromInt(25)}}, 583 }; 584 585 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 586 for (size_t i = 0; i < num_snippets; i++) { 587 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 588 auto callable = tester.GetCallable<>(); 589 Handle<Object> return_value = callable().ToHandleChecked(); 590 CHECK(return_value->SameValue(*snippets[i].return_value())); 591 } 592 } 593 594 595 TEST(BytecodeGraphBuilderCreateClosure) { 596 HandleAndZoneScope scope; 597 Isolate* isolate = scope.main_isolate(); 598 Zone* zone = scope.main_zone(); 599 Factory* factory = isolate->factory(); 600 601 ExpectedSnippet<0> snippets[] = { 602 {"function f() {\n" 603 " function counter() { this.count = 20; }\n" 604 " var c = new counter();\n" 605 " return c.count;\n" 606 "}; f()", 607 {factory->NewNumberFromInt(20)}}, 608 {"function f() {\n" 609 " function counter(arg0) { this.count = 17; this.x = arg0; }\n" 610 " var c = new counter(6);\n" 611 " return c.count + c.x;\n" 612 "}; f()", 613 {factory->NewNumberFromInt(23)}}, 614 {"function f() {\n" 615 " function counter(arg0, arg1) {\n" 616 " this.count = 17; this.x = arg0; this.y = arg1;\n" 617 " }\n" 618 " var c = new counter(3, 5);\n" 619 " return c.count + c.x + c.y;\n" 620 "}; f()", 621 {factory->NewNumberFromInt(25)}}, 622 }; 623 624 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 625 for (size_t i = 0; i < num_snippets; i++) { 626 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 627 auto callable = tester.GetCallable<>(); 628 Handle<Object> return_value = callable().ToHandleChecked(); 629 CHECK(return_value->SameValue(*snippets[i].return_value())); 630 } 631 } 632 633 634 TEST(BytecodeGraphBuilderCallRuntime) { 635 HandleAndZoneScope scope; 636 Isolate* isolate = scope.main_isolate(); 637 Zone* zone = scope.main_zone(); 638 Factory* factory = isolate->factory(); 639 640 ExpectedSnippet<1> snippets[] = { 641 {"function f(arg0) { return %MaxSmi(); }\nf()", 642 {factory->NewNumberFromInt(Smi::kMaxValue), factory->undefined_value()}}, 643 {"function f(arg0) { return %IsArray(arg0) }\nf(undefined)", 644 {factory->true_value(), BytecodeGraphTester::NewObject("[1, 2, 3]")}}, 645 {"function f(arg0) { return %Add(arg0, 2) }\nf(1)", 646 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(3)}}, 647 {"function f(arg0) { return %spread_arguments(arg0).length }\nf([])", 648 {factory->NewNumberFromInt(3), 649 BytecodeGraphTester::NewObject("[1, 2, 3]")}}, 650 }; 651 652 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 653 for (size_t i = 0; i < num_snippets; i++) { 654 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 655 auto callable = tester.GetCallable<Handle<Object>>(); 656 Handle<Object> return_value = 657 callable(snippets[i].parameter(0)).ToHandleChecked(); 658 CHECK(return_value->SameValue(*snippets[i].return_value())); 659 } 660 } 661 662 663 TEST(BytecodeGraphBuilderGlobals) { 664 HandleAndZoneScope scope; 665 Isolate* isolate = scope.main_isolate(); 666 Zone* zone = scope.main_zone(); 667 Factory* factory = isolate->factory(); 668 669 ExpectedSnippet<0> snippets[] = { 670 {"var global = 321;\n function f() { return global; };\n f();", 671 {factory->NewNumberFromInt(321)}}, 672 {"var global = 321;\n" 673 "function f() { global = 123; return global };\n f();", 674 {factory->NewNumberFromInt(123)}}, 675 {"var global = function() { return 'abc'};\n" 676 "function f() { return global(); };\n f();", 677 {factory->NewStringFromStaticChars("abc")}}, 678 {"var global = 456;\n" 679 "function f() { 'use strict'; return global; };\n f();", 680 {factory->NewNumberFromInt(456)}}, 681 {"var global = 987;\n" 682 "function f() { 'use strict'; global = 789; return global };\n f();", 683 {factory->NewNumberFromInt(789)}}, 684 {"var global = function() { return 'xyz'};\n" 685 "function f() { 'use strict'; return global(); };\n f();", 686 {factory->NewStringFromStaticChars("xyz")}}, 687 {"var global = 'abc'; var global_obj = {val:123};\n" 688 "function f() {\n" REPEAT_127( 689 SPACE, " var b = global_obj.name;\n") "return global; };\n f();\n", 690 {factory->NewStringFromStaticChars("abc")}}, 691 {"var global = 'abc'; var global_obj = {val:123};\n" 692 "function f() { 'use strict';\n" REPEAT_127( 693 SPACE, " var b = global_obj.name;\n") "global = 'xyz'; return " 694 "global };\n f();\n", 695 {factory->NewStringFromStaticChars("xyz")}}, 696 {"function f() { return typeof(undeclared_var); }\n; f();\n", 697 {factory->NewStringFromStaticChars("undefined")}}, 698 {"var defined_var = 10; function f() { return typeof(defined_var); }\n; " 699 "f();\n", 700 {factory->NewStringFromStaticChars("number")}}, 701 }; 702 703 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 704 for (size_t i = 0; i < num_snippets; i++) { 705 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 706 auto callable = tester.GetCallable<>(); 707 Handle<Object> return_value = callable().ToHandleChecked(); 708 CHECK(return_value->SameValue(*snippets[i].return_value())); 709 } 710 } 711 712 713 TEST(BytecodeGraphBuilderToObject) { 714 // TODO(mythria): tests for ToObject. Needs ForIn. 715 } 716 717 718 TEST(BytecodeGraphBuilderToName) { 719 HandleAndZoneScope scope; 720 Isolate* isolate = scope.main_isolate(); 721 Zone* zone = scope.main_zone(); 722 Factory* factory = isolate->factory(); 723 724 ExpectedSnippet<0> snippets[] = { 725 {"var a = 'val'; var obj = {[a] : 10}; return obj.val;", 726 {factory->NewNumberFromInt(10)}}, 727 {"var a = 20; var obj = {[a] : 10}; return obj['20'];", 728 {factory->NewNumberFromInt(10)}}, 729 {"var a = 20; var obj = {[a] : 10}; return obj[20];", 730 {factory->NewNumberFromInt(10)}}, 731 {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];", 732 {factory->NewNumberFromInt(10)}}, 733 {"var a = {val:23}; var obj = {[a] : 10}; return obj['[object Object]'];", 734 {factory->NewNumberFromInt(10)}}, 735 {"var a = {toString : function() { return 'x'}};\n" 736 "var obj = {[a] : 10};\n" 737 "return obj.x;", 738 {factory->NewNumberFromInt(10)}}, 739 {"var a = {valueOf : function() { return 'x'}};\n" 740 "var obj = {[a] : 10};\n" 741 "return obj.x;", 742 {factory->undefined_value()}}, 743 {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n" 744 "var obj = {[a] : 10};\n" 745 "return obj.x;", 746 {factory->NewNumberFromInt(10)}}, 747 }; 748 749 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 750 for (size_t i = 0; i < num_snippets; i++) { 751 ScopedVector<char> script(1024); 752 SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName, 753 snippets[i].code_snippet, kFunctionName); 754 755 BytecodeGraphTester tester(isolate, zone, script.start()); 756 auto callable = tester.GetCallable<>(); 757 Handle<Object> return_value = callable().ToHandleChecked(); 758 CHECK(return_value->SameValue(*snippets[i].return_value())); 759 } 760 } 761 762 763 TEST(BytecodeGraphBuilderLogicalNot) { 764 HandleAndZoneScope scope; 765 Isolate* isolate = scope.main_isolate(); 766 Zone* zone = scope.main_zone(); 767 Factory* factory = isolate->factory(); 768 769 ExpectedSnippet<1> snippets[] = { 770 {"return !p1;", 771 {factory->false_value(), 772 BytecodeGraphTester::NewObject("({val : 10})")}}, 773 {"return !p1;", {factory->true_value(), factory->NewNumberFromInt(0)}}, 774 {"return !p1;", {factory->true_value(), factory->undefined_value()}}, 775 {"return !p1;", {factory->false_value(), factory->NewNumberFromInt(10)}}, 776 {"return !p1;", {factory->false_value(), factory->true_value()}}, 777 {"return !p1;", 778 {factory->false_value(), factory->NewStringFromStaticChars("abc")}}, 779 }; 780 781 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 782 for (size_t i = 0; i < num_snippets; i++) { 783 ScopedVector<char> script(1024); 784 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 785 snippets[i].code_snippet, kFunctionName); 786 787 BytecodeGraphTester tester(isolate, zone, script.start()); 788 auto callable = tester.GetCallable<Handle<Object>>(); 789 Handle<Object> return_value = 790 callable(snippets[i].parameter(0)).ToHandleChecked(); 791 CHECK(return_value->SameValue(*snippets[i].return_value())); 792 } 793 } 794 795 796 TEST(BytecodeGraphBuilderTypeOf) { 797 HandleAndZoneScope scope; 798 Isolate* isolate = scope.main_isolate(); 799 Zone* zone = scope.main_zone(); 800 Factory* factory = isolate->factory(); 801 802 ExpectedSnippet<1> snippets[] = { 803 {"return typeof p1;", 804 {factory->NewStringFromStaticChars("object"), 805 BytecodeGraphTester::NewObject("({val : 10})")}}, 806 {"return typeof p1;", 807 {factory->NewStringFromStaticChars("undefined"), 808 factory->undefined_value()}}, 809 {"return typeof p1;", 810 {factory->NewStringFromStaticChars("number"), 811 factory->NewNumberFromInt(10)}}, 812 {"return typeof p1;", 813 {factory->NewStringFromStaticChars("boolean"), factory->true_value()}}, 814 {"return typeof p1;", 815 {factory->NewStringFromStaticChars("string"), 816 factory->NewStringFromStaticChars("abc")}}, 817 }; 818 819 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 820 for (size_t i = 0; i < num_snippets; i++) { 821 ScopedVector<char> script(1024); 822 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 823 snippets[i].code_snippet, kFunctionName); 824 825 BytecodeGraphTester tester(isolate, zone, script.start()); 826 auto callable = tester.GetCallable<Handle<Object>>(); 827 Handle<Object> return_value = 828 callable(snippets[i].parameter(0)).ToHandleChecked(); 829 CHECK(return_value->SameValue(*snippets[i].return_value())); 830 } 831 } 832 833 834 TEST(BytecodeGraphBuilderCountOperation) { 835 HandleAndZoneScope scope; 836 Isolate* isolate = scope.main_isolate(); 837 Zone* zone = scope.main_zone(); 838 Factory* factory = isolate->factory(); 839 840 ExpectedSnippet<1> snippets[] = { 841 {"return ++p1;", 842 {factory->NewNumberFromInt(11), factory->NewNumberFromInt(10)}}, 843 {"return p1++;", 844 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}}, 845 {"return p1++ + 10;", 846 {factory->NewHeapNumber(15.23), factory->NewHeapNumber(5.23)}}, 847 {"return 20 + ++p1;", 848 {factory->NewHeapNumber(27.23), factory->NewHeapNumber(6.23)}}, 849 {"return --p1;", 850 {factory->NewHeapNumber(9.8), factory->NewHeapNumber(10.8)}}, 851 {"return p1--;", 852 {factory->NewHeapNumber(10.8), factory->NewHeapNumber(10.8)}}, 853 {"return p1-- + 10;", 854 {factory->NewNumberFromInt(20), factory->NewNumberFromInt(10)}}, 855 {"return 20 + --p1;", 856 {factory->NewNumberFromInt(29), factory->NewNumberFromInt(10)}}, 857 {"return p1.val--;", 858 {factory->NewNumberFromInt(10), 859 BytecodeGraphTester::NewObject("({val : 10})")}}, 860 {"return ++p1['val'];", 861 {factory->NewNumberFromInt(11), 862 BytecodeGraphTester::NewObject("({val : 10})")}}, 863 {"return ++p1[1];", 864 {factory->NewNumberFromInt(11), 865 BytecodeGraphTester::NewObject("({1 : 10})")}}, 866 {" function inner() { return p1 } return --p1;", 867 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(10)}}, 868 {" function inner() { return p1 } return p1--;", 869 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}}, 870 {"return ++p1;", 871 {factory->nan_value(), factory->NewStringFromStaticChars("String")}}, 872 }; 873 874 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 875 for (size_t i = 0; i < num_snippets; i++) { 876 ScopedVector<char> script(1024); 877 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 878 snippets[i].code_snippet, kFunctionName); 879 880 BytecodeGraphTester tester(isolate, zone, script.start()); 881 auto callable = tester.GetCallable<Handle<Object>>(); 882 Handle<Object> return_value = 883 callable(snippets[i].parameter(0)).ToHandleChecked(); 884 CHECK(return_value->SameValue(*snippets[i].return_value())); 885 } 886 } 887 888 889 TEST(BytecodeGraphBuilderDelete) { 890 HandleAndZoneScope scope; 891 Isolate* isolate = scope.main_isolate(); 892 Zone* zone = scope.main_zone(); 893 Factory* factory = isolate->factory(); 894 895 ExpectedSnippet<1> snippets[] = { 896 {"return delete p1.val;", 897 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 898 {"delete p1.val; return p1.val;", 899 {factory->undefined_value(), 900 BytecodeGraphTester::NewObject("({val : 10})")}}, 901 {"delete p1.name; return p1.val;", 902 {factory->NewNumberFromInt(10), 903 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, 904 {"'use strict'; return delete p1.val;", 905 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 906 {"'use strict'; delete p1.val; return p1.val;", 907 {factory->undefined_value(), 908 BytecodeGraphTester::NewObject("({val : 10})")}}, 909 {"'use strict'; delete p1.name; return p1.val;", 910 {factory->NewNumberFromInt(10), 911 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, 912 }; 913 914 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 915 for (size_t i = 0; i < num_snippets; i++) { 916 ScopedVector<char> script(1024); 917 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 918 snippets[i].code_snippet, kFunctionName); 919 920 BytecodeGraphTester tester(isolate, zone, script.start()); 921 auto callable = tester.GetCallable<Handle<Object>>(); 922 Handle<Object> return_value = 923 callable(snippets[i].parameter(0)).ToHandleChecked(); 924 CHECK(return_value->SameValue(*snippets[i].return_value())); 925 } 926 } 927 928 929 TEST(BytecodeGraphBuilderDeleteGlobal) { 930 HandleAndZoneScope scope; 931 Isolate* isolate = scope.main_isolate(); 932 Zone* zone = scope.main_zone(); 933 Factory* factory = isolate->factory(); 934 935 ExpectedSnippet<0> snippets[] = { 936 {"var obj = {val : 10, type : 'int'};" 937 "function f() {return delete obj;};", 938 {factory->false_value()}}, 939 {"function f() {return delete this;};", {factory->true_value()}}, 940 {"var obj = {val : 10, type : 'int'};" 941 "function f() {return delete obj.val;};", 942 {factory->true_value()}}, 943 {"var obj = {val : 10, type : 'int'};" 944 "function f() {'use strict'; return delete obj.val;};", 945 {factory->true_value()}}, 946 {"var obj = {val : 10, type : 'int'};" 947 "function f() {delete obj.val; return obj.val;};", 948 {factory->undefined_value()}}, 949 {"var obj = {val : 10, type : 'int'};" 950 "function f() {'use strict'; delete obj.val; return obj.val;};", 951 {factory->undefined_value()}}, 952 {"var obj = {1 : 10, 2 : 20};" 953 "function f() { return delete obj[1]; };", 954 {factory->true_value()}}, 955 {"var obj = {1 : 10, 2 : 20};" 956 "function f() { 'use strict'; return delete obj[1];};", 957 {factory->true_value()}}, 958 {"obj = {1 : 10, 2 : 20};" 959 "function f() { delete obj[1]; return obj[2];};", 960 {factory->NewNumberFromInt(20)}}, 961 {"function f() {" 962 " var obj = {1 : 10, 2 : 20};" 963 " function inner() { return obj[1]; };" 964 " return delete obj[1];" 965 "}", 966 {factory->true_value()}}, 967 }; 968 969 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 970 for (size_t i = 0; i < num_snippets; i++) { 971 ScopedVector<char> script(1024); 972 SNPrintF(script, "%s %s({});", snippets[i].code_snippet, kFunctionName); 973 974 BytecodeGraphTester tester(isolate, zone, script.start()); 975 auto callable = tester.GetCallable<>(); 976 Handle<Object> return_value = callable().ToHandleChecked(); 977 CHECK(return_value->SameValue(*snippets[i].return_value())); 978 } 979 } 980 981 982 TEST(BytecodeGraphBuilderDeleteLookupSlot) { 983 HandleAndZoneScope scope; 984 Isolate* isolate = scope.main_isolate(); 985 Zone* zone = scope.main_zone(); 986 Factory* factory = isolate->factory(); 987 988 // TODO(mythria): Add more tests when we have support for LdaLookupSlot. 989 const char* function_prologue = "var f;" 990 "var x = 1;" 991 "y = 10;" 992 "var obj = {val:10};" 993 "var z = 30;" 994 "function f1() {" 995 " var z = 20;" 996 " eval(\"function t() {"; 997 const char* function_epilogue = " }; f = t; t();\");" 998 "}" 999 "f1();"; 1000 1001 ExpectedSnippet<0> snippets[] = { 1002 {"return delete y;", {factory->true_value()}}, 1003 {"return delete z;", {factory->false_value()}}, 1004 }; 1005 1006 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1007 for (size_t i = 0; i < num_snippets; i++) { 1008 ScopedVector<char> script(1024); 1009 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1010 function_epilogue); 1011 1012 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1013 auto callable = tester.GetCallable<>(); 1014 Handle<Object> return_value = callable().ToHandleChecked(); 1015 CHECK(return_value->SameValue(*snippets[i].return_value())); 1016 } 1017 } 1018 1019 1020 TEST(BytecodeGraphBuilderLookupSlot) { 1021 HandleAndZoneScope scope; 1022 Isolate* isolate = scope.main_isolate(); 1023 Zone* zone = scope.main_zone(); 1024 Factory* factory = isolate->factory(); 1025 1026 const char* function_prologue = "var f;" 1027 "var x = 12;" 1028 "y = 10;" 1029 "var obj = {val:3.1414};" 1030 "var z = 30;" 1031 "function f1() {" 1032 " var z = 20;" 1033 " eval(\"function t() {"; 1034 const char* function_epilogue = " }; f = t; t();\");" 1035 "}" 1036 "f1();"; 1037 1038 ExpectedSnippet<0> snippets[] = { 1039 {"return x;", {factory->NewNumber(12)}}, 1040 {"return obj.val;", {factory->NewNumber(3.1414)}}, 1041 {"return typeof x;", {factory->NewStringFromStaticChars("number")}}, 1042 {"return typeof dummy;", 1043 {factory->NewStringFromStaticChars("undefined")}}, 1044 {"x = 23; return x;", {factory->NewNumber(23)}}, 1045 {"'use strict'; obj.val = 23.456; return obj.val;", 1046 {factory->NewNumber(23.456)}}}; 1047 1048 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1049 for (size_t i = 0; i < num_snippets; i++) { 1050 ScopedVector<char> script(1024); 1051 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1052 function_epilogue); 1053 1054 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1055 auto callable = tester.GetCallable<>(); 1056 Handle<Object> return_value = callable().ToHandleChecked(); 1057 CHECK(return_value->SameValue(*snippets[i].return_value())); 1058 } 1059 } 1060 1061 1062 TEST(BytecodeGraphBuilderLookupSlotWide) { 1063 HandleAndZoneScope scope; 1064 Isolate* isolate = scope.main_isolate(); 1065 Zone* zone = scope.main_zone(); 1066 Factory* factory = isolate->factory(); 1067 1068 const char* function_prologue = 1069 "var f;" 1070 "var x = 12;" 1071 "y = 10;" 1072 "var obj = {val:3.1414};" 1073 "var z = 30;" 1074 "function f1() {" 1075 " var z = 20;" 1076 " eval(\"function t() {"; 1077 const char* function_epilogue = 1078 " }; f = t; t();\");" 1079 "}" 1080 "f1();"; 1081 1082 ExpectedSnippet<0> snippets[] = { 1083 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x;", 1084 {factory->NewNumber(12)}}, 1085 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return typeof x;", 1086 {factory->NewStringFromStaticChars("number")}}, 1087 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x = 23;", 1088 {factory->NewNumber(23)}}, 1089 {"'use strict';" REPEAT_256(SPACE, "y = 2.3;") "return obj.val = 23.456;", 1090 {factory->NewNumber(23.456)}}}; 1091 1092 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1093 for (size_t i = 0; i < num_snippets; i++) { 1094 ScopedVector<char> script(3072); 1095 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, 1096 function_epilogue); 1097 1098 BytecodeGraphTester tester(isolate, zone, script.start(), "t"); 1099 auto callable = tester.GetCallable<>(); 1100 Handle<Object> return_value = callable().ToHandleChecked(); 1101 CHECK(return_value->SameValue(*snippets[i].return_value())); 1102 } 1103 } 1104 1105 1106 TEST(BytecodeGraphBuilderCallLookupSlot) { 1107 HandleAndZoneScope scope; 1108 Isolate* isolate = scope.main_isolate(); 1109 Zone* zone = scope.main_zone(); 1110 1111 ExpectedSnippet<0> snippets[] = { 1112 {"g = function(){ return 2 }; eval(''); return g();", 1113 {handle(Smi::FromInt(2), isolate)}}, 1114 {"g = function(){ return 2 }; eval('g = function() {return 3}');\n" 1115 "return g();", 1116 {handle(Smi::FromInt(3), isolate)}}, 1117 {"g = { x: function(){ return this.y }, y: 20 };\n" 1118 "eval('g = { x: g.x, y: 30 }');\n" 1119 "return g.x();", 1120 {handle(Smi::FromInt(30), isolate)}}, 1121 }; 1122 1123 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1124 for (size_t i = 0; i < num_snippets; i++) { 1125 ScopedVector<char> script(1024); 1126 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1127 snippets[i].code_snippet, kFunctionName); 1128 BytecodeGraphTester tester(isolate, zone, script.start()); 1129 auto callable = tester.GetCallable<>(); 1130 Handle<Object> return_value = callable().ToHandleChecked(); 1131 CHECK(return_value->SameValue(*snippets[i].return_value())); 1132 } 1133 } 1134 1135 1136 TEST(BytecodeGraphBuilderEval) { 1137 HandleAndZoneScope scope; 1138 Isolate* isolate = scope.main_isolate(); 1139 Zone* zone = scope.main_zone(); 1140 Factory* factory = isolate->factory(); 1141 1142 ExpectedSnippet<0> snippets[] = { 1143 {"return eval('1;');", {handle(Smi::FromInt(1), isolate)}}, 1144 {"return eval('100 * 20;');", {handle(Smi::FromInt(2000), isolate)}}, 1145 {"var x = 10; return eval('x + 20;');", 1146 {handle(Smi::FromInt(30), isolate)}}, 1147 {"var x = 10; eval('x = 33;'); return x;", 1148 {handle(Smi::FromInt(33), isolate)}}, 1149 {"'use strict'; var x = 20; var z = 0;\n" 1150 "eval('var x = 33; z = x;'); return x + z;", 1151 {handle(Smi::FromInt(53), isolate)}}, 1152 {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;", 1153 {handle(Smi::FromInt(86), isolate)}}, 1154 {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x", 1155 {handle(Smi::FromInt(11), isolate)}}, 1156 {"var x = 10; eval('var x = 20;'); return x;", 1157 {handle(Smi::FromInt(20), isolate)}}, 1158 {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;", 1159 {handle(Smi::FromInt(1), isolate)}}, 1160 {"'use strict'; var x = 1; eval('var x = 2;'); return x;", 1161 {handle(Smi::FromInt(1), isolate)}}, 1162 {"var x = 10; eval('x + 20;'); return typeof x;", 1163 {factory->NewStringFromStaticChars("number")}}, 1164 {"eval('var y = 10;'); return typeof unallocated;", 1165 {factory->NewStringFromStaticChars("undefined")}}, 1166 {"'use strict'; eval('var y = 10;'); return typeof unallocated;", 1167 {factory->NewStringFromStaticChars("undefined")}}, 1168 {"eval('var x = 10;'); return typeof x;", 1169 {factory->NewStringFromStaticChars("number")}}, 1170 {"var x = {}; eval('var x = 10;'); return typeof x;", 1171 {factory->NewStringFromStaticChars("number")}}, 1172 {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;", 1173 {factory->NewStringFromStaticChars("object")}}, 1174 }; 1175 1176 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1177 for (size_t i = 0; i < num_snippets; i++) { 1178 ScopedVector<char> script(1024); 1179 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1180 snippets[i].code_snippet, kFunctionName); 1181 BytecodeGraphTester tester(isolate, zone, script.start()); 1182 auto callable = tester.GetCallable<>(); 1183 Handle<Object> return_value = callable().ToHandleChecked(); 1184 CHECK(return_value->SameValue(*snippets[i].return_value())); 1185 } 1186 } 1187 1188 1189 TEST(BytecodeGraphBuilderEvalParams) { 1190 HandleAndZoneScope scope; 1191 Isolate* isolate = scope.main_isolate(); 1192 Zone* zone = scope.main_zone(); 1193 1194 ExpectedSnippet<1> snippets[] = { 1195 {"var x = 10; return eval('x + p1;');", 1196 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, 1197 {"var x = 10; eval('p1 = x;'); return p1;", 1198 {handle(Smi::FromInt(10), isolate), handle(Smi::FromInt(20), isolate)}}, 1199 {"var a = 10;" 1200 "function inner() { return eval('a + p1;');}" 1201 "return inner();", 1202 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, 1203 }; 1204 1205 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1206 for (size_t i = 0; i < num_snippets; i++) { 1207 ScopedVector<char> script(1024); 1208 SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName, 1209 snippets[i].code_snippet, kFunctionName); 1210 BytecodeGraphTester tester(isolate, zone, script.start()); 1211 auto callable = tester.GetCallable<Handle<Object>>(); 1212 Handle<Object> return_value = 1213 callable(snippets[i].parameter(0)).ToHandleChecked(); 1214 CHECK(return_value->SameValue(*snippets[i].return_value())); 1215 } 1216 } 1217 1218 1219 TEST(BytecodeGraphBuilderEvalGlobal) { 1220 HandleAndZoneScope scope; 1221 Isolate* isolate = scope.main_isolate(); 1222 Zone* zone = scope.main_zone(); 1223 Factory* factory = isolate->factory(); 1224 1225 ExpectedSnippet<0> snippets[] = { 1226 {"function add_global() { eval('function f() { z = 33; }; f()'); };" 1227 "function f() { add_global(); return z; }; f();", 1228 {handle(Smi::FromInt(33), isolate)}}, 1229 {"function add_global() {\n" 1230 " eval('\"use strict\"; function f() { y = 33; };" 1231 " try { f() } catch(e) {}');\n" 1232 "}\n" 1233 "function f() { add_global(); return typeof y; } f();", 1234 {factory->NewStringFromStaticChars("undefined")}}, 1235 }; 1236 1237 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1238 for (size_t i = 0; i < num_snippets; i++) { 1239 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); 1240 auto callable = tester.GetCallable<>(); 1241 Handle<Object> return_value = callable().ToHandleChecked(); 1242 CHECK(return_value->SameValue(*snippets[i].return_value())); 1243 } 1244 } 1245 1246 1247 bool get_compare_result(Token::Value opcode, Handle<Object> lhs_value, 1248 Handle<Object> rhs_value) { 1249 switch (opcode) { 1250 case Token::Value::EQ: 1251 return Object::Equals(lhs_value, rhs_value).FromJust(); 1252 case Token::Value::NE: 1253 return !Object::Equals(lhs_value, rhs_value).FromJust(); 1254 case Token::Value::EQ_STRICT: 1255 return lhs_value->StrictEquals(*rhs_value); 1256 case Token::Value::NE_STRICT: 1257 return !lhs_value->StrictEquals(*rhs_value); 1258 case Token::Value::LT: 1259 return Object::LessThan(lhs_value, rhs_value).FromJust(); 1260 case Token::Value::LTE: 1261 return Object::LessThanOrEqual(lhs_value, rhs_value).FromJust(); 1262 case Token::Value::GT: 1263 return Object::GreaterThan(lhs_value, rhs_value).FromJust(); 1264 case Token::Value::GTE: 1265 return Object::GreaterThanOrEqual(lhs_value, rhs_value).FromJust(); 1266 default: 1267 UNREACHABLE(); 1268 return false; 1269 } 1270 } 1271 1272 1273 const char* get_code_snippet(Token::Value opcode) { 1274 switch (opcode) { 1275 case Token::Value::EQ: 1276 return "return p1 == p2;"; 1277 case Token::Value::NE: 1278 return "return p1 != p2;"; 1279 case Token::Value::EQ_STRICT: 1280 return "return p1 === p2;"; 1281 case Token::Value::NE_STRICT: 1282 return "return p1 !== p2;"; 1283 case Token::Value::LT: 1284 return "return p1 < p2;"; 1285 case Token::Value::LTE: 1286 return "return p1 <= p2;"; 1287 case Token::Value::GT: 1288 return "return p1 > p2;"; 1289 case Token::Value::GTE: 1290 return "return p1 >= p2;"; 1291 default: 1292 UNREACHABLE(); 1293 return ""; 1294 } 1295 } 1296 1297 1298 TEST(BytecodeGraphBuilderCompare) { 1299 HandleAndZoneScope scope; 1300 Isolate* isolate = scope.main_isolate(); 1301 Zone* zone = scope.main_zone(); 1302 Factory* factory = isolate->factory(); 1303 Handle<Object> lhs_values[] = { 1304 factory->NewNumberFromInt(10), factory->NewHeapNumber(3.45), 1305 factory->NewStringFromStaticChars("abc"), 1306 factory->NewNumberFromInt(SMI_MAX), factory->NewNumberFromInt(SMI_MIN)}; 1307 Handle<Object> rhs_values[] = {factory->NewNumberFromInt(10), 1308 factory->NewStringFromStaticChars("10"), 1309 factory->NewNumberFromInt(20), 1310 factory->NewStringFromStaticChars("abc"), 1311 factory->NewHeapNumber(3.45), 1312 factory->NewNumberFromInt(SMI_MAX), 1313 factory->NewNumberFromInt(SMI_MIN)}; 1314 1315 for (size_t i = 0; i < arraysize(kCompareOperators); i++) { 1316 ScopedVector<char> script(1024); 1317 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, 1318 get_code_snippet(kCompareOperators[i]), kFunctionName); 1319 1320 BytecodeGraphTester tester(isolate, zone, script.start()); 1321 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 1322 for (size_t j = 0; j < arraysize(lhs_values); j++) { 1323 for (size_t k = 0; k < arraysize(rhs_values); k++) { 1324 Handle<Object> return_value = 1325 callable(lhs_values[j], rhs_values[k]).ToHandleChecked(); 1326 bool result = get_compare_result(kCompareOperators[i], lhs_values[j], 1327 rhs_values[k]); 1328 CHECK(return_value->SameValue(*factory->ToBoolean(result))); 1329 } 1330 } 1331 } 1332 } 1333 1334 1335 TEST(BytecodeGraphBuilderTestIn) { 1336 HandleAndZoneScope scope; 1337 Isolate* isolate = scope.main_isolate(); 1338 Zone* zone = scope.main_zone(); 1339 Factory* factory = isolate->factory(); 1340 1341 ExpectedSnippet<2> snippets[] = { 1342 {"return p2 in p1;", 1343 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1344 factory->NewStringFromStaticChars("val")}}, 1345 {"return p2 in p1;", 1346 {factory->true_value(), BytecodeGraphTester::NewObject("[]"), 1347 factory->NewStringFromStaticChars("length")}}, 1348 {"return p2 in p1;", 1349 {factory->true_value(), BytecodeGraphTester::NewObject("[]"), 1350 factory->NewStringFromStaticChars("toString")}}, 1351 {"return p2 in p1;", 1352 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1353 factory->NewStringFromStaticChars("toString")}}, 1354 {"return p2 in p1;", 1355 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1356 factory->NewStringFromStaticChars("abc")}}, 1357 {"return p2 in p1;", 1358 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"), 1359 factory->NewNumberFromInt(10)}}, 1360 {"return p2 in p1;", 1361 {factory->true_value(), BytecodeGraphTester::NewObject("({10 : 'val'})"), 1362 factory->NewNumberFromInt(10)}}, 1363 {"return p2 in p1;", 1364 {factory->false_value(), 1365 BytecodeGraphTester::NewObject("({10 : 'val'})"), 1366 factory->NewNumberFromInt(1)}}, 1367 }; 1368 1369 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1370 for (size_t i = 0; i < num_snippets; i++) { 1371 ScopedVector<char> script(1024); 1372 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, 1373 snippets[i].code_snippet, kFunctionName); 1374 1375 BytecodeGraphTester tester(isolate, zone, script.start()); 1376 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 1377 Handle<Object> return_value = 1378 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 1379 .ToHandleChecked(); 1380 CHECK(return_value->SameValue(*snippets[i].return_value())); 1381 } 1382 } 1383 1384 1385 TEST(BytecodeGraphBuilderTestInstanceOf) { 1386 HandleAndZoneScope scope; 1387 Isolate* isolate = scope.main_isolate(); 1388 Zone* zone = scope.main_zone(); 1389 Factory* factory = isolate->factory(); 1390 1391 ExpectedSnippet<1> snippets[] = { 1392 {"return p1 instanceof Object;", 1393 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, 1394 {"return p1 instanceof String;", 1395 {factory->false_value(), factory->NewStringFromStaticChars("string")}}, 1396 {"var cons = function() {};" 1397 "var obj = new cons();" 1398 "return obj instanceof cons;", 1399 {factory->true_value(), factory->undefined_value()}}, 1400 }; 1401 1402 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1403 for (size_t i = 0; i < num_snippets; i++) { 1404 ScopedVector<char> script(1024); 1405 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, 1406 snippets[i].code_snippet, kFunctionName); 1407 1408 BytecodeGraphTester tester(isolate, zone, script.start()); 1409 auto callable = tester.GetCallable<Handle<Object>>(); 1410 Handle<Object> return_value = 1411 callable(snippets[i].parameter(0)).ToHandleChecked(); 1412 CHECK(return_value->SameValue(*snippets[i].return_value())); 1413 } 1414 } 1415 1416 1417 TEST(BytecodeGraphBuilderThrow) { 1418 HandleAndZoneScope scope; 1419 Isolate* isolate = scope.main_isolate(); 1420 Zone* zone = scope.main_zone(); 1421 1422 // TODO(mythria): Add more tests when real try-catch and deoptimization 1423 // information are supported. 1424 ExpectedSnippet<0, const char*> snippets[] = { 1425 {"throw undefined;", {"Uncaught undefined"}}, 1426 {"throw 1;", {"Uncaught 1"}}, 1427 {"throw 'Error';", {"Uncaught Error"}}, 1428 {"throw 'Error1'; throw 'Error2'", {"Uncaught Error1"}}, 1429 // TODO(mythria): Enable these tests when JumpIfTrue is supported. 1430 // {"var a = true; if (a) { throw 'Error'; }", {"Error"}}, 1431 }; 1432 1433 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1434 for (size_t i = 0; i < num_snippets; i++) { 1435 ScopedVector<char> script(1024); 1436 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1437 snippets[i].code_snippet, kFunctionName); 1438 BytecodeGraphTester tester(isolate, zone, script.start()); 1439 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); 1440 v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); 1441 CHECK( 1442 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) 1443 .FromJust()); 1444 } 1445 } 1446 1447 1448 TEST(BytecodeGraphBuilderContext) { 1449 HandleAndZoneScope scope; 1450 Isolate* isolate = scope.main_isolate(); 1451 Zone* zone = scope.main_zone(); 1452 Factory* factory = isolate->factory(); 1453 1454 ExpectedSnippet<0> snippets[] = { 1455 {"var x = 'outer';" 1456 "function f() {" 1457 " 'use strict';" 1458 " {" 1459 " let x = 'inner';" 1460 " (function() {x});" 1461 " }" 1462 "return(x);" 1463 "}" 1464 "f();", 1465 {factory->NewStringFromStaticChars("outer")}}, 1466 {"var x = 'outer';" 1467 "function f() {" 1468 " 'use strict';" 1469 " {" 1470 " let x = 'inner ';" 1471 " var innerFunc = function() {return x};" 1472 " }" 1473 "return(innerFunc() + x);" 1474 "}" 1475 "f();", 1476 {factory->NewStringFromStaticChars("inner outer")}}, 1477 {"var x = 'outer';" 1478 "function f() {" 1479 " 'use strict';" 1480 " {" 1481 " let x = 'inner ';" 1482 " var innerFunc = function() {return x;};" 1483 " {" 1484 " let x = 'innermost ';" 1485 " var innerMostFunc = function() {return x + innerFunc();};" 1486 " }" 1487 " x = 'inner_changed ';" 1488 " }" 1489 " return(innerMostFunc() + x);" 1490 "}" 1491 "f();", 1492 {factory->NewStringFromStaticChars("innermost inner_changed outer")}}, 1493 }; 1494 1495 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1496 for (size_t i = 0; i < num_snippets; i++) { 1497 ScopedVector<char> script(1024); 1498 SNPrintF(script, "%s", snippets[i].code_snippet); 1499 1500 BytecodeGraphTester tester(isolate, zone, script.start(), "f"); 1501 auto callable = tester.GetCallable<>("f"); 1502 Handle<Object> return_value = callable().ToHandleChecked(); 1503 CHECK(return_value->SameValue(*snippets[i].return_value())); 1504 } 1505 } 1506 1507 1508 TEST(BytecodeGraphBuilderLoadContext) { 1509 HandleAndZoneScope scope; 1510 Isolate* isolate = scope.main_isolate(); 1511 Zone* zone = scope.main_zone(); 1512 Factory* factory = isolate->factory(); 1513 1514 ExpectedSnippet<1> snippets[] = { 1515 {"function Outer() {" 1516 " var outerVar = 2;" 1517 " function Inner(innerArg) {" 1518 " this.innerFunc = function () {" 1519 " return outerVar * innerArg;" 1520 " };" 1521 " };" 1522 " this.getInnerFunc = function GetInner() {" 1523 " return new Inner(3).innerFunc;" 1524 " }" 1525 "}" 1526 "var f = new Outer().getInnerFunc();" 1527 "f();", 1528 {factory->NewNumberFromInt(6), factory->undefined_value()}}, 1529 {"function Outer() {" 1530 " var outerVar = 2;" 1531 " function Inner(innerArg) {" 1532 " this.innerFunc = function () {" 1533 " outerVar = innerArg; return outerVar;" 1534 " };" 1535 " };" 1536 " this.getInnerFunc = function GetInner() {" 1537 " return new Inner(10).innerFunc;" 1538 " }" 1539 "}" 1540 "var f = new Outer().getInnerFunc();" 1541 "f();", 1542 {factory->NewNumberFromInt(10), factory->undefined_value()}}, 1543 {"function testOuter(outerArg) {" 1544 " this.testinnerFunc = function testInner(innerArg) {" 1545 " return innerArg + outerArg;" 1546 " }" 1547 "}" 1548 "var f = new testOuter(10).testinnerFunc;" 1549 "f(0);", 1550 {factory->NewNumberFromInt(14), factory->NewNumberFromInt(4)}}, 1551 {"function testOuter(outerArg) {" 1552 " var outerVar = outerArg * 2;" 1553 " this.testinnerFunc = function testInner(innerArg) {" 1554 " outerVar = outerVar + innerArg; return outerVar;" 1555 " }" 1556 "}" 1557 "var f = new testOuter(10).testinnerFunc;" 1558 "f(0);", 1559 {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}}; 1560 1561 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1562 for (size_t i = 0; i < num_snippets; i++) { 1563 ScopedVector<char> script(1024); 1564 SNPrintF(script, "%s", snippets[i].code_snippet); 1565 1566 BytecodeGraphTester tester(isolate, zone, script.start(), "*"); 1567 auto callable = tester.GetCallable<Handle<Object>>("f"); 1568 Handle<Object> return_value = 1569 callable(snippets[i].parameter(0)).ToHandleChecked(); 1570 CHECK(return_value->SameValue(*snippets[i].return_value())); 1571 } 1572 } 1573 1574 1575 TEST(BytecodeGraphBuilderCreateArgumentsNoParameters) { 1576 HandleAndZoneScope scope; 1577 Isolate* isolate = scope.main_isolate(); 1578 Zone* zone = scope.main_zone(); 1579 Factory* factory = isolate->factory(); 1580 1581 ExpectedSnippet<0> snippets[] = { 1582 {"function f() {return arguments[0];}", {factory->undefined_value()}}, 1583 {"function f(a) {return arguments[0];}", {factory->undefined_value()}}, 1584 {"function f() {'use strict'; return arguments[0];}", 1585 {factory->undefined_value()}}, 1586 {"function f(a) {'use strict'; return arguments[0];}", 1587 {factory->undefined_value()}}, 1588 }; 1589 1590 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1591 for (size_t i = 0; i < num_snippets; i++) { 1592 ScopedVector<char> script(1024); 1593 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); 1594 1595 BytecodeGraphTester tester(isolate, zone, script.start()); 1596 auto callable = tester.GetCallable<>(); 1597 Handle<Object> return_value = callable().ToHandleChecked(); 1598 CHECK(return_value->SameValue(*snippets[i].return_value())); 1599 } 1600 } 1601 1602 1603 TEST(BytecodeGraphBuilderCreateArguments) { 1604 HandleAndZoneScope scope; 1605 Isolate* isolate = scope.main_isolate(); 1606 Zone* zone = scope.main_zone(); 1607 Factory* factory = isolate->factory(); 1608 1609 ExpectedSnippet<3> snippets[] = { 1610 {"function f(a, b, c) {return arguments[0];}", 1611 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), 1612 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1613 {"function f(a, b, c) {return arguments[3];}", 1614 {factory->undefined_value(), factory->NewNumberFromInt(1), 1615 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1616 {"function f(a, b, c) { b = c; return arguments[1];}", 1617 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1618 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1619 {"function f(a, b, c) {'use strict'; return arguments[0];}", 1620 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), 1621 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1622 {"function f(a, b, c) {'use strict'; return arguments[3];}", 1623 {factory->undefined_value(), factory->NewNumberFromInt(1), 1624 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1625 {"function f(a, b, c) {'use strict'; b = c; return arguments[1];}", 1626 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1), 1627 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1628 {"function inline_func(a, b) { return arguments[0] }" 1629 "function f(a, b, c) {return inline_func(b, c) + arguments[0];}", 1630 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1631 factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, 1632 }; 1633 1634 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1635 for (size_t i = 0; i < num_snippets; i++) { 1636 ScopedVector<char> script(1024); 1637 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); 1638 1639 BytecodeGraphTester tester(isolate, zone, script.start()); 1640 auto callable = 1641 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); 1642 Handle<Object> return_value = 1643 callable(snippets[i].parameter(0), snippets[i].parameter(1), 1644 snippets[i].parameter(2)) 1645 .ToHandleChecked(); 1646 CHECK(return_value->SameValue(*snippets[i].return_value())); 1647 } 1648 } 1649 1650 1651 TEST(BytecodeGraphBuilderRegExpLiterals) { 1652 HandleAndZoneScope scope; 1653 Isolate* isolate = scope.main_isolate(); 1654 Zone* zone = scope.main_zone(); 1655 Factory* factory = isolate->factory(); 1656 1657 ExpectedSnippet<0> snippets[] = { 1658 {"return /abd/.exec('cccabbdd');", {factory->null_value()}}, 1659 {"return /ab+d/.exec('cccabbdd')[0];", 1660 {factory->NewStringFromStaticChars("abbd")}}, 1661 {"var a = 3.1414;" 1662 REPEAT_256(SPACE, "a = 3.1414;") 1663 "return /ab+d/.exec('cccabbdd')[0];", 1664 {factory->NewStringFromStaticChars("abbd")}}, 1665 {"return /ab+d/.exec('cccabbdd')[1];", {factory->undefined_value()}}, 1666 {"return /AbC/i.exec('ssaBC')[0];", 1667 {factory->NewStringFromStaticChars("aBC")}}, 1668 {"return 'ssaBC'.match(/AbC/i)[0];", 1669 {factory->NewStringFromStaticChars("aBC")}}, 1670 {"return 'ssaBCtAbC'.match(/(AbC)/gi)[1];", 1671 {factory->NewStringFromStaticChars("AbC")}}, 1672 }; 1673 1674 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1675 for (size_t i = 0; i < num_snippets; i++) { 1676 ScopedVector<char> script(4096); 1677 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1678 snippets[i].code_snippet, kFunctionName); 1679 1680 BytecodeGraphTester tester(isolate, zone, script.start()); 1681 auto callable = tester.GetCallable<>(); 1682 Handle<Object> return_value = callable().ToHandleChecked(); 1683 CHECK(return_value->SameValue(*snippets[i].return_value())); 1684 } 1685 } 1686 1687 1688 TEST(BytecodeGraphBuilderArrayLiterals) { 1689 HandleAndZoneScope scope; 1690 Isolate* isolate = scope.main_isolate(); 1691 Zone* zone = scope.main_zone(); 1692 Factory* factory = isolate->factory(); 1693 1694 ExpectedSnippet<0> snippets[] = { 1695 {"return [][0];", {factory->undefined_value()}}, 1696 {"return [1, 3, 2][1];", {factory->NewNumberFromInt(3)}}, 1697 {"var a;" REPEAT_256(SPACE, "a = 9.87;") "return [1, 3, 2][1];", 1698 {factory->NewNumberFromInt(3)}}, 1699 {"return ['a', 'b', 'c'][2];", {factory->NewStringFromStaticChars("c")}}, 1700 {"var a = 100; return [a, a++, a + 2, a + 3][2];", 1701 {factory->NewNumberFromInt(103)}}, 1702 {"var a = 100; return [a, ++a, a + 2, a + 3][1];", 1703 {factory->NewNumberFromInt(101)}}, 1704 {"var a = 9.2;" 1705 REPEAT_256(SPACE, "a = 9.34;") 1706 "return [a, ++a, a + 2, a + 3][2];", 1707 {factory->NewHeapNumber(12.34)}}, 1708 {"return [[1, 2, 3], ['a', 'b', 'c']][1][0];", 1709 {factory->NewStringFromStaticChars("a")}}, 1710 {"var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];", 1711 {factory->NewStringFromStaticChars("test")}}, 1712 {"var t = 't'; return [[t, t + 'est'], [1 + t]][1][0];", 1713 {factory->NewStringFromStaticChars("1t")}}}; 1714 1715 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1716 for (size_t i = 0; i < num_snippets; i++) { 1717 ScopedVector<char> script(4096); 1718 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1719 snippets[i].code_snippet, kFunctionName); 1720 1721 BytecodeGraphTester tester(isolate, zone, script.start()); 1722 auto callable = tester.GetCallable<>(); 1723 Handle<Object> return_value = callable().ToHandleChecked(); 1724 CHECK(return_value->SameValue(*snippets[i].return_value())); 1725 } 1726 } 1727 1728 1729 TEST(BytecodeGraphBuilderObjectLiterals) { 1730 HandleAndZoneScope scope; 1731 Isolate* isolate = scope.main_isolate(); 1732 Zone* zone = scope.main_zone(); 1733 Factory* factory = isolate->factory(); 1734 1735 ExpectedSnippet<0> snippets[] = { 1736 {"return { }.name;", {factory->undefined_value()}}, 1737 {"return { name: 'string', val: 9.2 }.name;", 1738 {factory->NewStringFromStaticChars("string")}}, 1739 {"var a;\n" 1740 REPEAT_256(SPACE, "a = 1.23;\n") 1741 "return { name: 'string', val: 9.2 }.name;", 1742 {factory->NewStringFromStaticChars("string")}}, 1743 {"return { name: 'string', val: 9.2 }['name'];", 1744 {factory->NewStringFromStaticChars("string")}}, 1745 {"var a = 15; return { name: 'string', val: a }.val;", 1746 {factory->NewNumberFromInt(15)}}, 1747 {"var a;" 1748 REPEAT_256(SPACE, "a = 1.23;") 1749 "return { name: 'string', val: a }.val;", 1750 {factory->NewHeapNumber(1.23)}}, 1751 {"var a = 15; var b = 'val'; return { name: 'string', val: a }[b];", 1752 {factory->NewNumberFromInt(15)}}, 1753 {"var a = 5; return { val: a, val: a + 1 }.val;", 1754 {factory->NewNumberFromInt(6)}}, 1755 {"return { func: function() { return 'test' } }.func();", 1756 {factory->NewStringFromStaticChars("test")}}, 1757 {"return { func(a) { return a + 'st'; } }.func('te');", 1758 {factory->NewStringFromStaticChars("test")}}, 1759 {"return { get a() { return 22; } }.a;", {factory->NewNumberFromInt(22)}}, 1760 {"var a = { get b() { return this.x + 't'; },\n" 1761 " set b(val) { this.x = val + 's' } };\n" 1762 "a.b = 'te';\n" 1763 "return a.b;", 1764 {factory->NewStringFromStaticChars("test")}}, 1765 {"var a = 123; return { 1: a }[1];", {factory->NewNumberFromInt(123)}}, 1766 {"return Object.getPrototypeOf({ __proto__: null });", 1767 {factory->null_value()}}, 1768 {"var a = 'test'; return { [a]: 1 }.test;", 1769 {factory->NewNumberFromInt(1)}}, 1770 {"var a = 'test'; return { b: a, [a]: a + 'ing' }['test']", 1771 {factory->NewStringFromStaticChars("testing")}}, 1772 {"var a = 'proto_str';\n" 1773 "var b = { [a]: 1, __proto__: { var : a } };\n" 1774 "return Object.getPrototypeOf(b).var", 1775 {factory->NewStringFromStaticChars("proto_str")}}, 1776 {"var n = 'name';\n" 1777 "return { [n]: 'val', get a() { return 987 } }['a'];", 1778 {factory->NewNumberFromInt(987)}}, 1779 }; 1780 1781 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1782 for (size_t i = 0; i < num_snippets; i++) { 1783 ScopedVector<char> script(4096); 1784 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 1785 snippets[i].code_snippet, kFunctionName); 1786 BytecodeGraphTester tester(isolate, zone, script.start()); 1787 auto callable = tester.GetCallable<>(); 1788 Handle<Object> return_value = callable().ToHandleChecked(); 1789 CHECK(return_value->SameValue(*snippets[i].return_value())); 1790 } 1791 } 1792 1793 1794 TEST(BytecodeGraphBuilderIf) { 1795 HandleAndZoneScope scope; 1796 Isolate* isolate = scope.main_isolate(); 1797 Zone* zone = scope.main_zone(); 1798 Factory* factory = isolate->factory(); 1799 1800 ExpectedSnippet<1> snippets[] = { 1801 {"if (p1 > 1) return 1;\n" 1802 "return -1;", 1803 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1804 {"if (p1 > 1) return 1;\n" 1805 "return -1;", 1806 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}}, 1807 {"if (p1 > 1) { return 1; } else { return -1; }", 1808 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1809 {"if (p1 > 1) { return 1; } else { return -1; }", 1810 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}}, 1811 {"if (p1 > 50) {\n" 1812 " return 1;\n" 1813 "} else if (p1 < 10) {\n" 1814 " return 10;\n" 1815 "} else {\n" 1816 " return -10;\n" 1817 "}", 1818 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(51)}}, 1819 {"if (p1 > 50) {\n" 1820 " return 1;\n" 1821 "} else if (p1 < 10) {\n" 1822 " return 10;\n" 1823 "} else {\n" 1824 " return 100;\n" 1825 "}", 1826 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}}, 1827 {"if (p1 > 50) {\n" 1828 " return 1;\n" 1829 "} else if (p1 < 10) {\n" 1830 " return 10;\n" 1831 "} else {\n" 1832 " return 100;\n" 1833 "}", 1834 {factory->NewNumberFromInt(100), factory->NewNumberFromInt(10)}}, 1835 {"if (p1 >= 0) {\n" 1836 " if (p1 > 10) { return 2; } else { return 1; }\n" 1837 "} else {\n" 1838 " if (p1 < -10) { return -2; } else { return -1; }\n" 1839 "}", 1840 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(100)}}, 1841 {"if (p1 >= 0) {\n" 1842 " if (p1 > 10) { return 2; } else { return 1; }\n" 1843 "} else {\n" 1844 " if (p1 < -10) { return -2; } else { return -1; }\n" 1845 "}", 1846 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(10)}}, 1847 {"if (p1 >= 0) {\n" 1848 " if (p1 > 10) { return 2; } else { return 1; }\n" 1849 "} else {\n" 1850 " if (p1 < -10) { return -2; } else { return -1; }\n" 1851 "}", 1852 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(-11)}}, 1853 {"if (p1 >= 0) {\n" 1854 " if (p1 > 10) { return 2; } else { return 1; }\n" 1855 "} else {\n" 1856 " if (p1 < -10) { return -2; } else { return -1; }\n" 1857 "}", 1858 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-10)}}, 1859 }; 1860 1861 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1862 for (size_t i = 0; i < num_snippets; i++) { 1863 ScopedVector<char> script(2048); 1864 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 1865 snippets[i].code_snippet, kFunctionName); 1866 1867 BytecodeGraphTester tester(isolate, zone, script.start()); 1868 auto callable = tester.GetCallable<Handle<Object>>(); 1869 Handle<Object> return_value = 1870 callable(snippets[i].parameter(0)).ToHandleChecked(); 1871 CHECK(return_value->SameValue(*snippets[i].return_value())); 1872 } 1873 } 1874 1875 1876 TEST(BytecodeGraphBuilderConditionalOperator) { 1877 HandleAndZoneScope scope; 1878 Isolate* isolate = scope.main_isolate(); 1879 Zone* zone = scope.main_zone(); 1880 Factory* factory = isolate->factory(); 1881 1882 ExpectedSnippet<1> snippets[] = { 1883 {"return (p1 > 1) ? 1 : -1;", 1884 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1885 {"return (p1 > 1) ? 1 : -1;", 1886 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0)}}, 1887 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);", 1888 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(2)}}, 1889 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);", 1890 {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(20)}}, 1891 }; 1892 1893 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); 1894 for (size_t i = 0; i < num_snippets; i++) { 1895 ScopedVector<char> script(2048); 1896 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 1897 snippets[i].code_snippet, kFunctionName); 1898 1899 BytecodeGraphTester tester(isolate, zone, script.start()); 1900 auto callable = tester.GetCallable<Handle<Object>>(); 1901 Handle<Object> return_value = 1902 callable(snippets[i].parameter(0)).ToHandleChecked(); 1903 CHECK(return_value->SameValue(*snippets[i].return_value())); 1904 } 1905 } 1906 1907 1908 TEST(BytecodeGraphBuilderSwitch) { 1909 HandleAndZoneScope scope; 1910 Isolate* isolate = scope.main_isolate(); 1911 Zone* zone = scope.main_zone(); 1912 Factory* factory = isolate->factory(); 1913 1914 const char* switch_code = 1915 "switch (p1) {\n" 1916 " case 1: return 0;\n" 1917 " case 2: return 1;\n" 1918 " case 3:\n" 1919 " case 4: return 2;\n" 1920 " case 9: break;\n" 1921 " default: return 3;\n" 1922 "}\n" 1923 "return 9;"; 1924 1925 ExpectedSnippet<1> snippets[] = { 1926 {switch_code, 1927 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(1)}}, 1928 {switch_code, 1929 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}}, 1930 {switch_code, 1931 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, 1932 {switch_code, 1933 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}}, 1934 {switch_code, 1935 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(9)}}, 1936 {switch_code, 1937 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}}, 1938 {switch_code, 1939 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(6)}}, 1940 }; 1941 1942 for (size_t i = 0; i < arraysize(snippets); i++) { 1943 ScopedVector<char> script(2048); 1944 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, 1945 snippets[i].code_snippet, kFunctionName); 1946 1947 BytecodeGraphTester tester(isolate, zone, script.start()); 1948 auto callable = tester.GetCallable<Handle<Object>>(); 1949 Handle<Object> return_value = 1950 callable(snippets[i].parameter(0)).ToHandleChecked(); 1951 CHECK(return_value->SameValue(*snippets[i].return_value())); 1952 } 1953 } 1954 1955 1956 TEST(BytecodeGraphBuilderNestedSwitch) { 1957 HandleAndZoneScope scope; 1958 Isolate* isolate = scope.main_isolate(); 1959 Zone* zone = scope.main_zone(); 1960 Factory* factory = isolate->factory(); 1961 1962 const char* switch_code = 1963 "switch (p1) {\n" 1964 " case 0: {" 1965 " switch (p2) { case 0: return 0; case 1: return 1; case 2: break; }\n" 1966 " return -1;" 1967 " }\n" 1968 " case 1: {" 1969 " switch (p2) { case 0: return 2; case 1: return 3; }\n" 1970 " }\n" 1971 " case 2: break;" 1972 " }\n" 1973 "return -2;"; 1974 1975 ExpectedSnippet<2> snippets[] = { 1976 {switch_code, 1977 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(0), 1978 factory->NewNumberFromInt(0)}}, 1979 {switch_code, 1980 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(0), 1981 factory->NewNumberFromInt(1)}}, 1982 {switch_code, 1983 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0), 1984 factory->NewNumberFromInt(2)}}, 1985 {switch_code, 1986 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0), 1987 factory->NewNumberFromInt(3)}}, 1988 {switch_code, 1989 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1), 1990 factory->NewNumberFromInt(0)}}, 1991 {switch_code, 1992 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), 1993 factory->NewNumberFromInt(1)}}, 1994 {switch_code, 1995 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(1), 1996 factory->NewNumberFromInt(2)}}, 1997 {switch_code, 1998 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(2), 1999 factory->NewNumberFromInt(0)}}, 2000 }; 2001 2002 for (size_t i = 0; i < arraysize(snippets); i++) { 2003 ScopedVector<char> script(2048); 2004 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0, 0);", kFunctionName, 2005 snippets[i].code_snippet, kFunctionName); 2006 2007 BytecodeGraphTester tester(isolate, zone, script.start()); 2008 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); 2009 Handle<Object> return_value = 2010 callable(snippets[i].parameter(0), snippets[i].parameter(1)) 2011 .ToHandleChecked(); 2012 CHECK(return_value->SameValue(*snippets[i].return_value())); 2013 } 2014 } 2015 2016 2017 TEST(BytecodeGraphBuilderBreakableBlocks) { 2018 HandleAndZoneScope scope; 2019 Isolate* isolate = scope.main_isolate(); 2020 Zone* zone = scope.main_zone(); 2021 Factory* factory = isolate->factory(); 2022 2023 ExpectedSnippet<0> snippets[] = { 2024 {"var x = 0;\n" 2025 "my_heart: {\n" 2026 " x = x + 1;\n" 2027 " break my_heart;\n" 2028 " x = x + 2;\n" 2029 "}\n" 2030 "return x;\n", 2031 {factory->NewNumberFromInt(1)}}, 2032 {"var sum = 0;\n" 2033 "outta_here: {\n" 2034 " for (var x = 0; x < 10; ++x) {\n" 2035 " for (var y = 0; y < 3; ++y) {\n" 2036 " ++sum;\n" 2037 " if (x + y == 12) { break outta_here; }\n" 2038 " }\n" 2039 " }\n" 2040 "}\n" 2041 "return sum;", 2042 {factory->NewNumber(30)}}, 2043 }; 2044 2045 for (size_t i = 0; i < arraysize(snippets); i++) { 2046 ScopedVector<char> script(1024); 2047 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2048 snippets[i].code_snippet, kFunctionName); 2049 2050 BytecodeGraphTester tester(isolate, zone, script.start()); 2051 auto callable = tester.GetCallable<>(); 2052 Handle<Object> return_value = callable().ToHandleChecked(); 2053 CHECK(return_value->SameValue(*snippets[i].return_value())); 2054 } 2055 } 2056 2057 2058 TEST(BytecodeGraphBuilderWhile) { 2059 HandleAndZoneScope scope; 2060 Isolate* isolate = scope.main_isolate(); 2061 Zone* zone = scope.main_zone(); 2062 Factory* factory = isolate->factory(); 2063 2064 ExpectedSnippet<0> snippets[] = { 2065 {"var x = 1; while (x < 1) { x *= 100; } return x;", 2066 {factory->NewNumberFromInt(1)}}, 2067 {"var x = 1, y = 0; while (x < 7) { y += x * x; x += 1; } return y;", 2068 {factory->NewNumberFromInt(91)}}, 2069 {"var x = 1; while (true) { x += 1; if (x == 10) break; } return x;", 2070 {factory->NewNumberFromInt(10)}}, 2071 {"var x = 1; while (false) { x += 1; } return x;", 2072 {factory->NewNumberFromInt(1)}}, 2073 {"var x = 0;\n" 2074 "while (true) {\n" 2075 " while (x < 10) {\n" 2076 " x = x * x + 1;\n" 2077 " }" 2078 " x += 1;\n" 2079 " break;\n" 2080 "}\n" 2081 "return x;", 2082 {factory->NewNumberFromInt(27)}}, 2083 {"var x = 1, y = 0;\n" 2084 "while (x < 7) {\n" 2085 " x += 1;\n" 2086 " if (x == 2) continue;\n" 2087 " if (x == 3) continue;\n" 2088 " y += x * x;\n" 2089 " if (x == 4) break;\n" 2090 "}\n" 2091 "return y;", 2092 {factory->NewNumberFromInt(16)}}}; 2093 2094 for (size_t i = 0; i < arraysize(snippets); i++) { 2095 ScopedVector<char> script(1024); 2096 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2097 snippets[i].code_snippet, kFunctionName); 2098 2099 BytecodeGraphTester tester(isolate, zone, script.start()); 2100 auto callable = tester.GetCallable<>(); 2101 Handle<Object> return_value = callable().ToHandleChecked(); 2102 CHECK(return_value->SameValue(*snippets[i].return_value())); 2103 } 2104 } 2105 2106 2107 TEST(BytecodeGraphBuilderDo) { 2108 HandleAndZoneScope scope; 2109 Isolate* isolate = scope.main_isolate(); 2110 Zone* zone = scope.main_zone(); 2111 Factory* factory = isolate->factory(); 2112 2113 ExpectedSnippet<0> snippets[] = { 2114 {"var x = 1; do { x *= 100; } while (x < 100); return x;", 2115 {factory->NewNumberFromInt(100)}}, 2116 {"var x = 1; do { x = x * x + 1; } while (x < 7) return x;", 2117 {factory->NewNumberFromInt(26)}}, 2118 {"var x = 1; do { x += 1; } while (false); return x;", 2119 {factory->NewNumberFromInt(2)}}, 2120 {"var x = 1, y = 0;\n" 2121 "do {\n" 2122 " x += 1;\n" 2123 " if (x == 2) continue;\n" 2124 " if (x == 3) continue;\n" 2125 " y += x * x;\n" 2126 " if (x == 4) break;\n" 2127 "} while (x < 7);\n" 2128 "return y;", 2129 {factory->NewNumberFromInt(16)}}}; 2130 2131 for (size_t i = 0; i < arraysize(snippets); i++) { 2132 ScopedVector<char> script(1024); 2133 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2134 snippets[i].code_snippet, kFunctionName); 2135 2136 BytecodeGraphTester tester(isolate, zone, script.start()); 2137 auto callable = tester.GetCallable<>(); 2138 Handle<Object> return_value = callable().ToHandleChecked(); 2139 CHECK(return_value->SameValue(*snippets[i].return_value())); 2140 } 2141 } 2142 2143 2144 TEST(BytecodeGraphBuilderFor) { 2145 HandleAndZoneScope scope; 2146 Isolate* isolate = scope.main_isolate(); 2147 Zone* zone = scope.main_zone(); 2148 Factory* factory = isolate->factory(); 2149 2150 ExpectedSnippet<0> snippets[] = { 2151 {"for (var x = 0;; x = 2 * x + 1) { if (x > 10) return x; }", 2152 {factory->NewNumberFromInt(15)}}, 2153 {"for (var x = 0; true; x = 2 * x + 1) { if (x > 100) return x; }", 2154 {factory->NewNumberFromInt(127)}}, 2155 {"for (var x = 0; false; x = 2 * x + 1) { if (x > 100) return x; } " 2156 "return 0;", 2157 {factory->NewNumberFromInt(0)}}, 2158 {"for (var x = 0; x < 200; x = 2 * x + 1) { x = x; } return x;", 2159 {factory->NewNumberFromInt(255)}}, 2160 {"for (var x = 0; x < 200; x = 2 * x + 1) {} return x;", 2161 {factory->NewNumberFromInt(255)}}, 2162 {"var sum = 0;\n" 2163 "for (var x = 0; x < 200; x += 1) {\n" 2164 " if (x % 2) continue;\n" 2165 " if (sum > 10) break;\n" 2166 " sum += x;\n" 2167 "}\n" 2168 "return sum;", 2169 {factory->NewNumberFromInt(12)}}, 2170 {"var sum = 0;\n" 2171 "for (var w = 0; w < 2; w++) {\n" 2172 " for (var x = 0; x < 200; x += 1) {\n" 2173 " if (x % 2) continue;\n" 2174 " if (x > 4) break;\n" 2175 " sum += x + w;\n" 2176 " }\n" 2177 "}\n" 2178 "return sum;", 2179 {factory->NewNumberFromInt(15)}}, 2180 {"var sum = 0;\n" 2181 "for (var w = 0; w < 2; w++) {\n" 2182 " if (w == 1) break;\n" 2183 " for (var x = 0; x < 200; x += 1) {\n" 2184 " if (x % 2) continue;\n" 2185 " if (x > 4) break;\n" 2186 " sum += x + w;\n" 2187 " }\n" 2188 "}\n" 2189 "return sum;", 2190 {factory->NewNumberFromInt(6)}}, 2191 {"var sum = 0;\n" 2192 "for (var w = 0; w < 3; w++) {\n" 2193 " if (w == 1) continue;\n" 2194 " for (var x = 0; x < 200; x += 1) {\n" 2195 " if (x % 2) continue;\n" 2196 " if (x > 4) break;\n" 2197 " sum += x + w;\n" 2198 " }\n" 2199 "}\n" 2200 "return sum;", 2201 {factory->NewNumberFromInt(18)}}, 2202 {"var sum = 0;\n" 2203 "for (var x = 1; x < 10; x += 2) {\n" 2204 " for (var y = x; y < x + 2; y++) {\n" 2205 " sum += y * y;\n" 2206 " }\n" 2207 "}\n" 2208 "return sum;", 2209 {factory->NewNumberFromInt(385)}}, 2210 }; 2211 2212 for (size_t i = 0; i < arraysize(snippets); i++) { 2213 ScopedVector<char> script(1024); 2214 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2215 snippets[i].code_snippet, kFunctionName); 2216 2217 BytecodeGraphTester tester(isolate, zone, script.start()); 2218 auto callable = tester.GetCallable<>(); 2219 Handle<Object> return_value = callable().ToHandleChecked(); 2220 CHECK(return_value->SameValue(*snippets[i].return_value())); 2221 } 2222 } 2223 2224 2225 TEST(BytecodeGraphBuilderForIn) { 2226 HandleAndZoneScope scope; 2227 Isolate* isolate = scope.main_isolate(); 2228 Zone* zone = scope.main_zone(); 2229 Factory* factory = isolate->factory(); 2230 ExpectedSnippet<0> snippets[] = { 2231 {"var sum = 0;\n" 2232 "var empty = null;\n" 2233 "for (var x in empty) { sum++; }\n" 2234 "return sum;", 2235 {factory->NewNumberFromInt(0)}}, 2236 {"var sum = 100;\n" 2237 "var empty = 1;\n" 2238 "for (var x in empty) { sum++; }\n" 2239 "return sum;", 2240 {factory->NewNumberFromInt(100)}}, 2241 {"for (var x in [ 10, 20, 30 ]) {}\n" 2242 "return 2;", 2243 {factory->NewNumberFromInt(2)}}, 2244 {"var last = 0;\n" 2245 "for (var x in [ 10, 20, 30 ]) {\n" 2246 " last = x;\n" 2247 "}\n" 2248 "return +last;", 2249 {factory->NewNumberFromInt(2)}}, 2250 {"var first = -1;\n" 2251 "for (var x in [ 10, 20, 30 ]) {\n" 2252 " first = +x;\n" 2253 " if (first > 0) break;\n" 2254 "}\n" 2255 "return first;", 2256 {factory->NewNumberFromInt(1)}}, 2257 {"var first = -1;\n" 2258 "for (var x in [ 10, 20, 30 ]) {\n" 2259 " if (first >= 0) continue;\n" 2260 " first = x;\n" 2261 "}\n" 2262 "return +first;", 2263 {factory->NewNumberFromInt(0)}}, 2264 {"var sum = 0;\n" 2265 "for (var x in [ 10, 20, 30 ]) {\n" 2266 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n" 2267 " sum += 1;\n" 2268 " }\n" 2269 "}\n" 2270 "return sum;", 2271 {factory->NewNumberFromInt(21)}}, 2272 {"var sum = 0;\n" 2273 "for (var x in [ 10, 20, 30 ]) {\n" 2274 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n" 2275 " if (sum == 7) break;\n" 2276 " if (sum == 6) continue;\n" 2277 " sum += 1;\n" 2278 " }\n" 2279 "}\n" 2280 "return sum;", 2281 {factory->NewNumberFromInt(6)}}, 2282 }; 2283 2284 for (size_t i = 0; i < arraysize(snippets); i++) { 2285 ScopedVector<char> script(1024); 2286 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, 2287 snippets[i].code_snippet, kFunctionName); 2288 2289 BytecodeGraphTester tester(isolate, zone, script.start()); 2290 auto callable = tester.GetCallable<>(); 2291 Handle<Object> return_value = callable().ToHandleChecked(); 2292 CHECK(return_value->SameValue(*snippets[i].return_value())); 2293 } 2294 } 2295 2296 2297 TEST(JumpWithConstantsAndWideConstants) { 2298 HandleAndZoneScope scope; 2299 auto isolate = scope.main_isolate(); 2300 const int kStep = 19; 2301 int start = 7; 2302 for (int constants = start; constants < 256 + 3 * kStep; constants += kStep) { 2303 std::stringstream filler_os; 2304 // Generate a string that consumes constant pool entries and 2305 // spread out branch distances in script below. 2306 for (int i = 0; i < constants; i++) { 2307 filler_os << "var x_ = 'x_" << i << "';\n"; 2308 } 2309 std::string filler(filler_os.str()); 2310 2311 std::stringstream script_os; 2312 script_os << "function " << kFunctionName << "(a) {\n"; 2313 script_os << " " << filler; 2314 script_os << " for (var i = a; i < 2; i++) {\n"; 2315 script_os << " " << filler; 2316 script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n"; 2317 script_os << " else if (i == a) { " << filler << "i = 12; break; }\n"; 2318 script_os << " else { " << filler << " }\n"; 2319 script_os << " }\n"; 2320 script_os << " return i;\n"; 2321 script_os << "}\n"; 2322 script_os << kFunctionName << "(0);\n"; 2323 std::string script(script_os.str()); 2324 auto factory = isolate->factory(); 2325 auto zone = scope.main_zone(); 2326 for (int a = 0; a < 3; a++) { 2327 BytecodeGraphTester tester(isolate, zone, script.c_str()); 2328 auto callable = tester.GetCallable<Handle<Object>>(); 2329 Handle<Object> return_val = 2330 callable(factory->NewNumberFromInt(a)).ToHandleChecked(); 2331 static const int results[] = {11, 12, 2}; 2332 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]); 2333 } 2334 } 2335 } 2336 2337 } // namespace compiler 2338 } // namespace internal 2339 } // namespace v8 2340