Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: runtime/vm/parser_test.cc

Issue 267583002: Add some testing for the variable allocation code in the Parser. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: improve tests Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/object.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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/longjump.h" 9 #include "vm/longjump.h"
9 #include "vm/object.h" 10 #include "vm/object.h"
10 #include "vm/parser.h" 11 #include "vm/parser.h"
11 #include "vm/symbols.h" 12 #include "vm/symbols.h"
12 #include "vm/unit_test.h" 13 #include "vm/unit_test.h"
13 14
14 namespace dart { 15 namespace dart {
15 16
17 DECLARE_FLAG(bool, show_invisible_frames);
18
16 19
17 void DumpFunction(const Library& lib, const char* cname, const char* fname) { 20 void DumpFunction(const Library& lib, const char* cname, const char* fname) {
18 const String& classname = String::Handle(Symbols::New(cname)); 21 const String& classname = String::Handle(Symbols::New(cname));
19 Class& cls = Class::Handle(lib.LookupClass(classname)); 22 Class& cls = Class::Handle(lib.LookupClass(classname));
20 EXPECT(!cls.IsNull()); 23 EXPECT(!cls.IsNull());
21 24
22 String& funcname = String::Handle(String::New(fname)); 25 String& funcname = String::Handle(String::New(fname));
23 Function& function = Function::ZoneHandle(cls.LookupStaticFunction(funcname)); 26 Function& function = Function::ZoneHandle(cls.LookupStaticFunction(funcname));
24 EXPECT(!function.IsNull()); 27 EXPECT(!function.IsNull());
25 28
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 158
156 Parser::ParseCompilationUnit(lib, script); 159 Parser::ParseCompilationUnit(lib, script);
157 EXPECT(ClassFinalizer::ProcessPendingClasses()); 160 EXPECT(ClassFinalizer::ProcessPendingClasses());
158 161
159 DumpFunction(lib, "A", "foo"); 162 DumpFunction(lib, "A", "foo");
160 DumpFunction(lib, "A", "bar"); 163 DumpFunction(lib, "A", "bar");
161 DumpFunction(lib, "A", "baz"); 164 DumpFunction(lib, "A", "baz");
162 DumpFunction(lib, "B", "bam"); 165 DumpFunction(lib, "B", "bam");
163 } 166 }
164 167
168
169 const char* saved_vars = NULL;
170
171
172 // Saves the var descriptors for all frames on the stack as a string.
173 static void SaveVars(Dart_IsolateId isolate_id,
174 intptr_t bp_id,
175 const Dart_CodeLocation& loc) {
176 DebuggerStackTrace* stack =
177 Isolate::Current()->debugger()->StackTrace();
178 intptr_t num_frames = stack->Length();
179 const int kBufferLen = 2048;
180 char* buffer = new char[kBufferLen];
181 char* pos = buffer;
182 LocalVarDescriptors& var_desc = LocalVarDescriptors::Handle();
183 for (intptr_t i = 0; i < num_frames; i++) {
184 ActivationFrame* frame = stack->FrameAt(i);
185 var_desc = frame->code().var_descriptors();
186 pos += OS::SNPrint(pos, (kBufferLen - (pos - buffer)),
187 "%s\n%s",
188 frame->function().ToQualifiedCString(),
189 var_desc.ToCString());
190 }
191 pos[0] = '\0';
192 saved_vars = buffer;
193 }
194
195
196 // Uses the debugger to pause the program and capture the variable
197 // descriptors for all frames on the stack.
198 static const char* CaptureVarsAtLine(Dart_Handle lib,
199 const char* entry,
200 int line) {
201 EXPECT(ClassFinalizer::ProcessPendingClasses());
202 bool saved_flag = FLAG_show_invisible_frames;
203 FLAG_show_invisible_frames = true;
204 Isolate* isolate = Isolate::Current();
205 Debugger* debugger = isolate->debugger();
206 const String& url = String::Handle(String::New(TestCase::url()));
207 Dart_SetPausedEventHandler(SaveVars);
208 debugger->SetBreakpointAtLine(url, line);
209 saved_vars = NULL;
210 EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL));
211 const char* tmp = saved_vars;
212 saved_vars = NULL;
213 FLAG_show_invisible_frames = saved_flag;
214 return tmp;
215 }
216
217
218 TEST_CASE(Parser_AllocateVariables_CapturedVar) {
219 const char* kScriptChars =
220 "int main() {\n"
221 " var value = 11;\n"
222 " int f(var param) {\n"
223 " return param + value;\n" // line 4
224 " }\n"
225 " return f(22);\n"
226 "}\n";
227 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
228 EXPECT_VALID(lib);
229 EXPECT_STREQ(
230 // function f uses one ctx var at (0,0); doesn't save ctx.
231 "::.main_f\n"
232 " 0 ContextVar level=0 index=0 begin=14 end=28 name=value\n"
233 " 1 StackVar scope=1 index=2 begin=16 end=28 name=param\n"
234
235 // Closure call saves current context.
236 "(dynamic, dynamic) => int.call\n"
237 " 0 StackVar scope=1 index=3 begin=0 end=0 name=this\n"
238 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
239 " name=:saved_current_context_var\n"
240
241 // function main uses one ctx var at (1,0); saves caller ctx.
242 "::.main\n"
243 " 0 ContextLevel level=1 scope=1 begin=2 end=37\n"
244 " 1 SavedEntryCtx scope=0 index=-4 begin=0 end=0"
245 " name=:saved_entry_context_var\n"
246 " 2 ContextVar level=1 index=0 begin=7 end=37 name=value\n"
247 " 3 StackVar scope=2 index=-3 begin=12 end=37 name=f\n",
248 CaptureVarsAtLine(lib, "main", 4));
249 }
250
251
252 TEST_CASE(Parser_AllocateVariables_NestedCapturedVar) {
253 const char* kScriptChars =
254 "int a() {\n"
255 " int b() {\n"
256 " var value = 11;\n"
257 " int c() {\n"
258 " return value;\n" // line 5
259 " }\n"
260 " return c();\n"
261 " }\n"
262 " return b();\n"
263 "}\n";
264 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
265 EXPECT_VALID(lib);
266 EXPECT_STREQ(
267 // Innermost function uses captured variable 'value' from middle
268 // function.
269 "::.a_b_c\n"
270 " 0 ContextVar level=0 index=0 begin=20 end=30 name=value\n"
271
272 // Closure call saves current context.
273 "(dynamic) => int.call\n"
274 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
275 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
276 " name=:saved_current_context_var\n"
277
278 // Middle function saves the entry context. Notice that this
279 // happens here and not in the outermost function. We always
280 // save the entry context at the last possible moment.
281 "::.a_b\n"
282 " 0 ContextLevel level=1 scope=1 begin=8 end=38\n"
283 " 1 SavedEntryCtx scope=0 index=-4 begin=0 end=0"
284 " name=:saved_entry_context_var\n"
285 " 2 ContextVar level=1 index=0 begin=13 end=38 name=value\n"
286 " 3 StackVar scope=2 index=-3 begin=18 end=38 name=c\n"
287
288 // Closure call saves current context.
289 "(dynamic) => int.call\n"
290 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
291 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
292 " name=:saved_current_context_var\n"
293
294 // Outermost function neglects to save the entry context. We
295 // don't save the entry context if the function has no captured
296 // variables.
297 "::.a\n"
298 " 0 StackVar scope=2 index=-3 begin=6 end=46 name=b\n",
299 CaptureVarsAtLine(lib, "a", 5));
300 }
301
302
303 TEST_CASE(Parser_AllocateVariables_TwoChains) {
304 const char* kScriptChars =
305 "int a() {\n"
306 " var value1 = 11;\n"
307 " int b() {\n"
308 " int aa() {\n"
309 " var value2 = 12;\n"
310 " int bb() {\n"
311 " return value2;\n" // line 7
312 " }\n"
313 " return bb();\n"
314 " }\n"
315 " return value1 + aa();\n"
316 " }\n"
317 " return b();\n"
318 "}\n";
319 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
320 EXPECT_VALID(lib);
321 EXPECT_STREQ(
322 // bb captures only value2 from aa. No others.
323 "::.a_b_aa_bb\n"
324 " 0 ContextVar level=0 index=0 begin=32 end=42 name=value2\n"
325
326 // Closure call saves current context.
327 "(dynamic) => int.call\n"
328 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
329 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
330 " name=:saved_current_context_var\n"
331
332 // aa shares value2. Notice that we save the entry ctx instead
333 // of chaining from b. This keeps us from holding onto closures
334 // that we would never access.
335 "::.a_b_aa\n"
336 " 0 ContextLevel level=1 scope=1 begin=20 end=50\n"
337 " 1 SavedEntryCtx scope=0 index=-4 begin=0 end=0"
338 " name=:saved_entry_context_var\n"
339 " 2 ContextVar level=1 index=0 begin=25 end=50 name=value2\n"
340 " 3 StackVar scope=2 index=-3 begin=30 end=50 name=bb\n"
341
342 // Closure call saves current context.
343 "(dynamic) => int.call\n"
344 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
345 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
346 " name=:saved_current_context_var\n"
347
348 // b captures value1 from a.
349 "::.a_b\n"
350 " 0 ContextVar level=0 index=0 begin=14 end=60 name=value1\n"
351 " 1 StackVar scope=2 index=-3 begin=18 end=60 name=aa\n"
352
353 // Closure call saves current context.
354 "(dynamic) => int.call\n"
355 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
356 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
357 " name=:saved_current_context_var\n"
358
359 // a shares value1, saves entry ctx.
360 "::.a\n"
361 " 0 ContextLevel level=1 scope=1 begin=2 end=68\n"
362 " 1 SavedEntryCtx scope=0 index=-4 begin=0 end=0"
363 " name=:saved_entry_context_var\n"
364 " 2 ContextVar level=1 index=0 begin=7 end=68 name=value1\n"
365 " 3 StackVar scope=2 index=-3 begin=12 end=68 name=b\n",
366 CaptureVarsAtLine(lib, "a", 7));
367 }
368
369
370 TEST_CASE(Parser_AllocateVariables_Issue7681) {
371 // This is a distilled version of the program from Issue 7681.
372 //
373 // When we create the closure at line 11, we need to make sure to
374 // save the entry context instead of chaining to the parent context.
375 //
376 // This test is somewhat redundant with CapturedVarChain but
377 // included for good measure.
378 const char* kScriptChars =
379 "class X {\n"
380 " Function onX;\n"
381 "}\n"
382 "\n"
383 "class Y {\n"
384 " Function onY;\n"
385 "}\n"
386 "\n"
387 "void doIt() {\n"
388 " var x = new X();\n"
389 " x.onX = (y) {\n"
390 " y.onY = () {\n" // line 12
391 " return y;\n"
392 " };\n"
393 " };\n"
394 " x.onX(new Y());\n"
395 "}\n";
396 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
397 EXPECT_VALID(lib);
398 EXPECT_STREQ(
399 // This frame saves the entry context instead of chaining. Good.
400 "::.doIt_<anonymous closure>\n"
401 " 0 ContextLevel level=1 scope=1 begin=41 end=62\n"
402 " 1 ContextVar level=1 index=0 begin=42 end=62 name=y\n"
403 " 2 SavedEntryCtx scope=0 index=-3 begin=0 end=0"
404 " name=:saved_entry_context_var\n"
405
406 // Closure call saves current context.
407 "(dynamic, dynamic) => dynamic.call\n"
408 " 0 StackVar scope=1 index=3 begin=0 end=0 name=this\n"
409 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
410 " name=:saved_current_context_var\n"
411
412 "X.onX\n"
413 " 0 StackVar scope=1 index=3 begin=0 end=0 name=this\n"
414
415 // No context is saved here since no vars are captured.
416 "::.doIt\n"
417 " 0 StackVar scope=2 index=-3 begin=29 end=77 name=x\n",
418 CaptureVarsAtLine(lib, "doIt", 12));
419 }
420
421
422 TEST_CASE(Parser_AllocateVariables_CaptureLoopVar) {
423 const char* kScriptChars =
424 "int outer() {\n"
425 " for(int i = 0; i < 1; i++) {\n"
426 " var value = 11 + i;\n"
427 " int inner() {\n"
428 " return value;\n" // line 5
429 " }\n"
430 " return inner();\n"
431 " }\n"
432 "}\n";
433 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
434 EXPECT_VALID(lib);
435 EXPECT_STREQ(
436 // inner function captures variable value. That's fine.
437 "::.outer_inner\n"
438 " 0 ContextVar level=0 index=0 begin=32 end=42 name=value\n"
439
440 // Closure call saves current context.
441 "(dynamic) => int.call\n"
442 " 0 StackVar scope=1 index=2 begin=0 end=0 name=this\n"
443 " 1 SavedCurrentCtx scope=0 index=-3 begin=0 end=0"
444 " name=:saved_current_context_var\n"
445
446 // Notice that the outer function neglects to save the entry
447 // context. This is a bug.
448 //
449 // TODO(turnidge): Fix this very soon and update this test.
450 //
451 // https://code.google.com/p/dart/issues/detail?id=18561
452 "::.outer\n"
453 " 0 StackVar scope=3 index=-3 begin=9 end=50 name=i\n"
454 " 1 ContextLevel level=1 scope=4 begin=20 end=50\n"
455 " 2 ContextVar level=1 index=0 begin=23 end=50 name=value\n"
456 " 3 StackVar scope=4 index=-4 begin=30 end=50 name=inner\n",
457 CaptureVarsAtLine(lib, "outer", 5));
458 }
459
165 } // namespace dart 460 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/object.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698