OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 | 5 #include "vm/parser.h" |
6 #include "vm/ast_printer.h" | 6 #include "vm/ast_printer.h" |
7 #include "vm/class_finalizer.h" | 7 #include "vm/class_finalizer.h" |
8 #include "vm/debugger.h" | 8 #include "vm/debugger.h" |
9 #include "vm/longjump.h" | 9 #include "vm/longjump.h" |
10 #include "vm/object.h" | 10 #include "vm/object.h" |
11 #include "vm/parser.h" | |
12 #include "vm/symbols.h" | 11 #include "vm/symbols.h" |
13 #include "vm/thread.h" | 12 #include "vm/thread.h" |
14 #include "vm/unit_test.h" | 13 #include "vm/unit_test.h" |
15 | 14 |
16 namespace dart { | 15 namespace dart { |
17 | 16 |
18 DECLARE_FLAG(bool, show_invisible_frames); | 17 DECLARE_FLAG(bool, show_invisible_frames); |
19 | 18 |
20 | |
21 static void DumpFunction(const Library& lib, | 19 static void DumpFunction(const Library& lib, |
22 const char* cname, | 20 const char* cname, |
23 const char* fname) { | 21 const char* fname) { |
24 const String& classname = | 22 const String& classname = |
25 String::Handle(Symbols::New(Thread::Current(), cname)); | 23 String::Handle(Symbols::New(Thread::Current(), cname)); |
26 String& funcname = String::Handle(String::New(fname)); | 24 String& funcname = String::Handle(String::New(fname)); |
27 | 25 |
28 bool retval; | 26 bool retval; |
29 EXPECT(Isolate::Current() != NULL); | 27 EXPECT(Isolate::Current() != NULL); |
30 LongJumpScope jump; | 28 LongJumpScope jump; |
(...skipping 14 matching lines...) Expand all Loading... |
45 } else { | 43 } else { |
46 OS::Print("AST printer not supported."); | 44 OS::Print("AST printer not supported."); |
47 } | 45 } |
48 retval = true; | 46 retval = true; |
49 } else { | 47 } else { |
50 retval = false; | 48 retval = false; |
51 } | 49 } |
52 EXPECT(retval); | 50 EXPECT(retval); |
53 } | 51 } |
54 | 52 |
55 | |
56 void CheckField(const Library& lib, | 53 void CheckField(const Library& lib, |
57 const char* class_name, | 54 const char* class_name, |
58 const char* field_name, | 55 const char* field_name, |
59 bool expect_static, | 56 bool expect_static, |
60 bool is_final) { | 57 bool is_final) { |
61 const String& classname = | 58 const String& classname = |
62 String::Handle(Symbols::New(Thread::Current(), class_name)); | 59 String::Handle(Symbols::New(Thread::Current(), class_name)); |
63 Class& cls = Class::Handle(lib.LookupClass(classname)); | 60 Class& cls = Class::Handle(lib.LookupClass(classname)); |
64 EXPECT(!cls.IsNull()); | 61 EXPECT(!cls.IsNull()); |
65 | 62 |
(...skipping 16 matching lines...) Expand all Loading... |
82 EXPECT(!function.IsNull()); | 79 EXPECT(!function.IsNull()); |
83 functionname ^= Field::SetterName(fieldname); | 80 functionname ^= Field::SetterName(fieldname); |
84 function ^= cls.LookupDynamicFunction(functionname); | 81 function ^= cls.LookupDynamicFunction(functionname); |
85 EXPECT(is_final ? function.IsNull() : !function.IsNull()); | 82 EXPECT(is_final ? function.IsNull() : !function.IsNull()); |
86 } | 83 } |
87 EXPECT(!field.IsNull()); | 84 EXPECT(!field.IsNull()); |
88 | 85 |
89 EXPECT_EQ(field.is_static(), expect_static); | 86 EXPECT_EQ(field.is_static(), expect_static); |
90 } | 87 } |
91 | 88 |
92 | |
93 void CheckFunction(const Library& lib, | 89 void CheckFunction(const Library& lib, |
94 const char* class_name, | 90 const char* class_name, |
95 const char* function_name, | 91 const char* function_name, |
96 bool expect_static) { | 92 bool expect_static) { |
97 const String& classname = | 93 const String& classname = |
98 String::Handle(Symbols::New(Thread::Current(), class_name)); | 94 String::Handle(Symbols::New(Thread::Current(), class_name)); |
99 Class& cls = Class::Handle(lib.LookupClass(classname)); | 95 Class& cls = Class::Handle(lib.LookupClass(classname)); |
100 EXPECT(!cls.IsNull()); | 96 EXPECT(!cls.IsNull()); |
101 | 97 |
102 String& functionname = String::Handle(String::New(function_name)); | 98 String& functionname = String::Handle(String::New(function_name)); |
103 Function& function = Function::Handle(); | 99 Function& function = Function::Handle(); |
104 if (expect_static) { | 100 if (expect_static) { |
105 function ^= cls.LookupStaticFunction(functionname); | 101 function ^= cls.LookupStaticFunction(functionname); |
106 } else { | 102 } else { |
107 function ^= cls.LookupDynamicFunction(functionname); | 103 function ^= cls.LookupDynamicFunction(functionname); |
108 } | 104 } |
109 EXPECT(!function.IsNull()); | 105 EXPECT(!function.IsNull()); |
110 } | 106 } |
111 | 107 |
112 | |
113 TEST_CASE(ParseClassDefinition) { | 108 TEST_CASE(ParseClassDefinition) { |
114 const char* script_chars = | 109 const char* script_chars = |
115 "class C { } \n" | 110 "class C { } \n" |
116 "class A { \n" | 111 "class A { \n" |
117 " var f0; \n" | 112 " var f0; \n" |
118 " int f1; \n" | 113 " int f1; \n" |
119 " final f2; \n" | 114 " final f2; \n" |
120 " final int f3, f4; \n" | 115 " final int f3, f4; \n" |
121 " static String s1, s2; \n" | 116 " static String s1, s2; \n" |
122 " static const int s3 = 8675309; \n" | 117 " static const int s3 = 8675309; \n" |
(...skipping 15 matching lines...) Expand all Loading... |
138 CheckField(lib, "A", "f2", false, true); | 133 CheckField(lib, "A", "f2", false, true); |
139 CheckField(lib, "A", "f3", false, true); | 134 CheckField(lib, "A", "f3", false, true); |
140 CheckField(lib, "A", "f4", false, true); | 135 CheckField(lib, "A", "f4", false, true); |
141 CheckField(lib, "A", "s1", true, false); | 136 CheckField(lib, "A", "s1", true, false); |
142 CheckField(lib, "A", "s2", true, false); | 137 CheckField(lib, "A", "s2", true, false); |
143 CheckField(lib, "A", "s3", true, true); | 138 CheckField(lib, "A", "s3", true, true); |
144 CheckFunction(lib, "A", "bar", true); | 139 CheckFunction(lib, "A", "bar", true); |
145 CheckFunction(lib, "A", "foo", true); | 140 CheckFunction(lib, "A", "foo", true); |
146 } | 141 } |
147 | 142 |
148 | |
149 TEST_CASE(Parser_TopLevel) { | 143 TEST_CASE(Parser_TopLevel) { |
150 const char* script_chars = | 144 const char* script_chars = |
151 "class A extends B { \n" | 145 "class A extends B { \n" |
152 " static bar(var i, [var d = 5]) { return 77; } \n" | 146 " static bar(var i, [var d = 5]) { return 77; } \n" |
153 " static foo() { return 42; } \n" | 147 " static foo() { return 42; } \n" |
154 " static baz(var i) { var q = 5; return i + q; } \n" | 148 " static baz(var i) { var q = 5; return i + q; } \n" |
155 "} \n" | 149 "} \n" |
156 " \n" | 150 " \n" |
157 "class B { \n" | 151 "class B { \n" |
158 " static bam(k) { return A.foo(); } \n" | 152 " static bam(k) { return A.foo(); } \n" |
159 "} \n"; | 153 "} \n"; |
160 | 154 |
161 String& url = String::Handle(String::New("dart-test:Parser_TopLevel")); | 155 String& url = String::Handle(String::New("dart-test:Parser_TopLevel")); |
162 String& source = String::Handle(String::New(script_chars)); | 156 String& source = String::Handle(String::New(script_chars)); |
163 Script& script = | 157 Script& script = |
164 Script::Handle(Script::New(url, source, RawScript::kScriptTag)); | 158 Script::Handle(Script::New(url, source, RawScript::kScriptTag)); |
165 Library& lib = Library::ZoneHandle(Library::CoreLibrary()); | 159 Library& lib = Library::ZoneHandle(Library::CoreLibrary()); |
166 | 160 |
167 script.Tokenize(String::Handle(String::New(""))); | 161 script.Tokenize(String::Handle(String::New(""))); |
168 | 162 |
169 Parser::ParseCompilationUnit(lib, script); | 163 Parser::ParseCompilationUnit(lib, script); |
170 EXPECT(ClassFinalizer::ProcessPendingClasses()); | 164 EXPECT(ClassFinalizer::ProcessPendingClasses()); |
171 | 165 |
172 DumpFunction(lib, "A", "foo"); | 166 DumpFunction(lib, "A", "foo"); |
173 DumpFunction(lib, "A", "bar"); | 167 DumpFunction(lib, "A", "bar"); |
174 DumpFunction(lib, "A", "baz"); | 168 DumpFunction(lib, "A", "baz"); |
175 DumpFunction(lib, "B", "bam"); | 169 DumpFunction(lib, "B", "bam"); |
176 } | 170 } |
177 | 171 |
178 | |
179 #ifndef PRODUCT | 172 #ifndef PRODUCT |
180 | 173 |
181 | |
182 static char* saved_vars = NULL; | 174 static char* saved_vars = NULL; |
183 | 175 |
184 | |
185 static char* SkipIndex(const char* input) { | 176 static char* SkipIndex(const char* input) { |
186 char* output_buffer = new char[strlen(input)]; | 177 char* output_buffer = new char[strlen(input)]; |
187 char* output = output_buffer; | 178 char* output = output_buffer; |
188 | 179 |
189 while (input[0] != '\0') { | 180 while (input[0] != '\0') { |
190 const char* index_pos = strstr(input, "index="); | 181 const char* index_pos = strstr(input, "index="); |
191 if (index_pos == NULL) { | 182 if (index_pos == NULL) { |
192 while (input[0] != '\0') { | 183 while (input[0] != '\0') { |
193 *output++ = *input++; | 184 *output++ = *input++; |
194 } | 185 } |
195 break; | 186 break; |
196 } | 187 } |
197 | 188 |
198 // Copy prefix until "index=" | 189 // Copy prefix until "index=" |
199 while (input < index_pos) { | 190 while (input < index_pos) { |
200 *output++ = *input++; | 191 *output++ = *input++; |
201 } | 192 } |
202 | 193 |
203 // Skip until space. | 194 // Skip until space. |
204 input += strcspn(input, " "); | 195 input += strcspn(input, " "); |
205 // Skip until next non-space. | 196 // Skip until next non-space. |
206 input += strspn(input, " "); | 197 input += strspn(input, " "); |
207 } | 198 } |
208 | 199 |
209 output[0] = '\0'; | 200 output[0] = '\0'; |
210 return output_buffer; | 201 return output_buffer; |
211 } | 202 } |
212 | 203 |
213 | |
214 // Saves the var descriptors for all frames on the stack as a string. | 204 // Saves the var descriptors for all frames on the stack as a string. |
215 static void SaveVars(Dart_IsolateId isolate_id, | 205 static void SaveVars(Dart_IsolateId isolate_id, |
216 intptr_t bp_id, | 206 intptr_t bp_id, |
217 const Dart_CodeLocation& loc) { | 207 const Dart_CodeLocation& loc) { |
218 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); | 208 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); |
219 intptr_t num_frames = stack->Length(); | 209 intptr_t num_frames = stack->Length(); |
220 const int kBufferLen = 2048; | 210 const int kBufferLen = 2048; |
221 char* buffer = reinterpret_cast<char*>(malloc(kBufferLen)); | 211 char* buffer = reinterpret_cast<char*>(malloc(kBufferLen)); |
222 char* pos = buffer; | 212 char* pos = buffer; |
223 LocalVarDescriptors& var_desc = LocalVarDescriptors::Handle(); | 213 LocalVarDescriptors& var_desc = LocalVarDescriptors::Handle(); |
224 for (intptr_t i = 0; i < num_frames; i++) { | 214 for (intptr_t i = 0; i < num_frames; i++) { |
225 ActivationFrame* frame = stack->FrameAt(i); | 215 ActivationFrame* frame = stack->FrameAt(i); |
226 var_desc = frame->code().GetLocalVarDescriptors(); | 216 var_desc = frame->code().GetLocalVarDescriptors(); |
227 const char* var_str = SkipIndex(var_desc.ToCString()); | 217 const char* var_str = SkipIndex(var_desc.ToCString()); |
228 const char* function_str = | 218 const char* function_str = |
229 String::Handle(frame->function().QualifiedUserVisibleName()) | 219 String::Handle(frame->function().QualifiedUserVisibleName()) |
230 .ToCString(); | 220 .ToCString(); |
231 pos += OS::SNPrint(pos, (kBufferLen - (pos - buffer)), "%s\n%s", | 221 pos += OS::SNPrint(pos, (kBufferLen - (pos - buffer)), "%s\n%s", |
232 function_str, var_str); | 222 function_str, var_str); |
233 delete[] var_str; | 223 delete[] var_str; |
234 } | 224 } |
235 pos[0] = '\0'; | 225 pos[0] = '\0'; |
236 if (saved_vars != NULL) { | 226 if (saved_vars != NULL) { |
237 free(saved_vars); | 227 free(saved_vars); |
238 } | 228 } |
239 saved_vars = buffer; | 229 saved_vars = buffer; |
240 } | 230 } |
241 | 231 |
242 | |
243 // Uses the debugger to pause the program and capture the variable | 232 // Uses the debugger to pause the program and capture the variable |
244 // descriptors for all frames on the stack. | 233 // descriptors for all frames on the stack. |
245 static char* CaptureVarsAtLine(Dart_Handle lib, const char* entry, int line) { | 234 static char* CaptureVarsAtLine(Dart_Handle lib, const char* entry, int line) { |
246 EXPECT(ClassFinalizer::ProcessPendingClasses()); | 235 EXPECT(ClassFinalizer::ProcessPendingClasses()); |
247 bool saved_flag = FLAG_show_invisible_frames; | 236 bool saved_flag = FLAG_show_invisible_frames; |
248 FLAG_show_invisible_frames = true; | 237 FLAG_show_invisible_frames = true; |
249 Dart_SetPausedEventHandler(SaveVars); | 238 Dart_SetPausedEventHandler(SaveVars); |
250 EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), line)); | 239 EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), line)); |
251 saved_vars = NULL; | 240 saved_vars = NULL; |
252 EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL)); | 241 EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL)); |
253 char* tmp = saved_vars; | 242 char* tmp = saved_vars; |
254 saved_vars = NULL; | 243 saved_vars = NULL; |
255 FLAG_show_invisible_frames = saved_flag; | 244 FLAG_show_invisible_frames = saved_flag; |
256 return tmp; | 245 return tmp; |
257 } | 246 } |
258 | 247 |
259 | |
260 TEST_CASE(Parser_AllocateVariables_CapturedVar) { | 248 TEST_CASE(Parser_AllocateVariables_CapturedVar) { |
261 const char* kScriptChars = | 249 const char* kScriptChars = |
262 "int main() {\n" | 250 "int main() {\n" |
263 " var value = 11;\n" | 251 " var value = 11;\n" |
264 " int f(var param) {\n" | 252 " int f(var param) {\n" |
265 " return param + value;\n" // line 4 | 253 " return param + value;\n" // line 4 |
266 " }\n" | 254 " }\n" |
267 " return f(22);\n" | 255 " return f(22);\n" |
268 "}\n"; | 256 "}\n"; |
269 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 257 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
(...skipping 17 matching lines...) Expand all Loading... |
287 "main\n" | 275 "main\n" |
288 " 0 ContextLevel level=0 begin=0 end=6\n" | 276 " 0 ContextLevel level=0 begin=0 end=6\n" |
289 " 1 ContextLevel level=1 begin=8 end=16\n" | 277 " 1 ContextLevel level=1 begin=8 end=16\n" |
290 " 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" | 278 " 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" |
291 " 3 ContextVar level=1 begin=10 end=37 name=value\n" | 279 " 3 ContextVar level=1 begin=10 end=37 name=value\n" |
292 " 4 StackVar scope=2 begin=12 end=37 name=f\n", | 280 " 4 StackVar scope=2 begin=12 end=37 name=f\n", |
293 vars); | 281 vars); |
294 free(vars); | 282 free(vars); |
295 } | 283 } |
296 | 284 |
297 | |
298 TEST_CASE(Parser_AllocateVariables_NestedCapturedVar) { | 285 TEST_CASE(Parser_AllocateVariables_NestedCapturedVar) { |
299 const char* kScriptChars = | 286 const char* kScriptChars = |
300 "int a() {\n" | 287 "int a() {\n" |
301 " int b() {\n" | 288 " int b() {\n" |
302 " var value = 11;\n" | 289 " var value = 11;\n" |
303 " int c() {\n" | 290 " int c() {\n" |
304 " return value;\n" // line 5 | 291 " return value;\n" // line 5 |
305 " }\n" | 292 " }\n" |
306 " return c();\n" | 293 " return c();\n" |
307 " }\n" | 294 " }\n" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 // don't save the entry context if the function has no captured | 330 // don't save the entry context if the function has no captured |
344 // variables. | 331 // variables. |
345 "a\n" | 332 "a\n" |
346 " 0 ContextLevel level=0 begin=0 end=14\n" | 333 " 0 ContextLevel level=0 begin=0 end=14\n" |
347 " 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" | 334 " 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" |
348 " 2 StackVar scope=2 begin=6 end=46 name=b\n", | 335 " 2 StackVar scope=2 begin=6 end=46 name=b\n", |
349 vars); | 336 vars); |
350 free(vars); | 337 free(vars); |
351 } | 338 } |
352 | 339 |
353 | |
354 TEST_CASE(Parser_AllocateVariables_TwoChains) { | 340 TEST_CASE(Parser_AllocateVariables_TwoChains) { |
355 const char* kScriptChars = | 341 const char* kScriptChars = |
356 "int a() {\n" | 342 "int a() {\n" |
357 " var value1 = 11;\n" | 343 " var value1 = 11;\n" |
358 " int b() {\n" | 344 " int b() {\n" |
359 " int aa() {\n" | 345 " int aa() {\n" |
360 " var value2 = 12;\n" | 346 " var value2 = 12;\n" |
361 " int bb() {\n" | 347 " int bb() {\n" |
362 " return value2;\n" // line 7 | 348 " return value2;\n" // line 7 |
363 " }\n" | 349 " }\n" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 " 0 ContextLevel level=0 begin=0 end=6\n" | 409 " 0 ContextLevel level=0 begin=0 end=6\n" |
424 " 1 ContextLevel level=1 begin=8 end=16\n" | 410 " 1 ContextLevel level=1 begin=8 end=16\n" |
425 " 2 CurrentCtx scope=0 begin=0 end=0" | 411 " 2 CurrentCtx scope=0 begin=0 end=0" |
426 " name=:current_context_var\n" | 412 " name=:current_context_var\n" |
427 " 3 ContextVar level=1 begin=10 end=71 name=value1\n" | 413 " 3 ContextVar level=1 begin=10 end=71 name=value1\n" |
428 " 4 StackVar scope=2 begin=12 end=71 name=b\n", | 414 " 4 StackVar scope=2 begin=12 end=71 name=b\n", |
429 vars); | 415 vars); |
430 free(vars); | 416 free(vars); |
431 } | 417 } |
432 | 418 |
433 | |
434 TEST_CASE(Parser_AllocateVariables_Issue7681) { | 419 TEST_CASE(Parser_AllocateVariables_Issue7681) { |
435 // This is a distilled version of the program from Issue 7681. | 420 // This is a distilled version of the program from Issue 7681. |
436 // | 421 // |
437 // When we create the closure at line 11, we need to make sure to | 422 // When we create the closure at line 11, we need to make sure to |
438 // save the entry context instead of chaining to the parent context. | 423 // save the entry context instead of chaining to the parent context. |
439 // | 424 // |
440 // This test is somewhat redundant with CapturedVarChain but | 425 // This test is somewhat redundant with CapturedVarChain but |
441 // included for good measure. | 426 // included for good measure. |
442 const char* kScriptChars = | 427 const char* kScriptChars = |
443 "class X {\n" | 428 "class X {\n" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 | 466 |
482 // No context is saved here since no vars are captured. | 467 // No context is saved here since no vars are captured. |
483 "doIt\n" | 468 "doIt\n" |
484 " 0 ContextLevel level=0 begin=0 end=18\n" | 469 " 0 ContextLevel level=0 begin=0 end=18\n" |
485 " 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" | 470 " 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" |
486 " 2 StackVar scope=2 begin=35 end=80 name=x\n", | 471 " 2 StackVar scope=2 begin=35 end=80 name=x\n", |
487 vars); | 472 vars); |
488 free(vars); | 473 free(vars); |
489 } | 474 } |
490 | 475 |
491 | |
492 TEST_CASE(Parser_AllocateVariables_CaptureLoopVar) { | 476 TEST_CASE(Parser_AllocateVariables_CaptureLoopVar) { |
493 // This test verifies that... | 477 // This test verifies that... |
494 // | 478 // |
495 // https://code.google.com/p/dart/issues/detail?id=18561 | 479 // https://code.google.com/p/dart/issues/detail?id=18561 |
496 // | 480 // |
497 // ...stays fixed. | 481 // ...stays fixed. |
498 const char* kScriptChars = | 482 const char* kScriptChars = |
499 "int outer() {\n" | 483 "int outer() {\n" |
500 " for(int i = 0; i < 1; i++) {\n" | 484 " for(int i = 0; i < 1; i++) {\n" |
501 " var value = 11 + i;\n" | 485 " var value = 11 + i;\n" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 " 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" | 572 " 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n" |
589 " 3 ContextVar level=1 begin=9 end=81 name=x\n" | 573 " 3 ContextVar level=1 begin=9 end=81 name=x\n" |
590 " 4 StackVar scope=2 begin=11 end=81 name=b\n", | 574 " 4 StackVar scope=2 begin=11 end=81 name=b\n", |
591 vars); | 575 vars); |
592 free(vars); | 576 free(vars); |
593 } | 577 } |
594 | 578 |
595 #endif // !PRODUCT | 579 #endif // !PRODUCT |
596 | 580 |
597 } // namespace dart | 581 } // namespace dart |
OLD | NEW |