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

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

Issue 2986583002: Reapply "Add nonboxed closure class fields." (Closed)
Patch Set: Created 3 years, 5 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/closure_visitors.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/tasks.dart'; 8 import '../common/tasks.dart';
9 import '../elements/elements.dart';
9 import '../elements/entities.dart'; 10 import '../elements/entities.dart';
11 import '../elements/entity_utils.dart' as utils;
12 import '../elements/names.dart' show Name;
10 import '../kernel/element_map.dart'; 13 import '../kernel/element_map.dart';
11 import '../world.dart'; 14 import '../world.dart';
12 import 'elements.dart'; 15 import 'elements.dart';
13 import 'closure_visitors.dart'; 16 import 'closure_visitors.dart';
14 import 'locals.dart'; 17 import 'locals.dart';
15 18
16 /// Closure conversion code using our new Entity model. Closure conversion is 19 /// Closure conversion code using our new Entity model. Closure conversion is
17 /// necessary because the semantics of closures are slightly different in Dart 20 /// necessary because the semantics of closures are slightly different in Dart
18 /// than JavaScript. Closure conversion is separated out into two phases: 21 /// than JavaScript. Closure conversion is separated out into two phases:
19 /// generation of a new (temporary) representation to store where variables need 22 /// generation of a new (temporary) representation to store where variables need
20 /// to be hoisted/captured up at another level to re-write the closure, and then 23 /// to be hoisted/captured up at another level to re-write the closure, and then
21 /// the code generation phase where we generate elements and/or instructions to 24 /// the code generation phase where we generate elements and/or instructions to
22 /// represent this new code path. 25 /// represent this new code path.
23 /// 26 ///
24 /// For a general explanation of how closure conversion works at a high level, 27 /// For a general explanation of how closure conversion works at a high level,
25 /// check out: 28 /// check out:
26 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or 29 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or
27 /// http://matt.might.net/articles/closure-conversion/. 30 /// http://matt.might.net/articles/closure-conversion/.
28 // TODO(efortuna): Change inheritance hierarchy so that the 31 // TODO(efortuna): Change inheritance hierarchy so that the
29 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a 32 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a
30 // glorified timer. 33 // glorified timer.
31 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { 34 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
32 final KernelToElementMapForBuilding _elementMap; 35 final KernelToElementMapForBuilding _elementMap;
33 final GlobalLocalsMap _globalLocalsMap; 36 final GlobalLocalsMap _globalLocalsMap;
34 37
35 /// Map of the scoping information that corresponds to a particular entity. 38 /// Map of the scoping information that corresponds to a particular entity.
36 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{}; 39 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{};
37 Map<ir.Node, CapturedScope> _scopesCapturedInClosureMap = 40 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{};
38 <ir.Node, CapturedScope>{};
39 41
40 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap = 42 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap =
41 <Entity, ClosureRepresentationInfo>{}; 43 <Entity, ClosureRepresentationInfo>{};
42 44
43 /// Should only be used at the very beginning to ensure we are looking at the 45 /// Should only be used at the very beginning to ensure we are looking at the
44 /// right kind of elements. 46 /// right kind of elements.
45 // TODO(efortuna): Remove this map once we have one kernel backend strategy. 47 // TODO(efortuna): Remove this map once we have one kernel backend strategy.
46 final JsToFrontendMap _kToJElementMap; 48 final JsToFrontendMap _kToJElementMap;
47 49
48 KernelClosureConversionTask(Measurer measurer, this._elementMap, 50 KernelClosureConversionTask(Measurer measurer, this._elementMap,
49 this._kToJElementMap, this._globalLocalsMap) 51 this._kToJElementMap, this._globalLocalsMap)
50 : super(measurer); 52 : super(measurer);
51 53
52 /// The combined steps of generating our intermediate representation of 54 /// The combined steps of generating our intermediate representation of
53 /// closures that need to be rewritten and generating the element model. 55 /// closures that need to be rewritten and generating the element model.
54 /// Ultimately these two steps will be split apart with the second step 56 /// Ultimately these two steps will be split apart with the second step
55 /// happening later in compilation just before codegen. These steps are 57 /// happening later in compilation just before codegen. These steps are
56 /// combined here currently to provide a consistent interface to the rest of 58 /// combined here currently to provide a consistent interface to the rest of
57 /// the compiler until we are ready to separate these phases. 59 /// the compiler until we are ready to separate these phases.
58 @override 60 @override
59 void convertClosures(Iterable<MemberEntity> processedEntities, 61 void convertClosures(Iterable<MemberEntity> processedEntities,
60 ClosedWorldRefiner closedWorldRefiner) { 62 ClosedWorldRefiner closedWorldRefiner) {
61 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; 63 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{};
62 processedEntities.forEach((MemberEntity kEntity) { 64 processedEntities.forEach((MemberEntity kEntity) {
63 MemberEntity entity = kEntity; 65 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity);
64 if (_kToJElementMap != null) {
65 entity = _kToJElementMap.toBackendMember(kEntity);
66 }
67 if (entity.isAbstract) return; 66 if (entity.isAbstract) return;
68 if (entity.isField && !entity.isInstanceMember) { 67 if (entity.isField && !entity.isInstanceMember) {
69 ir.Field field = _elementMap.getMemberNode(entity); 68 ir.Field field = _elementMap.getMemberNode(entity);
70 // Skip top-level/static fields without an initializer. 69 // Skip top-level/static fields without an initializer.
71 if (field.initializer == null) return; 70 if (field.initializer == null) return;
72 } 71 }
73 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); 72 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner);
74 }); 73 });
75 74
76 for (ir.TreeNode node in closuresToGenerate.keys) { 75 for (ir.TreeNode node in closuresToGenerate.keys) {
77 _produceSyntheticElements( 76 _produceSyntheticElements(
78 node, closuresToGenerate[node], closedWorldRefiner); 77 node, closuresToGenerate[node], closedWorldRefiner);
79 } 78 }
80 } 79 }
81 80
82 /// Inspect members and mark if those members capture any state that needs to 81 /// Inspect members and mark if those members capture any state that needs to
83 /// be marked as free variables. 82 /// be marked as free variables.
84 void _buildClosureModel( 83 void _buildClosureModel(
85 MemberEntity entity, 84 MemberEntity entity,
86 Map<ir.TreeNode, ScopeInfo> closuresToGenerate, 85 Map<ir.TreeNode, ScopeInfo> closuresToGenerate,
87 ClosedWorldRefiner closedWorldRefiner) { 86 ClosedWorldRefiner closedWorldRefiner) {
88 if (_scopeMap.keys.contains(entity)) return; 87 if (_scopeMap.keys.contains(entity)) return;
89 ir.Node node = _elementMap.getMemberNode(entity); 88 ir.Node node = _elementMap.getMemberNode(entity);
90 if (_scopesCapturedInClosureMap.keys.contains(node)) return; 89 if (_capturedScopesMap.keys.contains(node)) return;
91 CapturedScopeBuilder translator = new CapturedScopeBuilder( 90 CapturedScopeBuilder translator = new CapturedScopeBuilder(
92 _scopesCapturedInClosureMap, 91 _capturedScopesMap,
93 _scopeMap, 92 _scopeMap,
94 entity, 93 entity,
95 closuresToGenerate, 94 closuresToGenerate,
96 _globalLocalsMap.getLocalsMap(entity), 95 _globalLocalsMap.getLocalsMap(entity),
97 _elementMap); 96 _elementMap);
98 if (entity.isField) { 97 if (entity.isField) {
99 if (node is ir.Field && node.initializer != null) { 98 if (node is ir.Field && node.initializer != null) {
100 translator.translateLazyInitializer(node); 99 translator.translateLazyInitializer(node);
101 } 100 }
102 } else { 101 } else {
103 assert(node is ir.Procedure || node is ir.Constructor); 102 assert(node is ir.Procedure || node is ir.Constructor);
104 translator.translateConstructorOrProcedure(node); 103 translator.translateConstructorOrProcedure(node);
105 } 104 }
106 } 105 }
107 106
108 /// Given what variables are captured at each point, construct closure classes 107 /// Given what variables are captured at each point, construct closure classes
109 /// with fields containing the captured variables to replicate the Dart 108 /// with fields containing the captured variables to replicate the Dart
110 /// closure semantics in JS. 109 /// closure semantics in JS. If this closure captures any variables (meaning
110 /// the closure accesses a variable that gets accessed at some point), then
111 /// boxForCapturedVariables stores the local context for those variables.
112 /// If no variables are captured, this parameter is null.
111 void _produceSyntheticElements( 113 void _produceSyntheticElements(
112 ir.TreeNode /* ir.Field | ir.FunctionNode */ node, 114 ir.TreeNode /* ir.Field | ir.FunctionNode */ node,
113 ScopeInfo info, 115 ScopeInfo info,
114 ClosedWorldRefiner closedWorldRefiner) { 116 ClosedWorldRefiner closedWorldRefiner) {
115 Entity entity; 117 Entity entity;
116 KernelClosureClass closureClass = 118 ir.Library library;
117 new KernelClosureClass.fromScopeInfo(info); 119 if (node is ir.Member) {
120 entity = _elementMap.getMember(node);
121 library = node.enclosingLibrary;
122 } else {
123 entity = _elementMap.getLocalFunction(node);
124 // TODO(efortuna): Consider the less roundabout way of getting this value
125 // which is just storing the "enclosingLibrary" value of the original call
126 // to CapturedScopeBuilder.
127 ir.TreeNode temp = node;
128 while (temp != null && temp is! ir.Library) {
129 temp = temp.parent;
130 }
131 assert(temp is ir.Library);
132 library = temp;
133 }
134 assert(entity != null);
135
136 String name = _computeClosureName(node);
137 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo(
138 name, _elementMap.getLibrary(library), info);
118 if (node is ir.FunctionNode) { 139 if (node is ir.FunctionNode) {
119 // We want the original declaration where that function is used to point 140 // We want the original declaration where that function is used to point
120 // to the correct closure class. 141 // to the correct closure class.
121 // TODO(efortuna): entity equivalent of element.declaration? 142 // TODO(efortuna): entity equivalent of element.declaration?
122 node = (node as ir.FunctionNode).parent; 143 node = (node as ir.FunctionNode).parent;
123 _closureRepresentationMap[closureClass.callMethod] = closureClass; 144 _closureRepresentationMap[closureClass.callMethod] = closureClass;
124 } 145 }
125 146
126 if (node is ir.Member) {
127 entity = _elementMap.getMember(node);
128 } else {
129 entity = _elementMap.getLocalFunction(node);
130 }
131 assert(entity != null);
132
133 _closureRepresentationMap[entity] = closureClass; 147 _closureRepresentationMap[entity] = closureClass;
134 148
135 // Register that a new class has been created. 149 // Register that a new class has been created.
136 closedWorldRefiner.registerClosureClass( 150 closedWorldRefiner.registerClosureClass(
137 closureClass, node is ir.Member && node.isInstanceMember); 151 closureClass, node is ir.Member && node.isInstanceMember);
138 } 152 }
139 153
154 // Returns a non-unique name for the given closure element.
155 String _computeClosureName(ir.TreeNode treeNode) {
156 var parts = <String>[];
157 if (treeNode is ir.Field && treeNode.name.name != "") {
158 parts.add(treeNode.name.name);
159 } else {
160 parts.add('closure');
161 }
162 ir.TreeNode node = treeNode.parent;
163 while (node != null &&
164 (node is ir.Constructor ||
165 node is ir.Class ||
166 node is ir.FunctionNode ||
167 node is ir.Procedure)) {
168 // TODO(johnniwinther): Simplify computed names.
169 if (node is ir.Constructor ||
170 node.parent is ir.Constructor ||
171 (node is ir.Procedure && node.kind == ir.ProcedureKind.Factory)) {
172 FunctionEntity entity;
173 if (node.parent is ir.Constructor) {
174 entity = _elementMap.getConstructorBody(node);
175 } else {
176 entity = _elementMap.getMember(node);
177 }
178 parts.add(utils.reconstructConstructorName(entity));
179 } else {
180 String surroundingName = '';
181 if (node is ir.Class) {
182 surroundingName = Elements.operatorNameToIdentifier(node.name);
183 } else if (node is ir.Procedure) {
184 surroundingName = Elements.operatorNameToIdentifier(node.name.name);
185 }
186 parts.add(surroundingName);
187 }
188 // A generative constructors's parent is the class; the class name is
189 // already part of the generative constructor's name.
190 if (node is ir.Constructor) break;
191 node = node.parent;
192 }
193 return parts.reversed.join('_');
194 }
195
140 @override 196 @override
141 ScopeInfo getScopeInfo(Entity entity) { 197 ScopeInfo getScopeInfo(Entity entity) {
142 // TODO(johnniwinther): Remove this check when constructor bodies a created 198 // TODO(johnniwinther): Remove this check when constructor bodies a created
143 // eagerly with the J-model; a constructor body should have it's own 199 // eagerly with the J-model; a constructor body should have it's own
144 // [ClosureRepresentationInfo]. 200 // [ClosureRepresentationInfo].
145 if (entity is ConstructorBodyEntity) { 201 if (entity is ConstructorBodyEntity) {
146 ConstructorBodyEntity constructorBody = entity; 202 ConstructorBodyEntity constructorBody = entity;
147 entity = constructorBody.constructor; 203 entity = constructorBody.constructor;
148 } 204 }
149 205
150 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity); 206 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity);
151 } 207 }
152 208
153 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always 209 // TODO(efortuna): Eventually capturedScopesMap[node] should always
154 // be non-null, and we should just test that with an assert. 210 // be non-null, and we should just test that with an assert.
155 @override 211 @override
156 CapturedScope getCapturedScope(MemberEntity entity) => 212 CapturedScope getCapturedScope(MemberEntity entity) =>
157 _scopesCapturedInClosureMap[_elementMap.getMemberNode(entity)] ?? 213 _capturedScopesMap[_elementMap.getMemberNode(entity)] ??
158 const CapturedScope(); 214 const CapturedScope();
159 215
160 @override 216 @override
161 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always 217 // TODO(efortuna): Eventually capturedScopesMap[node] should always
162 // be non-null, and we should just test that with an assert. 218 // be non-null, and we should just test that with an assert.
163 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => 219 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) =>
164 _scopesCapturedInClosureMap[loopNode] ?? const CapturedLoopScope(); 220 _capturedScopesMap[loopNode] ?? const CapturedLoopScope();
165 221
166 @override 222 @override
167 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be 223 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be
168 // non-null, and we should just test that with an assert. 224 // non-null, and we should just test that with an assert.
169 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { 225 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) {
170 return _closureRepresentationMap[entity] ?? 226 return _closureRepresentationMap[entity] ??
171 const ClosureRepresentationInfo(); 227 const ClosureRepresentationInfo();
172 } 228 }
173 } 229 }
174 230
175 class KernelScopeInfo extends ScopeInfo { 231 class KernelScopeInfo extends ScopeInfo {
176 final Set<Local> localsUsedInTryOrSync; 232 final Set<Local> localsUsedInTryOrSync;
177 final Local thisLocal; 233 final Local thisLocal;
178 final Set<Local> boxedVariables; 234 final Set<Local> boxedVariables;
179 235
180 /// The set of variables that were defined in another scope, but are used in 236 /// The set of variables that were defined in another scope, but are used in
181 /// this scope. 237 /// this scope.
182 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); 238 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();
183 239
184 KernelScopeInfo(this.thisLocal) 240 /// Used to map [freeVariables] to their corresponding locals.
241 final KernelToLocalsMap localsMap;
242
243 KernelScopeInfo(this.thisLocal, this.localsMap)
185 : localsUsedInTryOrSync = new Set<Local>(), 244 : localsUsedInTryOrSync = new Set<Local>(),
186 boxedVariables = new Set<Local>(); 245 boxedVariables = new Set<Local>();
187 246
188 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info) 247 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info)
189 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, 248 : localsUsedInTryOrSync = info.localsUsedInTryOrSync,
190 boxedVariables = info.boxedVariables; 249 boxedVariables = info.boxedVariables,
250 localsMap = info.localsMap;
191 251
192 KernelScopeInfo.withBoxedVariables(this.boxedVariables, this.thisLocal) 252 KernelScopeInfo.withBoxedVariables(
193 : localsUsedInTryOrSync = new Set<Local>(); 253 this.boxedVariables,
254 this.localsUsedInTryOrSync,
255 this.freeVariables,
256 this.localsMap,
257 this.thisLocal);
194 258
195 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 259 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
196 boxedVariables.forEach((Local l) { 260 boxedVariables.forEach((Local l) {
197 // TODO(efortuna): add FieldEntities as created. 261 // TODO(efortuna): add FieldEntities as created.
198 f(l, null); 262 f(l, null);
199 }); 263 });
200 } 264 }
201 265
202 bool localIsUsedInTryOrSync(Local variable) => 266 bool localIsUsedInTryOrSync(Local variable) =>
203 localsUsedInTryOrSync.contains(variable); 267 localsUsedInTryOrSync.contains(variable);
204 268
205 String toString() { 269 String toString() {
206 StringBuffer sb = new StringBuffer(); 270 StringBuffer sb = new StringBuffer();
207 sb.write('this=$thisLocal,'); 271 sb.write('this=$thisLocal,');
208 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 272 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
209 return sb.toString(); 273 return sb.toString();
210 } 274 }
211 275
212 bool isBoxed(Local variable) => boxedVariables.contains(variable); 276 bool isBoxed(Local variable) => boxedVariables.contains(variable);
213 } 277 }
214 278
215 class KernelCapturedScope extends KernelScopeInfo implements CapturedScope { 279 class KernelCapturedScope extends KernelScopeInfo implements CapturedScope {
216 final Local context; 280 final Local context;
217 281
218 KernelCapturedScope(Set<Local> boxedVariables, this.context, Local thisLocal) 282 KernelCapturedScope(
219 : super.withBoxedVariables(boxedVariables, thisLocal); 283 Set<Local> boxedVariables,
284 this.context,
285 Set<Local> localsUsedInTryOrSync,
286 Set<ir.VariableDeclaration> freeVariables,
287 KernelToLocalsMap localsMap,
288 Local thisLocal)
289 : super.withBoxedVariables(boxedVariables, localsUsedInTryOrSync,
290 freeVariables, localsMap, thisLocal);
220 291
221 bool get requiresContextBox => boxedVariables.isNotEmpty; 292 bool get requiresContextBox => boxedVariables.isNotEmpty;
222 } 293 }
223 294
224 class KernelCapturedLoopScope extends KernelCapturedScope 295 class KernelCapturedLoopScope extends KernelCapturedScope
225 implements CapturedLoopScope { 296 implements CapturedLoopScope {
226 final List<Local> boxedLoopVariables; 297 final List<Local> boxedLoopVariables;
227 298
228 KernelCapturedLoopScope(Set<Local> boxedVariables, this.boxedLoopVariables, 299 KernelCapturedLoopScope(
229 Local context, Local thisLocal) 300 Set<Local> boxedVariables,
230 : super(boxedVariables, context, thisLocal); 301 this.boxedLoopVariables,
302 Local context,
303 Set<Local> localsUsedInTryOrSync,
304 Set<ir.VariableDeclaration> freeVariables,
305 KernelToLocalsMap localsMap,
306 Local thisLocal)
307 : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables,
308 localsMap, thisLocal);
231 309
232 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 310 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
233 } 311 }
234 312
235 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 313 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
236 class KernelClosureClass extends KernelScopeInfo 314 class KernelClosureClass extends KernelScopeInfo
237 implements ClosureRepresentationInfo, JClass { 315 implements ClosureRepresentationInfo, JClass {
238 // TODO(efortuna): Generate unique name for each closure class. 316 final String name;
239 final String name = 'ClosureClass'; 317 final JLibrary library;
240 318
241 /// Index into the classData, classList and classEnvironment lists where this 319 /// Index into the classData, classList and classEnvironment lists where this
242 /// entity is stored in [JsToFrontendMapImpl]. 320 /// entity is stored in [JsToFrontendMapImpl].
243 int classIndex; 321 int classIndex;
244 322
245 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 323 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
246 324
247 KernelClosureClass.fromScopeInfo(KernelScopeInfo info) 325 KernelClosureClass.fromScopeInfo(
248 : super.from(info.thisLocal, info); 326 this.name, this.library, KernelScopeInfo info)
327 : super.from(info.thisLocal, info) {
328 // Make a corresponding field entity in this closure class for every single
329 // freeVariable in the KernelScopeInfo.freeVariable.
330 int i = 0;
331 for (ir.VariableDeclaration variable in info.freeVariables) {
332 // NOTE: This construction order may be slightly different than the
333 // old Element version. The old version did all the boxed items and then
334 // all the others.
335 Local capturedLocal = info.localsMap.getLocal(variable);
336 if (info.isBoxed(capturedLocal)) {
337 // TODO(efortuna): Coming soon.
338 } else {
339 localToFieldMap[capturedLocal] = new ClosureField(
340 _getClosureVariableName(capturedLocal.name, i),
341 this,
342 variable.isConst,
343 variable.isFinal || variable.isConst);
344 // TODO(efortuna): These probably need to get registered somewhere.
345 }
346 i++;
347 }
348 }
349
350 /// Generate a unique name for the [id]th closure field, with proposed name
351 /// [name].
352 ///
353 /// The result is used as the name of [ClosureFieldElement]s, and must
354 /// therefore be unique to avoid breaking an invariant in the element model
355 /// (classes cannot declare multiple fields with the same name).
356 ///
357 /// Also, the names should be distinct from real field names to prevent
358 /// clashes with selectors for those fields.
359 ///
360 /// These names are not used in generated code, just as element name.
361 String _getClosureVariableName(String name, int id) {
362 return "_captured_${name}_$id";
363 }
249 364
250 // TODO(efortuna): Implement. 365 // TODO(efortuna): Implement.
251 Local get closureEntity => null; 366 Local get closureEntity => null;
252 367
253 ClassEntity get closureClassEntity => this; 368 ClassEntity get closureClassEntity => this;
254 369
255 // TODO(efortuna): Implement. 370 // TODO(efortuna): Implement.
256 FunctionEntity get callMethod => null; 371 FunctionEntity get callMethod => null;
257 372
258 // TODO(efortuna): Implement. 373 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
259 List<Local> get createdFieldEntities => const <Local>[];
260 374
261 // TODO(efortuna): Implement. 375 // TODO(efortuna): Implement.
262 FieldEntity get thisFieldEntity => null; 376 FieldEntity get thisFieldEntity => null;
263 377
264 // TODO(efortuna): Implement. 378 void forEachCapturedVariable(f(Local from, JField to)) {
265 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} 379 localToFieldMap.forEach(f);
380 }
266 381
267 // TODO(efortuna): Implement. 382 // TODO(efortuna): Implement.
268 @override 383 @override
269 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} 384 void forEachBoxedVariable(f(Local local, JField field)) {}
270 385
271 // TODO(efortuna): Implement. 386 // TODO(efortuna): Implement.
272 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} 387 void forEachFreeVariable(f(Local variable, JField field)) {}
273 388
274 // TODO(efortuna): Implement. 389 // TODO(efortuna): Implement.
275 bool isVariableBoxed(Local variable) => false; 390 bool isVariableBoxed(Local variable) => false;
276 391
277 // TODO(efortuna): Implement. 392 bool get isClosure => true;
278 // Why is this closure not actually a closure? Well, to properly call
279 // ourselves a closure, we need to register the new closure class with the
280 // ClosedWorldRefiner, which currently only takes elements. The change to
281 // that (and the subsequent adjustment here) will follow soon.
282 bool get isClosure => false;
283 393
284 bool get isAbstract => false; 394 bool get isAbstract => false;
285 395
286 // TODO(efortuna): Talk to Johnni.
287 JLibrary get library => null;
288
289 String toString() => '${jsElementPrefix}class($name)'; 396 String toString() => '${jsElementPrefix}class($name)';
290 } 397 }
398
399 class ClosureField extends JField {
400 ClosureField(String name, KernelClosureClass containingClass, bool isConst,
401 bool isAssignable)
402 : super(-1, containingClass.library, containingClass,
403 new Name(name, containingClass.library),
404 isAssignable: isAssignable, isConst: isConst);
405 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698