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 | 8 import 'common/names.dart' show Identifiers; |
9 Identifiers; | 9 import 'common/resolution.dart' show Parsing, Resolution; |
10 import 'common/resolution.dart' show | 10 import 'common/tasks.dart' show CompilerTask; |
11 Parsing, | 11 import 'compiler.dart' show Compiler; |
12 Resolution; | |
13 import 'common/tasks.dart' show | |
14 CompilerTask; | |
15 import 'compiler.dart' show | |
16 Compiler; | |
17 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
18 import 'dart_types.dart'; | 13 import 'dart_types.dart'; |
19 import 'elements/elements.dart'; | 14 import 'elements/elements.dart'; |
20 import 'elements/modelx.dart' show | 15 import 'elements/modelx.dart' |
21 BaseFunctionElementX, | 16 show BaseFunctionElementX, ClassElementX, ElementX, LocalFunctionElementX; |
22 ClassElementX, | |
23 ElementX, | |
24 LocalFunctionElementX; | |
25 import 'elements/visitor.dart' show ElementVisitor; | 17 import 'elements/visitor.dart' show ElementVisitor; |
26 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 18 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
27 import 'resolution/tree_elements.dart' show TreeElements; | 19 import 'resolution/tree_elements.dart' show TreeElements; |
28 import 'tokens/token.dart' show Token; | 20 import 'tokens/token.dart' show Token; |
29 import 'tree/tree.dart'; | 21 import 'tree/tree.dart'; |
30 import 'util/util.dart'; | 22 import 'util/util.dart'; |
31 import 'universe/universe.dart' show | 23 import 'universe/universe.dart' show Universe; |
32 Universe; | |
33 | 24 |
34 class ClosureTask extends CompilerTask { | 25 class ClosureTask extends CompilerTask { |
35 Map<Node, ClosureClassMap> closureMappingCache; | 26 Map<Node, ClosureClassMap> closureMappingCache; |
36 ClosureTask(Compiler compiler) | 27 ClosureTask(Compiler compiler) |
37 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 28 : closureMappingCache = new Map<Node, ClosureClassMap>(), |
38 super(compiler); | 29 super(compiler); |
39 | 30 |
40 String get name => "Closure Simplifier"; | 31 String get name => "Closure Simplifier"; |
41 | 32 |
42 ClosureClassMap computeClosureToClassMapping(Element element, | 33 ClosureClassMap computeClosureToClassMapping( |
43 Node node, | 34 Element element, Node node, TreeElements elements) { |
44 TreeElements elements) { | |
45 return measure(() { | 35 return measure(() { |
46 ClosureClassMap cached = closureMappingCache[node]; | 36 ClosureClassMap cached = closureMappingCache[node]; |
47 if (cached != null) return cached; | 37 if (cached != null) return cached; |
48 | 38 |
49 ClosureTranslator translator = | 39 ClosureTranslator translator = |
50 new ClosureTranslator(compiler, elements, closureMappingCache); | 40 new ClosureTranslator(compiler, elements, closureMappingCache); |
51 | 41 |
52 // The translator will store the computed closure-mappings inside the | 42 // The translator will store the computed closure-mappings inside the |
53 // cache. One for given node and one for each nested closure. | 43 // cache. One for given node and one for each nested closure. |
54 if (node is FunctionExpression) { | 44 if (node is FunctionExpression) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 /// non-elements. | 90 /// non-elements. |
101 abstract class CapturedVariable implements Element {} | 91 abstract class CapturedVariable implements Element {} |
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. |
105 class ClosureFieldElement extends ElementX | 95 class ClosureFieldElement extends ElementX |
106 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { | 96 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { |
107 /// The [BoxLocal] or [LocalElement] being accessed through the field. | 97 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
108 final Local local; | 98 final Local local; |
109 | 99 |
110 ClosureFieldElement(String name, | 100 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) |
111 this.local, | |
112 ClosureClassElement enclosing) | |
113 : super(name, ElementKind.FIELD, enclosing); | 101 : super(name, ElementKind.FIELD, enclosing); |
114 | 102 |
115 /// Use [closureClass] instead. | 103 /// Use [closureClass] instead. |
116 @deprecated | 104 @deprecated |
117 get enclosingElement => super.enclosingElement; | 105 get enclosingElement => super.enclosingElement; |
118 | 106 |
119 ClosureClassElement get closureClass => super.enclosingElement; | 107 ClosureClassElement get closureClass => super.enclosingElement; |
120 | 108 |
121 MemberElement get memberContext => closureClass.methodElement.memberContext; | 109 MemberElement get memberContext => closureClass.methodElement.memberContext; |
122 | 110 |
123 @override | 111 @override |
124 Entity get declaredEntity => local; | 112 Entity get declaredEntity => local; |
125 @override | 113 @override |
126 Entity get rootOfScope => closureClass; | 114 Entity get rootOfScope => closureClass; |
127 | 115 |
128 bool get hasNode => false; | 116 bool get hasNode => false; |
129 | 117 |
130 Node get node { | 118 Node get node { |
131 throw new SpannableAssertionFailure(local, | 119 throw new SpannableAssertionFailure( |
132 'Should not access node of ClosureFieldElement.'); | 120 local, 'Should not access node of ClosureFieldElement.'); |
133 } | 121 } |
134 | 122 |
135 bool get hasResolvedAst => hasTreeElements; | 123 bool get hasResolvedAst => hasTreeElements; |
136 | 124 |
137 ResolvedAst get resolvedAst { | 125 ResolvedAst get resolvedAst { |
138 return new ResolvedAst(this, null, treeElements); | 126 return new ResolvedAst(this, null, treeElements); |
139 } | 127 } |
140 | 128 |
141 Expression get initializer { | 129 Expression get initializer { |
142 throw new SpannableAssertionFailure(local, | 130 throw new SpannableAssertionFailure( |
143 'Should not access initializer of ClosureFieldElement.'); | 131 local, 'Should not access initializer of ClosureFieldElement.'); |
144 } | 132 } |
145 | 133 |
146 bool get isInstanceMember => true; | 134 bool get isInstanceMember => true; |
147 bool get isAssignable => false; | 135 bool get isAssignable => false; |
148 | 136 |
149 DartType computeType(Resolution resolution) => type; | 137 DartType computeType(Resolution resolution) => type; |
150 | 138 |
151 DartType get type { | 139 DartType get type { |
152 if (local is LocalElement) { | 140 if (local is LocalElement) { |
153 LocalElement element = local; | 141 LocalElement element = local; |
(...skipping 16 matching lines...) Expand all Loading... |
170 @override | 158 @override |
171 ConstantExpression get constant => null; | 159 ConstantExpression get constant => null; |
172 } | 160 } |
173 | 161 |
174 // TODO(ahe): These classes continuously cause problems. We need to find | 162 // TODO(ahe): These classes continuously cause problems. We need to find |
175 // a more general solution. | 163 // a more general solution. |
176 class ClosureClassElement extends ClassElementX { | 164 class ClosureClassElement extends ClassElementX { |
177 DartType rawType; | 165 DartType rawType; |
178 DartType thisType; | 166 DartType thisType; |
179 FunctionType callType; | 167 FunctionType callType; |
| 168 |
180 /// Node that corresponds to this closure, used for source position. | 169 /// Node that corresponds to this closure, used for source position. |
181 final FunctionExpression node; | 170 final FunctionExpression node; |
182 | 171 |
183 /** | 172 /** |
184 * The element for the declaration of the function expression. | 173 * The element for the declaration of the function expression. |
185 */ | 174 */ |
186 final LocalFunctionElement methodElement; | 175 final LocalFunctionElement methodElement; |
187 | 176 |
188 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; | 177 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; |
189 | 178 |
190 ClosureClassElement(this.node, | 179 ClosureClassElement( |
191 String name, | 180 this.node, String name, Compiler compiler, LocalFunctionElement closure) |
192 Compiler compiler, | |
193 LocalFunctionElement closure) | |
194 : this.methodElement = closure, | 181 : this.methodElement = closure, |
195 super(name, | 182 super( |
196 closure.compilationUnit, | 183 name, |
197 // By assigning a fresh class-id we make sure that the hashcode | 184 closure.compilationUnit, |
198 // is unique, but also emit closure classes after all other | 185 // By assigning a fresh class-id we make sure that the hashcode |
199 // classes (since the emitter sorts classes by their id). | 186 // is unique, but also emit closure classes after all other |
200 compiler.getNextFreeClassId(), | 187 // classes (since the emitter sorts classes by their id). |
201 STATE_DONE) { | 188 compiler.getNextFreeClassId(), |
| 189 STATE_DONE) { |
202 JavaScriptBackend backend = compiler.backend; | 190 JavaScriptBackend backend = compiler.backend; |
203 ClassElement superclass = methodElement.isInstanceMember | 191 ClassElement superclass = methodElement.isInstanceMember |
204 ? backend.helpers.boundClosureClass | 192 ? backend.helpers.boundClosureClass |
205 : backend.helpers.closureClass; | 193 : backend.helpers.closureClass; |
206 superclass.ensureResolved(compiler.resolution); | 194 superclass.ensureResolved(compiler.resolution); |
207 supertype = superclass.thisType; | 195 supertype = superclass.thisType; |
208 interfaces = const Link<DartType>(); | 196 interfaces = const Link<DartType>(); |
209 thisType = rawType = new InterfaceType(this); | 197 thisType = rawType = new InterfaceType(this); |
210 allSupertypesAndSelf = | 198 allSupertypesAndSelf = |
211 superclass.allSupertypesAndSelf.extendClass(thisType); | 199 superclass.allSupertypesAndSelf.extendClass(thisType); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 class BoxLocal extends Local { | 232 class BoxLocal extends Local { |
245 final String name; | 233 final String name; |
246 final ExecutableElement executableContext; | 234 final ExecutableElement executableContext; |
247 | 235 |
248 BoxLocal(this.name, this.executableContext); | 236 BoxLocal(this.name, this.executableContext); |
249 } | 237 } |
250 | 238 |
251 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to | 239 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to |
252 // find a more general solution. | 240 // find a more general solution. |
253 class BoxFieldElement extends ElementX | 241 class BoxFieldElement extends ElementX |
254 implements TypedElement, CapturedVariable, FieldElement, | 242 implements |
| 243 TypedElement, |
| 244 CapturedVariable, |
| 245 FieldElement, |
255 PrivatelyNamedJSEntity { | 246 PrivatelyNamedJSEntity { |
256 final BoxLocal box; | 247 final BoxLocal box; |
257 | 248 |
258 BoxFieldElement(String name, this.variableElement, | 249 BoxFieldElement(String name, this.variableElement, BoxLocal box) |
259 BoxLocal box) | |
260 : this.box = box, | 250 : this.box = box, |
261 super(name, ElementKind.FIELD, box.executableContext); | 251 super(name, ElementKind.FIELD, box.executableContext); |
262 | 252 |
263 DartType computeType(Resolution resolution) => type; | 253 DartType computeType(Resolution resolution) => type; |
264 | 254 |
265 DartType get type => variableElement.type; | 255 DartType get type => variableElement.type; |
266 | 256 |
267 @override | 257 @override |
268 Entity get declaredEntity => variableElement; | 258 Entity get declaredEntity => variableElement; |
269 @override | 259 @override |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 String get name => 'this'; | 306 String get name => 'this'; |
317 | 307 |
318 ClassElement get enclosingClass => executableContext.enclosingClass; | 308 ClassElement get enclosingClass => executableContext.enclosingClass; |
319 } | 309 } |
320 | 310 |
321 /// Call method of a closure class. | 311 /// Call method of a closure class. |
322 class SynthesizedCallMethodElementX extends BaseFunctionElementX | 312 class SynthesizedCallMethodElementX extends BaseFunctionElementX |
323 implements MethodElement { | 313 implements MethodElement { |
324 final LocalFunctionElement expression; | 314 final LocalFunctionElement expression; |
325 | 315 |
326 SynthesizedCallMethodElementX(String name, | 316 SynthesizedCallMethodElementX( |
327 LocalFunctionElementX other, | 317 String name, LocalFunctionElementX other, ClosureClassElement enclosing) |
328 ClosureClassElement enclosing) | |
329 : expression = other, | 318 : expression = other, |
330 super(name, other.kind, other.modifiers, enclosing) { | 319 super(name, other.kind, other.modifiers, enclosing) { |
331 asyncMarker = other.asyncMarker; | 320 asyncMarker = other.asyncMarker; |
332 functionSignature = other.functionSignature; | 321 functionSignature = other.functionSignature; |
333 } | 322 } |
334 | 323 |
335 /// Use [closureClass] instead. | 324 /// Use [closureClass] instead. |
336 @deprecated | 325 @deprecated |
337 get enclosingElement => super.enclosingElement; | 326 get enclosingElement => super.enclosingElement; |
338 | 327 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; | 360 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; |
372 | 361 |
373 ClosureScope(this.boxElement, this.capturedVariables); | 362 ClosureScope(this.boxElement, this.capturedVariables); |
374 | 363 |
375 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; | 364 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
376 | 365 |
377 bool isCapturedVariable(VariableElement variable) { | 366 bool isCapturedVariable(VariableElement variable) { |
378 return capturedVariables.containsKey(variable); | 367 return capturedVariables.containsKey(variable); |
379 } | 368 } |
380 | 369 |
381 void forEachCapturedVariable(f(LocalVariableElement variable, | 370 void forEachCapturedVariable( |
382 BoxFieldElement boxField)) { | 371 f(LocalVariableElement variable, BoxFieldElement boxField)) { |
383 capturedVariables.forEach(f); | 372 capturedVariables.forEach(f); |
384 } | 373 } |
385 } | 374 } |
386 | 375 |
387 class ClosureClassMap { | 376 class ClosureClassMap { |
388 // The closure's element before any translation. Will be null for methods. | 377 // The closure's element before any translation. Will be null for methods. |
389 final LocalFunctionElement closureElement; | 378 final LocalFunctionElement closureElement; |
390 // The closureClassElement will be null for methods that are not local | 379 // The closureClassElement will be null for methods that are not local |
391 // closures. | 380 // closures. |
392 final ClosureClassElement closureClassElement; | 381 final ClosureClassElement closureClassElement; |
(...skipping 16 matching lines...) Expand all Loading... |
409 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 398 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
410 | 399 |
411 /// Variables that are used in a try must be treated as boxed because the | 400 /// Variables that are used in a try must be treated as boxed because the |
412 /// control flow can be non-linear. | 401 /// control flow can be non-linear. |
413 /// | 402 /// |
414 /// Also parameters to a `sync*` generator must be boxed, because of the way | 403 /// Also parameters to a `sync*` generator must be boxed, because of the way |
415 /// we rewrite sync* functions. See also comments in [useLocal]. | 404 /// we rewrite sync* functions. See also comments in [useLocal]. |
416 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. | 405 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. |
417 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 406 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
418 | 407 |
419 ClosureClassMap(this.closureElement, | 408 ClosureClassMap(this.closureElement, this.closureClassElement, |
420 this.closureClassElement, | 409 this.callElement, this.thisLocal); |
421 this.callElement, | |
422 this.thisLocal); | |
423 | 410 |
424 void addFreeVariable(Local element) { | 411 void addFreeVariable(Local element) { |
425 assert(freeVariableMap[element] == null); | 412 assert(freeVariableMap[element] == null); |
426 freeVariableMap[element] = null; | 413 freeVariableMap[element] = null; |
427 } | 414 } |
428 | 415 |
429 Iterable<Local> get freeVariables => freeVariableMap.keys; | 416 Iterable<Local> get freeVariables => freeVariableMap.keys; |
430 | 417 |
431 bool isFreeVariable(Local element) { | 418 bool isFreeVariable(Local element) { |
432 return freeVariableMap.containsKey(element); | 419 return freeVariableMap.containsKey(element); |
433 } | 420 } |
434 | 421 |
435 void forEachFreeVariable(f(Local variable, | 422 void forEachFreeVariable(f(Local variable, CapturedVariable field)) { |
436 CapturedVariable field)) { | |
437 freeVariableMap.forEach(f); | 423 freeVariableMap.forEach(f); |
438 } | 424 } |
439 | 425 |
440 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 426 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
441 return field.local; | 427 return field.local; |
442 } | 428 } |
443 | 429 |
444 bool get isClosure => closureElement != null; | 430 bool get isClosure => closureElement != null; |
445 | 431 |
446 bool capturingScopesBox(Local variable) { | 432 bool capturingScopesBox(Local variable) { |
447 return capturingScopes.values.any((scope) { | 433 return capturingScopes.values.any((scope) { |
448 return scope.boxedLoopVariables.contains(variable); | 434 return scope.boxedLoopVariables.contains(variable); |
449 }); | 435 }); |
450 } | 436 } |
451 | 437 |
452 bool isVariableBoxed(Local variable) { | 438 bool isVariableBoxed(Local variable) { |
453 CapturedVariable copy = freeVariableMap[variable]; | 439 CapturedVariable copy = freeVariableMap[variable]; |
454 if (copy is BoxFieldElement) { | 440 if (copy is BoxFieldElement) { |
455 return true; | 441 return true; |
456 } | 442 } |
457 return capturingScopesBox(variable); | 443 return capturingScopesBox(variable); |
458 } | 444 } |
459 | 445 |
460 void forEachCapturedVariable(void f(Local variable, | 446 void forEachCapturedVariable(void f(Local variable, CapturedVariable field)) { |
461 CapturedVariable field)) { | |
462 freeVariableMap.forEach((variable, copy) { | 447 freeVariableMap.forEach((variable, copy) { |
463 if (variable is BoxLocal) return; | 448 if (variable is BoxLocal) return; |
464 f(variable, copy); | 449 f(variable, copy); |
465 }); | 450 }); |
466 capturingScopes.values.forEach((ClosureScope scope) { | 451 capturingScopes.values.forEach((ClosureScope scope) { |
467 scope.forEachCapturedVariable(f); | 452 scope.forEachCapturedVariable(f); |
468 }); | 453 }); |
469 } | 454 } |
470 | 455 |
471 void forEachBoxedVariable(void f(LocalVariableElement local, | 456 void forEachBoxedVariable( |
472 BoxFieldElement field)) { | 457 void f(LocalVariableElement local, BoxFieldElement field)) { |
473 freeVariableMap.forEach((variable, copy) { | 458 freeVariableMap.forEach((variable, copy) { |
474 if (!isVariableBoxed(variable)) return; | 459 if (!isVariableBoxed(variable)) return; |
475 f(variable, copy); | 460 f(variable, copy); |
476 }); | 461 }); |
477 capturingScopes.values.forEach((ClosureScope scope) { | 462 capturingScopes.values.forEach((ClosureScope scope) { |
478 scope.forEachCapturedVariable(f); | 463 scope.forEachCapturedVariable(f); |
479 }); | 464 }); |
480 } | 465 } |
481 | 466 |
482 void removeMyselfFrom(Universe universe) { | 467 void removeMyselfFrom(Universe universe) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); | 499 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); |
515 | 500 |
516 MemberElement outermostElement; | 501 MemberElement outermostElement; |
517 ExecutableElement executableContext; | 502 ExecutableElement executableContext; |
518 | 503 |
519 // The closureData of the currentFunctionElement. | 504 // The closureData of the currentFunctionElement. |
520 ClosureClassMap closureData; | 505 ClosureClassMap closureData; |
521 | 506 |
522 bool insideClosure = false; | 507 bool insideClosure = false; |
523 | 508 |
524 ClosureTranslator(this.compiler, | 509 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache); |
525 this.elements, | |
526 this.closureMappingCache); | |
527 | 510 |
528 DiagnosticReporter get reporter => compiler.reporter; | 511 DiagnosticReporter get reporter => compiler.reporter; |
529 | 512 |
530 /// Generate a unique name for the [id]th closure field, with proposed name | 513 /// Generate a unique name for the [id]th closure field, with proposed name |
531 /// [name]. | 514 /// [name]. |
532 /// | 515 /// |
533 /// The result is used as the name of [ClosureFieldElement]s, and must | 516 /// The result is used as the name of [ClosureFieldElement]s, and must |
534 /// therefore be unique to avoid breaking an invariant in the element model | 517 /// therefore be unique to avoid breaking an invariant in the element model |
535 /// (classes cannot declare multiple fields with the same name). | 518 /// (classes cannot declare multiple fields with the same name). |
536 /// | 519 /// |
(...skipping 24 matching lines...) Expand all Loading... |
561 return _capturedVariableMapping.containsKey(element); | 544 return _capturedVariableMapping.containsKey(element); |
562 } | 545 } |
563 | 546 |
564 void addCapturedVariable(Node node, Local variable) { | 547 void addCapturedVariable(Node node, Local variable) { |
565 if (_capturedVariableMapping[variable] != null) { | 548 if (_capturedVariableMapping[variable] != null) { |
566 reporter.internalError(node, 'In closure analyzer.'); | 549 reporter.internalError(node, 'In closure analyzer.'); |
567 } | 550 } |
568 _capturedVariableMapping[variable] = null; | 551 _capturedVariableMapping[variable] = null; |
569 } | 552 } |
570 | 553 |
571 void setCapturedVariableBoxField(Local variable, | 554 void setCapturedVariableBoxField(Local variable, BoxFieldElement boxField) { |
572 BoxFieldElement boxField) { | |
573 assert(isCapturedVariable(variable)); | 555 assert(isCapturedVariable(variable)); |
574 _capturedVariableMapping[variable] = boxField; | 556 _capturedVariableMapping[variable] = boxField; |
575 } | 557 } |
576 | 558 |
577 BoxFieldElement getCapturedVariableBoxField(Local variable) { | 559 BoxFieldElement getCapturedVariableBoxField(Local variable) { |
578 return _capturedVariableMapping[variable]; | 560 return _capturedVariableMapping[variable]; |
579 } | 561 } |
580 | 562 |
581 void translateFunction(Element element, FunctionExpression node) { | 563 void translateFunction(Element element, FunctionExpression node) { |
582 // For constructors the [element] and the [:elements[node]:] may differ. | 564 // For constructors the [element] and the [:elements[node]:] may differ. |
583 // The [:elements[node]:] always points to the generative-constructor | 565 // The [:elements[node]:] always points to the generative-constructor |
584 // element, whereas the [element] might be the constructor-body element. | 566 // element, whereas the [element] might be the constructor-body element. |
585 visit(node); // [visitFunctionExpression] will call [visitInvokable]. | 567 visit(node); // [visitFunctionExpression] will call [visitInvokable]. |
586 // When variables need to be boxed their [_capturedVariableMapping] is | 568 // When variables need to be boxed their [_capturedVariableMapping] is |
587 // updated, but we delay updating the similar freeVariableMapping in the | 569 // updated, but we delay updating the similar freeVariableMapping in the |
588 // closure datas that capture these variables. | 570 // closure datas that capture these variables. |
589 // The closures don't have their fields (in the closure class) set, either. | 571 // The closures don't have their fields (in the closure class) set, either. |
590 updateClosures(); | 572 updateClosures(); |
591 } | 573 } |
592 | 574 |
593 void translateLazyInitializer(VariableElement element, | 575 void translateLazyInitializer(VariableElement element, |
594 VariableDefinitions node, | 576 VariableDefinitions node, Expression initializer) { |
595 Expression initializer) { | 577 visitInvokable(element, node, () { |
596 visitInvokable(element, node, () { visit(initializer); }); | 578 visit(initializer); |
| 579 }); |
597 updateClosures(); | 580 updateClosures(); |
598 } | 581 } |
599 | 582 |
600 // This function runs through all of the existing closures and updates their | 583 // This function runs through all of the existing closures and updates their |
601 // free variables to the boxed value. It also adds the field-elements to the | 584 // free variables to the boxed value. It also adds the field-elements to the |
602 // class representing the closure. | 585 // class representing the closure. |
603 void updateClosures() { | 586 void updateClosures() { |
604 for (Expression closure in closures) { | 587 for (Expression closure in closures) { |
605 // The captured variables that need to be stored in a field of the closure | 588 // The captured variables that need to be stored in a field of the closure |
606 // class. | 589 // class. |
(...skipping 13 matching lines...) Expand all Loading... |
620 assert(fromElement is! BoxLocal); | 603 assert(fromElement is! BoxLocal); |
621 // The variable has not been boxed. | 604 // The variable has not been boxed. |
622 fieldCaptures.add(fromElement); | 605 fieldCaptures.add(fromElement); |
623 } else { | 606 } else { |
624 // A boxed element. | 607 // A boxed element. |
625 data.freeVariableMap[fromElement] = boxFieldElement; | 608 data.freeVariableMap[fromElement] = boxFieldElement; |
626 boxes.add(boxFieldElement.box); | 609 boxes.add(boxFieldElement.box); |
627 } | 610 } |
628 }); | 611 }); |
629 ClosureClassElement closureClass = data.closureClassElement; | 612 ClosureClassElement closureClass = data.closureClassElement; |
630 assert(closureClass != null || | 613 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); |
631 (fieldCaptures.isEmpty && boxes.isEmpty)); | |
632 | 614 |
633 void addClosureField(Local local, String name) { | 615 void addClosureField(Local local, String name) { |
634 ClosureFieldElement closureField = | 616 ClosureFieldElement closureField = |
635 new ClosureFieldElement(name, local, closureClass); | 617 new ClosureFieldElement(name, local, closureClass); |
636 closureClass.addField(closureField, reporter); | 618 closureClass.addField(closureField, reporter); |
637 data.freeVariableMap[local] = closureField; | 619 data.freeVariableMap[local] = closureField; |
638 } | 620 } |
639 | 621 |
640 // Add the box elements first so we get the same ordering. | 622 // Add the box elements first so we get the same ordering. |
641 // TODO(sra): What is the canonical order of multiple boxes? | 623 // TODO(sra): What is the canonical order of multiple boxes? |
(...skipping 25 matching lines...) Expand all Loading... |
667 | 649 |
668 void useLocal(Local variable) { | 650 void useLocal(Local variable) { |
669 // If the element is not declared in the current function and the element | 651 // If the element is not declared in the current function and the element |
670 // is not the closure itself we need to mark the element as free variable. | 652 // is not the closure itself we need to mark the element as free variable. |
671 // Note that the check on [insideClosure] is not just an | 653 // Note that the check on [insideClosure] is not just an |
672 // optimization: factories have type parameters as function | 654 // optimization: factories have type parameters as function |
673 // parameters, and type parameters are declared in the class, not | 655 // parameters, and type parameters are declared in the class, not |
674 // the factory. | 656 // the factory. |
675 bool inCurrentContext(Local variable) { | 657 bool inCurrentContext(Local variable) { |
676 return variable == executableContext || | 658 return variable == executableContext || |
677 variable.executableContext == executableContext; | 659 variable.executableContext == executableContext; |
678 } | 660 } |
679 | 661 |
680 if (insideClosure && !inCurrentContext(variable)) { | 662 if (insideClosure && !inCurrentContext(variable)) { |
681 closureData.addFreeVariable(variable); | 663 closureData.addFreeVariable(variable); |
682 } else if (inTryStatement) { | 664 } else if (inTryStatement) { |
683 // Don't mark the this-element or a self-reference. This would complicate | 665 // Don't mark the this-element or a self-reference. This would complicate |
684 // things in the builder. | 666 // things in the builder. |
685 // Note that nested (named) functions are immutable. | 667 // Note that nested (named) functions are immutable. |
686 if (variable != closureData.thisLocal && | 668 if (variable != closureData.thisLocal && |
687 variable != closureData.closureElement && | 669 variable != closureData.closureElement && |
(...skipping 24 matching lines...) Expand all Loading... |
712 | 694 |
713 visit(Node node) => node.accept(this); | 695 visit(Node node) => node.accept(this); |
714 | 696 |
715 visitNode(Node node) => node.visitChildren(this); | 697 visitNode(Node node) => node.visitChildren(this); |
716 | 698 |
717 visitVariableDefinitions(VariableDefinitions node) { | 699 visitVariableDefinitions(VariableDefinitions node) { |
718 if (node.type != null) { | 700 if (node.type != null) { |
719 visit(node.type); | 701 visit(node.type); |
720 } | 702 } |
721 for (Link<Node> link = node.definitions.nodes; | 703 for (Link<Node> link = node.definitions.nodes; |
722 !link.isEmpty; | 704 !link.isEmpty; |
723 link = link.tail) { | 705 link = link.tail) { |
724 Node definition = link.head; | 706 Node definition = link.head; |
725 LocalElement element = elements[definition]; | 707 LocalElement element = elements[definition]; |
726 assert(element != null); | 708 assert(element != null); |
727 if (!element.isInitializingFormal) { | 709 if (!element.isInitializingFormal) { |
728 declareLocal(element); | 710 declareLocal(element); |
729 } | 711 } |
730 // We still need to visit the right-hand sides of the init-assignments. | 712 // We still need to visit the right-hand sides of the init-assignments. |
731 // For SendSets don't visit the left again. Otherwise it would be marked | 713 // For SendSets don't visit the left again. Otherwise it would be marked |
732 // as mutated. | 714 // as mutated. |
733 if (definition is Send) { | 715 if (definition is Send) { |
734 Send assignment = definition; | 716 Send assignment = definition; |
735 Node arguments = assignment.argumentsNode; | 717 Node arguments = assignment.argumentsNode; |
736 if (arguments != null) { | 718 if (arguments != null) { |
737 visit(arguments); | 719 visit(arguments); |
738 } | 720 } |
739 } else { | 721 } else { |
740 visit(definition); | 722 visit(definition); |
741 } | 723 } |
742 } | 724 } |
743 } | 725 } |
744 | 726 |
745 visitTypeAnnotation(TypeAnnotation node) { | 727 visitTypeAnnotation(TypeAnnotation node) { |
746 MemberElement member = executableContext.memberContext; | 728 MemberElement member = executableContext.memberContext; |
747 DartType type = elements.getType(node); | 729 DartType type = elements.getType(node); |
748 // TODO(karlklose,johnniwinther): if the type is null, the annotation is | 730 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
749 // from a parameter which has been analyzed before the method has been | 731 // from a parameter which has been analyzed before the method has been |
750 // resolved and the result has been thrown away. | 732 // resolved and the result has been thrown away. |
751 if (compiler.options.enableTypeAssertions && type != null && | 733 if (compiler.options.enableTypeAssertions && |
| 734 type != null && |
752 type.containsTypeVariables) { | 735 type.containsTypeVariables) { |
753 if (insideClosure && member.isFactoryConstructor) { | 736 if (insideClosure && member.isFactoryConstructor) { |
754 // This is a closure in a factory constructor. Since there is no | 737 // This is a closure in a factory constructor. Since there is no |
755 // [:this:], we have to mark the type arguments as free variables to | 738 // [:this:], we have to mark the type arguments as free variables to |
756 // capture them in the closure. | 739 // capture them in the closure. |
757 type.forEachTypeVariable((TypeVariableType variable) { | 740 type.forEachTypeVariable((TypeVariableType variable) { |
758 useTypeVariableAsLocal(variable); | 741 useTypeVariableAsLocal(variable); |
759 }); | 742 }); |
760 } | 743 } |
761 if (member.isInstanceMember && !member.isField) { | 744 if (member.isInstanceMember && !member.isField) { |
762 // In checked mode, using a type variable in a type annotation may lead | 745 // In checked mode, using a type variable in a type annotation may lead |
763 // to a runtime type check that needs to access the type argument and | 746 // to a runtime type check that needs to access the type argument and |
764 // therefore the closure needs a this-element, if it is not in a field | 747 // therefore the closure needs a this-element, if it is not in a field |
765 // initializer; field initatializers are evaluated in a context where | 748 // initializer; field initatializers are evaluated in a context where |
766 // the type arguments are available in locals. | 749 // the type arguments are available in locals. |
767 registerNeedsThis(); | 750 registerNeedsThis(); |
768 } | 751 } |
769 } | 752 } |
770 } | 753 } |
771 | 754 |
772 visitIdentifier(Identifier node) { | 755 visitIdentifier(Identifier node) { |
773 if (node.isThis()) { | 756 if (node.isThis()) { |
774 registerNeedsThis(); | 757 registerNeedsThis(); |
775 } else { | 758 } else { |
776 Element element = elements[node]; | 759 Element element = elements[node]; |
777 if (element != null && element.isTypeVariable) { | 760 if (element != null && element.isTypeVariable) { |
778 if (outermostElement.isConstructor || | 761 if (outermostElement.isConstructor || outermostElement.isField) { |
779 outermostElement.isField) { | |
780 TypeVariableElement typeVariable = element; | 762 TypeVariableElement typeVariable = element; |
781 useTypeVariableAsLocal(typeVariable.type); | 763 useTypeVariableAsLocal(typeVariable.type); |
782 } else { | 764 } else { |
783 registerNeedsThis(); | 765 registerNeedsThis(); |
784 } | 766 } |
785 } | 767 } |
786 } | 768 } |
787 node.visitChildren(this); | 769 node.visitChildren(this); |
788 } | 770 } |
789 | 771 |
790 visitSend(Send node) { | 772 visitSend(Send node) { |
791 Element element = elements[node]; | 773 Element element = elements[node]; |
792 if (Elements.isLocal(element)) { | 774 if (Elements.isLocal(element)) { |
793 LocalElement localElement = element; | 775 LocalElement localElement = element; |
794 useLocal(localElement); | 776 useLocal(localElement); |
795 } else if (element != null && element.isTypeVariable) { | 777 } else if (element != null && element.isTypeVariable) { |
796 TypeVariableElement variable = element; | 778 TypeVariableElement variable = element; |
797 analyzeType(variable.type); | 779 analyzeType(variable.type); |
798 } else if (node.receiver == null && | 780 } else if (node.receiver == null && |
799 Elements.isInstanceSend(node, elements)) { | 781 Elements.isInstanceSend(node, elements)) { |
800 registerNeedsThis(); | 782 registerNeedsThis(); |
801 } else if (node.isSuperCall) { | 783 } else if (node.isSuperCall) { |
802 registerNeedsThis(); | 784 registerNeedsThis(); |
803 } else if (node.isTypeTest || node.isTypeCast) { | 785 } else if (node.isTypeTest || node.isTypeCast) { |
804 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; | 786 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; |
805 DartType type = elements.getType(annotation); | 787 DartType type = elements.getType(annotation); |
806 analyzeType(type); | 788 analyzeType(type); |
807 } else if (node.isTypeTest) { | 789 } else if (node.isTypeTest) { |
808 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 790 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); |
809 analyzeType(type); | 791 analyzeType(type); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 visitLiteralMap(LiteralMap node) { | 823 visitLiteralMap(LiteralMap node) { |
842 DartType type = elements.getType(node); | 824 DartType type = elements.getType(node); |
843 analyzeType(type); | 825 analyzeType(type); |
844 node.visitChildren(this); | 826 node.visitChildren(this); |
845 } | 827 } |
846 | 828 |
847 void analyzeTypeVariables(DartType type) { | 829 void analyzeTypeVariables(DartType type) { |
848 type.forEachTypeVariable((TypeVariableType typeVariable) { | 830 type.forEachTypeVariable((TypeVariableType typeVariable) { |
849 // Field initializers are inlined and access the type variable as | 831 // Field initializers are inlined and access the type variable as |
850 // normal parameters. | 832 // normal parameters. |
851 if (!outermostElement.isField && | 833 if (!outermostElement.isField && !outermostElement.isConstructor) { |
852 !outermostElement.isConstructor) { | |
853 registerNeedsThis(); | 834 registerNeedsThis(); |
854 } else { | 835 } else { |
855 useTypeVariableAsLocal(typeVariable); | 836 useTypeVariableAsLocal(typeVariable); |
856 } | 837 } |
857 }); | 838 }); |
858 } | 839 } |
859 | 840 |
860 void analyzeType(DartType type) { | 841 void analyzeType(DartType type) { |
861 // TODO(johnniwinther): Find out why this can be null. | 842 // TODO(johnniwinther): Find out why this can be null. |
862 if (type == null) return; | 843 if (type == null) return; |
863 if (outermostElement.isClassMember && | 844 if (outermostElement.isClassMember && |
864 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { | 845 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { |
865 if (outermostElement.isConstructor || | 846 if (outermostElement.isConstructor || outermostElement.isField) { |
866 outermostElement.isField) { | |
867 analyzeTypeVariables(type); | 847 analyzeTypeVariables(type); |
868 } else if (outermostElement.isInstanceMember) { | 848 } else if (outermostElement.isInstanceMember) { |
869 if (type.containsTypeVariables) { | 849 if (type.containsTypeVariables) { |
870 registerNeedsThis(); | 850 registerNeedsThis(); |
871 } | 851 } |
872 } | 852 } |
873 } | 853 } |
874 } | 854 } |
875 | 855 |
876 // If variables that are declared in the [node] scope are captured and need | 856 // If variables that are declared in the [node] scope are captured and need |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 // condition or body are indeed flagged as mutated. | 931 // condition or body are indeed flagged as mutated. |
952 if (node.conditionStatement != null) visit(node.conditionStatement); | 932 if (node.conditionStatement != null) visit(node.conditionStatement); |
953 if (node.body != null) visit(node.body); | 933 if (node.body != null) visit(node.body); |
954 | 934 |
955 // See if we have declared loop variables that need to be boxed. | 935 // See if we have declared loop variables that need to be boxed. |
956 if (node.initializer == null) return; | 936 if (node.initializer == null) return; |
957 VariableDefinitions definitions = | 937 VariableDefinitions definitions = |
958 node.initializer.asVariableDefinitions(); | 938 node.initializer.asVariableDefinitions(); |
959 if (definitions == null) return; | 939 if (definitions == null) return; |
960 for (Link<Node> link = definitions.definitions.nodes; | 940 for (Link<Node> link = definitions.definitions.nodes; |
961 !link.isEmpty; | 941 !link.isEmpty; |
962 link = link.tail) { | 942 link = link.tail) { |
963 Node definition = link.head; | 943 Node definition = link.head; |
964 LocalVariableElement element = elements[definition]; | 944 LocalVariableElement element = elements[definition]; |
965 // Non-mutated variables should not be boxed. The mutatedVariables set | 945 // Non-mutated variables should not be boxed. The mutatedVariables set |
966 // gets cleared when 'inNewScope' returns, so check it here. | 946 // gets cleared when 'inNewScope' returns, so check it here. |
967 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { | 947 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { |
968 boxedLoopVariables.add(element); | 948 boxedLoopVariables.add(element); |
969 } | 949 } |
970 } | 950 } |
971 }); | 951 }); |
972 ClosureScope scopeData = closureData.capturingScopes[node]; | 952 ClosureScope scopeData = closureData.capturingScopes[node]; |
973 if (scopeData == null) return; | 953 if (scopeData == null) return; |
974 scopeData.boxedLoopVariables = boxedLoopVariables; | 954 scopeData.boxedLoopVariables = boxedLoopVariables; |
975 } | 955 } |
976 | 956 |
977 /** Returns a non-unique name for the given closure element. */ | 957 /** Returns a non-unique name for the given closure element. */ |
978 String computeClosureName(Element element) { | 958 String computeClosureName(Element element) { |
979 Link<String> parts = const Link<String>(); | 959 Link<String> parts = const Link<String>(); |
980 String ownName = element.name; | 960 String ownName = element.name; |
981 if (ownName == null || ownName == "") { | 961 if (ownName == null || ownName == "") { |
982 parts = parts.prepend("closure"); | 962 parts = parts.prepend("closure"); |
983 } else { | 963 } else { |
984 parts = parts.prepend(ownName); | 964 parts = parts.prepend(ownName); |
985 } | 965 } |
986 for (Element enclosingElement = element.enclosingElement; | 966 for (Element enclosingElement = element.enclosingElement; |
987 enclosingElement != null && | 967 enclosingElement != null && |
988 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 968 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || |
989 || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR | 969 enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR || |
990 || enclosingElement.kind == ElementKind.CLASS | 970 enclosingElement.kind == ElementKind.CLASS || |
991 || enclosingElement.kind == ElementKind.FUNCTION | 971 enclosingElement.kind == ElementKind.FUNCTION || |
992 || enclosingElement.kind == ElementKind.GETTER | 972 enclosingElement.kind == ElementKind.GETTER || |
993 || enclosingElement.kind == ElementKind.SETTER); | 973 enclosingElement.kind == ElementKind.SETTER); |
994 enclosingElement = enclosingElement.enclosingElement) { | 974 enclosingElement = enclosingElement.enclosingElement) { |
995 // TODO(johnniwinther): Simplify computed names. | 975 // TODO(johnniwinther): Simplify computed names. |
996 if (enclosingElement.isGenerativeConstructor || | 976 if (enclosingElement.isGenerativeConstructor || |
997 enclosingElement.isGenerativeConstructorBody || | 977 enclosingElement.isGenerativeConstructorBody || |
998 enclosingElement.isFactoryConstructor) { | 978 enclosingElement.isFactoryConstructor) { |
999 parts = parts.prepend( | 979 parts = parts |
1000 Elements.reconstructConstructorName(enclosingElement)); | 980 .prepend(Elements.reconstructConstructorName(enclosingElement)); |
1001 } else { | 981 } else { |
1002 String surroundingName = | 982 String surroundingName = |
1003 Elements.operatorNameToIdentifier(enclosingElement.name); | 983 Elements.operatorNameToIdentifier(enclosingElement.name); |
1004 parts = parts.prepend(surroundingName); | 984 parts = parts.prepend(surroundingName); |
1005 } | 985 } |
1006 // A generative constructors's parent is the class; the class name is | 986 // A generative constructors's parent is the class; the class name is |
1007 // already part of the generative constructor's name. | 987 // already part of the generative constructor's name. |
1008 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; | 988 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; |
1009 } | 989 } |
1010 StringBuffer sb = new StringBuffer(); | 990 StringBuffer sb = new StringBuffer(); |
1011 parts.printOn(sb, '_'); | 991 parts.printOn(sb, '_'); |
1012 return sb.toString(); | 992 return sb.toString(); |
1013 } | 993 } |
1014 | 994 |
1015 JavaScriptBackend get backend => compiler.backend; | 995 JavaScriptBackend get backend => compiler.backend; |
1016 | 996 |
1017 ClosureClassMap globalizeClosure(FunctionExpression node, | 997 ClosureClassMap globalizeClosure( |
1018 LocalFunctionElement element) { | 998 FunctionExpression node, LocalFunctionElement element) { |
1019 String closureName = computeClosureName(element); | 999 String closureName = computeClosureName(element); |
1020 ClosureClassElement globalizedElement = new ClosureClassElement( | 1000 ClosureClassElement globalizedElement = |
1021 node, closureName, compiler, element); | 1001 new ClosureClassElement(node, closureName, compiler, element); |
1022 // Extend [globalizedElement] as an instantiated class in the closed world. | 1002 // Extend [globalizedElement] as an instantiated class in the closed world. |
1023 compiler.world.registerClass( | 1003 compiler.world |
1024 globalizedElement, isDirectlyInstantiated: true); | 1004 .registerClass(globalizedElement, isDirectlyInstantiated: true); |
1025 FunctionElement callElement = | 1005 FunctionElement callElement = new SynthesizedCallMethodElementX( |
1026 new SynthesizedCallMethodElementX(Identifiers.call, | 1006 Identifiers.call, element, globalizedElement); |
1027 element, | |
1028 globalizedElement); | |
1029 backend.maybeMarkClosureAsNeededForReflection( | 1007 backend.maybeMarkClosureAsNeededForReflection( |
1030 globalizedElement, callElement, element); | 1008 globalizedElement, callElement, element); |
1031 MemberElement enclosing = element.memberContext; | 1009 MemberElement enclosing = element.memberContext; |
1032 enclosing.nestedClosures.add(callElement); | 1010 enclosing.nestedClosures.add(callElement); |
1033 globalizedElement.addMember(callElement, reporter); | 1011 globalizedElement.addMember(callElement, reporter); |
1034 globalizedElement.computeAllClassMembers(compiler); | 1012 globalizedElement.computeAllClassMembers(compiler); |
1035 // The nested function's 'this' is the same as the one for the outer | 1013 // The nested function's 'this' is the same as the one for the outer |
1036 // function. It could be [null] if we are inside a static method. | 1014 // function. It could be [null] if we are inside a static method. |
1037 ThisLocal thisElement = closureData.thisLocal; | 1015 ThisLocal thisElement = closureData.thisLocal; |
1038 | 1016 |
1039 return new ClosureClassMap(element, globalizedElement, | 1017 return new ClosureClassMap( |
1040 callElement, thisElement); | 1018 element, globalizedElement, callElement, thisElement); |
1041 } | 1019 } |
1042 | 1020 |
1043 void visitInvokable(ExecutableElement element, | 1021 void visitInvokable( |
1044 Node node, | 1022 ExecutableElement element, Node node, void visitChildren()) { |
1045 void visitChildren()) { | |
1046 bool oldInsideClosure = insideClosure; | 1023 bool oldInsideClosure = insideClosure; |
1047 Element oldFunctionElement = executableContext; | 1024 Element oldFunctionElement = executableContext; |
1048 ClosureClassMap oldClosureData = closureData; | 1025 ClosureClassMap oldClosureData = closureData; |
1049 | 1026 |
1050 insideClosure = outermostElement != null; | 1027 insideClosure = outermostElement != null; |
1051 LocalFunctionElement closure; | 1028 LocalFunctionElement closure; |
1052 executableContext = element; | 1029 executableContext = element; |
1053 if (insideClosure) { | 1030 if (insideClosure) { |
1054 closure = element; | 1031 closure = element; |
1055 closures.add(node); | 1032 closures.add(node); |
1056 closureData = globalizeClosure(node, closure); | 1033 closureData = globalizeClosure(node, closure); |
1057 } else { | 1034 } else { |
1058 outermostElement = element; | 1035 outermostElement = element; |
1059 ThisLocal thisElement = null; | 1036 ThisLocal thisElement = null; |
1060 if (element.isInstanceMember || element.isGenerativeConstructor) { | 1037 if (element.isInstanceMember || element.isGenerativeConstructor) { |
1061 thisElement = new ThisLocal(element); | 1038 thisElement = new ThisLocal(element); |
1062 } | 1039 } |
1063 closureData = new ClosureClassMap(null, null, null, thisElement); | 1040 closureData = new ClosureClassMap(null, null, null, thisElement); |
1064 } | 1041 } |
1065 closureMappingCache[node] = closureData; | 1042 closureMappingCache[node] = closureData; |
1066 | 1043 |
1067 inNewScope(node, () { | 1044 inNewScope(node, () { |
1068 DartType type = element.type; | 1045 DartType type = element.type; |
1069 // If the method needs RTI, or checked mode is set, we need to | 1046 // If the method needs RTI, or checked mode is set, we need to |
1070 // escape the potential type variables used in that closure. | 1047 // escape the potential type variables used in that closure. |
1071 if (element is FunctionElement && | 1048 if (element is FunctionElement && |
1072 (compiler.backend.methodNeedsRti(element) || | 1049 (compiler.backend.methodNeedsRti(element) || |
1073 compiler.options.enableTypeAssertions)) { | 1050 compiler.options.enableTypeAssertions)) { |
1074 analyzeTypeVariables(type); | 1051 analyzeTypeVariables(type); |
1075 } | 1052 } |
1076 | 1053 |
1077 visitChildren(); | 1054 visitChildren(); |
1078 }); | 1055 }); |
1079 | 1056 |
1080 | |
1081 ClosureClassMap savedClosureData = closureData; | 1057 ClosureClassMap savedClosureData = closureData; |
1082 bool savedInsideClosure = insideClosure; | 1058 bool savedInsideClosure = insideClosure; |
1083 | 1059 |
1084 // Restore old values. | 1060 // Restore old values. |
1085 insideClosure = oldInsideClosure; | 1061 insideClosure = oldInsideClosure; |
1086 closureData = oldClosureData; | 1062 closureData = oldClosureData; |
1087 executableContext = oldFunctionElement; | 1063 executableContext = oldFunctionElement; |
1088 | 1064 |
1089 // Mark all free variables as captured and use them in the outer function. | 1065 // Mark all free variables as captured and use them in the outer function. |
1090 Iterable<Local> freeVariables = savedClosureData.freeVariables; | 1066 Iterable<Local> freeVariables = savedClosureData.freeVariables; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1162 /// | 1138 /// |
1163 /// Move the below classes to a JS model eventually. | 1139 /// Move the below classes to a JS model eventually. |
1164 /// | 1140 /// |
1165 abstract class JSEntity implements Entity { | 1141 abstract class JSEntity implements Entity { |
1166 Entity get declaredEntity; | 1142 Entity get declaredEntity; |
1167 } | 1143 } |
1168 | 1144 |
1169 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1145 abstract class PrivatelyNamedJSEntity implements JSEntity { |
1170 Entity get rootOfScope; | 1146 Entity get rootOfScope; |
1171 } | 1147 } |
OLD | NEW |