| Index: runtime/vm/flow_graph_builder_test.cc
|
| diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc
|
| index 14ae5968da0bcb3c4b2285b1b063b210561d3893..57d18373970cc45e9274e8326d66afdd11d4bf70 100644
|
| --- a/runtime/vm/flow_graph_builder_test.cc
|
| +++ b/runtime/vm/flow_graph_builder_test.cc
|
| @@ -11,12 +11,13 @@
|
|
|
| namespace dart {
|
|
|
| -#define DUMP_EXPECT(condition) \
|
| +#define DUMP_ASSERT(condition) \
|
| if (!(condition)) { \
|
| dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \
|
| THR_Print(">>> BEGIN source position table for `%s`\n", graph_name_); \
|
| Dump(); \
|
| THR_Print("<<< END source position table for `%s`\n", graph_name_); \
|
| + OS::Abort(); \
|
| }
|
|
|
| class SourcePositionTest : public ValueObject {
|
| @@ -77,18 +78,42 @@ class SourcePositionTest : public ValueObject {
|
| Token::Kind kind = Token::kNumTokens) {
|
| ZoneGrowableArray<Instruction*>* instructions =
|
| FindInstructionsAt(line, column);
|
| - DUMP_EXPECT(instructions->length() > 0);
|
| + intptr_t count = 0;
|
| for (intptr_t i = 0; i < instructions->length(); i++) {
|
| Instruction* instr = instructions->At(i);
|
| EXPECT(instr != NULL);
|
| if (instr->IsInstanceCall()) {
|
| if (kind != Token::kNumTokens) {
|
| - DUMP_EXPECT(instr->AsInstanceCall()->token_kind() == kind);
|
| + if (instr->AsInstanceCall()->token_kind() == kind) {
|
| + count++;
|
| + }
|
| + } else {
|
| + count++;
|
| }
|
| - return;
|
| }
|
| }
|
| - DUMP_EXPECT(false);
|
| + DUMP_ASSERT(count > 0);
|
| + }
|
| +
|
| + // Expect to find at least one static call at |line| and |column|. The
|
| + // static call will have |needle| in its |ToCString| representation.
|
| + void StaticCallAt(const char* needle,
|
| + intptr_t line,
|
| + intptr_t column = -1) {
|
| + ZoneGrowableArray<Instruction*>* instructions =
|
| + FindInstructionsAt(line, column);
|
| + intptr_t count = 0;
|
| + for (intptr_t i = 0; i < instructions->length(); i++) {
|
| + Instruction* instr = instructions->At(i);
|
| + EXPECT(instr != NULL);
|
| + if (instr->IsStaticCall()) {
|
| + const char* haystack = instr->ToCString();
|
| + if (strstr(haystack, needle) != NULL) {
|
| + count++;
|
| + }
|
| + }
|
| + }
|
| + DUMP_ASSERT(count > 0);
|
| }
|
|
|
| // Expect that at least one of the instructions found at |line| and |column|
|
| @@ -98,7 +123,6 @@ class SourcePositionTest : public ValueObject {
|
| intptr_t column = -1) {
|
| ZoneGrowableArray<Instruction*>* instructions =
|
| FindInstructionsAt(line, column);
|
| - DUMP_EXPECT(instructions->length() > 0);
|
| intptr_t count = 0;
|
| for (intptr_t i = 0; i < instructions->length(); i++) {
|
| Instruction* instr = instructions->At(i);
|
| @@ -107,7 +131,7 @@ class SourcePositionTest : public ValueObject {
|
| count++;
|
| }
|
| }
|
| - DUMP_EXPECT(count > 0);
|
| + DUMP_ASSERT(count > 0);
|
| }
|
|
|
| // Utility to dump the instructions with token positions or line numbers.
|
| @@ -115,30 +139,34 @@ class SourcePositionTest : public ValueObject {
|
| for (intptr_t i = 0; i < blocks_->length(); i++) {
|
| BlockEntryInstr* entry = (*blocks_)[i];
|
| THR_Print("B%" Pd ":\n", entry->block_id());
|
| + DumpInstruction(entry);
|
| for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
|
| - Instruction* instr = it.Current();
|
| - const intptr_t token_pos = instr->token_pos();
|
| - if (token_pos < 0) {
|
| - const char* token_pos_string =
|
| - ClassifyingTokenPositions::ToCString(token_pos);
|
| - THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString());
|
| - continue;
|
| - }
|
| - intptr_t token_line = -1;
|
| - intptr_t token_column = -1;
|
| - root_script_.GetTokenLocation(token_pos,
|
| - &token_line,
|
| - &token_column,
|
| - NULL);
|
| - THR_Print(" %02d:%02d -- %s\n",
|
| - static_cast<int>(token_line),
|
| - static_cast<int>(token_column),
|
| - instr->ToCString());
|
| + DumpInstruction(it.Current());
|
| }
|
| }
|
| }
|
|
|
| private:
|
| + void DumpInstruction(Instruction* instr) {
|
| + const intptr_t token_pos = instr->token_pos();
|
| + if (token_pos < 0) {
|
| + const char* token_pos_string =
|
| + ClassifyingTokenPositions::ToCString(token_pos);
|
| + THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString());
|
| + return;
|
| + }
|
| + intptr_t token_line = -1;
|
| + intptr_t token_column = -1;
|
| + root_script_.GetTokenLocation(token_pos,
|
| + &token_line,
|
| + &token_column,
|
| + NULL);
|
| + THR_Print(" %02d:%02d -- %s\n",
|
| + static_cast<int>(token_line),
|
| + static_cast<int>(token_column),
|
| + instr->ToCString());
|
| + }
|
| +
|
| Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) {
|
| ZoneGrowableArray<Instruction*>* instructions =
|
| FindInstructionsAt(line, column);
|
| @@ -344,4 +372,170 @@ TEST_CASE(SourcePosition_While) {
|
| spt.FuzzyInstructionMatchAt("Return", 10, 3);
|
| }
|
|
|
| +
|
| +TEST_CASE(SourcePosition_WhileContinueBreak) {
|
| + const char* kScript =
|
| + "var x = 0;\n"
|
| + "var y = 5;\n"
|
| + "main() {\n"
|
| + " while (x < 10) {\n"
|
| + " if (y == 5) {\n"
|
| + " continue;\n"
|
| + " }\n"
|
| + " break;\n"
|
| + " }\n"
|
| + " return x;\n"
|
| + "}\n";
|
| +
|
| + SourcePositionTest spt(thread, kScript);
|
| + spt.BuildGraphFor("main");
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
|
| + spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5);
|
| +
|
| + spt.FuzzyInstructionMatchAt("CheckStackOverflow", 4, 3);
|
| + spt.FuzzyInstructionMatchAt("Constant(#Field", 4, 10);
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 10);
|
| + spt.FuzzyInstructionMatchAt("Constant(#10", 4, 14);
|
| + spt.InstanceCallAt(4, 12, Token::kLT);
|
| + spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 12);
|
| +
|
| + spt.FuzzyInstructionMatchAt("Constant(#Field", 5, 9);
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 9);
|
| + spt.FuzzyInstructionMatchAt("Constant(#5", 5, 14);
|
| + spt.InstanceCallAt(5, 11, Token::kEQ);
|
| + spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 5, 11);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
|
| + spt.FuzzyInstructionMatchAt("Return", 10, 3);
|
| +}
|
| +
|
| +
|
| +TEST_CASE(SourcePosition_LoadIndexed) {
|
| + const char* kScript =
|
| + "var x = 0;\n"
|
| + "var z = new List(3);\n"
|
| + "main() {\n"
|
| + " z[0];\n"
|
| + " var y = z[0] + z[1] + z[2];\n"
|
| + "}\n";
|
| +
|
| + SourcePositionTest spt(thread, kScript);
|
| + spt.BuildGraphFor("main");
|
| +
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
|
| + spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5);
|
| + spt.StaticCallAt("get:z", 4, 3);
|
| + spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5);
|
| + spt.InstanceCallAt(4, 4, Token::kINDEX);
|
| +
|
| + spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 13);
|
| + spt.InstanceCallAt(5, 12, Token::kINDEX);
|
| + spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 20);
|
| + spt.InstanceCallAt(5, 19, Token::kINDEX);
|
| +
|
| + spt.InstanceCallAt(5, 16, Token::kADD);
|
| +
|
| + spt.StaticCallAt("get:z", 5, 25);
|
| + spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 27);
|
| + spt.InstanceCallAt(5, 26, Token::kINDEX);
|
| +
|
| + spt.InstanceCallAt(5, 23, Token::kADD);
|
| +
|
| + spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
|
| + spt.FuzzyInstructionMatchAt("Return", 6, 1);
|
| +}
|
| +
|
| +
|
| +TEST_CASE(SourcePosition_StoreIndexed) {
|
| + const char* kScript =
|
| + "var x = 0;\n"
|
| + "var z = new List(4);\n"
|
| + "main() {\n"
|
| + " z[0];\n"
|
| + " z[3] = z[0] + z[1] + z[2];\n"
|
| + "}\n";
|
| +
|
| + SourcePositionTest spt(thread, kScript);
|
| + spt.BuildGraphFor("main");
|
| +
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
|
| + spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5);
|
| + spt.StaticCallAt("get:z", 4, 3);
|
| + spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5);
|
| + spt.InstanceCallAt(4, 4, Token::kINDEX);
|
| +
|
| + spt.FuzzyInstructionMatchAt("Constant(#3)", 5, 5);
|
| +
|
| + spt.StaticCallAt("get:z", 5, 10);
|
| + spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 12);
|
| + spt.InstanceCallAt(5, 11, Token::kINDEX);
|
| +
|
| + spt.InstanceCallAt(5, 15, Token::kADD);
|
| +
|
| + spt.StaticCallAt("get:z", 5, 17);
|
| + spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 19);
|
| + spt.InstanceCallAt(5, 18, Token::kINDEX);
|
| +
|
| + spt.StaticCallAt("get:z", 5, 24);
|
| + spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 26);
|
| + spt.InstanceCallAt(5, 25, Token::kINDEX);
|
| +
|
| + spt.InstanceCallAt(5, 4, Token::kASSIGN_INDEX);
|
| +
|
| + spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
|
| + spt.FuzzyInstructionMatchAt("Return", 6, 1);
|
| +}
|
| +
|
| +
|
| +TEST_CASE(SourcePosition_BitwiseOperations) {
|
| + const char* kScript =
|
| + "var x = 0;\n"
|
| + "var y = 1;\n"
|
| + "main() {\n"
|
| + " var z;\n"
|
| + " z = x & y;\n"
|
| + " z = x | y;\n"
|
| + " z = x ^ y;\n"
|
| + " z = ~z;\n"
|
| + " return z;\n"
|
| + "}\n";
|
| +
|
| + SourcePositionTest spt(thread, kScript);
|
| + spt.BuildGraphFor("main");
|
| +
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
|
| + spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5);
|
| +
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 4, 7);
|
| + spt.FuzzyInstructionMatchAt("Constant(#null", 4, 7);
|
| + spt.FuzzyInstructionMatchAt("StoreLocal(z", 4, 7);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 7);
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 11);
|
| + spt.InstanceCallAt(5, 9, Token::kBIT_AND);
|
| + spt.FuzzyInstructionMatchAt("StoreLocal(z", 5, 3);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 7);
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 11);
|
| + spt.InstanceCallAt(6, 9, Token::kBIT_OR);
|
| + spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 3);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 7);
|
| + spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 11);
|
| + spt.InstanceCallAt(7, 9, Token::kBIT_XOR);
|
| + spt.FuzzyInstructionMatchAt("StoreLocal(z", 7, 3);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadLocal(z", 8, 8);
|
| + spt.InstanceCallAt(8, 7, Token::kBIT_NOT);
|
| + spt.FuzzyInstructionMatchAt("StoreLocal(z", 8, 3);
|
| +
|
| + spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10);
|
| + spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
|
| + spt.FuzzyInstructionMatchAt("Return", 9, 3);
|
| +}
|
| +
|
| } // namespace dart
|
| +
|
|
|