| 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.dart'; | 7 import 'common.dart'; |
| 8 import 'common/names.dart' show Identifiers; | 8 import 'common/names.dart' show Identifiers; |
| 9 import 'common/resolution.dart' show ParsingContext, Resolution; | 9 import 'common/resolution.dart' show ParsingContext, Resolution; |
| 10 import 'common/tasks.dart' show CompilerTask; | 10 import 'common/tasks.dart' show CompilerTask; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 super(compiler); | 29 super(compiler); |
| 30 | 30 |
| 31 String get name => "Closure Simplifier"; | 31 String get name => "Closure Simplifier"; |
| 32 | 32 |
| 33 ClosureClassMap computeClosureToClassMapping(ResolvedAst resolvedAst) { | 33 ClosureClassMap computeClosureToClassMapping(ResolvedAst resolvedAst) { |
| 34 return measure(() { | 34 return measure(() { |
| 35 Element element = resolvedAst.element; | 35 Element element = resolvedAst.element; |
| 36 if (resolvedAst.kind != ResolvedAstKind.PARSED) { | 36 if (resolvedAst.kind != ResolvedAstKind.PARSED) { |
| 37 return new ClosureClassMap(null, null, null, new ThisLocal(element)); | 37 return new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 38 } | 38 } |
| 39 Node node = resolvedAst.node; | 39 return reporter.withCurrentElement(element.implementation, () { |
| 40 TreeElements elements = resolvedAst.elements; | 40 Node node = resolvedAst.node; |
| 41 TreeElements elements = resolvedAst.elements; |
| 41 | 42 |
| 42 ClosureClassMap cached = closureMappingCache[node]; | 43 ClosureClassMap cached = closureMappingCache[node]; |
| 43 if (cached != null) return cached; | 44 if (cached != null) return cached; |
| 44 | 45 |
| 45 ClosureTranslator translator = | 46 ClosureTranslator translator = |
| 46 new ClosureTranslator(compiler, elements, closureMappingCache); | 47 new ClosureTranslator(compiler, elements, closureMappingCache); |
| 47 | 48 |
| 48 // The translator will store the computed closure-mappings inside the | 49 // The translator will store the computed closure-mappings inside the |
| 49 // cache. One for given node and one for each nested closure. | 50 // cache. One for given node and one for each nested closure. |
| 50 if (node is FunctionExpression) { | 51 if (node is FunctionExpression) { |
| 51 translator.translateFunction(element, node); | 52 translator.translateFunction(element, node); |
| 52 } else if (element.isSynthesized) { | 53 } else if (element.isSynthesized) { |
| 53 reporter.internalError( | 54 reporter.internalError( |
| 54 element, "Unexpected synthesized element: $element"); | 55 element, "Unexpected synthesized element: $element"); |
| 55 return new ClosureClassMap(null, null, null, new ThisLocal(element)); | 56 return new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 56 } else { | |
| 57 assert(element.isField); | |
| 58 Node initializer = resolvedAst.body; | |
| 59 if (initializer != null) { | |
| 60 // The lazy initializer of a static. | |
| 61 translator.translateLazyInitializer(element, node, initializer); | |
| 62 } else { | 57 } else { |
| 63 assert(element.isInstanceMember); | 58 assert(invariant(element, element.isField, |
| 64 closureMappingCache[node] = | 59 message: "Expected $element to be a field.")); |
| 65 new ClosureClassMap(null, null, null, new ThisLocal(element)); | 60 Node initializer = resolvedAst.body; |
| 61 if (initializer != null) { |
| 62 // The lazy initializer of a static. |
| 63 translator.translateLazyInitializer(element, node, initializer); |
| 64 } else { |
| 65 assert(invariant(element, element.isInstanceMember, |
| 66 message: "Expected $element (${element |
| 67 .runtimeType}) to be an instance field.")); |
| 68 closureMappingCache[node] = |
| 69 new ClosureClassMap(null, null, null, new ThisLocal(element)); |
| 70 } |
| 66 } | 71 } |
| 67 } | 72 assert(closureMappingCache[node] != null); |
| 68 assert(closureMappingCache[node] != null); | 73 return closureMappingCache[node]; |
| 69 return closureMappingCache[node]; | 74 }); |
| 70 }); | 75 }); |
| 71 } | 76 } |
| 72 | 77 |
| 73 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { | 78 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { |
| 74 return measure(() { | 79 return measure(() { |
| 75 ClosureClassMap nestedClosureData = closureMappingCache[node]; | 80 ClosureClassMap nestedClosureData = closureMappingCache[node]; |
| 76 if (nestedClosureData == null) { | 81 if (nestedClosureData == null) { |
| 77 reporter.internalError(node, "No closure cache."); | 82 reporter.internalError(node, "No closure cache."); |
| 78 } | 83 } |
| 79 return nestedClosureData; | 84 return nestedClosureData; |
| 80 }); | 85 }); |
| 81 } | 86 } |
| 82 | 87 |
| 83 void forgetElement(var closure) { | 88 void forgetElement(var closure) { |
| 84 ClosureClassElement cls; | 89 ClosureClassElement cls; |
| 85 if (closure is ClosureFieldElement) { | 90 if (closure is ClosureFieldElement) { |
| 86 cls = closure.closureClass; | 91 cls = closure.closureClass; |
| 87 } else if (closure is SynthesizedCallMethodElementX) { | 92 } else if (closure is SynthesizedCallMethodElementX) { |
| 88 cls = closure.closureClass; | 93 cls = closure.closureClass; |
| 89 } else { | 94 } else { |
| 90 throw new SpannableAssertionFailure( | 95 throw new SpannableAssertionFailure( |
| 91 closure, 'Not a closure: $closure (${closure.runtimeType}).'); | 96 closure, 'Not a closure: $closure (${closure.runtimeType}).'); |
| 92 } | 97 } |
| 93 compiler.enqueuer.codegen.forgetElement(cls); | 98 compiler.enqueuer.codegen.forgetElement(cls); |
| 94 } | 99 } |
| 95 } | 100 } |
| 96 | 101 |
| 97 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as | 102 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as |
| 98 /// non-elements. | 103 /// non-elements. |
| 104 // TODO(johnniwinther): Remove `implements Element`. |
| 99 abstract class CapturedVariable implements Element {} | 105 abstract class CapturedVariable implements Element {} |
| 100 | 106 |
| 101 // TODO(ahe): These classes continuously cause problems. We need to | 107 // TODO(ahe): These classes continuously cause problems. We need to |
| 102 // find a more general solution. | 108 // find a more general solution. |
| 103 class ClosureFieldElement extends ElementX | 109 class ClosureFieldElement extends ElementX |
| 104 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { | 110 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { |
| 105 /// The [BoxLocal] or [LocalElement] being accessed through the field. | 111 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
| 106 final Local local; | 112 final Local local; |
| 107 | 113 |
| 108 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) | 114 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 242 } |
| 237 } | 243 } |
| 238 | 244 |
| 239 /// A local variable that contains the box object holding the [BoxFieldElement] | 245 /// A local variable that contains the box object holding the [BoxFieldElement] |
| 240 /// fields. | 246 /// fields. |
| 241 class BoxLocal extends Local { | 247 class BoxLocal extends Local { |
| 242 final String name; | 248 final String name; |
| 243 final ExecutableElement executableContext; | 249 final ExecutableElement executableContext; |
| 244 | 250 |
| 245 BoxLocal(this.name, this.executableContext); | 251 BoxLocal(this.name, this.executableContext); |
| 252 |
| 253 String toString() => 'BoxLocal($name)'; |
| 246 } | 254 } |
| 247 | 255 |
| 248 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to | 256 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to |
| 249 // find a more general solution. | 257 // find a more general solution. |
| 250 class BoxFieldElement extends ElementX | 258 class BoxFieldElement extends ElementX |
| 251 implements | 259 implements |
| 252 TypedElement, | 260 TypedElement, |
| 253 CapturedVariable, | 261 CapturedVariable, |
| 254 FieldElement, | 262 FieldElement, |
| 255 PrivatelyNamedJSEntity { | 263 PrivatelyNamedJSEntity { |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 // captured variables that are stored in the box. | 434 // captured variables that are stored in the box. |
| 427 // This map will be empty if the method/closure of this [ClosureData] does not | 435 // This map will be empty if the method/closure of this [ClosureData] does not |
| 428 // contain any nested closure. | 436 // contain any nested closure. |
| 429 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 437 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
| 430 | 438 |
| 431 /// Variables that are used in a try must be treated as boxed because the | 439 /// Variables that are used in a try must be treated as boxed because the |
| 432 /// control flow can be non-linear. | 440 /// control flow can be non-linear. |
| 433 /// | 441 /// |
| 434 /// Also parameters to a `sync*` generator must be boxed, because of the way | 442 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 435 /// we rewrite sync* functions. See also comments in [useLocal]. | 443 /// we rewrite sync* functions. See also comments in [useLocal]. |
| 436 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. | 444 // TODO(johnniwinther): Add variables to this only if the variable is mutated. |
| 437 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 445 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
| 438 | 446 |
| 439 ClosureClassMap(this.closureElement, this.closureClassElement, | 447 ClosureClassMap(this.closureElement, this.closureClassElement, |
| 440 this.callElement, this.thisLocal); | 448 this.callElement, this.thisLocal); |
| 441 | 449 |
| 442 void addFreeVariable(Local element) { | 450 void addFreeVariable(Local element) { |
| 443 assert(freeVariableMap[element] == null); | 451 assert(freeVariableMap[element] == null); |
| 444 freeVariableMap[element] = null; | 452 freeVariableMap[element] = null; |
| 445 } | 453 } |
| 446 | 454 |
| (...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 /// | 1177 /// |
| 1170 /// Move the below classes to a JS model eventually. | 1178 /// Move the below classes to a JS model eventually. |
| 1171 /// | 1179 /// |
| 1172 abstract class JSEntity implements Entity { | 1180 abstract class JSEntity implements Entity { |
| 1173 Entity get declaredEntity; | 1181 Entity get declaredEntity; |
| 1174 } | 1182 } |
| 1175 | 1183 |
| 1176 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1184 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1177 Entity get rootOfScope; | 1185 Entity get rootOfScope; |
| 1178 } | 1186 } |
| OLD | NEW |