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

Side by Side Diff: pkg/compiler/lib/src/js_model/closure.dart

Issue 2995353002: Test the CapturedScope for local functions (Closed)
Patch Set: Created 3 years, 4 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
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../closure.dart'; 7 import '../closure.dart';
8 import '../common.dart'; 8 import '../common.dart';
9 import '../common/tasks.dart'; 9 import '../common/tasks.dart';
10 import '../constants/expressions.dart'; 10 import '../constants/expressions.dart';
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 var closure = _localClosureRepresentationMap[node]; 259 var closure = _localClosureRepresentationMap[node];
260 assert( 260 assert(
261 closure != null, 261 closure != null,
262 "Corresponding closure class not found for $node. " 262 "Corresponding closure class not found for $node. "
263 "Closures found for ${_localClosureRepresentationMap.keys}"); 263 "Closures found for ${_localClosureRepresentationMap.keys}");
264 return closure; 264 return closure;
265 } 265 }
266 } 266 }
267 267
268 class KernelScopeInfo { 268 class KernelScopeInfo {
269 // TODO(johnniwinther): Remove this. It seems to be unneeded.
269 final ir.TreeNode node; 270 final ir.TreeNode node;
Emily Fortuna 2017/08/22 23:47:36 why not just delete it then?
Johnni Winther 2017/08/23 07:47:18 It's good for debugging and it seemed that I might
270 final Set<ir.VariableDeclaration> localsUsedInTryOrSync; 271 final Set<ir.VariableDeclaration> localsUsedInTryOrSync;
271 final bool hasThisLocal; 272 final bool hasThisLocal;
272 273
273 /// The set of variables that were defined in another scope, but are used in 274 /// The set of variables that were defined in another scope, but are used in
274 /// this scope. 275 /// this scope.
275 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); 276 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();
276 277
277 KernelScopeInfo(this.node, this.hasThisLocal) 278 KernelScopeInfo(this.node, this.hasThisLocal)
278 : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(); 279 : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>();
279 280
280 KernelScopeInfo.from(this.node, this.hasThisLocal, KernelScopeInfo info) 281 KernelScopeInfo.from(this.node, this.hasThisLocal, KernelScopeInfo info)
281 : localsUsedInTryOrSync = info.localsUsedInTryOrSync; 282 : localsUsedInTryOrSync = info.localsUsedInTryOrSync;
282 283
283 KernelScopeInfo.withBoxedVariables(this.node, this.localsUsedInTryOrSync, 284 KernelScopeInfo.withBoxedVariables(this.node, this.localsUsedInTryOrSync,
284 this.freeVariables, this.hasThisLocal); 285 this.freeVariables, this.hasThisLocal);
285 286
287 bool _printOn(StringBuffer sb, bool needsComma) {
288 if (node != null) {
289 if (needsComma) {
290 sb.write(',');
291 }
292 sb.write('node=$node');
293 needsComma = true;
294 }
295 if (hasThisLocal) {
296 if (needsComma) {
297 sb.write(',');
298 }
299 sb.write('hasThisLocal');
300 needsComma = true;
301 }
302 if (localsUsedInTryOrSync.isNotEmpty) {
303 if (needsComma) {
304 sb.write(',');
305 }
306 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
307 needsComma = true;
308 }
309 /*if (freeVariables.isNotEmpty) {
Emily Fortuna 2017/08/22 23:47:37 delete or uncomment?
310 if (needsComma) {
311 sb.write(',');
312 }
313 sb.write('freeVariables=${freeVariables}');
314 needsComma = true;
315 }*/
316 return needsComma;
317 }
318
286 String toString() { 319 String toString() {
287 StringBuffer sb = new StringBuffer(); 320 StringBuffer sb = new StringBuffer();
288 sb.write('this=$hasThisLocal,'); 321 sb.write('KernelScopeInfo(');
289 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 322 _printOn(sb, false);
323 sb.write(')');
290 return sb.toString(); 324 return sb.toString();
291 } 325 }
292 } 326 }
293 327
294 class JsScopeInfo extends ScopeInfo { 328 class JsScopeInfo extends ScopeInfo {
295 final Set<Local> localsUsedInTryOrSync; 329 final Set<Local> localsUsedInTryOrSync;
296 final Local thisLocal; 330 final Local thisLocal;
297 331
298 /// The set of variables that were defined in another scope, but are used in
299 /// this scope.
300 final Set<Local> freeVariables;
301
302 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap) 332 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
303 : this.thisLocal = 333 : this.thisLocal =
304 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 334 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
305 this.localsUsedInTryOrSync = 335 this.localsUsedInTryOrSync =
306 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(), 336 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet();
307 this.freeVariables =
308 info.freeVariables.map(localsMap.getLocalVariable).toSet();
309 337
310 bool localIsUsedInTryOrSync(Local variable) => 338 bool localIsUsedInTryOrSync(Local variable) =>
311 localsUsedInTryOrSync.contains(variable); 339 localsUsedInTryOrSync.contains(variable);
312 340
341 bool _printOn(StringBuffer sb, bool needsComma) {
342 if (thisLocal != null) {
343 if (needsComma) {
344 sb.write(',');
345 }
346 sb.write('this=$thisLocal');
347 needsComma = true;
348 }
349 if (localsUsedInTryOrSync.isNotEmpty) {
350 if (needsComma) {
351 sb.write(',');
352 }
353 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
354 needsComma = true;
355 }
356 return needsComma;
357 }
358
313 String toString() { 359 String toString() {
314 StringBuffer sb = new StringBuffer(); 360 StringBuffer sb = new StringBuffer();
315 sb.write('this=$thisLocal,'); 361 sb.write('JsScopeInfo(');
316 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 362 _printOn(sb, false);
363 sb.write(')');
317 return sb.toString(); 364 return sb.toString();
318 } 365 }
319 } 366 }
320 367
321 class KernelCapturedScope extends KernelScopeInfo { 368 class KernelCapturedScope extends KernelScopeInfo {
322 final NodeBox box; 369 final NodeBox box;
323 final Set<ir.VariableDeclaration> boxedVariables; 370 final Set<ir.VariableDeclaration> boxedVariables;
324 371
325 KernelCapturedScope( 372 KernelCapturedScope(
326 ir.TreeNode node, 373 ir.TreeNode node,
327 this.box, 374 this.box,
328 this.boxedVariables, 375 this.boxedVariables,
329 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 376 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
330 Set<ir.VariableDeclaration> freeVariables, 377 Set<ir.VariableDeclaration> freeVariables,
331 bool hasThisLocal) 378 bool hasThisLocal)
332 : super.withBoxedVariables( 379 : super.withBoxedVariables(
333 node, localsUsedInTryOrSync, freeVariables, hasThisLocal); 380 node, localsUsedInTryOrSync, freeVariables, hasThisLocal);
334 381
335 bool get requiresContextBox => boxedVariables.isNotEmpty; 382 bool get requiresContextBox => boxedVariables.isNotEmpty;
383
384 bool _printOn(StringBuffer sb, bool needsComma) {
385 needsComma = super._printOn(sb, needsComma);
386 if (box != null) {
387 if (needsComma) {
388 sb.write(',');
389 }
390 sb.write('box=${box}');
391 needsComma = true;
392 }
393 if (boxedVariables.isNotEmpty) {
394 if (needsComma) {
395 sb.write(',');
396 }
397 sb.write('boxedVariables={${boxedVariables.join(',')}}');
398 needsComma = true;
399 }
400 return needsComma;
401 }
402
403 String toString() {
404 StringBuffer sb = new StringBuffer();
405 sb.write('KernelCapturedScope(');
406 _printOn(sb, false);
407 sb.write(')');
408 return sb.toString();
409 }
336 } 410 }
337 411
338 class JsCapturedScope extends JsScopeInfo implements CapturedScope { 412 class JsCapturedScope extends JsScopeInfo implements CapturedScope {
339 final Local context; 413 final Local box;
340 final Map<Local, FieldEntity> boxedVariables; 414 final Map<Local, FieldEntity> boxedVariables;
341 415
342 JsCapturedScope.from(KernelCapturedScope capturedScope, 416 JsCapturedScope.from(KernelCapturedScope capturedScope,
343 KernelToLocalsMap localsMap, this.context, this.boxedVariables) 417 KernelToLocalsMap localsMap, this.box, this.boxedVariables)
344 : super.from(capturedScope, localsMap); 418 : super.from(capturedScope, localsMap);
345 419
346 bool get requiresContextBox => boxedVariables.isNotEmpty; 420 bool get hasBox => box != null;
347 421
348 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 422 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
349 boxedVariables.forEach(f); 423 boxedVariables.forEach(f);
350 } 424 }
351 425
352 bool isBoxed(Local variable) => boxedVariables.containsKey(variable); 426 bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
427
428 bool _printOn(StringBuffer sb, bool needsComma) {
429 needsComma = super._printOn(sb, needsComma);
430 if (box != null) {
431 if (needsComma) {
432 sb.write(',');
433 }
434 sb.write('box=${box}');
435 needsComma = true;
436 }
437 if (boxedVariables.isNotEmpty) {
438 if (needsComma) {
439 sb.write(',');
440 }
441 sb.write('boxedVariables=${boxedVariables}');
442 needsComma = true;
443 }
444 return needsComma;
445 }
446
447 String toString() {
448 StringBuffer sb = new StringBuffer();
449 sb.write('JsCapturedScope(');
450 _printOn(sb, false);
451 sb.write(')');
452 return sb.toString();
453 }
353 } 454 }
354 455
355 class KernelCapturedLoopScope extends KernelCapturedScope { 456 class KernelCapturedLoopScope extends KernelCapturedScope {
356 final List<ir.VariableDeclaration> boxedLoopVariables; 457 final List<ir.VariableDeclaration> boxedLoopVariables;
357 458
358 KernelCapturedLoopScope( 459 KernelCapturedLoopScope(
359 ir.TreeNode node, 460 ir.TreeNode node,
360 NodeBox box, 461 NodeBox box,
361 Set<ir.VariableDeclaration> boxedVariables, 462 Set<ir.VariableDeclaration> boxedVariables,
362 this.boxedLoopVariables, 463 this.boxedLoopVariables,
363 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 464 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
364 Set<ir.VariableDeclaration> freeVariables, 465 Set<ir.VariableDeclaration> freeVariables,
365 bool hasThisLocal) 466 bool hasThisLocal)
366 : super(node, box, boxedVariables, localsUsedInTryOrSync, freeVariables, 467 : super(node, box, boxedVariables, localsUsedInTryOrSync, freeVariables,
367 hasThisLocal); 468 hasThisLocal);
368 469
369 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 470 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
471
472 bool _printOn(StringBuffer sb, bool needsComma) {
473 needsComma = super._printOn(sb, needsComma);
474 if (boxedLoopVariables.isNotEmpty) {
475 if (needsComma) {
476 sb.write(',');
477 }
478 sb.write('boxedLoopVariables={${boxedLoopVariables.join(',')}}');
479 needsComma = true;
480 }
481 return needsComma;
482 }
483
484 String toString() {
485 StringBuffer sb = new StringBuffer();
486 sb.write('KernelCapturedLoopScope(');
487 _printOn(sb, false);
488 sb.write(')');
489 return sb.toString();
490 }
370 } 491 }
371 492
372 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope { 493 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
373 final List<Local> boxedLoopVariables; 494 final List<Local> boxedLoopVariables;
374 495
375 JsCapturedLoopScope.from( 496 JsCapturedLoopScope.from(
376 KernelCapturedLoopScope capturedScope, 497 KernelCapturedLoopScope capturedScope,
377 KernelToLocalsMap localsMap, 498 KernelToLocalsMap localsMap,
378 Local box, 499 Local box,
379 Map<Local, FieldEntity> boxedVariables) 500 Map<Local, FieldEntity> boxedVariables)
380 : this.boxedLoopVariables = capturedScope.boxedLoopVariables 501 : this.boxedLoopVariables = capturedScope.boxedLoopVariables
381 .map(localsMap.getLocalVariable) 502 .map(localsMap.getLocalVariable)
382 .toList(), 503 .toList(),
383 super.from(capturedScope, localsMap, box, boxedVariables); 504 super.from(capturedScope, localsMap, box, boxedVariables);
384 505
385 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 506 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
507
508 bool _printOn(StringBuffer sb, bool needsComma) {
509 needsComma = super._printOn(sb, needsComma);
510 if (boxedLoopVariables.isNotEmpty) {
511 if (needsComma) {
512 sb.write(',');
513 }
514 sb.write('boxedLoopVariables={${boxedLoopVariables.join(',')}}');
515 needsComma = true;
516 }
517 return needsComma;
518 }
519
520 String toString() {
521 StringBuffer sb = new StringBuffer();
522 sb.write('JsCapturedLoopScope(');
523 _printOn(sb, false);
524 sb.write(')');
525 return sb.toString();
526 }
386 } 527 }
387 528
388 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 529 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
389 class KernelClosureClass extends JsScopeInfo 530 class KernelClosureClass extends JsScopeInfo
390 implements ClosureRepresentationInfo { 531 implements ClosureRepresentationInfo {
391 JFunction callMethod; 532 JFunction callMethod;
392 final Local closureEntity; 533 final Local closureEntity;
393 final Local thisLocal; 534 final Local thisLocal;
394 final JClass closureClassEntity; 535 final JClass closureClassEntity;
395 final Map<Local, FieldEntity> boxedVariables; 536 final Map<Local, FieldEntity> boxedVariables;
(...skipping 19 matching lines...) Expand all
415 : localsMap.getLocalFunction(closureSourceNode.parent), 556 : localsMap.getLocalFunction(closureSourceNode.parent),
416 thisLocal = 557 thisLocal =
417 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 558 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
418 super.from(info, localsMap); 559 super.from(info, localsMap);
419 560
420 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 561 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
421 562
422 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; 563 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
423 564
424 void forEachBoxedVariable(f(Local from, FieldEntity to)) { 565 void forEachBoxedVariable(f(Local from, FieldEntity to)) {
425 boxedVariables.forEach(f); 566 throw new UnsupportedError('KernelClosureClass.forEachBoxedVariable');
426 } 567 }
427 568
428 void forEachCapturedVariable(f(Local from, FieldEntity to)) { 569 void forEachCapturedVariable(f(Local from, FieldEntity to)) {
429 for (Local local in localToFieldMap.keys) { 570 throw new UnsupportedError('KernelClosureClass.forEachCapturedVariable');
430 FieldEntity field = localToFieldMap[local];
431 if (local is! BoxLocal) f(local, field);
432 }
433 boxedVariables.forEach(f);
434 } 571 }
435 572
436 void forEachFreeVariable(f(Local variable, FieldEntity field)) { 573 void forEachFreeVariable(f(Local variable, FieldEntity field)) {
437 localToFieldMap.forEach(f); 574 localToFieldMap.forEach(f);
438 boxedVariables.forEach(f); 575 boxedVariables.forEach(f);
439 } 576 }
440 577
441 bool isVariableBoxed(Local variable) => boxedVariables.containsKey(variable); 578 bool isVariableBoxed(Local variable) {
579 throw new UnsupportedError('KernelClosureClass.isVariableBoxed');
580 }
442 581
443 bool get isClosure => true; 582 bool get isClosure => true;
444 } 583 }
445 584
446 /// A local variable to disambiguate between a variable that has been captured 585 /// A local variable to disambiguate between a variable that has been captured
447 /// from one scope to another. This is the ir.Node version that corresponds to 586 /// from one scope to another. This is the ir.Node version that corresponds to
448 /// [BoxLocal]. 587 /// [BoxLocal].
449 class NodeBox { 588 class NodeBox {
450 final String name; 589 final String name;
451 590
452 NodeBox(this.name); 591 NodeBox(this.name);
592
593 String toString() => 'NodeBox(name=$name)';
453 } 594 }
454 595
455 class JClosureClass extends JClass { 596 class JClosureClass extends JClass {
456 JClosureClass(JLibrary library, int classIndex, String name) 597 JClosureClass(JLibrary library, int classIndex, String name)
457 : super(library, classIndex, name, isAbstract: false); 598 : super(library, classIndex, name, isAbstract: false);
458 599
459 @override 600 @override
460 bool get isClosure => true; 601 bool get isClosure => true;
461 602
462 String toString() => '${jsElementPrefix}closure_class($name)'; 603 String toString() => '${jsElementPrefix}closure_class($name)';
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 KernelScopeInfo scopeInfo; 745 KernelScopeInfo scopeInfo;
605 746
606 /// Collected [CapturedScope] data for nodes. 747 /// Collected [CapturedScope] data for nodes.
607 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 748 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
608 <ir.Node, KernelCapturedScope>{}; 749 <ir.Node, KernelCapturedScope>{};
609 750
610 /// Collected [ScopeInfo] data for nodes. 751 /// Collected [ScopeInfo] data for nodes.
611 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 752 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
612 <ir.TreeNode, KernelScopeInfo>{}; 753 <ir.TreeNode, KernelScopeInfo>{};
613 } 754 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698