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

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

Issue 2984263002: Make the ClosedWorld build the closure class on the kernel side. (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 '../elements/elements.dart'; 10 import '../elements/elements.dart';
11 import '../elements/entities.dart'; 11 import '../elements/entities.dart';
12 import '../elements/entity_utils.dart' as utils; 12 import '../elements/entity_utils.dart' as utils;
13 import '../elements/names.dart' show Name; 13 import '../elements/names.dart' show Name;
14 import '../kernel/element_map.dart'; 14 import '../kernel/element_map.dart';
15 import '../world.dart'; 15 import '../world.dart';
16 import 'elements.dart'; 16 import 'elements.dart';
17 import 'closure_visitors.dart'; 17 import 'closure_visitors.dart';
18 import 'locals.dart'; 18 import 'locals.dart';
19 import 'js_strategy.dart' show JsClosedWorld;
19 20
20 /// Closure conversion code using our new Entity model. Closure conversion is 21 /// Closure conversion code using our new Entity model. Closure conversion is
21 /// necessary because the semantics of closures are slightly different in Dart 22 /// necessary because the semantics of closures are slightly different in Dart
22 /// than JavaScript. Closure conversion is separated out into two phases: 23 /// than JavaScript. Closure conversion is separated out into two phases:
23 /// generation of a new (temporary) representation to store where variables need 24 /// generation of a new (temporary) representation to store where variables need
24 /// to be hoisted/captured up at another level to re-write the closure, and then 25 /// to be hoisted/captured up at another level to re-write the closure, and then
25 /// the code generation phase where we generate elements and/or instructions to 26 /// the code generation phase where we generate elements and/or instructions to
26 /// represent this new code path. 27 /// represent this new code path.
27 /// 28 ///
28 /// For a general explanation of how closure conversion works at a high level, 29 /// For a general explanation of how closure conversion works at a high level,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 ir.Field field = definition.node; 83 ir.Field field = definition.node;
83 // Skip top-level/static fields without an initializer. 84 // Skip top-level/static fields without an initializer.
84 if (field.initializer == null) return; 85 if (field.initializer == null) return;
85 } 86 }
86 closureModels[entity] = _buildClosureModel(entity); 87 closureModels[entity] = _buildClosureModel(entity);
87 }); 88 });
88 return closureModels; 89 return closureModels;
89 } 90 }
90 91
91 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels, 92 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels,
92 ClosedWorldRefiner closedWorldRefiner) { 93 JsClosedWorld closedWorldRefiner) {
93 closureModels.forEach((MemberEntity member, ClosureModel model) { 94 closureModels.forEach((MemberEntity member, ClosureModel model) {
94 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 95 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
95 if (model.scopeInfo != null) { 96 if (model.scopeInfo != null) {
96 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); 97 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap);
97 } 98 }
98 99
99 model.capturedScopesMap 100 model.capturedScopesMap
100 .forEach((ir.Node node, KernelCapturedScope scope) { 101 .forEach((ir.Node node, KernelCapturedScope scope) {
101 if (scope is KernelCapturedLoopScope) { 102 if (scope is KernelCapturedLoopScope) {
102 _capturedScopesMap[node] = 103 _capturedScopesMap[node] =
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 /// Given what variables are captured at each point, construct closure classes 145 /// Given what variables are captured at each point, construct closure classes
145 /// with fields containing the captured variables to replicate the Dart 146 /// with fields containing the captured variables to replicate the Dart
146 /// closure semantics in JS. If this closure captures any variables (meaning 147 /// closure semantics in JS. If this closure captures any variables (meaning
147 /// the closure accesses a variable that gets accessed at some point), then 148 /// the closure accesses a variable that gets accessed at some point), then
148 /// boxForCapturedVariables stores the local context for those variables. 149 /// boxForCapturedVariables stores the local context for those variables.
149 /// If no variables are captured, this parameter is null. 150 /// If no variables are captured, this parameter is null.
150 void _produceSyntheticElements( 151 void _produceSyntheticElements(
151 MemberEntity member, 152 MemberEntity member,
152 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, 153 ir.TreeNode /* ir.Member | ir.FunctionNode */ node,
153 KernelScopeInfo info, 154 KernelScopeInfo info,
154 ClosedWorldRefiner closedWorldRefiner) { 155 JsClosedWorld closedWorldRefiner) {
155 String name = _computeClosureName(node); 156 String name = _computeClosureName(node);
156 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 157 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
157 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( 158 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass(
158 name, member.library, info, node.location, localsMap); 159 name, member.library, info, node.location, localsMap);
159 160
160 Entity entity; 161 Entity entity;
161 if (node is ir.Member) { 162 if (node is ir.Member) {
162 entity = member; 163 entity = member;
163 } else { 164 } else {
164 assert(node is ir.FunctionNode); 165 assert(node is ir.FunctionNode);
165 entity = localsMap.getLocalFunction(node.parent); 166 entity = localsMap.getLocalFunction(node.parent);
166 // We want the original declaration where that function is used to point 167 // We want the original declaration where that function is used to point
167 // to the correct closure class. 168 // to the correct closure class.
168 _closureRepresentationMap[closureClass.callMethod] = closureClass; 169 _closureRepresentationMap[closureClass.callMethod] = closureClass;
169 } 170 }
170 assert(entity != null); 171 assert(entity != null);
171 _closureRepresentationMap[entity] = closureClass; 172 _closureRepresentationMap[entity] = closureClass;
172
173 // Register that a new class has been created.
174 closedWorldRefiner.registerClosureClass(closureClass);
175 } 173 }
176 174
177 // Returns a non-unique name for the given closure element. 175 // Returns a non-unique name for the given closure element.
178 String _computeClosureName(ir.TreeNode treeNode) { 176 String _computeClosureName(ir.TreeNode treeNode) {
179 var parts = <String>[]; 177 var parts = <String>[];
180 if (treeNode is ir.Field && treeNode.name.name != "") { 178 if (treeNode is ir.Field && treeNode.name.name != "") {
181 parts.add(treeNode.name.name); 179 parts.add(treeNode.name.name);
182 } else { 180 } else {
183 parts.add('closure'); 181 parts.add('closure');
184 } 182 }
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 385 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
388 class KernelClosureClass extends JsScopeInfo 386 class KernelClosureClass extends JsScopeInfo
389 implements ClosureRepresentationInfo, JClass { 387 implements ClosureRepresentationInfo, JClass {
390 final ir.Location location; 388 final ir.Location location;
391 389
392 final String name; 390 final String name;
393 final JLibrary library; 391 final JLibrary library;
394 392
395 /// Index into the classData, classList and classEnvironment lists where this 393 /// Index into the classData, classList and classEnvironment lists where this
396 /// entity is stored in [JsToFrontendMapImpl]. 394 /// entity is stored in [JsToFrontendMapImpl].
397 int classIndex; 395 final int classIndex;
398 396
399 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 397 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
400 398
401 KernelClosureClass.fromScopeInfo(this.name, this.library, 399 KernelClosureClass.fromScopeInfo(this.name, this.classIndex, this.library,
402 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) 400 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap)
403 : super.from(info, localsMap) { 401 : super.from(info, localsMap);
404 // Make a corresponding field entity in this closure class for every single
405 // freeVariable in the KernelScopeInfo.freeVariable.
406 int i = 0;
407 for (ir.VariableDeclaration variable in info.freeVariables) {
408 // NOTE: This construction order may be slightly different than the
409 // old Element version. The old version did all the boxed items and then
410 // all the others.
411 Local capturedLocal = localsMap.getLocalVariable(variable);
412 if (isBoxed(capturedLocal)) {
413 // TODO(efortuna): Coming soon.
414 } else {
415 localToFieldMap[capturedLocal] = new ClosureField(
416 _getClosureVariableName(capturedLocal.name, i),
417 this,
418 variable.isConst,
419 variable.isFinal || variable.isConst);
420 // TODO(efortuna): These probably need to get registered somewhere.
421 }
422 i++;
423 }
424 }
425
426 /// Generate a unique name for the [id]th closure field, with proposed name
427 /// [name].
428 ///
429 /// The result is used as the name of [ClosureFieldElement]s, and must
430 /// therefore be unique to avoid breaking an invariant in the element model
431 /// (classes cannot declare multiple fields with the same name).
432 ///
433 /// Also, the names should be distinct from real field names to prevent
434 /// clashes with selectors for those fields.
435 ///
436 /// These names are not used in generated code, just as element name.
437 String _getClosureVariableName(String name, int id) {
438 return "_captured_${name}_$id";
439 }
440 402
441 // TODO(efortuna): Implement. 403 // TODO(efortuna): Implement.
442 Local get closureEntity => null; 404 Local get closureEntity => null;
443 405
444 ClassEntity get closureClassEntity => this; 406 ClassEntity get closureClassEntity => this;
445 407
446 // TODO(efortuna): Implement. 408 // TODO(efortuna): Implement.
447 FunctionEntity get callMethod => null; 409 FunctionEntity get callMethod => null;
448 410
449 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 411 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
(...skipping 16 matching lines...) Expand all
466 bool isVariableBoxed(Local variable) => false; 428 bool isVariableBoxed(Local variable) => false;
467 429
468 bool get isClosure => true; 430 bool get isClosure => true;
469 431
470 bool get isAbstract => false; 432 bool get isAbstract => false;
471 433
472 String toString() => '${jsElementPrefix}class($name)'; 434 String toString() => '${jsElementPrefix}class($name)';
473 } 435 }
474 436
475 class ClosureField extends JField { 437 class ClosureField extends JField {
476 ClosureField(String name, KernelClosureClass containingClass, bool isConst, 438 ClosureField(String name, int memberIndex, KernelClosureClass containingClass,
477 bool isAssignable) 439 bool isConst, bool isAssignable)
478 : super(-1, containingClass.library, containingClass, 440 : super(memberIndex, containingClass.library, containingClass,
479 new Name(name, containingClass.library), 441 new Name(name, containingClass.library),
480 isAssignable: isAssignable, isConst: isConst); 442 isAssignable: isAssignable, isConst: isConst);
481 } 443 }
482 444
483 class ClosureClassDefinition implements ClassDefinition { 445 class ClosureClassDefinition implements ClassDefinition {
484 final ClassEntity cls; 446 final ClassEntity cls;
485 final ir.Location location; 447 final ir.Location location;
486 448
487 ClosureClassDefinition(this.cls, this.location); 449 ClosureClassDefinition(this.cls, this.location);
488 450
489 ClassKind get kind => ClassKind.closure; 451 ClassKind get kind => ClassKind.closure;
490 452
491 ir.Node get node => 453 ir.Node get node =>
492 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); 454 throw new UnsupportedError('ClosureClassDefinition.node for $cls');
493 455
494 String toString() => 456 String toString() =>
495 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; 457 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)';
496 } 458 }
497 459
460 class ClosureMemberDefinition implements MemberDefinition {
461 final MemberEntity member;
462 final ir.Location location;
463 final MemberKind kind;
464 final ir.Node node;
465
466 ClosureMemberDefinition(this.member, this.location, this.kind, this.node);
467
468 String toString() =>
469 'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)';
470 }
471
498 /// Collection of closure data collected for a single member. 472 /// Collection of closure data collected for a single member.
499 class ClosureModel { 473 class ClosureModel {
500 /// Collection [ScopeInfo] data for the member, if any. 474 /// Collection [ScopeInfo] data for the member, if any.
501 KernelScopeInfo scopeInfo; 475 KernelScopeInfo scopeInfo;
502 476
503 /// Collected [CapturedScope] data for nodes. 477 /// Collected [CapturedScope] data for nodes.
504 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 478 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
505 <ir.Node, KernelCapturedScope>{}; 479 <ir.Node, KernelCapturedScope>{};
506 480
507 /// Collected [ScopeInof] data for nodes. 481 /// Collected [ScopeInof] data for nodes.
508 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 482 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
509 <ir.TreeNode, KernelScopeInfo>{}; 483 <ir.TreeNode, KernelScopeInfo>{};
510 } 484 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/elements.dart » ('j') | pkg/compiler/lib/src/kernel/element_map_impl.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698