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 |