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

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

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