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

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

Issue 2994353002: Fix the locals lookup of variables and partial implementation of boxing of variables.
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 '../constants/expressions.dart'; 10 import '../constants/expressions.dart';
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 @override 89 @override
90 void convertClosures(Iterable<MemberEntity> processedEntities, 90 void convertClosures(Iterable<MemberEntity> processedEntities,
91 ClosedWorldRefiner closedWorldRefiner) { 91 ClosedWorldRefiner closedWorldRefiner) {
92 _createClosureEntities(_closureModels, closedWorldRefiner); 92 _createClosureEntities(_closureModels, closedWorldRefiner);
93 } 93 }
94 94
95 void _createClosureEntities(Map<MemberEntity, ScopeModel> closureModels, 95 void _createClosureEntities(Map<MemberEntity, ScopeModel> closureModels,
96 JsClosedWorld closedWorldRefiner) { 96 JsClosedWorld closedWorldRefiner) {
97 closureModels.forEach((MemberEntity member, ScopeModel model) { 97 closureModels.forEach((MemberEntity member, ScopeModel model) {
98 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 98 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
99 if (model.scopeInfo != null) { 99 assert(model.scopeInfo != null);
100 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); 100 var boxedVariables =
101 } 101 _elementMap.makeRecordContainer(model.scopeInfo, member, localsMap);
102 _scopeMap[member] =
103 new JsScopeInfo.from(boxedVariables, model.scopeInfo, localsMap);
104 print('created the following scope info $member ${_scopeMap[member]}');
102 105
106 Set<JsCapturedScope> capturedScopes = new Set<JsCaptuerdScope>();
103 model.capturedScopesMap 107 model.capturedScopesMap
104 .forEach((ir.Node node, KernelCapturedScope scope) { 108 .forEach((ir.Node node, KernelCapturedScope scope) {
109 boxedVariables = _elementMap.makeRecordContainer(
110 model.scopeInfo,
111 _elementMap.getMember(node),
112 localsMap); // TODO: (maybe don't need to call this again.)
105 if (scope is KernelCapturedLoopScope) { 113 if (scope is KernelCapturedLoopScope) {
106 _capturedScopesMap[node] = 114 _capturedScopesMap[node] =
107 new JsCapturedLoopScope.from(scope, localsMap); 115 new JsCapturedLoopScope.from(boxedVariables, scope, localsMap);
108 } else { 116 } else {
109 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); 117 _capturedScopesMap[node] =
118 new JsCapturedScope.from(boxedVariables, scope, localsMap);
110 } 119 }
120 capturedScopes.add(_capturedScopesMap[node]);
121 print('captured scope info $node ${_capturedScopesMap[node]}');
111 }); 122 });
112 123
113 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = 124 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate =
114 model.closuresToGenerate; 125 model.closuresToGenerate;
115 for (ir.FunctionNode node in closuresToGenerate.keys) { 126 for (ir.FunctionNode node in closuresToGenerate.keys) {
116 _produceSyntheticElements( 127 KernelClosureClass closureClass = _produceSyntheticElements(member,
117 member, node, closuresToGenerate[node], closedWorldRefiner); 128 node, closuresToGenerate[node], capturedScopes, closedWorldRefiner);
129 // Add one for each call method.
130 KernelToLocalsMap localsMap =
131 _globalLocalsMap.getLocalsMap(closureClass.callMethod);
132 _scopeMap[closureClass.callMethod] = closureClass;
133 print('then we made $closureClass starting from ${node.parent}');
118 } 134 }
119 }); 135 });
120 } 136 }
121 137
122 /// Given what variables are captured at each point, construct closure classes 138 /// Given what variables are captured at each point, construct closure classes
123 /// with fields containing the captured variables to replicate the Dart 139 /// with fields containing the captured variables to replicate the Dart
124 /// closure semantics in JS. If this closure captures any variables (meaning 140 /// closure semantics in JS. If this closure captures any variables (meaning
125 /// the closure accesses a variable that gets accessed at some point), then 141 /// the closure accesses a variable that gets accessed at some point), then
126 /// boxForCapturedVariables stores the local context for those variables. 142 /// boxForCapturedVariables stores the local context for those variables.
127 /// If no variables are captured, this parameter is null. 143 /// If no variables are captured, this parameter is null.
128 void _produceSyntheticElements(MemberEntity member, ir.FunctionNode node, 144 KernelClosureClass _produceSyntheticElements(
129 KernelScopeInfo info, JsClosedWorld closedWorldRefiner) { 145 MemberEntity member,
146 ir.FunctionNode node,
147 KernelScopeInfo info,
148 Set<JsCaptuerdScope> capturedScopes,
149 JsClosedWorld closedWorldRefiner) {
130 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 150 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
151
131 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( 152 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass(
132 member, node, member.library, info, node.location, localsMap); 153 member,
154 node,
155 member.library,
156 capturedScopes,
157 info,
158 node.location,
159 localsMap);
133 160
134 // We want the original declaration where that function is used to point 161 // We want the original declaration where that function is used to point
135 // to the correct closure class. 162 // to the correct closure class.
136 _closureRepresentationMap[closureClass.callMethod] = closureClass; 163 _closureRepresentationMap[closureClass.callMethod] = closureClass;
137 Entity entity; 164 Entity entity;
138 if (node.parent is ir.Member) { 165 if (node.parent is ir.Member) {
139 entity = _elementMap.getMember(node.parent); 166 entity = _elementMap.getMember(node.parent);
140 } else { 167 } else {
141 entity = localsMap.getLocalFunction(node.parent); 168 entity = localsMap.getLocalFunction(node.parent);
142 } 169 }
143 assert(entity != null); 170 assert(entity != null);
144 _closureRepresentationMap[entity] = closureClass; 171 _closureRepresentationMap[entity] = closureClass;
172 return closureClass;
145 } 173 }
146 174
147 @override 175 @override
148 ScopeInfo getScopeInfo(Entity entity) { 176 ScopeInfo getScopeInfo(Entity entity) {
149 // TODO(johnniwinther): Remove this check when constructor bodies a created 177 // TODO(johnniwinther): Remove this check when constructor bodies a created
150 // eagerly with the J-model; a constructor body should have it's own 178 // eagerly with the J-model; a constructor body should have it's own
151 // [ClosureRepresentationInfo]. 179 // [ClosureRepresentationInfo].
152 if (entity is ConstructorBodyEntity) { 180 if (entity is ConstructorBodyEntity) {
153 ConstructorBodyEntity constructorBody = entity; 181 ConstructorBodyEntity constructorBody = entity;
154 entity = constructorBody.constructor; 182 entity = constructorBody.constructor;
155 } 183 }
156 184
157 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity); 185 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity);
158 } 186 }
159 187
160 // TODO(efortuna): Eventually capturedScopesMap[node] should always
161 // be non-null, and we should just test that with an assert.
162 @override 188 @override
163 CapturedScope getCapturedScope(MemberEntity entity) { 189 CapturedScope getCapturedScope(MemberEntity entity) {
164 MemberDefinition definition = _elementMap.getMemberDefinition(entity); 190 MemberDefinition definition = _elementMap.getMemberDefinition(entity);
165 switch (definition.kind) { 191 switch (definition.kind) {
166 case MemberKind.regular: 192 case MemberKind.regular:
167 case MemberKind.constructor: 193 case MemberKind.constructor:
168 case MemberKind.constructorBody: 194 case MemberKind.constructorBody:
169 case MemberKind.closureCall: 195 case MemberKind.closureCall:
170 return _capturedScopesMap[definition.node] ?? const CapturedScope(); 196 return _capturedScopesMap[definition.node] ?? const CapturedScope();
171 default: 197 default:
172 throw failedAt(entity, "Unexpected member definition $definition"); 198 throw failedAt(entity, "Unexpected member definition $definition");
173 } 199 }
174 } 200 }
175 201
176 @override 202 @override
177 // TODO(efortuna): Eventually capturedScopesMap[node] should always
178 // be non-null, and we should just test that with an assert.
179 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => 203 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) =>
180 _capturedScopesMap[loopNode] ?? const CapturedLoopScope(); 204 _capturedScopesMap[loopNode] ?? const CapturedLoopScope();
181 205
182 @override 206 @override
183 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { 207 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) {
184 var closure = _closureRepresentationMap[entity]; 208 var closure = _closureRepresentationMap[entity];
185 assert( 209 assert(
186 closure != null, 210 closure != null,
187 "Corresponding closure class not found for $entity. " 211 "Corresponding closure class not found for $entity. "
188 "Closures found for ${_closureRepresentationMap.keys}"); 212 "Closures found for ${_closureRepresentationMap.keys}");
(...skipping 12 matching lines...) Expand all
201 final bool hasThisLocal; 225 final bool hasThisLocal;
202 final Set<ir.VariableDeclaration> boxedVariables; 226 final Set<ir.VariableDeclaration> boxedVariables;
203 // If boxedVariables is empty, this will be null, because no variables will 227 // If boxedVariables is empty, this will be null, because no variables will
204 // need to be boxed. 228 // need to be boxed.
205 final NodeBox capturedVariablesAccessor; 229 final NodeBox capturedVariablesAccessor;
206 230
207 /// The set of variables that were defined in another scope, but are used in 231 /// The set of variables that were defined in another scope, but are used in
208 /// this scope. 232 /// this scope.
209 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); 233 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();
210 234
235 /// The set of scopes that this scope captures. In practice we only populate
236 /// it if this scope uses a particular variable that is defined in another
237 /// scope, and this information is only really useful for closures.
238 final Set<ir.Node> capturedScopes = new Set<ir.Node>();
239
211 KernelScopeInfo(this.hasThisLocal) 240 KernelScopeInfo(this.hasThisLocal)
212 : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(), 241 : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(),
213 boxedVariables = new Set<ir.VariableDeclaration>(), 242 boxedVariables = new Set<ir.VariableDeclaration>(),
214 capturedVariablesAccessor = null; 243 capturedVariablesAccessor = null;
215 244
216 KernelScopeInfo.from(this.hasThisLocal, KernelScopeInfo info) 245 KernelScopeInfo.from(this.hasThisLocal, KernelScopeInfo info)
217 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, 246 : localsUsedInTryOrSync = info.localsUsedInTryOrSync,
218 boxedVariables = info.boxedVariables, 247 boxedVariables = info.boxedVariables,
219 capturedVariablesAccessor = null; 248 capturedVariablesAccessor = null;
220 249
221 KernelScopeInfo.withBoxedVariables( 250 KernelScopeInfo.withBoxedVariables(
222 this.boxedVariables, 251 this.boxedVariables,
223 this.capturedVariablesAccessor, 252 this.capturedVariablesAccessor,
224 this.localsUsedInTryOrSync, 253 this.localsUsedInTryOrSync,
225 this.freeVariables, 254 this.freeVariables,
226 this.hasThisLocal); 255 this.hasThisLocal);
227 256
228 String toString() { 257 String toString() {
229 StringBuffer sb = new StringBuffer(); 258 StringBuffer sb = new StringBuffer();
230 sb.write('this=$hasThisLocal,'); 259 sb.write('this=$hasThisLocal,');
231 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 260 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}},');
261 sb.write('freeVariables={${freeVariables.join(', ')}},');
262 sb.write('boxedVariables={${boxedVariables.join(', ')}},');
263 sb.write('capturedVariablesAccessor=$capturedVariablesAccessor');
232 return sb.toString(); 264 return sb.toString();
233 } 265 }
234 } 266 }
235 267
236 class JsScopeInfo extends ScopeInfo { 268 class JsScopeInfo extends ScopeInfo {
237 final Set<Local> localsUsedInTryOrSync; 269 final Set<Local> localsUsedInTryOrSync;
238 final Local thisLocal; 270 final Local thisLocal;
239 final Set<Local> boxedVariables; 271 final Map<Local, JRecord> boxedVariables;
240 272
241 /// The set of variables that were defined in another scope, but are used in 273 /// The set of variables that were defined in another scope, but are used in
242 /// this scope. 274 /// this scope.
243 final Set<Local> freeVariables; 275 final Set<Local> freeVariables;
244 276
245 JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables, 277 JsScopeInfo.from(
246 this.freeVariables); 278 this.boxedVariables, KernelScopeInfo info, KernelToLocalsMap localsMap)
247
248 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
249 : this.thisLocal = 279 : this.thisLocal =
250 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 280 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
251 this.localsUsedInTryOrSync = 281 this.localsUsedInTryOrSync =
252 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(), 282 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
253 this.boxedVariables =
254 info.boxedVariables.map(localsMap.getLocalVariable).toSet(),
255 this.freeVariables = 283 this.freeVariables =
256 info.freeVariables.map(localsMap.getLocalVariable).toSet(); 284 info.freeVariables.map(localsMap.getLocalVariable).toSet();
257 285
258 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 286 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
259 boxedVariables.forEach((Local l) { 287 boxedVariables.forEach((Local l, JRecord box) {
260 // TODO(efortuna): add FieldEntities as created. 288 f(l, box);
261 f(l, null);
262 }); 289 });
263 } 290 }
264 291
265 bool localIsUsedInTryOrSync(Local variable) => 292 bool localIsUsedInTryOrSync(Local variable) =>
266 localsUsedInTryOrSync.contains(variable); 293 localsUsedInTryOrSync.contains(variable);
267 294
268 String toString() { 295 String toString() {
269 StringBuffer sb = new StringBuffer(); 296 StringBuffer sb = new StringBuffer();
297 sb.write('JsScopeInfo: ');
270 sb.write('this=$thisLocal,'); 298 sb.write('this=$thisLocal,');
271 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 299 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
300 sb.write('freeVariables={${freeVariables.join(', ')}}');
301 sb.write('boxedVariables={$boxedVariables}');
272 return sb.toString(); 302 return sb.toString();
273 } 303 }
274 304
275 bool isBoxed(Local variable) => boxedVariables.contains(variable); 305 bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
276 } 306 }
277 307
278 class KernelCapturedScope extends KernelScopeInfo { 308 class KernelCapturedScope extends KernelScopeInfo {
279 final ir.TreeNode context;
280
281 KernelCapturedScope( 309 KernelCapturedScope(
282 Set<ir.VariableDeclaration> boxedVariables, 310 Set<ir.VariableDeclaration> boxedVariables,
283 NodeBox capturedVariablesAccessor, 311 NodeBox capturedVariablesAccessor,
284 this.context,
285 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 312 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
286 Set<ir.VariableDeclaration> freeVariables, 313 Set<ir.VariableDeclaration> freeVariables,
287 bool hasThisLocal) 314 bool hasThisLocal)
288 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor, 315 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor,
289 localsUsedInTryOrSync, freeVariables, hasThisLocal); 316 localsUsedInTryOrSync, freeVariables, hasThisLocal);
290 317
291 bool get requiresContextBox => boxedVariables.isNotEmpty; 318 bool get requiresContextBox => boxedVariables.isNotEmpty;
292 } 319 }
293 320
294 class JsCapturedScope extends JsScopeInfo implements CapturedScope { 321 class JsCapturedScope extends JsScopeInfo implements CapturedScope {
295 final Local context; 322 final BoxLocal context;
296 323
297 JsCapturedScope.from( 324 JsCapturedScope.from(Map<Local, JRecord> boxedVariables,
298 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap) 325 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap)
299 : this.context = localsMap.getLocalVariable(capturedScope.context), 326 : this.context =
300 super.from(capturedScope, localsMap); 327 boxedVariables.isNotEmpty ? boxedVariables.values.first.box : null,
328 super.from(boxedVariables, capturedScope, localsMap);
301 329
302 bool get requiresContextBox => boxedVariables.isNotEmpty; 330 bool get requiresContextBox => boxedVariables.isNotEmpty;
331
332 String toString() {
333 StringBuffer sb = new StringBuffer();
334 sb.write('this=$thisLocal,');
335 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
336 sb.write('freeVariables={${freeVariables.join(', ')}}');
337 sb.write('boxedVariables={$boxedVariables}');
338 sb.write('context={$context}');
339 return sb.toString();
340 }
303 } 341 }
304 342
305 class KernelCapturedLoopScope extends KernelCapturedScope { 343 class KernelCapturedLoopScope extends KernelCapturedScope {
306 final List<ir.VariableDeclaration> boxedLoopVariables; 344 final List<ir.VariableDeclaration> boxedLoopVariables;
307 345
308 KernelCapturedLoopScope( 346 KernelCapturedLoopScope(
309 Set<ir.VariableDeclaration> boxedVariables, 347 Set<ir.VariableDeclaration> boxedVariables,
310 NodeBox capturedVariablesAccessor, 348 NodeBox capturedVariablesAccessor,
311 this.boxedLoopVariables, 349 this.boxedLoopVariables,
312 ir.TreeNode context,
313 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 350 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
314 Set<ir.VariableDeclaration> freeVariables, 351 Set<ir.VariableDeclaration> freeVariables,
315 bool hasThisLocal) 352 bool hasThisLocal)
316 : super(boxedVariables, capturedVariablesAccessor, context, 353 : super(boxedVariables, capturedVariablesAccessor, localsUsedInTryOrSync,
317 localsUsedInTryOrSync, freeVariables, hasThisLocal); 354 freeVariables, hasThisLocal);
318 355
319 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 356 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
320 } 357 }
321 358
322 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope { 359 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
323 final List<Local> boxedLoopVariables; 360 final List<Local> boxedLoopVariables;
324 361
325 JsCapturedLoopScope.from( 362 JsCapturedLoopScope.from(Map<Local, JRecord> boxedVariables,
326 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap) 363 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap)
327 : this.boxedLoopVariables = capturedScope.boxedLoopVariables 364 : this.boxedLoopVariables = capturedScope.boxedLoopVariables
328 .map(localsMap.getLocalVariable) 365 .map(localsMap.getLocalVariable)
329 .toList(), 366 .toList(),
330 super.from(capturedScope, localsMap); 367 super.from(boxedVariables, capturedScope, localsMap);
331 368
332 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 369 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
333 } 370 }
334 371
335 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 372 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
336 class KernelClosureClass extends JsScopeInfo 373 class KernelClosureClass extends JsScopeInfo
337 implements ClosureRepresentationInfo, JClass { 374 implements ClosureRepresentationInfo {
338 final String name;
339 final JLibrary library;
340 JFunction callMethod; 375 JFunction callMethod;
341 final Local closureEntity; 376 final Local closureEntity;
342 final Local thisLocal; 377 final Local thisLocal;
343 378 final ClassEntity closureClassEntity;
344 /// Index into the classData, classList and classEnvironment lists where this
345 /// entity is stored in [JsToFrontendMapImpl].
346 final int classIndex;
347 379
348 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 380 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
349 381
382 /// The set of scopes that this scope captures. In practice we only populate
383 /// it if this scope uses a particular variable that is defined in another
384 /// scope, and this information is only really useful for closures.
385 final Set<JsCapturedScope> capturedScopes;
386
350 KernelClosureClass.fromScopeInfo( 387 KernelClosureClass.fromScopeInfo(
388 this.closureClassEntity,
351 ir.FunctionNode closureSourceNode, 389 ir.FunctionNode closureSourceNode,
352 this.name, 390 Map<Local, JRecord> boxedVariables,
353 this.classIndex, 391 this.capturedScopes,
354 this.library,
355 KernelScopeInfo info, 392 KernelScopeInfo info,
356 KernelToLocalsMap localsMap) 393 KernelToLocalsMap localsMap)
357 : closureEntity = closureSourceNode.parent is ir.Member 394 : closureEntity = closureSourceNode.parent is ir.Member
358 ? null 395 ? null
359 : localsMap.getLocalFunction(closureSourceNode.parent), 396 : localsMap.getLocalFunction(closureSourceNode.parent),
360 thisLocal = 397 thisLocal =
361 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 398 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
362 super.from(info, localsMap); 399 super.from(boxedVariables, info, localsMap);
363
364 ClassEntity get closureClassEntity => this;
365 400
366 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 401 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
367 402
368 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; 403 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
369 404
370 void forEachCapturedVariable(f(Local from, JField to)) { 405 void forEachCapturedVariable(f(Local from, JField to)) {
371 localToFieldMap.forEach(f); 406 localToFieldMap.forEach(f);
372 } 407 }
373 408
374 @override 409 @override
375 void forEachBoxedVariable(f(Local local, JField field)) { 410 void forEachBoxedVariable(f(Local local, JField field)) {
376 for (Local l in localToFieldMap.keys) { 411 for (Local l in localToFieldMap.keys) {
377 if (localToFieldMap[l] is JBoxedField) f(l, localToFieldMap[l]); 412 if (localToFieldMap[l] is JRecord) f(l, localToFieldMap[l]);
413 }
414 for (JsCapturedScope scope in capturedScopes) {
415 scope.forEachBoxedVariable(f);
378 } 416 }
379 } 417 }
380 418
381 void forEachFreeVariable(f(Local variable, JField field)) { 419 void forEachFreeVariable(f(Local variable, JField field)) {
382 for (Local l in localToFieldMap.keys) { 420 for (Local l in localToFieldMap.keys) {
383 var jField = localToFieldMap[l]; 421 var jField = localToFieldMap[l];
384 if (jField is! JBoxedField && jField is! BoxLocal) f(l, jField); 422 if (jField is! BoxLocal) f(l, jField);
385 } 423 }
386 } 424 }
387 425
388 bool isVariableBoxed(Local variable) => 426 bool isVariableBoxed(Local variable) {
389 localToFieldMap.keys.contains(variable); 427 print(
428 'RRRRRRRRRRR ${localToFieldMap.keys.contains(variable)} ${capturedScopes }');
429 return localToFieldMap.keys.contains(variable) ||
430 capturedScopes.any((JsCapturedScope scope) => scope.isBoxed(variable));
431 }
432
433 @override
434 bool isBoxed(Local variable) {
435 print(
436 'RRRRRRRRRRR ${localToFieldMap.keys.contains(variable)} ${capturedScopes }');
437 return localToFieldMap.keys.contains(variable) ||
438 capturedScopes.any((JsCapturedScope scope) => scope.isBoxed(variable));
439 }
390 440
391 bool get isClosure => true; 441 bool get isClosure => true;
392
393 bool get isAbstract => false;
394
395 String toString() => '${jsElementPrefix}class($name)';
396 } 442 }
397 443
398 /// A local variable to disambiguate between a variable that has been captured 444 /// A local variable to disambiguate between a variable that has been captured
399 /// from one scope to another. This is the ir.Node version that corresponds to 445 /// from one scope to another. This is the ir.Node version that corresponds to
400 /// [BoxLocal]. 446 /// [BoxLocal].
401 class NodeBox { 447 class NodeBox {
402 final String name; 448 final String name;
403 final ir.TreeNode executableContext; 449 final ir.TreeNode executableContext;
404 NodeBox(this.name, this.executableContext); 450 NodeBox(this.name, this.executableContext);
405 } 451 }
406 452
453 class JClosureClass extends JClass {
454 // TODO(efortuna): omg this is so horrible.
455 final KernelToLocalsMap localsMap;
456
457 JClosureClass(this.localsMap, JLibrary library, int classIndex, String name)
458 : super(library, classIndex, name, isAbstract: false);
459
460 @override
461 bool get isClosure => true;
462
463 String toString() => '${jsElementPrefix}closure_class($name)';
464 }
465
407 class JClosureField extends JField { 466 class JClosureField extends JField {
408 JClosureField(String name, int memberIndex, 467 JClosureField(String name, int memberIndex,
409 KernelClosureClass containingClass, bool isConst, bool isAssignable) 468 KernelClosureClass containingClass, bool isConst, bool isAssignable)
410 : super(memberIndex, containingClass.library, containingClass, 469 : super(
411 new Name(name, containingClass.library), 470 memberIndex,
412 isAssignable: isAssignable, isConst: isConst, isStatic: false); 471 containingClass.closureClassEntity.library,
472 containingClass.closureClassEntity,
473 new Name(name, containingClass.closureClassEntity.library),
474 isAssignable: isAssignable,
475 isConst: isConst,
476 isStatic: false);
413 } 477 }
414 478
415 /// A ClosureField that has been "boxed" to prevent name shadowing with the 479 /// A container for variables declared in a particular scope that are accessed
480 /// elsewhere.
481 // TODO(efortuna, johnniwinther): Don't implement JClass. This isn't actually a
482 // class.
483 class JRecordContainer implements JClass {
484 final JLibrary library;
485 final String name;
486
487 /// Index into the classData, classList and classEnvironment lists where this
488 /// entity is stored in [JsToFrontendMapImpl].
489 final int classIndex;
490
491 JRecordContainer(this.library, this.classIndex, this.name);
492
493 bool get isAbstract => false;
494
495 bool get isClosure => false;
496
497 String toString() => '${jsElementPrefix}record_container($name)';
498 }
499
500 /// A variable that has been "boxed" to prevent name shadowing with the
416 /// original variable and ensure that this variable is updated/read with the 501 /// original variable and ensure that this variable is updated/read with the
417 /// most recent value. 502 /// most recent value.
418 /// This corresponds to BoxFieldElement; we reuse BoxLocal from the original 503 /// This corresponds to BoxFieldElement; we reuse BoxLocal from the original
419 /// algorithm to correspond to the actual name of the variable. 504 /// algorithm to correspond to the actual name of the variable.
420 class JBoxedField extends JField { 505 class JRecord extends JField {
421 final BoxLocal box; 506 final BoxLocal box;
422 JBoxedField(String name, int memberIndex, this.box, 507 JRecord(String name, int memberIndex, this.box, JClass containingClass,
423 KernelClosureClass containingClass, bool isConst, bool isAssignable) 508 bool isConst, bool isAssignable)
424 : super(memberIndex, containingClass.library, containingClass, 509 : super(memberIndex, containingClass.library, containingClass,
425 new Name(name, containingClass.library), 510 new Name(name, containingClass.library),
426 isAssignable: isAssignable, isConst: isConst); 511 isAssignable: isAssignable, isConst: isConst);
427 } 512 }
428 513
429 class ClosureClassDefinition implements ClassDefinition { 514 class ClosureClassDefinition implements ClassDefinition {
430 final ClassEntity cls; 515 final ClassEntity cls;
431 final SourceSpan location; 516 final SourceSpan location;
432 517
433 ClosureClassDefinition(this.cls, this.location); 518 ClosureClassDefinition(this.cls, this.location);
434 519
435 ClassKind get kind => ClassKind.closure; 520 ClassKind get kind => ClassKind.closure;
436 521
437 ir.Node get node => 522 ir.Node get node => throw new UnsupportedError('JRecord.node for $cls');
438 throw new UnsupportedError('ClosureClassDefinition.node for $cls');
439 523
440 String toString() => 524 String toString() => 'JRecord(kind:$kind,cls:$cls,location:$location)';
441 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)';
442 } 525 }
443 526
444 class ClosureMemberData implements MemberData { 527 class ClosureMemberData implements MemberData {
445 final MemberDefinition definition; 528 final MemberDefinition definition;
446 529
447 ClosureMemberData(this.definition); 530 ClosureMemberData(this.definition);
448 531
449 @override 532 @override
450 Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) { 533 Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) {
451 return const <ConstantValue>[]; 534 return const <ConstantValue>[];
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 final SourceSpan location; 593 final SourceSpan location;
511 final MemberKind kind; 594 final MemberKind kind;
512 final ir.Node node; 595 final ir.Node node;
513 596
514 ClosureMemberDefinition(this.member, this.location, this.kind, this.node); 597 ClosureMemberDefinition(this.member, this.location, this.kind, this.node);
515 598
516 String toString() => 599 String toString() =>
517 'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)'; 600 'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)';
518 } 601 }
519 602
603 class RecordContainerDefinition implements ClassDefinition {
604 final ClassEntity cls;
605 final SourceSpan location;
606
607 RecordContainerDefinition(this.cls, this.location);
608
609 ClassKind get kind => ClassKind.container;
610
611 ir.Node get node =>
612 throw new UnsupportedError('RecordContainerDefinition.node for $cls');
613
614 String toString() =>
615 'RecordContainerDefinition(kind:$kind,cls:$cls,location:$location)';
616 }
617
520 /// Collection of scope data collected for a single member. 618 /// Collection of scope data collected for a single member.
521 class ScopeModel { 619 class ScopeModel {
522 /// Collection [ScopeInfo] data for the member. 620 /// Collection [ScopeInfo] data for the member.
523 KernelScopeInfo scopeInfo; 621 KernelScopeInfo scopeInfo;
524 622
525 /// Collected [CapturedScope] data for nodes. 623 /// Collected [CapturedScope] data for nodes.
526 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 624 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
527 <ir.Node, KernelCapturedScope>{}; 625 <ir.Node, KernelCapturedScope>{};
528 626
529 /// Collected [ScopeInfo] data for nodes. 627 /// Collected [ScopeInfo] data for nodes.
530 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = 628 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate =
531 <ir.FunctionNode, KernelScopeInfo>{}; 629 <ir.FunctionNode, KernelScopeInfo>{};
532 } 630 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/field_naming_mixin.dart ('k') | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698