| 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'; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 assert(_closureMappingCache[element] != null, | 125 assert(_closureMappingCache[element] != null, |
| 126 failedAt(element, "No ClosureClassMap computed for ${element}.")); | 126 failedAt(element, "No ClosureClassMap computed for ${element}.")); |
| 127 return _closureMappingCache[element]; | 127 return _closureMappingCache[element]; |
| 128 }); | 128 }); |
| 129 }); | 129 }); |
| 130 } | 130 } |
| 131 } | 131 } |
| 132 | 132 |
| 133 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as |
| 134 /// non-elements. |
| 135 // TODO(johnniwinther): Remove `implements Element`. |
| 136 abstract class CapturedVariable implements Element {} |
| 137 |
| 133 // TODO(ahe): These classes continuously cause problems. We need to | 138 // TODO(ahe): These classes continuously cause problems. We need to |
| 134 // find a more general solution. | 139 // find a more general solution. |
| 135 class ClosureFieldElement extends ElementX | 140 class ClosureFieldElement extends ElementX |
| 136 implements FieldElement, PrivatelyNamedJSEntity { | 141 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { |
| 137 /// The [BoxLocal] or [LocalElement] being accessed through the field. | 142 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
| 138 final Local local; | 143 final Local local; |
| 139 | 144 |
| 140 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) | 145 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) |
| 141 : super(name, ElementKind.FIELD, enclosing); | 146 : super(name, ElementKind.FIELD, enclosing); |
| 142 | 147 |
| 143 /// Use [closureClass] instead. | 148 /// Use [closureClass] instead. |
| 144 @deprecated | 149 @deprecated |
| 145 get enclosingElement => super.enclosingElement; | 150 get enclosingElement => super.enclosingElement; |
| 146 | 151 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 | 288 |
| 284 @override | 289 @override |
| 285 MemberElement get memberContext => executableContext.memberContext; | 290 MemberElement get memberContext => executableContext.memberContext; |
| 286 | 291 |
| 287 String toString() => 'BoxLocal($name)'; | 292 String toString() => 'BoxLocal($name)'; |
| 288 } | 293 } |
| 289 | 294 |
| 290 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to | 295 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to |
| 291 // find a more general solution. | 296 // find a more general solution. |
| 292 class BoxFieldElement extends ElementX | 297 class BoxFieldElement extends ElementX |
| 293 implements TypedElement, FieldElement, PrivatelyNamedJSEntity { | 298 implements |
| 299 TypedElement, |
| 300 CapturedVariable, |
| 301 FieldElement, |
| 302 PrivatelyNamedJSEntity { |
| 294 final BoxLocal box; | 303 final BoxLocal box; |
| 295 | 304 |
| 296 BoxFieldElement(String name, this.variableElement, BoxLocal box) | 305 BoxFieldElement(String name, this.variableElement, BoxLocal box) |
| 297 : this.box = box, | 306 : this.box = box, |
| 298 super(name, ElementKind.FIELD, box.executableContext); | 307 super(name, ElementKind.FIELD, box.executableContext); |
| 299 | 308 |
| 300 ResolutionDartType computeType(Resolution resolution) => type; | 309 ResolutionDartType computeType(Resolution resolution) => type; |
| 301 | 310 |
| 302 ResolutionDartType get type => variableElement.type; | 311 ResolutionDartType get type => variableElement.type; |
| 303 | 312 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 | 415 |
| 407 // The box-element for a scope, and the captured variables that need to be | 416 // The box-element for a scope, and the captured variables that need to be |
| 408 // stored in the box. | 417 // stored in the box. |
| 409 class ClosureScope { | 418 class ClosureScope { |
| 410 final BoxLocal boxElement; | 419 final BoxLocal boxElement; |
| 411 final Map<Local, BoxFieldElement> capturedVariables; | 420 final Map<Local, BoxFieldElement> capturedVariables; |
| 412 | 421 |
| 413 // If the scope is attached to a [For] contains the variables that are | 422 // If the scope is attached to a [For] contains the variables that are |
| 414 // declared in the initializer of the [For] and that need to be boxed. | 423 // declared in the initializer of the [For] and that need to be boxed. |
| 415 // Otherwise contains the empty List. | 424 // Otherwise contains the empty List. |
| 416 List<Local> boxedLoopVariables = const <Local>[]; | 425 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; |
| 417 | 426 |
| 418 ClosureScope(this.boxElement, this.capturedVariables); | 427 ClosureScope(this.boxElement, this.capturedVariables); |
| 419 | 428 |
| 420 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; | 429 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
| 421 | 430 |
| 422 bool isCapturedVariable(VariableElement variable) { | 431 bool isCapturedVariable(VariableElement variable) { |
| 423 return capturedVariables.containsKey(variable); | 432 return capturedVariables.containsKey(variable); |
| 424 } | 433 } |
| 425 | 434 |
| 426 void forEachCapturedVariable( | 435 void forEachCapturedVariable( |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 /// | 475 /// |
| 467 /// The callElement will be null for methods that are not local closures. | 476 /// The callElement will be null for methods that are not local closures. |
| 468 final MethodElement callElement; | 477 final MethodElement callElement; |
| 469 | 478 |
| 470 /// The [thisElement] makes handling 'this' easier by treating it like any | 479 /// The [thisElement] makes handling 'this' easier by treating it like any |
| 471 /// other argument. It is only set for instance-members. | 480 /// other argument. It is only set for instance-members. |
| 472 final ThisLocal thisLocal; | 481 final ThisLocal thisLocal; |
| 473 | 482 |
| 474 /// Maps free locals, arguments, function elements, and box locals to | 483 /// Maps free locals, arguments, function elements, and box locals to |
| 475 /// their locations. | 484 /// their locations. |
| 476 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); | 485 final Map<Local, CapturedVariable> freeVariableMap = |
| 486 new Map<Local, CapturedVariable>(); |
| 477 | 487 |
| 478 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which | 488 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which |
| 479 /// contains their box and the captured variables that are stored in the box. | 489 /// contains their box and the captured variables that are stored in the box. |
| 480 /// This map will be empty if the method/closure of this [ClosureData] does | 490 /// This map will be empty if the method/closure of this [ClosureData] does |
| 481 /// not contain any nested closure. | 491 /// not contain any nested closure. |
| 482 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 492 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
| 483 | 493 |
| 484 /// Variables that are used in a try must be treated as boxed because the | 494 /// Variables that are used in a try must be treated as boxed because the |
| 485 /// control flow can be non-linear. | 495 /// control flow can be non-linear. |
| 486 /// | 496 /// |
| 487 /// Also parameters to a `sync*` generator must be boxed, because of the way | 497 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 488 /// we rewrite sync* functions. See also comments in [useLocal]. | 498 /// we rewrite sync* functions. See also comments in [useLocal]. |
| 489 // TODO(johnniwinther): Add variables to this only if the variable is mutated. | 499 // TODO(johnniwinther): Add variables to this only if the variable is mutated. |
| 490 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 500 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
| 491 | 501 |
| 492 ClosureClassMap(this.closureElement, this.closureClassElement, | 502 ClosureClassMap(this.closureElement, this.closureClassElement, |
| 493 this.callElement, this.thisLocal); | 503 this.callElement, this.thisLocal); |
| 494 | 504 |
| 495 void addFreeVariable(Local element) { | 505 void addFreeVariable(Local element) { |
| 496 assert(freeVariableMap[element] == null); | 506 assert(freeVariableMap[element] == null); |
| 497 freeVariableMap[element] = null; | 507 freeVariableMap[element] = null; |
| 498 } | 508 } |
| 499 | 509 |
| 500 Iterable<Local> get freeVariables => freeVariableMap.keys; | 510 Iterable<Local> get freeVariables => freeVariableMap.keys; |
| 501 | 511 |
| 502 bool isFreeVariable(Local element) { | 512 bool isFreeVariable(Local element) { |
| 503 return freeVariableMap.containsKey(element); | 513 return freeVariableMap.containsKey(element); |
| 504 } | 514 } |
| 505 | 515 |
| 506 void forEachFreeVariable(f(Local variable, FieldEntity field)) { | 516 void forEachFreeVariable(f(Local variable, CapturedVariable field)) { |
| 507 freeVariableMap.forEach(f); | 517 freeVariableMap.forEach(f); |
| 508 } | 518 } |
| 509 | 519 |
| 510 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 520 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
| 511 return field.local; | 521 return field.local; |
| 512 } | 522 } |
| 513 | 523 |
| 514 bool get isClosure => closureElement != null; | 524 bool get isClosure => closureElement != null; |
| 515 | 525 |
| 516 bool capturingScopesBox(Local variable) { | 526 bool capturingScopesBox(Local variable) { |
| 517 return capturingScopes.values.any((scope) { | 527 return capturingScopes.values.any((scope) { |
| 518 return scope.boxedLoopVariables.contains(variable); | 528 return scope.boxedLoopVariables.contains(variable); |
| 519 }); | 529 }); |
| 520 } | 530 } |
| 521 | 531 |
| 522 bool isVariableBoxed(Local variable) { | 532 bool isVariableBoxed(Local variable) { |
| 523 FieldEntity copy = freeVariableMap[variable]; | 533 CapturedVariable copy = freeVariableMap[variable]; |
| 524 if (copy is BoxFieldElement) { | 534 if (copy is BoxFieldElement) { |
| 525 return true; | 535 return true; |
| 526 } | 536 } |
| 527 return capturingScopesBox(variable); | 537 return capturingScopesBox(variable); |
| 528 } | 538 } |
| 529 | 539 |
| 530 void forEachCapturedVariable(void f(Local variable, FieldEntity field)) { | 540 void forEachCapturedVariable(void f(Local variable, CapturedVariable field)) { |
| 531 freeVariableMap.forEach((variable, copy) { | 541 freeVariableMap.forEach((variable, copy) { |
| 532 if (variable is BoxLocal) return; | 542 if (variable is BoxLocal) return; |
| 533 f(variable, copy); | 543 f(variable, copy); |
| 534 }); | 544 }); |
| 535 capturingScopes.values.forEach((ClosureScope scope) { | 545 capturingScopes.values.forEach((ClosureScope scope) { |
| 536 scope.forEachCapturedVariable(f); | 546 scope.forEachCapturedVariable(f); |
| 537 }); | 547 }); |
| 538 } | 548 } |
| 539 | 549 |
| 540 void forEachBoxedVariable( | 550 void forEachBoxedVariable( |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 /// | 1238 /// |
| 1229 /// Move the below classes to a JS model eventually. | 1239 /// Move the below classes to a JS model eventually. |
| 1230 /// | 1240 /// |
| 1231 abstract class JSEntity implements Entity { | 1241 abstract class JSEntity implements Entity { |
| 1232 Entity get declaredEntity; | 1242 Entity get declaredEntity; |
| 1233 } | 1243 } |
| 1234 | 1244 |
| 1235 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1245 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1236 Entity get rootOfScope; | 1246 Entity get rootOfScope; |
| 1237 } | 1247 } |
| OLD | NEW |