OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library closureToClassMapper; | 5 library closureToClassMapper; |
6 | 6 |
7 import "elements/elements.dart"; | 7 import "elements/elements.dart"; |
8 import "dart2jslib.dart"; | 8 import "dart2jslib.dart"; |
9 import "dart_types.dart"; | 9 import "dart_types.dart"; |
10 import "js_backend/js_backend.dart" show JavaScriptBackend; | 10 import "js_backend/js_backend.dart" show JavaScriptBackend; |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 | 265 |
266 /// Call method of a closure class. | 266 /// Call method of a closure class. |
267 class SynthesizedCallMethodElementX extends BaseFunctionElementX { | 267 class SynthesizedCallMethodElementX extends BaseFunctionElementX { |
268 final LocalFunctionElement expression; | 268 final LocalFunctionElement expression; |
269 | 269 |
270 SynthesizedCallMethodElementX(String name, | 270 SynthesizedCallMethodElementX(String name, |
271 LocalFunctionElementX other, | 271 LocalFunctionElementX other, |
272 ClosureClassElement enclosing) | 272 ClosureClassElement enclosing) |
273 : expression = other, | 273 : expression = other, |
274 super(name, other.kind, other.modifiers, enclosing, false) { | 274 super(name, other.kind, other.modifiers, enclosing, false) { |
| 275 asyncMarker = other.asyncMarker; |
275 functionSignatureCache = other.functionSignature; | 276 functionSignatureCache = other.functionSignature; |
276 } | 277 } |
277 | 278 |
278 /// Use [closureClass] instead. | 279 /// Use [closureClass] instead. |
279 @deprecated | 280 @deprecated |
280 get enclosingElement => super.enclosingElement; | 281 get enclosingElement => super.enclosingElement; |
281 | 282 |
282 ClosureClassElement get closureClass => super.enclosingElement; | 283 ClosureClassElement get closureClass => super.enclosingElement; |
283 | 284 |
284 MemberElement get memberContext { | 285 MemberElement get memberContext { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 final Map<Local, CapturedVariable> freeVariableMap = | 341 final Map<Local, CapturedVariable> freeVariableMap = |
341 new Map<Local, CapturedVariable>(); | 342 new Map<Local, CapturedVariable>(); |
342 | 343 |
343 // Maps [Loop] and [FunctionExpression] nodes to their | 344 // Maps [Loop] and [FunctionExpression] nodes to their |
344 // [ClosureScope] which contains their box and the | 345 // [ClosureScope] which contains their box and the |
345 // captured variables that are stored in the box. | 346 // captured variables that are stored in the box. |
346 // This map will be empty if the method/closure of this [ClosureData] does not | 347 // This map will be empty if the method/closure of this [ClosureData] does not |
347 // contain any nested closure. | 348 // contain any nested closure. |
348 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 349 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
349 | 350 |
350 final Set<Local> usedVariablesInTry = new Set<Local>(); | 351 /// Variables that are used in a try must be treated as boxed because the |
| 352 /// control flow can be non-linear. |
| 353 /// |
| 354 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 355 /// we rewrite sync* functions. See also comments in [useLocal]. |
| 356 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. |
| 357 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
351 | 358 |
352 ClosureClassMap(this.closureElement, | 359 ClosureClassMap(this.closureElement, |
353 this.closureClassElement, | 360 this.closureClassElement, |
354 this.callElement, | 361 this.callElement, |
355 this.thisLocal); | 362 this.thisLocal); |
356 | 363 |
357 void addFreeVariable(Local element) { | 364 void addFreeVariable(Local element) { |
358 assert(freeVariableMap[element] == null); | 365 assert(freeVariableMap[element] == null); |
359 freeVariableMap[element] = null; | 366 freeVariableMap[element] = null; |
360 } | 367 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 }); | 427 }); |
421 } | 428 } |
422 } | 429 } |
423 | 430 |
424 class ClosureTranslator extends Visitor { | 431 class ClosureTranslator extends Visitor { |
425 final Compiler compiler; | 432 final Compiler compiler; |
426 final TreeElements elements; | 433 final TreeElements elements; |
427 int closureFieldCounter = 0; | 434 int closureFieldCounter = 0; |
428 int boxedFieldCounter = 0; | 435 int boxedFieldCounter = 0; |
429 bool inTryStatement = false; | 436 bool inTryStatement = false; |
| 437 |
430 final Map<Node, ClosureClassMap> closureMappingCache; | 438 final Map<Node, ClosureClassMap> closureMappingCache; |
431 | 439 |
432 // Map of captured variables. Initially they will map to `null`. If | 440 // Map of captured variables. Initially they will map to `null`. If |
433 // a variable needs to be boxed then the scope declaring the variable | 441 // a variable needs to be boxed then the scope declaring the variable |
434 // will update this to mapping to the capturing [BoxFieldElement]. | 442 // will update this to mapping to the capturing [BoxFieldElement]. |
435 Map<Local, BoxFieldElement> _capturedVariableMapping = | 443 Map<Local, BoxFieldElement> _capturedVariableMapping = |
436 new Map<Local, BoxFieldElement>(); | 444 new Map<Local, BoxFieldElement>(); |
437 | 445 |
438 // List of encountered closures. | 446 // List of encountered closures. |
439 List<Expression> closures = <Expression>[]; | 447 List<Expression> closures = <Expression>[]; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 } | 589 } |
582 | 590 |
583 if (insideClosure && !inCurrentContext(variable)) { | 591 if (insideClosure && !inCurrentContext(variable)) { |
584 closureData.addFreeVariable(variable); | 592 closureData.addFreeVariable(variable); |
585 } else if (inTryStatement) { | 593 } else if (inTryStatement) { |
586 // Don't mark the this-element or a self-reference. This would complicate | 594 // Don't mark the this-element or a self-reference. This would complicate |
587 // things in the builder. | 595 // things in the builder. |
588 // Note that nested (named) functions are immutable. | 596 // Note that nested (named) functions are immutable. |
589 if (variable != closureData.thisLocal && | 597 if (variable != closureData.thisLocal && |
590 variable != closureData.closureElement) { | 598 variable != closureData.closureElement) { |
591 // TODO(ngeoffray): only do this if the variable is mutated. | 599 closureData.variablesUsedInTryOrGenerator.add(variable); |
592 closureData.usedVariablesInTry.add(variable); | |
593 } | 600 } |
| 601 } else if (variable is LocalParameterElement && |
| 602 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { |
| 603 // Parameters in a sync* function are shared between each Iterator created |
| 604 // by the Iterable returned by the function, therefore they must be boxed. |
| 605 closureData.variablesUsedInTryOrGenerator.add(variable); |
594 } | 606 } |
595 } | 607 } |
596 | 608 |
597 void useTypeVariableAsLocal(TypeVariableType typeVariable) { | 609 void useTypeVariableAsLocal(TypeVariableType typeVariable) { |
598 useLocal(new TypeVariableLocal(typeVariable, outermostElement)); | 610 useLocal(new TypeVariableLocal(typeVariable, outermostElement)); |
599 } | 611 } |
600 | 612 |
601 void declareLocal(LocalVariableElement element) { | 613 void declareLocal(LocalVariableElement element) { |
602 scopeVariables.add(element); | 614 scopeVariables.add(element); |
603 } | 615 } |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 | 1039 |
1028 String get name => typeVariable.name; | 1040 String get name => typeVariable.name; |
1029 | 1041 |
1030 int get hashCode => typeVariable.hashCode; | 1042 int get hashCode => typeVariable.hashCode; |
1031 | 1043 |
1032 bool operator ==(other) { | 1044 bool operator ==(other) { |
1033 if (other is! TypeVariableLocal) return false; | 1045 if (other is! TypeVariableLocal) return false; |
1034 return typeVariable == other.typeVariable; | 1046 return typeVariable == other.typeVariable; |
1035 } | 1047 } |
1036 } | 1048 } |
OLD | NEW |