| 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 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
| 8 import 'common/resolution.dart' show ParsingContext, Resolution; | 8 import 'common/resolution.dart' show ParsingContext, Resolution; |
| 9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
| 10 import 'common.dart'; | 10 import 'common.dart'; |
| 11 import 'compiler.dart' show Compiler; | 11 import 'compiler.dart' show Compiler; |
| 12 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
| 13 import 'dart_types.dart'; | 13 import 'dart_types.dart'; |
| 14 import 'elements/elements.dart'; | 14 import 'elements/elements.dart'; |
| 15 import 'elements/modelx.dart' | 15 import 'elements/modelx.dart' |
| 16 show BaseFunctionElementX, ClassElementX, ElementX; | 16 show BaseFunctionElementX, ClassElementX, ElementX; |
| 17 import 'elements/visitor.dart' show ElementVisitor; | 17 import 'elements/visitor.dart' show ElementVisitor; |
| 18 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 18 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
| 19 import 'resolution/tree_elements.dart' show TreeElements; | 19 import 'resolution/tree_elements.dart' show TreeElements; |
| 20 import 'tokens/token.dart' show Token; | 20 import 'tokens/token.dart' show Token; |
| 21 import 'tree/tree.dart'; | 21 import 'tree/tree.dart'; |
| 22 import 'universe/world_builder.dart' show CodegenWorldBuilder; | 22 import 'universe/world_builder.dart' show CodegenWorldBuilder; |
| 23 import 'util/util.dart'; | 23 import 'util/util.dart'; |
| 24 | 24 |
| 25 class ClosureTask extends CompilerTask { | 25 class ClosureTask extends CompilerTask { |
| 26 Map<Node, ClosureClassMap> closureMappingCache; | 26 Map<Element, ClosureClassMap> _closureMappingCache = |
| 27 <Element, ClosureClassMap>{}; |
| 27 Compiler compiler; | 28 Compiler compiler; |
| 28 ClosureTask(Compiler compiler) | 29 ClosureTask(Compiler compiler) |
| 29 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 30 : compiler = compiler, |
| 30 compiler = compiler, | |
| 31 super(compiler.measurer); | 31 super(compiler.measurer); |
| 32 | 32 |
| 33 String get name => "Closure Simplifier"; | 33 String get name => "Closure Simplifier"; |
| 34 | 34 |
| 35 DiagnosticReporter get reporter => compiler.reporter; | 35 DiagnosticReporter get reporter => compiler.reporter; |
| 36 | 36 |
| 37 /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
| 38 ClosureClassMap getClosureToClassMapping(ResolvedAst resolvedAst) { |
| 39 return measure(() { |
| 40 Element element = resolvedAst.element; |
| 41 if (element.isGenerativeConstructorBody) { |
| 42 ConstructorBodyElement constructorBody = element; |
| 43 element = constructorBody.constructor; |
| 44 } |
| 45 ClosureClassMap closureClassMap = _closureMappingCache[element]; |
| 46 assert(invariant(resolvedAst.element, closureClassMap != null, |
| 47 message: "No ClosureClassMap computed for ${element}.")); |
| 48 return closureClassMap; |
| 49 }); |
| 50 } |
| 51 |
| 52 /// Create [ClosureClassMap]s for all live members. |
| 53 void createClosureClasses() { |
| 54 compiler.enqueuer.resolution.processedElements |
| 55 .forEach((AstElement element) { |
| 56 ResolvedAst resolvedAst = element.resolvedAst; |
| 57 if (element.isAbstract) return; |
| 58 if (element.isField && |
| 59 !element.isInstanceMember && |
| 60 resolvedAst.body == null) { |
| 61 // Skip top-level/static fields without an initializer. |
| 62 return; |
| 63 } |
| 64 computeClosureToClassMapping(resolvedAst); |
| 65 }); |
| 66 } |
| 67 |
| 37 ClosureClassMap computeClosureToClassMapping(ResolvedAst resolvedAst) { | 68 ClosureClassMap computeClosureToClassMapping(ResolvedAst resolvedAst) { |
| 38 return measure(() { | 69 return measure(() { |
| 39 Element element = resolvedAst.element; | 70 Element element = resolvedAst.element; |
| 71 ClosureClassMap cached = _closureMappingCache[element]; |
| 72 if (cached != null) return cached; |
| 40 if (resolvedAst.kind != ResolvedAstKind.PARSED) { | 73 if (resolvedAst.kind != ResolvedAstKind.PARSED) { |
| 41 return new ClosureClassMap(null, null, null, new ThisLocal(element)); | 74 return _closureMappingCache[element] = |
| 75 new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 42 } | 76 } |
| 43 return reporter.withCurrentElement(element.implementation, () { | 77 return reporter.withCurrentElement(element.implementation, () { |
| 44 Node node = resolvedAst.node; | 78 Node node = resolvedAst.node; |
| 45 TreeElements elements = resolvedAst.elements; | 79 TreeElements elements = resolvedAst.elements; |
| 46 | 80 |
| 47 ClosureClassMap cached = closureMappingCache[node]; | |
| 48 if (cached != null) return cached; | |
| 49 | |
| 50 ClosureTranslator translator = | 81 ClosureTranslator translator = |
| 51 new ClosureTranslator(compiler, elements, closureMappingCache); | 82 new ClosureTranslator(compiler, elements, _closureMappingCache); |
| 52 | 83 |
| 53 // The translator will store the computed closure-mappings inside the | 84 // The translator will store the computed closure-mappings inside the |
| 54 // cache. One for given node and one for each nested closure. | 85 // cache. One for given node and one for each nested closure. |
| 55 if (node is FunctionExpression) { | 86 if (node is FunctionExpression) { |
| 56 translator.translateFunction(element, node); | 87 translator.translateFunction(element, node); |
| 57 } else if (element.isSynthesized) { | 88 } else if (element.isSynthesized) { |
| 58 reporter.internalError( | 89 reporter.internalError( |
| 59 element, "Unexpected synthesized element: $element"); | 90 element, "Unexpected synthesized element: $element"); |
| 60 return new ClosureClassMap(null, null, null, new ThisLocal(element)); | 91 _closureMappingCache[element] = |
| 92 new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 61 } else { | 93 } else { |
| 62 assert(invariant(element, element.isField, | 94 assert(invariant(element, element.isField, |
| 63 message: "Expected $element to be a field.")); | 95 message: "Expected $element to be a field.")); |
| 64 Node initializer = resolvedAst.body; | 96 Node initializer = resolvedAst.body; |
| 65 if (initializer != null) { | 97 if (initializer != null) { |
| 66 // The lazy initializer of a static. | 98 // The lazy initializer of a static. |
| 67 translator.translateLazyInitializer(element, node, initializer); | 99 translator.translateLazyInitializer(element, node, initializer); |
| 68 } else { | 100 } else { |
| 69 assert(invariant(element, element.isInstanceMember, | 101 assert(invariant(element, element.isInstanceMember, |
| 70 message: "Expected $element (${element | 102 message: "Expected $element (${element |
| 71 .runtimeType}) to be an instance field.")); | 103 .runtimeType}) to be an instance field.")); |
| 72 closureMappingCache[node] = | 104 _closureMappingCache[element] = |
| 73 new ClosureClassMap(null, null, null, new ThisLocal(element)); | 105 new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 74 } | 106 } |
| 75 } | 107 } |
| 76 assert(closureMappingCache[node] != null); | 108 assert(invariant(element, _closureMappingCache[element] != null, |
| 77 return closureMappingCache[node]; | 109 message: "No ClosureClassMap computed for ${element}.")); |
| 110 return _closureMappingCache[element]; |
| 78 }); | 111 }); |
| 79 }); | 112 }); |
| 80 } | 113 } |
| 81 | 114 |
| 82 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { | |
| 83 return measure(() { | |
| 84 ClosureClassMap nestedClosureData = closureMappingCache[node]; | |
| 85 if (nestedClosureData == null) { | |
| 86 reporter.internalError(node, "No closure cache."); | |
| 87 } | |
| 88 return nestedClosureData; | |
| 89 }); | |
| 90 } | |
| 91 | |
| 92 void forgetElement(var closure) { | 115 void forgetElement(var closure) { |
| 93 ClosureClassElement cls; | 116 ClosureClassElement cls; |
| 94 if (closure is ClosureFieldElement) { | 117 if (closure is ClosureFieldElement) { |
| 95 cls = closure.closureClass; | 118 cls = closure.closureClass; |
| 96 } else if (closure is SynthesizedCallMethodElementX) { | 119 } else if (closure is SynthesizedCallMethodElementX) { |
| 97 cls = closure.closureClass; | 120 cls = closure.closureClass; |
| 98 } else { | 121 } else { |
| 99 throw new SpannableAssertionFailure( | 122 throw new SpannableAssertionFailure( |
| 100 closure, 'Not a closure: $closure (${closure.runtimeType}).'); | 123 closure, 'Not a closure: $closure (${closure.runtimeType}).'); |
| 101 } | 124 } |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 } | 542 } |
| 520 } | 543 } |
| 521 | 544 |
| 522 class ClosureTranslator extends Visitor { | 545 class ClosureTranslator extends Visitor { |
| 523 final Compiler compiler; | 546 final Compiler compiler; |
| 524 final TreeElements elements; | 547 final TreeElements elements; |
| 525 int closureFieldCounter = 0; | 548 int closureFieldCounter = 0; |
| 526 int boxedFieldCounter = 0; | 549 int boxedFieldCounter = 0; |
| 527 bool inTryStatement = false; | 550 bool inTryStatement = false; |
| 528 | 551 |
| 529 final Map<Node, ClosureClassMap> closureMappingCache; | 552 final Map<Element, ClosureClassMap> closureMappingCache; |
| 530 | 553 |
| 531 // Map of captured variables. Initially they will map to `null`. If | 554 // Map of captured variables. Initially they will map to `null`. If |
| 532 // a variable needs to be boxed then the scope declaring the variable | 555 // a variable needs to be boxed then the scope declaring the variable |
| 533 // will update this to mapping to the capturing [BoxFieldElement]. | 556 // will update this to mapping to the capturing [BoxFieldElement]. |
| 534 Map<Local, BoxFieldElement> _capturedVariableMapping = | 557 Map<Local, BoxFieldElement> _capturedVariableMapping = |
| 535 new Map<Local, BoxFieldElement>(); | 558 new Map<Local, BoxFieldElement>(); |
| 536 | 559 |
| 537 // List of encountered closures. | 560 // List of encountered closures. |
| 538 List<Expression> closures = <Expression>[]; | 561 List<LocalFunctionElement> closures = <LocalFunctionElement>[]; |
| 539 | 562 |
| 540 // The local variables that have been declared in the current scope. | 563 // The local variables that have been declared in the current scope. |
| 541 List<LocalVariableElement> scopeVariables; | 564 List<LocalVariableElement> scopeVariables; |
| 542 | 565 |
| 543 // Keep track of the mutated local variables so that we don't need to box | 566 // Keep track of the mutated local variables so that we don't need to box |
| 544 // non-mutated variables. | 567 // non-mutated variables. |
| 545 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); | 568 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); |
| 546 | 569 |
| 547 MemberElement outermostElement; | 570 MemberElement outermostElement; |
| 548 ExecutableElement executableContext; | 571 ExecutableElement executableContext; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 visitInvokable(element, node, () { | 646 visitInvokable(element, node, () { |
| 624 visit(initializer); | 647 visit(initializer); |
| 625 }); | 648 }); |
| 626 updateClosures(); | 649 updateClosures(); |
| 627 } | 650 } |
| 628 | 651 |
| 629 // This function runs through all of the existing closures and updates their | 652 // This function runs through all of the existing closures and updates their |
| 630 // free variables to the boxed value. It also adds the field-elements to the | 653 // free variables to the boxed value. It also adds the field-elements to the |
| 631 // class representing the closure. | 654 // class representing the closure. |
| 632 void updateClosures() { | 655 void updateClosures() { |
| 633 for (Expression closure in closures) { | 656 for (LocalFunctionElement closure in closures) { |
| 634 // The captured variables that need to be stored in a field of the closure | 657 // The captured variables that need to be stored in a field of the closure |
| 635 // class. | 658 // class. |
| 636 Set<Local> fieldCaptures = new Set<Local>(); | 659 Set<Local> fieldCaptures = new Set<Local>(); |
| 637 Set<BoxLocal> boxes = new Set<BoxLocal>(); | 660 Set<BoxLocal> boxes = new Set<BoxLocal>(); |
| 638 ClosureClassMap data = closureMappingCache[closure]; | 661 ClosureClassMap data = closureMappingCache[closure]; |
| 639 // We get a copy of the keys and iterate over it, to avoid modifications | 662 // We get a copy of the keys and iterate over it, to avoid modifications |
| 640 // to the map while iterating over it. | 663 // to the map while iterating over it. |
| 641 Iterable<Local> freeVariables = data.freeVariables.toList(); | 664 Iterable<Local> freeVariables = data.freeVariables.toList(); |
| 642 freeVariables.forEach((Local fromElement) { | 665 freeVariables.forEach((Local fromElement) { |
| 643 assert(data.isFreeVariable(fromElement)); | 666 assert(data.isFreeVariable(fromElement)); |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 ExecutableElement element, Node node, void visitChildren()) { | 1090 ExecutableElement element, Node node, void visitChildren()) { |
| 1068 bool oldInsideClosure = insideClosure; | 1091 bool oldInsideClosure = insideClosure; |
| 1069 Element oldFunctionElement = executableContext; | 1092 Element oldFunctionElement = executableContext; |
| 1070 ClosureClassMap oldClosureData = closureData; | 1093 ClosureClassMap oldClosureData = closureData; |
| 1071 | 1094 |
| 1072 insideClosure = outermostElement != null; | 1095 insideClosure = outermostElement != null; |
| 1073 LocalFunctionElement closure; | 1096 LocalFunctionElement closure; |
| 1074 executableContext = element; | 1097 executableContext = element; |
| 1075 if (insideClosure) { | 1098 if (insideClosure) { |
| 1076 closure = element; | 1099 closure = element; |
| 1077 closures.add(node); | 1100 closures.add(closure); |
| 1078 closureData = globalizeClosure(node, closure); | 1101 closureData = globalizeClosure(node, closure); |
| 1079 } else { | 1102 } else { |
| 1080 outermostElement = element; | 1103 outermostElement = element; |
| 1081 ThisLocal thisElement = null; | 1104 ThisLocal thisElement = null; |
| 1082 if (element.isInstanceMember || element.isGenerativeConstructor) { | 1105 if (element.isInstanceMember || element.isGenerativeConstructor) { |
| 1083 thisElement = new ThisLocal(element); | 1106 thisElement = new ThisLocal(element); |
| 1084 } | 1107 } |
| 1085 closureData = new ClosureClassMap(null, null, null, thisElement); | 1108 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 1086 } | 1109 } |
| 1087 closureMappingCache[node] = closureData; | 1110 closureMappingCache[element.declaration] = closureData; |
| 1111 if (closureData.callElement != null) { |
| 1112 closureMappingCache[closureData.callElement] = closureData; |
| 1113 } |
| 1088 | 1114 |
| 1089 inNewScope(node, () { | 1115 inNewScope(node, () { |
| 1090 DartType type = element.type; | 1116 DartType type = element.type; |
| 1091 // If the method needs RTI, or checked mode is set, we need to | 1117 // If the method needs RTI, or checked mode is set, we need to |
| 1092 // escape the potential type variables used in that closure. | 1118 // escape the potential type variables used in that closure. |
| 1093 if (element is FunctionElement && | 1119 if (element is FunctionElement && |
| 1094 (compiler.backend.methodNeedsRti(element) || | 1120 (compiler.backend.methodNeedsRti(element) || |
| 1095 compiler.options.enableTypeAssertions)) { | 1121 compiler.options.enableTypeAssertions)) { |
| 1096 analyzeTypeVariables(type); | 1122 analyzeTypeVariables(type); |
| 1097 } | 1123 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1183 /// | 1209 /// |
| 1184 /// Move the below classes to a JS model eventually. | 1210 /// Move the below classes to a JS model eventually. |
| 1185 /// | 1211 /// |
| 1186 abstract class JSEntity implements Entity { | 1212 abstract class JSEntity implements Entity { |
| 1187 Entity get declaredEntity; | 1213 Entity get declaredEntity; |
| 1188 } | 1214 } |
| 1189 | 1215 |
| 1190 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1216 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1191 Entity get rootOfScope; | 1217 Entity get rootOfScope; |
| 1192 } | 1218 } |
| OLD | NEW |