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