| 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; |
| 11 import "scanner/scannerlib.dart" show Token; | 11 import "scanner/scannerlib.dart" show Token; |
| 12 import "tree/tree.dart"; | 12 import "tree/tree.dart"; |
| 13 import "util/util.dart"; | 13 import "util/util.dart"; |
| 14 import "elements/modelx.dart" | 14 import "elements/modelx.dart" |
| 15 show BaseFunctionElementX, | 15 show BaseFunctionElementX, |
| 16 ClassElementX, | 16 ClassElementX, |
| 17 ElementX, | 17 ElementX, |
| 18 LocalFunctionElementX; | 18 LocalFunctionElementX; |
| 19 import "elements/visitor.dart" show ElementVisitor; | 19 import "elements/visitor.dart" show ElementVisitor; |
| 20 | 20 |
| 21 import 'universe/universe.dart' show | 21 import 'universe/universe.dart' show |
| 22 Universe; | 22 Universe; |
| 23 | 23 |
| 24 class ClosureNamer { |
| 25 String getClosureVariableName(String name, int id) { |
| 26 return "${name}_$id"; |
| 27 } |
| 28 |
| 29 void forgetElement(Element element) {} |
| 30 } |
| 31 |
| 24 class ClosureTask extends CompilerTask { | 32 class ClosureTask extends CompilerTask { |
| 25 Map<Node, ClosureClassMap> closureMappingCache; | 33 Map<Node, ClosureClassMap> closureMappingCache; |
| 26 ClosureTask(Compiler compiler) | 34 ClosureNamer namer; |
| 35 ClosureTask(Compiler compiler, this.namer) |
| 27 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 36 : closureMappingCache = new Map<Node, ClosureClassMap>(), |
| 28 super(compiler); | 37 super(compiler); |
| 29 | 38 |
| 30 String get name => "Closure Simplifier"; | 39 String get name => "Closure Simplifier"; |
| 31 | 40 |
| 32 ClosureClassMap computeClosureToClassMapping(Element element, | 41 ClosureClassMap computeClosureToClassMapping(Element element, |
| 33 Node node, | 42 Node node, |
| 34 TreeElements elements) { | 43 TreeElements elements) { |
| 35 return measure(() { | 44 return measure(() { |
| 36 ClosureClassMap cached = closureMappingCache[node]; | 45 ClosureClassMap cached = closureMappingCache[node]; |
| 37 if (cached != null) return cached; | 46 if (cached != null) return cached; |
| 38 | 47 |
| 39 ClosureTranslator translator = | 48 ClosureTranslator translator = |
| 40 new ClosureTranslator(compiler, elements, closureMappingCache); | 49 new ClosureTranslator(compiler, elements, closureMappingCache, namer); |
| 41 | 50 |
| 42 // The translator will store the computed closure-mappings inside the | 51 // The translator will store the computed closure-mappings inside the |
| 43 // cache. One for given node and one for each nested closure. | 52 // cache. One for given node and one for each nested closure. |
| 44 if (node is FunctionExpression) { | 53 if (node is FunctionExpression) { |
| 45 translator.translateFunction(element, node); | 54 translator.translateFunction(element, node); |
| 46 } else if (element.isSynthesized) { | 55 } else if (element.isSynthesized) { |
| 47 return new ClosureClassMap(null, null, null, new ThisLocal(element)); | 56 return new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 48 } else { | 57 } else { |
| 49 assert(element.isField); | 58 assert(element.isField); |
| 50 VariableElement field = element; | 59 VariableElement field = element; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 75 void forgetElement(var closure) { | 84 void forgetElement(var closure) { |
| 76 ClosureClassElement cls; | 85 ClosureClassElement cls; |
| 77 if (closure is ClosureFieldElement) { | 86 if (closure is ClosureFieldElement) { |
| 78 cls = closure.closureClass; | 87 cls = closure.closureClass; |
| 79 } else if (closure is SynthesizedCallMethodElementX) { | 88 } else if (closure is SynthesizedCallMethodElementX) { |
| 80 cls = closure.closureClass; | 89 cls = closure.closureClass; |
| 81 } else { | 90 } else { |
| 82 throw new SpannableAssertionFailure( | 91 throw new SpannableAssertionFailure( |
| 83 closure, 'Not a closure: $closure (${closure.runtimeType}).'); | 92 closure, 'Not a closure: $closure (${closure.runtimeType}).'); |
| 84 } | 93 } |
| 94 namer.forgetElement(cls); |
| 85 compiler.enqueuer.codegen.forgetElement(cls); | 95 compiler.enqueuer.codegen.forgetElement(cls); |
| 86 } | 96 } |
| 87 } | 97 } |
| 88 | 98 |
| 89 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as | 99 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as |
| 90 /// non-elements. | 100 /// non-elements. |
| 91 abstract class CapturedVariable {} | 101 abstract class CapturedVariable {} |
| 92 | 102 |
| 93 // TODO(ahe): These classes continuously cause problems. We need to | 103 // TODO(ahe): These classes continuously cause problems. We need to |
| 94 // find a more general solution. | 104 // find a more general solution. |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 // Keep track of the mutated local variables so that we don't need to box | 452 // Keep track of the mutated local variables so that we don't need to box |
| 443 // non-mutated variables. | 453 // non-mutated variables. |
| 444 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); | 454 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); |
| 445 | 455 |
| 446 MemberElement outermostElement; | 456 MemberElement outermostElement; |
| 447 ExecutableElement executableContext; | 457 ExecutableElement executableContext; |
| 448 | 458 |
| 449 // The closureData of the currentFunctionElement. | 459 // The closureData of the currentFunctionElement. |
| 450 ClosureClassMap closureData; | 460 ClosureClassMap closureData; |
| 451 | 461 |
| 462 ClosureNamer namer; |
| 463 |
| 452 bool insideClosure = false; | 464 bool insideClosure = false; |
| 453 | 465 |
| 454 ClosureTranslator(this.compiler, | 466 ClosureTranslator(this.compiler, |
| 455 this.elements, | 467 this.elements, |
| 456 this.closureMappingCache); | 468 this.closureMappingCache, |
| 457 | 469 this.namer); |
| 458 /// Generate a unique name for the [id]th closure variable, with proposed name | |
| 459 /// [name]. | |
| 460 /// | |
| 461 /// The result is used as the name of [BoxFieldElement]s and | |
| 462 /// [ClosureFieldElement]s, and must therefore be unique to avoid breaking an | |
| 463 /// invariant in the element model (classes cannot declare multiple fields | |
| 464 /// with the same name). | |
| 465 /// | |
| 466 /// Also, the names should be distinct from real field names to prevent | |
| 467 /// clashes with selectors for those fields. | |
| 468 String getClosureVariableName(String name, int id) { | |
| 469 return "${outermostElement.name}_${name}_$id"; | |
| 470 } | |
| 471 | 470 |
| 472 bool isCapturedVariable(Local element) { | 471 bool isCapturedVariable(Local element) { |
| 473 return _capturedVariableMapping.containsKey(element); | 472 return _capturedVariableMapping.containsKey(element); |
| 474 } | 473 } |
| 475 | 474 |
| 476 void addCapturedVariable(Node node, Local variable) { | 475 void addCapturedVariable(Node node, Local variable) { |
| 477 if (_capturedVariableMapping[variable] != null) { | 476 if (_capturedVariableMapping[variable] != null) { |
| 478 compiler.internalError(node, 'In closure analyzer.'); | 477 compiler.internalError(node, 'In closure analyzer.'); |
| 479 } | 478 } |
| 480 _capturedVariableMapping[variable] = null; | 479 _capturedVariableMapping[variable] = null; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 return 1; | 562 return 1; |
| 564 } else if (b is Element) { | 563 } else if (b is Element) { |
| 565 return -1; | 564 return -1; |
| 566 } else { | 565 } else { |
| 567 return a.name.compareTo(b.name); | 566 return a.name.compareTo(b.name); |
| 568 } | 567 } |
| 569 } | 568 } |
| 570 | 569 |
| 571 for (Local capturedLocal in fieldCaptures.toList()..sort(compareLocals)) { | 570 for (Local capturedLocal in fieldCaptures.toList()..sort(compareLocals)) { |
| 572 int id = closureFieldCounter++; | 571 int id = closureFieldCounter++; |
| 573 String name = getClosureVariableName(capturedLocal.name, id); | 572 String name = namer.getClosureVariableName(capturedLocal.name, id); |
| 574 addClosureField(capturedLocal, name); | 573 addClosureField(capturedLocal, name); |
| 575 } | 574 } |
| 576 closureClass.reverseBackendMembers(); | 575 closureClass.reverseBackendMembers(); |
| 577 } | 576 } |
| 578 } | 577 } |
| 579 | 578 |
| 580 void useLocal(Local variable) { | 579 void useLocal(Local variable) { |
| 581 // If the element is not declared in the current function and the element | 580 // If the element is not declared in the current function and the element |
| 582 // is not the closure itself we need to mark the element as free variable. | 581 // is not the closure itself we need to mark the element as free variable. |
| 583 // Note that the check on [insideClosure] is not just an | 582 // Note that the check on [insideClosure] is not just an |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 void attachCapturedScopeVariables(Node node) { | 791 void attachCapturedScopeVariables(Node node) { |
| 793 BoxLocal box = null; | 792 BoxLocal box = null; |
| 794 Map<LocalVariableElement, BoxFieldElement> scopeMapping = | 793 Map<LocalVariableElement, BoxFieldElement> scopeMapping = |
| 795 new Map<LocalVariableElement, BoxFieldElement>(); | 794 new Map<LocalVariableElement, BoxFieldElement>(); |
| 796 | 795 |
| 797 void boxCapturedVariable(LocalVariableElement variable) { | 796 void boxCapturedVariable(LocalVariableElement variable) { |
| 798 if (isCapturedVariable(variable)) { | 797 if (isCapturedVariable(variable)) { |
| 799 if (box == null) { | 798 if (box == null) { |
| 800 // TODO(floitsch): construct better box names. | 799 // TODO(floitsch): construct better box names. |
| 801 String boxName = | 800 String boxName = |
| 802 getClosureVariableName('box', closureFieldCounter++); | 801 namer.getClosureVariableName('box', closureFieldCounter++); |
| 803 box = new BoxLocal(boxName, executableContext); | 802 box = new BoxLocal(boxName, executableContext); |
| 804 } | 803 } |
| 805 String elementName = variable.name; | 804 String elementName = variable.name; |
| 806 String boxedName = | 805 String boxedName = |
| 807 getClosureVariableName(elementName, boxedFieldCounter++); | 806 namer.getClosureVariableName(elementName, boxedFieldCounter++); |
| 808 // TODO(kasperl): Should this be a FieldElement instead? | 807 // TODO(kasperl): Should this be a FieldElement instead? |
| 809 BoxFieldElement boxed = new BoxFieldElement(boxedName, variable, box); | 808 BoxFieldElement boxed = new BoxFieldElement(boxedName, variable, box); |
| 810 // No need to rename the fields of a box, so we give them a native name | 809 // No need to rename the fields of a box, so we give them a native name |
| 811 // right now. | 810 // right now. |
| 812 boxed.setFixedBackendName(boxedName); | 811 boxed.setFixedBackendName(boxedName); |
| 813 scopeMapping[variable] = boxed; | 812 scopeMapping[variable] = boxed; |
| 814 setCapturedVariableBoxField(variable, boxed); | 813 setCapturedVariableBoxField(variable, boxed); |
| 815 } | 814 } |
| 816 } | 815 } |
| 817 | 816 |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1052 | 1051 |
| 1053 String get name => typeVariable.name; | 1052 String get name => typeVariable.name; |
| 1054 | 1053 |
| 1055 int get hashCode => typeVariable.hashCode; | 1054 int get hashCode => typeVariable.hashCode; |
| 1056 | 1055 |
| 1057 bool operator ==(other) { | 1056 bool operator ==(other) { |
| 1058 if (other is! TypeVariableLocal) return false; | 1057 if (other is! TypeVariableLocal) return false; |
| 1059 return typeVariable == other.typeVariable; | 1058 return typeVariable == other.typeVariable; |
| 1060 } | 1059 } |
| 1061 } | 1060 } |
| OLD | NEW |