Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/compiler.h" | 5 #include "vm/compiler.h" |
| 6 #include "vm/dart_api_impl.h" | 6 #include "vm/dart_api_impl.h" |
| 7 #include "vm/dart_entry.h" | 7 #include "vm/dart_entry.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/unit_test.h" | 10 #include "vm/unit_test.h" |
| 11 | 11 |
| 12 namespace dart { | 12 namespace dart { |
| 13 | 13 |
| 14 #define DUMP_EXPECT(condition) \ | 14 #define DUMP_EXPECT(condition) \ |
|
rmacnak
2016/01/11 22:03:22
Maybe DUMP_ASSERT since this now behaves like ASSE
Cutch
2016/01/11 22:14:58
Done.
| |
| 15 if (!(condition)) { \ | 15 if (!(condition)) { \ |
| 16 dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \ | 16 dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \ |
| 17 THR_Print(">>> BEGIN source position table for `%s`\n", graph_name_); \ | 17 THR_Print(">>> BEGIN source position table for `%s`\n", graph_name_); \ |
| 18 Dump(); \ | 18 Dump(); \ |
| 19 THR_Print("<<< END source position table for `%s`\n", graph_name_); \ | 19 THR_Print("<<< END source position table for `%s`\n", graph_name_); \ |
| 20 OS::Abort(); \ | |
| 20 } | 21 } |
| 21 | 22 |
| 22 class SourcePositionTest : public ValueObject { | 23 class SourcePositionTest : public ValueObject { |
| 23 public: | 24 public: |
| 24 SourcePositionTest(Thread* thread, | 25 SourcePositionTest(Thread* thread, |
| 25 const char* script) | 26 const char* script) |
| 26 : thread_(thread), | 27 : thread_(thread), |
| 27 isolate_(thread->isolate()), | 28 isolate_(thread->isolate()), |
| 28 script_(script), | 29 script_(script), |
| 29 root_lib_(Library::Handle()), | 30 root_lib_(Library::Handle()), |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 graph_name_ = function_name; | 71 graph_name_ = function_name; |
| 71 EXPECT(graph_name_ != NULL); | 72 EXPECT(graph_name_ != NULL); |
| 72 } | 73 } |
| 73 | 74 |
| 74 // Expect to find an instance call at |line| and |column|. | 75 // Expect to find an instance call at |line| and |column|. |
| 75 void InstanceCallAt(intptr_t line, | 76 void InstanceCallAt(intptr_t line, |
| 76 intptr_t column = -1, | 77 intptr_t column = -1, |
| 77 Token::Kind kind = Token::kNumTokens) { | 78 Token::Kind kind = Token::kNumTokens) { |
| 78 ZoneGrowableArray<Instruction*>* instructions = | 79 ZoneGrowableArray<Instruction*>* instructions = |
| 79 FindInstructionsAt(line, column); | 80 FindInstructionsAt(line, column); |
| 80 DUMP_EXPECT(instructions->length() > 0); | 81 intptr_t count = 0; |
| 81 for (intptr_t i = 0; i < instructions->length(); i++) { | 82 for (intptr_t i = 0; i < instructions->length(); i++) { |
| 82 Instruction* instr = instructions->At(i); | 83 Instruction* instr = instructions->At(i); |
| 83 EXPECT(instr != NULL); | 84 EXPECT(instr != NULL); |
| 84 if (instr->IsInstanceCall()) { | 85 if (instr->IsInstanceCall()) { |
| 85 if (kind != Token::kNumTokens) { | 86 if (kind != Token::kNumTokens) { |
| 86 DUMP_EXPECT(instr->AsInstanceCall()->token_kind() == kind); | 87 if (instr->AsInstanceCall()->token_kind() == kind) { |
| 88 count++; | |
| 89 } | |
| 90 } else { | |
| 91 count++; | |
| 87 } | 92 } |
| 88 return; | |
| 89 } | 93 } |
| 90 } | 94 } |
| 91 DUMP_EXPECT(false); | 95 DUMP_EXPECT(count > 0); |
| 96 } | |
| 97 | |
| 98 // Expect to find at least one ctatic call at |line| and |column|. The | |
|
rmacnak
2016/01/11 22:03:22
ctatic -> static
Cutch
2016/01/11 22:14:58
Done.
| |
| 99 // static call will have |needle| in its |ToCString| representation. | |
| 100 void StaticCallAt(const char* needle, | |
| 101 intptr_t line, | |
| 102 intptr_t column = -1) { | |
| 103 ZoneGrowableArray<Instruction*>* instructions = | |
| 104 FindInstructionsAt(line, column); | |
| 105 intptr_t count = 0; | |
| 106 for (intptr_t i = 0; i < instructions->length(); i++) { | |
| 107 Instruction* instr = instructions->At(i); | |
| 108 EXPECT(instr != NULL); | |
| 109 if (instr->IsStaticCall()) { | |
| 110 const char* haystack = instr->ToCString(); | |
| 111 if (strstr(haystack, needle) != NULL) { | |
| 112 count++; | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 DUMP_EXPECT(count > 0); | |
| 92 } | 117 } |
| 93 | 118 |
| 94 // Expect that at least one of the instructions found at |line| and |column| | 119 // Expect that at least one of the instructions found at |line| and |column| |
| 95 // contain |needle| in their |ToCString| representation. | 120 // contain |needle| in their |ToCString| representation. |
| 96 void FuzzyInstructionMatchAt(const char* needle, | 121 void FuzzyInstructionMatchAt(const char* needle, |
| 97 intptr_t line, | 122 intptr_t line, |
| 98 intptr_t column = -1) { | 123 intptr_t column = -1) { |
| 99 ZoneGrowableArray<Instruction*>* instructions = | 124 ZoneGrowableArray<Instruction*>* instructions = |
| 100 FindInstructionsAt(line, column); | 125 FindInstructionsAt(line, column); |
| 101 DUMP_EXPECT(instructions->length() > 0); | |
| 102 intptr_t count = 0; | 126 intptr_t count = 0; |
| 103 for (intptr_t i = 0; i < instructions->length(); i++) { | 127 for (intptr_t i = 0; i < instructions->length(); i++) { |
| 104 Instruction* instr = instructions->At(i); | 128 Instruction* instr = instructions->At(i); |
| 105 const char* haystack = instr->ToCString(); | 129 const char* haystack = instr->ToCString(); |
| 106 if (strstr(haystack, needle) != NULL) { | 130 if (strstr(haystack, needle) != NULL) { |
| 107 count++; | 131 count++; |
| 108 } | 132 } |
| 109 } | 133 } |
| 110 DUMP_EXPECT(count > 0); | 134 DUMP_EXPECT(count > 0); |
| 111 } | 135 } |
| 112 | 136 |
| 113 // Utility to dump the instructions with token positions or line numbers. | 137 // Utility to dump the instructions with token positions or line numbers. |
| 114 void Dump() { | 138 void Dump() { |
| 115 for (intptr_t i = 0; i < blocks_->length(); i++) { | 139 for (intptr_t i = 0; i < blocks_->length(); i++) { |
| 116 BlockEntryInstr* entry = (*blocks_)[i]; | 140 BlockEntryInstr* entry = (*blocks_)[i]; |
| 117 THR_Print("B%" Pd ":\n", entry->block_id()); | 141 THR_Print("B%" Pd ":\n", entry->block_id()); |
| 142 DumpInstruction(entry); | |
| 118 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 143 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 119 Instruction* instr = it.Current(); | 144 DumpInstruction(it.Current()); |
| 120 const intptr_t token_pos = instr->token_pos(); | |
| 121 if (token_pos < 0) { | |
| 122 const char* token_pos_string = | |
| 123 ClassifyingTokenPositions::ToCString(token_pos); | |
| 124 THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString()); | |
| 125 continue; | |
| 126 } | |
| 127 intptr_t token_line = -1; | |
| 128 intptr_t token_column = -1; | |
| 129 root_script_.GetTokenLocation(token_pos, | |
| 130 &token_line, | |
| 131 &token_column, | |
| 132 NULL); | |
| 133 THR_Print(" %02d:%02d -- %s\n", | |
| 134 static_cast<int>(token_line), | |
| 135 static_cast<int>(token_column), | |
| 136 instr->ToCString()); | |
| 137 } | 145 } |
| 138 } | 146 } |
| 139 } | 147 } |
| 140 | 148 |
| 141 private: | 149 private: |
| 150 void DumpInstruction(Instruction* instr) { | |
| 151 const intptr_t token_pos = instr->token_pos(); | |
| 152 if (token_pos < 0) { | |
| 153 const char* token_pos_string = | |
| 154 ClassifyingTokenPositions::ToCString(token_pos); | |
| 155 THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString()); | |
| 156 return; | |
| 157 } | |
| 158 intptr_t token_line = -1; | |
| 159 intptr_t token_column = -1; | |
| 160 root_script_.GetTokenLocation(token_pos, | |
| 161 &token_line, | |
| 162 &token_column, | |
| 163 NULL); | |
| 164 THR_Print(" %02d:%02d -- %s\n", | |
| 165 static_cast<int>(token_line), | |
| 166 static_cast<int>(token_column), | |
| 167 instr->ToCString()); | |
| 168 } | |
| 169 | |
| 142 Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) { | 170 Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) { |
| 143 ZoneGrowableArray<Instruction*>* instructions = | 171 ZoneGrowableArray<Instruction*>* instructions = |
| 144 FindInstructionsAt(line, column); | 172 FindInstructionsAt(line, column); |
| 145 if (instructions->length() == 0) { | 173 if (instructions->length() == 0) { |
| 146 return NULL; | 174 return NULL; |
| 147 } | 175 } |
| 148 return instructions->At(0); | 176 return instructions->At(0); |
| 149 } | 177 } |
| 150 | 178 |
| 151 ZoneGrowableArray<Instruction*>* FindInstructionsAt( | 179 ZoneGrowableArray<Instruction*>* FindInstructionsAt( |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 spt.FuzzyInstructionMatchAt("LoadStaticField", 8, 5); | 365 spt.FuzzyInstructionMatchAt("LoadStaticField", 8, 5); |
| 338 spt.FuzzyInstructionMatchAt("Constant(#1)", 8, 6); | 366 spt.FuzzyInstructionMatchAt("Constant(#1)", 8, 6); |
| 339 spt.InstanceCallAt(8, 6, Token::kADD); | 367 spt.InstanceCallAt(8, 6, Token::kADD); |
| 340 spt.FuzzyInstructionMatchAt("StoreStaticField", 8, 5); | 368 spt.FuzzyInstructionMatchAt("StoreStaticField", 8, 5); |
| 341 | 369 |
| 342 spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10); | 370 spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10); |
| 343 spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3); | 371 spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3); |
| 344 spt.FuzzyInstructionMatchAt("Return", 10, 3); | 372 spt.FuzzyInstructionMatchAt("Return", 10, 3); |
| 345 } | 373 } |
| 346 | 374 |
| 375 | |
| 376 TEST_CASE(SourcePosition_WhileContinueBreak) { | |
| 377 const char* kScript = | |
| 378 "var x = 0;\n" | |
| 379 "var y = 5;\n" | |
| 380 "main() {\n" | |
| 381 " while (x < 10) {\n" | |
| 382 " if (y == 5) {\n" | |
| 383 " continue;\n" | |
| 384 " }\n" | |
| 385 " break;\n" | |
| 386 " }\n" | |
| 387 " return x;\n" | |
| 388 "}\n"; | |
| 389 | |
| 390 SourcePositionTest spt(thread, kScript); | |
| 391 spt.BuildGraphFor("main"); | |
| 392 spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5); | |
| 393 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5); | |
| 394 | |
| 395 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 4, 3); | |
| 396 spt.FuzzyInstructionMatchAt("Constant", 4, 10); | |
|
rmacnak
2016/01/11 22:03:22
This is the position of "x", should be that of "10
Cutch
2016/01/11 22:14:58
Done.
| |
| 397 spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 10); | |
| 398 spt.InstanceCallAt(4, 12, Token::kLT); | |
| 399 spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 12); | |
| 400 | |
| 401 spt.FuzzyInstructionMatchAt("Constant", 5, 9); | |
|
rmacnak
2016/01/11 22:03:22
This is the position of "y", should be that of "5"
Cutch
2016/01/11 22:14:58
Done.
| |
| 402 spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 9); | |
| 403 spt.InstanceCallAt(5, 11, Token::kEQ); | |
| 404 spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 5, 11); | |
| 405 | |
| 406 spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10); | |
| 407 spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3); | |
| 408 spt.FuzzyInstructionMatchAt("Return", 10, 3); | |
| 409 } | |
| 410 | |
| 411 | |
| 412 TEST_CASE(SourcePosition_LoadIndexed) { | |
| 413 const char* kScript = | |
| 414 "var x = 0;\n" | |
| 415 "var z = new List(3);\n" | |
| 416 "main() {\n" | |
| 417 " z[0];\n" | |
| 418 " var y = z[0] + z[1] + z[2];\n" | |
| 419 "}\n"; | |
| 420 | |
| 421 SourcePositionTest spt(thread, kScript); | |
| 422 spt.BuildGraphFor("main"); | |
| 423 | |
| 424 spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5); | |
| 425 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5); | |
| 426 spt.StaticCallAt("get:z", 4, 3); | |
| 427 spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5); | |
| 428 spt.InstanceCallAt(4, 4, Token::kINDEX); | |
| 429 | |
| 430 spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 13); | |
| 431 spt.InstanceCallAt(5, 12, Token::kINDEX); | |
| 432 spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 20); | |
| 433 spt.InstanceCallAt(5, 19, Token::kINDEX); | |
| 434 | |
| 435 spt.InstanceCallAt(5, 16, Token::kADD); | |
| 436 | |
| 437 spt.StaticCallAt("get:z", 5, 25); | |
| 438 spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 27); | |
| 439 spt.InstanceCallAt(5, 26, Token::kINDEX); | |
| 440 | |
| 441 spt.InstanceCallAt(5, 23, Token::kADD); | |
| 442 | |
| 443 spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1); | |
| 444 spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1); | |
| 445 spt.FuzzyInstructionMatchAt("Return", 6, 1); | |
| 446 } | |
| 447 | |
| 448 | |
| 449 TEST_CASE(SourcePosition_StoreIndexed) { | |
| 450 const char* kScript = | |
| 451 "var x = 0;\n" | |
| 452 "var z = new List(4);\n" | |
| 453 "main() {\n" | |
| 454 " z[0];\n" | |
| 455 " z[3] = z[0] + z[1] + z[2];\n" | |
| 456 "}\n"; | |
| 457 | |
| 458 SourcePositionTest spt(thread, kScript); | |
| 459 spt.BuildGraphFor("main"); | |
| 460 | |
| 461 spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5); | |
| 462 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5); | |
| 463 spt.StaticCallAt("get:z", 4, 3); | |
| 464 spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5); | |
| 465 spt.InstanceCallAt(4, 4, Token::kINDEX); | |
| 466 | |
| 467 spt.FuzzyInstructionMatchAt("Constant(#3)", 5, 5); | |
| 468 | |
| 469 spt.StaticCallAt("get:z", 5, 10); | |
| 470 spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 12); | |
| 471 spt.InstanceCallAt(5, 11, Token::kINDEX); | |
| 472 | |
| 473 spt.InstanceCallAt(5, 15, Token::kADD); | |
| 474 | |
| 475 spt.StaticCallAt("get:z", 5, 17); | |
| 476 spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 19); | |
| 477 spt.InstanceCallAt(5, 18, Token::kINDEX); | |
| 478 | |
| 479 spt.StaticCallAt("get:z", 5, 24); | |
| 480 spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 26); | |
| 481 spt.InstanceCallAt(5, 25, Token::kINDEX); | |
| 482 | |
| 483 spt.InstanceCallAt(5, 4, Token::kASSIGN_INDEX); | |
| 484 | |
| 485 spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1); | |
| 486 spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1); | |
| 487 spt.FuzzyInstructionMatchAt("Return", 6, 1); | |
| 488 } | |
| 489 | |
| 490 | |
| 491 TEST_CASE(SourcePosition_BitwiseOperations) { | |
| 492 const char* kScript = | |
| 493 "var x = 0;\n" | |
| 494 "var y = 1;\n" | |
| 495 "main() {\n" | |
| 496 " var z;\n" | |
| 497 " z = x & y;\n" | |
| 498 " z = x | y;\n" | |
| 499 " z = x ^ y;\n" | |
| 500 " z = ~z;\n" | |
| 501 " return z;\n" | |
| 502 "}\n"; | |
| 503 | |
| 504 SourcePositionTest spt(thread, kScript); | |
| 505 spt.BuildGraphFor("main"); | |
| 506 | |
| 507 spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5); | |
| 508 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5); | |
| 509 | |
| 510 spt.FuzzyInstructionMatchAt("DebugStepCheck", 4, 7); | |
| 511 spt.FuzzyInstructionMatchAt("Constant(#null", 4, 7); | |
| 512 spt.FuzzyInstructionMatchAt("StoreLocal(z", 4, 7); | |
| 513 | |
| 514 spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 7); | |
| 515 spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 11); | |
| 516 spt.InstanceCallAt(5, 9, Token::kBIT_AND); | |
| 517 spt.FuzzyInstructionMatchAt("StoreLocal(z", 5, 3); | |
| 518 | |
| 519 spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 7); | |
| 520 spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 11); | |
| 521 spt.InstanceCallAt(6, 9, Token::kBIT_OR); | |
| 522 spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 3); | |
| 523 | |
| 524 spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 7); | |
| 525 spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 11); | |
| 526 spt.InstanceCallAt(7, 9, Token::kBIT_XOR); | |
| 527 spt.FuzzyInstructionMatchAt("StoreLocal(z", 7, 3); | |
| 528 | |
| 529 spt.FuzzyInstructionMatchAt("LoadLocal(z", 8, 8); | |
| 530 spt.InstanceCallAt(8, 7, Token::kBIT_NOT); | |
| 531 spt.FuzzyInstructionMatchAt("StoreLocal(z", 8, 3); | |
| 532 | |
| 533 spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10); | |
| 534 spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3); | |
| 535 spt.FuzzyInstructionMatchAt("Return", 9, 3); | |
| 536 } | |
| 537 | |
| 347 } // namespace dart | 538 } // namespace dart |
| 539 | |
| OLD | NEW |