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

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

Issue 2979373003: Compute closure model during resolution (Closed)
Patch Set: Rebased 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/js_strategy.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 19
20 class KernelClosureAnalysis {
21 /// Inspect members and mark if those members capture any state that needs to
22 /// be marked as free variables.
23 static ClosureModel computeClosureModel(MemberEntity entity, ir.Member node) {
24 if (entity.isAbstract) return null;
25 if (entity.isField && !entity.isInstanceMember) {
26 ir.Field field = node;
27 // Skip top-level/static fields without an initializer.
28 if (field.initializer == null) return null;
29 }
30
31 ClosureModel model = new ClosureModel();
32 CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
33 hasThisLocal: entity.isInstanceMember || entity.isConstructor);
34 if (entity.isField) {
35 if (node is ir.Field && node.initializer != null) {
36 translator.translateLazyInitializer(node);
37 }
38 } else {
39 assert(node is ir.Procedure || node is ir.Constructor);
40 translator.translateConstructorOrProcedure(node);
41 }
42 return model;
43 }
44 }
45
20 /// Closure conversion code using our new Entity model. Closure conversion is 46 /// Closure conversion code using our new Entity model. Closure conversion is
21 /// necessary because the semantics of closures are slightly different in Dart 47 /// necessary because the semantics of closures are slightly different in Dart
22 /// than JavaScript. Closure conversion is separated out into two phases: 48 /// than JavaScript. Closure conversion is separated out into two phases:
23 /// generation of a new (temporary) representation to store where variables need 49 /// 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 50 /// 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 51 /// the code generation phase where we generate elements and/or instructions to
26 /// represent this new code path. 52 /// represent this new code path.
27 /// 53 ///
28 /// For a general explanation of how closure conversion works at a high level, 54 /// For a general explanation of how closure conversion works at a high level,
29 /// check out: 55 /// check out:
30 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or 56 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or
31 /// http://matt.might.net/articles/closure-conversion/. 57 /// http://matt.might.net/articles/closure-conversion/.
32 // TODO(efortuna): Change inheritance hierarchy so that the 58 // TODO(efortuna): Change inheritance hierarchy so that the
33 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a 59 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a
34 // glorified timer. 60 // glorified timer.
35 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { 61 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
36 final KernelToElementMapForBuilding _elementMap; 62 final KernelToElementMapForBuilding _elementMap;
37 final GlobalLocalsMap _globalLocalsMap; 63 final GlobalLocalsMap _globalLocalsMap;
64 final Map<MemberEntity, ClosureModel> _closureModels;
38 65
39 /// Map of the scoping information that corresponds to a particular entity. 66 /// Map of the scoping information that corresponds to a particular entity.
40 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{}; 67 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{};
41 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{}; 68 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{};
42 69
43 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap = 70 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap =
44 <Entity, ClosureRepresentationInfo>{}; 71 <Entity, ClosureRepresentationInfo>{};
45 72
46 /// Should only be used at the very beginning to ensure we are looking at the
47 /// right kind of elements.
48 // TODO(efortuna): Remove this map once we have one kernel backend strategy.
49 final JsToFrontendMap _kToJElementMap;
50
51 KernelClosureConversionTask(Measurer measurer, this._elementMap, 73 KernelClosureConversionTask(Measurer measurer, this._elementMap,
52 this._kToJElementMap, this._globalLocalsMap) 74 this._globalLocalsMap, this._closureModels)
53 : super(measurer); 75 : super(measurer);
54 76
55 /// The combined steps of generating our intermediate representation of 77 /// The combined steps of generating our intermediate representation of
56 /// closures that need to be rewritten and generating the element model. 78 /// closures that need to be rewritten and generating the element model.
57 /// Ultimately these two steps will be split apart with the second step 79 /// Ultimately these two steps will be split apart with the second step
58 /// happening later in compilation just before codegen. These steps are 80 /// happening later in compilation just before codegen. These steps are
59 /// combined here currently to provide a consistent interface to the rest of 81 /// combined here currently to provide a consistent interface to the rest of
60 /// the compiler until we are ready to separate these phases. 82 /// the compiler until we are ready to separate these phases.
61 @override 83 @override
62 void convertClosures(Iterable<MemberEntity> processedEntities, 84 void convertClosures(Iterable<MemberEntity> processedEntities,
63 ClosedWorldRefiner closedWorldRefiner) { 85 ClosedWorldRefiner closedWorldRefiner) {
64 Map<MemberEntity, ClosureModel> closureModels = 86 _createClosureEntities(_closureModels, closedWorldRefiner);
65 _computeClosureModels(processedEntities);
66 _createClosureEntities(closureModels, closedWorldRefiner);
67 }
68
69 // TODO(johnniwinther,efortuna): Compute this during resolution. See
70 // documentation on [convertClosures].
71 Map<MemberEntity, ClosureModel> _computeClosureModels(
72 Iterable<MemberEntity> processedEntities) {
73 Map<MemberEntity, ClosureModel> closureModels =
74 <MemberEntity, ClosureModel>{};
75
76 processedEntities.forEach((MemberEntity kEntity) {
77 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity);
78 if (entity.isAbstract) return;
79 if (entity.isField && !entity.isInstanceMember) {
80 MemberDefinition definition = _elementMap.getMemberDefinition(entity);
81 assert(definition.kind == MemberKind.regular,
82 failedAt(entity, "Unexpected member definition $definition"));
83 ir.Field field = definition.node;
84 // Skip top-level/static fields without an initializer.
85 if (field.initializer == null) return;
86 }
87 closureModels[entity] = _buildClosureModel(entity);
88 });
89 return closureModels;
90 } 87 }
91 88
92 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels, 89 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels,
93 ClosedWorldRefiner closedWorldRefiner) { 90 ClosedWorldRefiner closedWorldRefiner) {
94 closureModels.forEach((MemberEntity member, ClosureModel model) { 91 closureModels.forEach((MemberEntity member, ClosureModel model) {
95 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 92 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
96 if (model.scopeInfo != null) { 93 if (model.scopeInfo != null) {
97 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); 94 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap);
98 } 95 }
99 96
100 model.capturedScopesMap 97 model.capturedScopesMap
101 .forEach((ir.Node node, KernelCapturedScope scope) { 98 .forEach((ir.Node node, KernelCapturedScope scope) {
102 if (scope is KernelCapturedLoopScope) { 99 if (scope is KernelCapturedLoopScope) {
103 _capturedScopesMap[node] = 100 _capturedScopesMap[node] =
104 new JsCapturedLoopScope.from(scope, localsMap); 101 new JsCapturedLoopScope.from(scope, localsMap);
105 } else { 102 } else {
106 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); 103 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap);
107 } 104 }
108 }); 105 });
109 106
110 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 107 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
111 model.closuresToGenerate; 108 model.closuresToGenerate;
112 for (ir.TreeNode node in closuresToGenerate.keys) { 109 for (ir.TreeNode node in closuresToGenerate.keys) {
113 _produceSyntheticElements( 110 _produceSyntheticElements(
114 member, node, closuresToGenerate[node], closedWorldRefiner); 111 member, node, closuresToGenerate[node], closedWorldRefiner);
115 } 112 }
116 }); 113 });
117 } 114 }
118 115
119 /// Inspect members and mark if those members capture any state that needs to
120 /// be marked as free variables.
121 ClosureModel _buildClosureModel(MemberEntity entity) {
122 ClosureModel model = new ClosureModel();
123 MemberDefinition definition = _elementMap.getMemberDefinition(entity);
124 switch (definition.kind) {
125 case MemberKind.regular:
126 case MemberKind.constructor:
127 break;
128 default:
129 failedAt(entity, "Unexpected member definition $definition");
130 }
131 ir.Node node = definition.node;
132 CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
133 hasThisLocal: entity.isInstanceMember || entity.isConstructor);
134 if (entity.isField) {
135 if (node is ir.Field && node.initializer != null) {
136 translator.translateLazyInitializer(node);
137 }
138 } else {
139 assert(node is ir.Procedure || node is ir.Constructor);
140 translator.translateConstructorOrProcedure(node);
141 }
142 return model;
143 }
144
145 /// Given what variables are captured at each point, construct closure classes 116 /// Given what variables are captured at each point, construct closure classes
146 /// with fields containing the captured variables to replicate the Dart 117 /// with fields containing the captured variables to replicate the Dart
147 /// closure semantics in JS. If this closure captures any variables (meaning 118 /// closure semantics in JS. If this closure captures any variables (meaning
148 /// the closure accesses a variable that gets accessed at some point), then 119 /// the closure accesses a variable that gets accessed at some point), then
149 /// boxForCapturedVariables stores the local context for those variables. 120 /// boxForCapturedVariables stores the local context for those variables.
150 /// If no variables are captured, this parameter is null. 121 /// If no variables are captured, this parameter is null.
151 void _produceSyntheticElements( 122 void _produceSyntheticElements(
152 MemberEntity member, 123 MemberEntity member,
153 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, 124 ir.TreeNode /* ir.Member | ir.FunctionNode */ node,
154 KernelScopeInfo info, 125 KernelScopeInfo info,
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 KernelScopeInfo scopeInfo; 476 KernelScopeInfo scopeInfo;
506 477
507 /// Collected [CapturedScope] data for nodes. 478 /// Collected [CapturedScope] data for nodes.
508 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 479 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
509 <ir.Node, KernelCapturedScope>{}; 480 <ir.Node, KernelCapturedScope>{};
510 481
511 /// Collected [ScopeInfo] data for nodes. 482 /// Collected [ScopeInfo] data for nodes.
512 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 483 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
513 <ir.TreeNode, KernelScopeInfo>{}; 484 <ir.TreeNode, KernelScopeInfo>{};
514 } 485 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/js_strategy.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698