Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #include "vm/compiler.h" | |
| 6 #include "vm/dart_api_impl.h" | |
| 7 #include "vm/dart_entry.h" | |
| 8 #include "vm/flow_graph_builder.h" | |
| 9 #include "vm/intermediate_language.h" | |
| 10 #include "vm/unit_test.h" | |
| 11 | |
| 12 namespace dart { | |
| 13 | |
| 14 #define DUMP_EXPECT(condition) \ | |
| 15 if (!(condition)) { \ | |
| 16 dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \ | |
| 17 THR_Print(">>> BEGIN source position table for `%s`\n", graph_name_); \ | |
| 18 Dump(); \ | |
| 19 THR_Print("<<< END source position table for `%s`\n", graph_name_); \ | |
| 20 } | |
| 21 | |
| 22 class SourcePositionTest : public ValueObject { | |
| 23 public: | |
| 24 SourcePositionTest(Thread* thread, | |
| 25 const char* script) | |
| 26 : thread_(thread), | |
| 27 isolate_(thread->isolate()), | |
| 28 script_(script), | |
| 29 root_lib_(Library::Handle()), | |
| 30 root_script_(Script::Handle()), | |
| 31 graph_(NULL), | |
| 32 blocks_(NULL) { | |
| 33 EXPECT(thread_ != NULL); | |
| 34 EXPECT(isolate_ != NULL); | |
| 35 EXPECT(script_ != NULL); | |
| 36 Dart_Handle lib = TestCase::LoadTestScript(script, NULL); | |
| 37 EXPECT_VALID(lib); | |
| 38 root_lib_ ^= Api::UnwrapHandle(lib); | |
| 39 EXPECT(!root_lib_.IsNull()); | |
| 40 root_script_ ^= root_lib_.LookupScript( | |
| 41 String::Handle(String::New(USER_TEST_URI))); | |
| 42 EXPECT(!root_script_.IsNull()); | |
| 43 } | |
| 44 | |
| 45 void BuildGraphFor(const char* function_name) { | |
| 46 graph_ = NULL; | |
| 47 blocks_ = NULL; | |
| 48 graph_name_ = NULL; | |
| 49 | |
| 50 // Only support unoptimized code for now. | |
| 51 const bool optimized = false; | |
| 52 | |
| 53 const Function& function = | |
| 54 Function::Handle(GetFunction(root_lib_, function_name)); | |
| 55 ZoneGrowableArray<const ICData*>* ic_data_array = | |
| 56 new ZoneGrowableArray<const ICData*>(); | |
| 57 ParsedFunction* parsed_function = new ParsedFunction( | |
| 58 thread_, Function::ZoneHandle(function.raw())); | |
| 59 Parser::ParseFunction(parsed_function); | |
| 60 parsed_function->AllocateVariables(); | |
| 61 FlowGraphBuilder builder( | |
| 62 *parsed_function, | |
| 63 *ic_data_array, | |
| 64 NULL, | |
| 65 Compiler::kNoOSRDeoptId); | |
| 66 graph_ = builder.BuildGraph(); | |
| 67 EXPECT(graph_ != NULL); | |
| 68 blocks_ = graph_->CodegenBlockOrder(optimized); | |
| 69 EXPECT(blocks_ != NULL); | |
| 70 graph_name_ = function_name; | |
| 71 EXPECT(graph_name_ != NULL); | |
| 72 } | |
| 73 | |
| 74 // Expect to find an instance call at |line| and |column|. | |
| 75 void InstanceCallAt(intptr_t line, | |
| 76 intptr_t column = -1, | |
| 77 Token::Kind kind = Token::kNumTokens) { | |
| 78 Instruction* instr = FindFirstInstructionAt(line, column); | |
| 79 DUMP_EXPECT(instr->IsInstanceCall()); | |
| 80 if (kind != Token::kNumTokens) { | |
| 81 DUMP_EXPECT(instr->AsInstanceCall()->token_kind() == kind); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 // Expect that at least one of the instructions found at |line| and |column| | |
| 86 // contain |needle| in their |ToCString| representation. | |
| 87 void FuzzyInstructionMatchAt(const char* needle, | |
| 88 intptr_t line, | |
| 89 intptr_t column = -1) { | |
| 90 ZoneGrowableArray<Instruction*>* instructions = | |
| 91 FindInstructionsAt(line, column); | |
| 92 DUMP_EXPECT(instructions->length() > 0); | |
| 93 intptr_t count = 0; | |
| 94 for (intptr_t i = 0; i < instructions->length(); i++) { | |
| 95 Instruction* instr = instructions->At(i); | |
| 96 const char* haystack = instr->ToCString(); | |
| 97 if (strstr(haystack, needle) != NULL) { | |
| 98 count++; | |
| 99 } | |
| 100 } | |
| 101 DUMP_EXPECT(count > 0); | |
| 102 } | |
| 103 | |
| 104 // Utility to dump the instructions with token positions or line numbers. | |
| 105 void Dump() { | |
| 106 for (intptr_t i = 0; i < blocks_->length(); i++) { | |
| 107 BlockEntryInstr* entry = (*blocks_)[i]; | |
| 108 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | |
| 109 Instruction* instr = it.Current(); | |
| 110 const intptr_t token_pos = instr->token_pos(); | |
| 111 if (token_pos < 0) { | |
| 112 THR_Print("%5d -- %s\n", | |
| 113 static_cast<int>(token_pos), instr->ToCString()); | |
| 114 continue; | |
| 115 } | |
| 116 intptr_t token_line = -1; | |
| 117 intptr_t token_column = -1; | |
| 118 root_script_.GetTokenLocation(token_pos, | |
| 119 &token_line, | |
| 120 &token_column, | |
| 121 NULL); | |
| 122 THR_Print("%02d:%02d -- %s\n", | |
| 123 static_cast<int>(token_line), | |
| 124 static_cast<int>(token_column), | |
| 125 instr->ToCString()); | |
| 126 } | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 private: | |
| 131 Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) { | |
| 132 ZoneGrowableArray<Instruction*>* instructions = | |
| 133 FindInstructionsAt(line, column); | |
| 134 DUMP_EXPECT(instructions->length() > 0); | |
| 135 return instructions->At(0); | |
| 136 } | |
| 137 | |
| 138 ZoneGrowableArray<Instruction*>* FindInstructionsAt( | |
| 139 intptr_t line, intptr_t column) { | |
| 140 ZoneGrowableArray<Instruction*>* instructions = | |
| 141 new ZoneGrowableArray<Instruction*>(); | |
| 142 for (intptr_t i = 0; i < blocks_->length(); i++) { | |
| 143 BlockEntryInstr* entry = (*blocks_)[i]; | |
| 144 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | |
| 145 Instruction* instr = it.Current(); | |
| 146 intptr_t token_pos = instr->token_pos(); | |
| 147 if (token_pos < 0) { | |
| 148 continue; | |
| 149 } | |
| 150 intptr_t token_line = -1; | |
| 151 intptr_t token_column = -1; | |
| 152 root_script_.GetTokenLocation(token_pos, | |
| 153 &token_line, | |
| 154 &token_column, | |
| 155 NULL); | |
| 156 if (token_line == line) { | |
| 157 if ((column < 0) || (column == token_column)) { | |
| 158 instructions->Add(instr); | |
| 159 } | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 return instructions; | |
| 164 } | |
| 165 | |
| 166 ZoneGrowableArray<Instruction*>* FindInstructionsAt(intptr_t token_pos) { | |
| 167 ZoneGrowableArray<Instruction*>* instructions = | |
| 168 new ZoneGrowableArray<Instruction*>(); | |
| 169 for (intptr_t i = 0; i < blocks_->length(); i++) { | |
| 170 BlockEntryInstr* entry = (*blocks_)[i]; | |
| 171 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | |
| 172 Instruction* instr = it.Current(); | |
| 173 if (instr->token_pos() == token_pos) { | |
| 174 instructions->Add(instr); | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 return instructions; | |
| 179 } | |
| 180 | |
| 181 RawFunction* GetFunction(const Library& lib, const char* name) { | |
| 182 const Function& result = Function::Handle(lib.LookupFunctionAllowPrivate( | |
| 183 String::Handle(String::New(name)))); | |
| 184 EXPECT(!result.IsNull()); | |
| 185 return result.raw(); | |
| 186 } | |
| 187 | |
| 188 RawFunction* GetFunction(const Class& cls, const char* name) { | |
| 189 const Function& result = Function::Handle(cls.LookupDynamicFunction( | |
|
rmacnak
2016/01/08 17:36:28
LookupFunctionAllowPrivate
Cutch
2016/01/08 19:03:28
Done.
| |
| 190 String::Handle(String::New(name)))); | |
| 191 EXPECT(!result.IsNull()); | |
| 192 return result.raw(); | |
| 193 } | |
| 194 | |
| 195 RawClass* GetClass(const Library& lib, const char* name) { | |
| 196 const Class& cls = Class::Handle( | |
| 197 lib.LookupClass(String::Handle(Symbols::New(name)))); | |
| 198 EXPECT(!cls.IsNull()); // No ambiguity error expected. | |
| 199 return cls.raw(); | |
| 200 } | |
| 201 | |
| 202 Thread* thread_; | |
| 203 Isolate* isolate_; | |
| 204 const char* script_; | |
| 205 Library& root_lib_; | |
| 206 Script& root_script_; | |
| 207 const char* graph_name_; | |
| 208 FlowGraph* graph_; | |
| 209 GrowableArray<BlockEntryInstr*>* blocks_; | |
| 210 }; | |
| 211 | |
| 212 | |
| 213 TEST_CASE(SourcePosition_InstanceCalls) { | |
| 214 const char* kScript = | |
| 215 "var x = 5;\n" | |
| 216 "var y = 5;\n" | |
| 217 "main() {\n" | |
| 218 " var z = x + y;\n" | |
| 219 " return z;\n" | |
| 220 "}\n"; | |
| 221 | |
| 222 SourcePositionTest spt(thread, kScript); | |
| 223 spt.BuildGraphFor("main"); | |
| 224 spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5); | |
| 225 spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 5); | |
| 226 spt.InstanceCallAt(4, 13, Token::kADD); | |
| 227 spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 3); | |
| 228 spt.FuzzyInstructionMatchAt("Return", 5, 3); | |
| 229 } | |
| 230 | |
| 231 } // namespace dart | |
| OLD | NEW |