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

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

Powered by Google App Engine
This is Rietveld 408576698