OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library closureToClassMapper; | 5 library closureToClassMapper; |
6 | 6 |
7 import "elements/elements.dart"; | 7 import "elements/elements.dart"; |
8 import "dart2jslib.dart"; | 8 import "dart2jslib.dart"; |
9 import "dart_types.dart"; | 9 import "dart_types.dart"; |
10 import "js_backend/js_backend.dart" show JavaScriptBackend; | 10 import "js_backend/js_backend.dart" show JavaScriptBackend; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 } | 97 } |
98 | 98 |
99 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as | 99 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as |
100 /// non-elements. | 100 /// non-elements. |
101 abstract class CapturedVariable {} | 101 abstract class CapturedVariable {} |
102 | 102 |
103 // TODO(ahe): These classes continuously cause problems. We need to | 103 // TODO(ahe): These classes continuously cause problems. We need to |
104 // find a more general solution. | 104 // find a more general solution. |
105 class ClosureFieldElement extends ElementX | 105 class ClosureFieldElement extends ElementX |
106 implements VariableElement, CapturedVariable { | 106 implements VariableElement, CapturedVariable { |
107 /// The source variable this element refers to. | 107 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
108 final Local local; | 108 final Local local; |
109 | 109 |
110 ClosureFieldElement(String name, | 110 ClosureFieldElement(String name, |
111 this.local, | 111 this.local, |
112 ClosureClassElement enclosing) | 112 ClosureClassElement enclosing) |
113 : super(name, ElementKind.FIELD, enclosing); | 113 : super(name, ElementKind.FIELD, enclosing); |
114 | 114 |
115 /// Use [closureClass] instead. | 115 /// Use [closureClass] instead. |
116 @deprecated | 116 @deprecated |
117 get enclosingElement => super.enclosingElement; | 117 get enclosingElement => super.enclosingElement; |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 ResolvedAst get resolvedAst { | 294 ResolvedAst get resolvedAst { |
295 return new ResolvedAst(this, node, treeElements); | 295 return new ResolvedAst(this, node, treeElements); |
296 } | 296 } |
297 | 297 |
298 Element get analyzableElement => closureClass.methodElement.analyzableElement; | 298 Element get analyzableElement => closureClass.methodElement.analyzableElement; |
299 } | 299 } |
300 | 300 |
301 // The box-element for a scope, and the captured variables that need to be | 301 // The box-element for a scope, and the captured variables that need to be |
302 // stored in the box. | 302 // stored in the box. |
303 class ClosureScope { | 303 class ClosureScope { |
304 BoxLocal boxElement; | 304 final BoxLocal boxElement; |
305 Map<VariableElement, BoxFieldElement> _capturedVariableMapping; | 305 final Map<Local, BoxFieldElement> capturedVariables; |
306 | 306 |
307 // If the scope is attached to a [For] contains the variables that are | 307 // If the scope is attached to a [For] contains the variables that are |
308 // declared in the initializer of the [For] and that need to be boxed. | 308 // declared in the initializer of the [For] and that need to be boxed. |
309 // Otherwise contains the empty List. | 309 // Otherwise contains the empty List. |
310 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; | 310 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; |
311 | 311 |
312 ClosureScope(this.boxElement, this._capturedVariableMapping); | 312 ClosureScope(this.boxElement, this.capturedVariables); |
313 | 313 |
314 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; | 314 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
315 | 315 |
316 bool isCapturedVariable(VariableElement variable) { | 316 bool isCapturedVariable(VariableElement variable) { |
317 return _capturedVariableMapping.containsKey(variable); | 317 return capturedVariables.containsKey(variable); |
318 } | 318 } |
319 | 319 |
320 void forEachCapturedVariable(f(LocalVariableElement variable, | 320 void forEachCapturedVariable(f(LocalVariableElement variable, |
321 BoxFieldElement boxField)) { | 321 BoxFieldElement boxField)) { |
322 _capturedVariableMapping.forEach(f); | 322 capturedVariables.forEach(f); |
323 } | 323 } |
324 } | 324 } |
325 | 325 |
326 class ClosureClassMap { | 326 class ClosureClassMap { |
327 // The closure's element before any translation. Will be null for methods. | 327 // The closure's element before any translation. Will be null for methods. |
328 final LocalFunctionElement closureElement; | 328 final LocalFunctionElement closureElement; |
329 // The closureClassElement will be null for methods that are not local | 329 // The closureClassElement will be null for methods that are not local |
330 // closures. | 330 // closures. |
331 final ClosureClassElement closureClassElement; | 331 final ClosureClassElement closureClassElement; |
332 // The callElement will be null for methods that are not local closures. | 332 // The callElement will be null for methods that are not local closures. |
333 final FunctionElement callElement; | 333 final FunctionElement callElement; |
334 // The [thisElement] makes handling 'this' easier by treating it like any | 334 // The [thisElement] makes handling 'this' easier by treating it like any |
335 // other argument. It is only set for instance-members. | 335 // other argument. It is only set for instance-members. |
336 final ThisLocal thisLocal; | 336 final ThisLocal thisLocal; |
337 | 337 |
338 // Maps free locals, arguments and function elements to their captured | 338 // Maps free locals, arguments, function elements, and box locals to |
339 // copies. | 339 // their locations. |
340 final Map<Local, CapturedVariable> _freeVariableMapping = | 340 final Map<Local, CapturedVariable> freeVariableMap = |
341 new Map<Local, CapturedVariable>(); | 341 new Map<Local, CapturedVariable>(); |
342 | 342 |
343 // Maps closure-fields to their captured elements. This is somehow the inverse | 343 // Maps [Loop] and [FunctionExpression] nodes to their |
344 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does | |
345 // not deal with boxes, here we map instance-fields (which might represent | |
346 // boxes) to their boxElement. | |
347 final Map<ClosureFieldElement, Local> _closureFieldMapping = | |
348 new Map<ClosureFieldElement, Local>(); | |
349 | |
350 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their | |
351 // [ClosureScope] which contains their box and the | 344 // [ClosureScope] which contains their box and the |
352 // captured variables that are stored in the box. | 345 // captured variables that are stored in the box. |
353 // This map will be empty if the method/closure of this [ClosureData] does not | 346 // This map will be empty if the method/closure of this [ClosureData] does not |
354 // contain any nested closure. | 347 // contain any nested closure. |
355 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 348 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
356 | 349 |
357 final Set<Local> usedVariablesInTry = new Set<Local>(); | 350 final Set<Local> usedVariablesInTry = new Set<Local>(); |
358 | 351 |
359 ClosureClassMap(this.closureElement, | 352 ClosureClassMap(this.closureElement, |
360 this.closureClassElement, | 353 this.closureClassElement, |
361 this.callElement, | 354 this.callElement, |
362 this.thisLocal); | 355 this.thisLocal); |
363 | 356 |
364 void addFreeVariable(Local element) { | 357 void addFreeVariable(Local element) { |
365 assert(_freeVariableMapping[element] == null); | 358 assert(freeVariableMap[element] == null); |
366 _freeVariableMapping[element] = null; | 359 freeVariableMap[element] = null; |
367 } | 360 } |
368 | 361 |
369 Iterable<Local> get freeVariables => _freeVariableMapping.keys; | 362 Iterable<Local> get freeVariables => freeVariableMap.keys; |
370 | 363 |
371 bool isFreeVariable(Local element) { | 364 bool isFreeVariable(Local element) { |
372 return _freeVariableMapping.containsKey(element); | 365 return freeVariableMap.containsKey(element); |
373 } | 366 } |
374 | 367 |
375 CapturedVariable getFreeVariableElement(Local element) { | |
376 return _freeVariableMapping[element]; | |
377 } | |
378 | |
379 /// Sets the free [variable] to be captured by the [boxField]. | |
380 void setFreeVariableBoxField(Local variable, | |
381 BoxFieldElement boxField) { | |
382 _freeVariableMapping[variable] = boxField; | |
383 } | |
384 | |
385 /// Sets the free [variable] to be captured by the [closureField]. | |
386 void setFreeVariableClosureField(Local variable, | |
387 ClosureFieldElement closureField) { | |
388 _freeVariableMapping[variable] = closureField; | |
389 } | |
390 | |
391 | |
392 void forEachFreeVariable(f(Local variable, | 368 void forEachFreeVariable(f(Local variable, |
393 CapturedVariable field)) { | 369 CapturedVariable field)) { |
394 _freeVariableMapping.forEach(f); | 370 freeVariableMap.forEach(f); |
395 } | 371 } |
396 | 372 |
397 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 373 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
398 return _closureFieldMapping[field]; | 374 return field.local; |
399 } | |
400 | |
401 void setLocalVariableForClosureField(ClosureFieldElement field, | |
402 Local variable) { | |
403 _closureFieldMapping[field] = variable; | |
404 } | 375 } |
405 | 376 |
406 bool get isClosure => closureElement != null; | 377 bool get isClosure => closureElement != null; |
407 | 378 |
408 bool capturingScopesBox(Local variable) { | 379 bool capturingScopesBox(Local variable) { |
409 return capturingScopes.values.any((scope) { | 380 return capturingScopes.values.any((scope) { |
410 return scope.boxedLoopVariables.contains(variable); | 381 return scope.boxedLoopVariables.contains(variable); |
411 }); | 382 }); |
412 } | 383 } |
413 | 384 |
414 bool isVariableBoxed(Local variable) { | 385 bool isVariableBoxed(Local variable) { |
415 CapturedVariable copy = _freeVariableMapping[variable]; | 386 CapturedVariable copy = freeVariableMap[variable]; |
416 if (copy is BoxFieldElement) { | 387 if (copy is BoxFieldElement) { |
417 return true; | 388 return true; |
418 } | 389 } |
419 return capturingScopesBox(variable); | 390 return capturingScopesBox(variable); |
420 } | 391 } |
421 | 392 |
422 void forEachCapturedVariable(void f(Local variable, | 393 void forEachCapturedVariable(void f(Local variable, |
423 CapturedVariable field)) { | 394 CapturedVariable field)) { |
424 _freeVariableMapping.forEach((variable, copy) { | 395 freeVariableMap.forEach((variable, copy) { |
425 if (variable is BoxLocal) return; | 396 if (variable is BoxLocal) return; |
426 f(variable, copy); | 397 f(variable, copy); |
427 }); | 398 }); |
428 capturingScopes.values.forEach((ClosureScope scope) { | 399 capturingScopes.values.forEach((ClosureScope scope) { |
429 scope.forEachCapturedVariable(f); | 400 scope.forEachCapturedVariable(f); |
430 }); | 401 }); |
431 } | 402 } |
432 | 403 |
433 void forEachBoxedVariable(void f(LocalVariableElement local, | 404 void forEachBoxedVariable(void f(LocalVariableElement local, |
434 BoxFieldElement field)) { | 405 BoxFieldElement field)) { |
435 _freeVariableMapping.forEach((variable, copy) { | 406 freeVariableMap.forEach((variable, copy) { |
436 if (!isVariableBoxed(variable)) return; | 407 if (!isVariableBoxed(variable)) return; |
437 f(variable, copy); | 408 f(variable, copy); |
438 }); | 409 }); |
439 capturingScopes.values.forEach((ClosureScope scope) { | 410 capturingScopes.values.forEach((ClosureScope scope) { |
440 scope.forEachCapturedVariable(f); | 411 scope.forEachCapturedVariable(f); |
441 }); | 412 }); |
442 } | 413 } |
443 | 414 |
444 void removeMyselfFrom(Universe universe) { | 415 void removeMyselfFrom(Universe universe) { |
445 _freeVariableMapping.values.forEach((e) { | 416 freeVariableMap.values.forEach((e) { |
446 universe.closurizedMembers.remove(e); | 417 universe.closurizedMembers.remove(e); |
447 universe.fieldSetters.remove(e); | 418 universe.fieldSetters.remove(e); |
448 universe.fieldGetters.remove(e); | 419 universe.fieldGetters.remove(e); |
449 }); | 420 }); |
450 } | 421 } |
451 } | 422 } |
452 | 423 |
453 class ClosureTranslator extends Visitor { | 424 class ClosureTranslator extends Visitor { |
454 final Compiler compiler; | 425 final Compiler compiler; |
455 final TreeElements elements; | 426 final TreeElements elements; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 // The captured variables that need to be stored in a field of the closure | 508 // The captured variables that need to be stored in a field of the closure |
538 // class. | 509 // class. |
539 Set<Local> fieldCaptures = new Set<Local>(); | 510 Set<Local> fieldCaptures = new Set<Local>(); |
540 Set<BoxLocal> boxes = new Set<BoxLocal>(); | 511 Set<BoxLocal> boxes = new Set<BoxLocal>(); |
541 ClosureClassMap data = closureMappingCache[closure]; | 512 ClosureClassMap data = closureMappingCache[closure]; |
542 // We get a copy of the keys and iterate over it, to avoid modifications | 513 // We get a copy of the keys and iterate over it, to avoid modifications |
543 // to the map while iterating over it. | 514 // to the map while iterating over it. |
544 Iterable<Local> freeVariables = data.freeVariables.toList(); | 515 Iterable<Local> freeVariables = data.freeVariables.toList(); |
545 freeVariables.forEach((Local fromElement) { | 516 freeVariables.forEach((Local fromElement) { |
546 assert(data.isFreeVariable(fromElement)); | 517 assert(data.isFreeVariable(fromElement)); |
547 assert(data.getFreeVariableElement(fromElement) == null); | 518 assert(data.freeVariableMap[fromElement] == null); |
548 assert(isCapturedVariable(fromElement)); | 519 assert(isCapturedVariable(fromElement)); |
549 BoxFieldElement boxFieldElement = | 520 BoxFieldElement boxFieldElement = |
550 getCapturedVariableBoxField(fromElement); | 521 getCapturedVariableBoxField(fromElement); |
551 if (boxFieldElement == null) { | 522 if (boxFieldElement == null) { |
552 assert(fromElement is! BoxLocal); | 523 assert(fromElement is! BoxLocal); |
553 // The variable has not been boxed. | 524 // The variable has not been boxed. |
554 fieldCaptures.add(fromElement); | 525 fieldCaptures.add(fromElement); |
555 } else { | 526 } else { |
556 // A boxed element. | 527 // A boxed element. |
557 data.setFreeVariableBoxField(fromElement, boxFieldElement); | 528 data.freeVariableMap[fromElement] = boxFieldElement; |
558 boxes.add(boxFieldElement.box); | 529 boxes.add(boxFieldElement.box); |
559 } | 530 } |
560 }); | 531 }); |
561 ClosureClassElement closureClass = data.closureClassElement; | 532 ClosureClassElement closureClass = data.closureClassElement; |
562 assert(closureClass != null || | 533 assert(closureClass != null || |
563 (fieldCaptures.isEmpty && boxes.isEmpty)); | 534 (fieldCaptures.isEmpty && boxes.isEmpty)); |
564 | 535 |
565 void addClosureField(Local local, String name) { | 536 void addClosureField(Local local, String name) { |
566 ClosureFieldElement closureField = | 537 ClosureFieldElement closureField = |
567 new ClosureFieldElement(name, local, closureClass); | 538 new ClosureFieldElement(name, local, closureClass); |
568 closureClass.addField(closureField, compiler); | 539 closureClass.addField(closureField, compiler); |
569 data.setLocalVariableForClosureField(closureField, local); | 540 data.freeVariableMap[local] = closureField; |
570 data.setFreeVariableClosureField(local, closureField); | |
571 } | 541 } |
572 | 542 |
573 // Add the box elements first so we get the same ordering. | 543 // Add the box elements first so we get the same ordering. |
574 // TODO(sra): What is the canonical order of multiple boxes? | 544 // TODO(sra): What is the canonical order of multiple boxes? |
575 for (BoxLocal capturedElement in boxes) { | 545 for (BoxLocal capturedElement in boxes) { |
576 addClosureField(capturedElement, capturedElement.name); | 546 addClosureField(capturedElement, capturedElement.name); |
577 } | 547 } |
578 | 548 |
579 /// Comparator for locals. Position boxes before elements. | 549 /// Comparator for locals. Position boxes before elements. |
580 int compareLocals(a, b) { | 550 int compareLocals(a, b) { |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1022 | 992 |
1023 String get name => typeVariable.name; | 993 String get name => typeVariable.name; |
1024 | 994 |
1025 int get hashCode => typeVariable.hashCode; | 995 int get hashCode => typeVariable.hashCode; |
1026 | 996 |
1027 bool operator ==(other) { | 997 bool operator ==(other) { |
1028 if (other is! TypeVariableLocal) return false; | 998 if (other is! TypeVariableLocal) return false; |
1029 return typeVariable == other.typeVariable; | 999 return typeVariable == other.typeVariable; |
1030 } | 1000 } |
1031 } | 1001 } |
OLD | NEW |