| 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 } | 97 } |
| 98 | 98 |
| 99 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as | 99 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as |
| 100 /// non-elements. | 100 /// non-elements. |
| 101 abstract class CapturedVariable {} | 101 abstract class CapturedVariable {} |
| 102 | 102 |
| 103 // TODO(ahe): These classes continuously cause problems. We need to | 103 // TODO(ahe): These classes continuously cause problems. We need to |
| 104 // find a more general solution. | 104 // find a more general solution. |
| 105 class ClosureFieldElement extends ElementX | 105 class ClosureFieldElement extends ElementX |
| 106 implements VariableElement, CapturedVariable { | 106 implements VariableElement, CapturedVariable { |
| 107 /// The source variable this element refers to. | 107 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
| 108 final Local local; | 108 final Local local; |
| 109 | 109 |
| 110 ClosureFieldElement(String name, | 110 ClosureFieldElement(String name, |
| 111 this.local, | 111 this.local, |
| 112 ClosureClassElement enclosing) | 112 ClosureClassElement enclosing) |
| 113 : super(name, ElementKind.FIELD, enclosing); | 113 : super(name, ElementKind.FIELD, enclosing); |
| 114 | 114 |
| 115 /// Use [closureClass] instead. | 115 /// Use [closureClass] instead. |
| 116 @deprecated | 116 @deprecated |
| 117 get enclosingElement => super.enclosingElement; | 117 get enclosingElement => super.enclosingElement; |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 ResolvedAst get resolvedAst { | 294 ResolvedAst get resolvedAst { |
| 295 return new ResolvedAst(this, node, treeElements); | 295 return new ResolvedAst(this, node, treeElements); |
| 296 } | 296 } |
| 297 | 297 |
| 298 Element get analyzableElement => closureClass.methodElement.analyzableElement; | 298 Element get analyzableElement => closureClass.methodElement.analyzableElement; |
| 299 } | 299 } |
| 300 | 300 |
| 301 // The box-element for a scope, and the captured variables that need to be | 301 // The box-element for a scope, and the captured variables that need to be |
| 302 // stored in the box. | 302 // stored in the box. |
| 303 class ClosureScope { | 303 class ClosureScope { |
| 304 BoxLocal boxElement; | 304 final BoxLocal boxElement; |
| 305 Map<VariableElement, BoxFieldElement> _capturedVariableMapping; | 305 final Map<Local, BoxFieldElement> capturedVariables; |
| 306 | 306 |
| 307 // If the scope is attached to a [For] contains the variables that are | 307 // If the scope is attached to a [For] contains the variables that are |
| 308 // declared in the initializer of the [For] and that need to be boxed. | 308 // declared in the initializer of the [For] and that need to be boxed. |
| 309 // Otherwise contains the empty List. | 309 // Otherwise contains the empty List. |
| 310 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; | 310 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; |
| 311 | 311 |
| 312 ClosureScope(this.boxElement, this._capturedVariableMapping); | 312 ClosureScope(this.boxElement, this.capturedVariables); |
| 313 | 313 |
| 314 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; | 314 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
| 315 | 315 |
| 316 bool isCapturedVariable(VariableElement variable) { | 316 bool isCapturedVariable(VariableElement variable) { |
| 317 return _capturedVariableMapping.containsKey(variable); | 317 return capturedVariables.containsKey(variable); |
| 318 } | 318 } |
| 319 | 319 |
| 320 void forEachCapturedVariable(f(LocalVariableElement variable, | 320 void forEachCapturedVariable(f(LocalVariableElement variable, |
| 321 BoxFieldElement boxField)) { | 321 BoxFieldElement boxField)) { |
| 322 _capturedVariableMapping.forEach(f); | 322 capturedVariables.forEach(f); |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 | 325 |
| 326 class ClosureClassMap { | 326 class ClosureClassMap { |
| 327 // The closure's element before any translation. Will be null for methods. | 327 // The closure's element before any translation. Will be null for methods. |
| 328 final LocalFunctionElement closureElement; | 328 final LocalFunctionElement closureElement; |
| 329 // The closureClassElement will be null for methods that are not local | 329 // The closureClassElement will be null for methods that are not local |
| 330 // closures. | 330 // closures. |
| 331 final ClosureClassElement closureClassElement; | 331 final ClosureClassElement closureClassElement; |
| 332 // The callElement will be null for methods that are not local closures. | 332 // The callElement will be null for methods that are not local closures. |
| 333 final FunctionElement callElement; | 333 final FunctionElement callElement; |
| 334 // The [thisElement] makes handling 'this' easier by treating it like any | 334 // The [thisElement] makes handling 'this' easier by treating it like any |
| 335 // other argument. It is only set for instance-members. | 335 // other argument. It is only set for instance-members. |
| 336 final ThisLocal thisLocal; | 336 final ThisLocal thisLocal; |
| 337 | 337 |
| 338 // Maps free locals, arguments and function elements to their captured | 338 // Maps free locals, arguments, function elements, and box locals to |
| 339 // copies. | 339 // their captured copies. |
| 340 final Map<Local, CapturedVariable> _freeVariableMapping = | 340 final Map<Local, CapturedVariable> freeVariableMap = |
| 341 new Map<Local, CapturedVariable>(); | 341 new Map<Local, CapturedVariable>(); |
| 342 | 342 |
| 343 // Maps closure-fields to their captured elements. This is somehow the inverse | |
| 344 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does | |
| 345 // not deal with boxes, here we map instance-fields (which might represent | |
| 346 // boxes) to their boxElement. | |
| 347 final Map<ClosureFieldElement, Local> _closureFieldMapping = | |
| 348 new Map<ClosureFieldElement, Local>(); | |
| 349 | |
| 350 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their | 343 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their |
| 351 // [ClosureScope] which contains their box and the | 344 // [ClosureScope] which contains their box and the |
| 352 // captured variables that are stored in the box. | 345 // captured variables that are stored in the box. |
| 353 // This map will be empty if the method/closure of this [ClosureData] does not | 346 // This map will be empty if the method/closure of this [ClosureData] does not |
| 354 // contain any nested closure. | 347 // contain any nested closure. |
| 355 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 348 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
| 356 | 349 |
| 357 final Set<Local> usedVariablesInTry = new Set<Local>(); | 350 final Set<Local> usedVariablesInTry = new Set<Local>(); |
| 358 | 351 |
| 359 ClosureClassMap(this.closureElement, | 352 ClosureClassMap(this.closureElement, |
| 360 this.closureClassElement, | 353 this.closureClassElement, |
| 361 this.callElement, | 354 this.callElement, |
| 362 this.thisLocal); | 355 this.thisLocal); |
| 363 | 356 |
| 364 void addFreeVariable(Local element) { | 357 void addFreeVariable(Local element) { |
| 365 assert(_freeVariableMapping[element] == null); | 358 assert(freeVariableMap[element] == null); |
| 366 _freeVariableMapping[element] = null; | 359 freeVariableMap[element] = null; |
| 367 } | 360 } |
| 368 | 361 |
| 369 Iterable<Local> get freeVariables => _freeVariableMapping.keys; | 362 Iterable<Local> get freeVariables => freeVariableMap.keys; |
| 370 | 363 |
| 371 bool isFreeVariable(Local element) { | 364 bool isFreeVariable(Local element) { |
| 372 return _freeVariableMapping.containsKey(element); | 365 return freeVariableMap.containsKey(element); |
| 373 } | 366 } |
| 374 | 367 |
| 375 CapturedVariable getFreeVariableElement(Local element) { | |
| 376 return _freeVariableMapping[element]; | |
| 377 } | |
| 378 | |
| 379 /// Sets the free [variable] to be captured by the [boxField]. | |
| 380 void setFreeVariableBoxField(Local variable, | |
| 381 BoxFieldElement boxField) { | |
| 382 _freeVariableMapping[variable] = boxField; | |
| 383 } | |
| 384 | |
| 385 /// Sets the free [variable] to be captured by the [closureField]. | |
| 386 void setFreeVariableClosureField(Local variable, | |
| 387 ClosureFieldElement closureField) { | |
| 388 _freeVariableMapping[variable] = closureField; | |
| 389 } | |
| 390 | |
| 391 | |
| 392 void forEachFreeVariable(f(Local variable, | 368 void forEachFreeVariable(f(Local variable, |
| 393 CapturedVariable field)) { | 369 CapturedVariable field)) { |
| 394 _freeVariableMapping.forEach(f); | 370 freeVariableMap.forEach(f); |
| 395 } | 371 } |
| 396 | 372 |
| 397 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 373 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
| 398 return _closureFieldMapping[field]; | 374 return field.local; |
| 399 } | |
| 400 | |
| 401 void setLocalVariableForClosureField(ClosureFieldElement field, | |
| 402 Local variable) { | |
| 403 _closureFieldMapping[field] = variable; | |
| 404 } | 375 } |
| 405 | 376 |
| 406 bool get isClosure => closureElement != null; | 377 bool get isClosure => closureElement != null; |
| 407 | 378 |
| 408 bool capturingScopesBox(Local variable) { | 379 bool capturingScopesBox(Local variable) { |
| 409 return capturingScopes.values.any((scope) { | 380 return capturingScopes.values.any((scope) { |
| 410 return scope.boxedLoopVariables.contains(variable); | 381 return scope.boxedLoopVariables.contains(variable); |
| 411 }); | 382 }); |
| 412 } | 383 } |
| 413 | 384 |
| 414 bool isVariableBoxed(Local variable) { | 385 bool isVariableBoxed(Local variable) { |
| 415 CapturedVariable copy = _freeVariableMapping[variable]; | 386 CapturedVariable copy = freeVariableMap[variable]; |
| 416 if (copy is BoxFieldElement) { | 387 if (copy is BoxFieldElement) { |
| 417 return true; | 388 return true; |
| 418 } | 389 } |
| 419 return capturingScopesBox(variable); | 390 return capturingScopesBox(variable); |
| 420 } | 391 } |
| 421 | 392 |
| 422 void forEachCapturedVariable(void f(Local variable, | 393 void forEachCapturedVariable(void f(Local variable, |
| 423 CapturedVariable field)) { | 394 CapturedVariable field)) { |
| 424 _freeVariableMapping.forEach((variable, copy) { | 395 freeVariableMap.forEach((variable, copy) { |
| 425 if (variable is BoxLocal) return; | 396 if (variable is BoxLocal) return; |
| 426 f(variable, copy); | 397 f(variable, copy); |
| 427 }); | 398 }); |
| 428 capturingScopes.values.forEach((ClosureScope scope) { | 399 capturingScopes.values.forEach((ClosureScope scope) { |
| 429 scope.forEachCapturedVariable(f); | 400 scope.forEachCapturedVariable(f); |
| 430 }); | 401 }); |
| 431 } | 402 } |
| 432 | 403 |
| 433 void forEachBoxedVariable(void f(LocalVariableElement local, | 404 void forEachBoxedVariable(void f(LocalVariableElement local, |
| 434 BoxFieldElement field)) { | 405 BoxFieldElement field)) { |
| 435 _freeVariableMapping.forEach((variable, copy) { | 406 freeVariableMap.forEach((variable, copy) { |
| 436 if (!isVariableBoxed(variable)) return; | 407 if (!isVariableBoxed(variable)) return; |
| 437 f(variable, copy); | 408 f(variable, copy); |
| 438 }); | 409 }); |
| 439 capturingScopes.values.forEach((ClosureScope scope) { | 410 capturingScopes.values.forEach((ClosureScope scope) { |
| 440 scope.forEachCapturedVariable(f); | 411 scope.forEachCapturedVariable(f); |
| 441 }); | 412 }); |
| 442 } | 413 } |
| 443 | 414 |
| 444 void removeMyselfFrom(Universe universe) { | 415 void removeMyselfFrom(Universe universe) { |
| 445 _freeVariableMapping.values.forEach((e) { | 416 freeVariableMap.values.forEach((e) { |
| 446 universe.closurizedMembers.remove(e); | 417 universe.closurizedMembers.remove(e); |
| 447 universe.fieldSetters.remove(e); | 418 universe.fieldSetters.remove(e); |
| 448 universe.fieldGetters.remove(e); | 419 universe.fieldGetters.remove(e); |
| 449 }); | 420 }); |
| 450 } | 421 } |
| 451 } | 422 } |
| 452 | 423 |
| 453 class ClosureTranslator extends Visitor { | 424 class ClosureTranslator extends Visitor { |
| 454 final Compiler compiler; | 425 final Compiler compiler; |
| 455 final TreeElements elements; | 426 final TreeElements elements; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 // The captured variables that need to be stored in a field of the closure | 508 // The captured variables that need to be stored in a field of the closure |
| 538 // class. | 509 // class. |
| 539 Set<Local> fieldCaptures = new Set<Local>(); | 510 Set<Local> fieldCaptures = new Set<Local>(); |
| 540 Set<BoxLocal> boxes = new Set<BoxLocal>(); | 511 Set<BoxLocal> boxes = new Set<BoxLocal>(); |
| 541 ClosureClassMap data = closureMappingCache[closure]; | 512 ClosureClassMap data = closureMappingCache[closure]; |
| 542 // We get a copy of the keys and iterate over it, to avoid modifications | 513 // We get a copy of the keys and iterate over it, to avoid modifications |
| 543 // to the map while iterating over it. | 514 // to the map while iterating over it. |
| 544 Iterable<Local> freeVariables = data.freeVariables.toList(); | 515 Iterable<Local> freeVariables = data.freeVariables.toList(); |
| 545 freeVariables.forEach((Local fromElement) { | 516 freeVariables.forEach((Local fromElement) { |
| 546 assert(data.isFreeVariable(fromElement)); | 517 assert(data.isFreeVariable(fromElement)); |
| 547 assert(data.getFreeVariableElement(fromElement) == null); | 518 assert(data.freeVariableMap[fromElement] == null); |
| 548 assert(isCapturedVariable(fromElement)); | 519 assert(isCapturedVariable(fromElement)); |
| 549 BoxFieldElement boxFieldElement = | 520 BoxFieldElement boxFieldElement = |
| 550 getCapturedVariableBoxField(fromElement); | 521 getCapturedVariableBoxField(fromElement); |
| 551 if (boxFieldElement == null) { | 522 if (boxFieldElement == null) { |
| 552 assert(fromElement is! BoxLocal); | 523 assert(fromElement is! BoxLocal); |
| 553 // The variable has not been boxed. | 524 // The variable has not been boxed. |
| 554 fieldCaptures.add(fromElement); | 525 fieldCaptures.add(fromElement); |
| 555 } else { | 526 } else { |
| 556 // A boxed element. | 527 // A boxed element. |
| 557 data.setFreeVariableBoxField(fromElement, boxFieldElement); | 528 data.freeVariableMap[fromElement] = boxFieldElement; |
| 558 boxes.add(boxFieldElement.box); | 529 boxes.add(boxFieldElement.box); |
| 559 } | 530 } |
| 560 }); | 531 }); |
| 561 ClosureClassElement closureClass = data.closureClassElement; | 532 ClosureClassElement closureClass = data.closureClassElement; |
| 562 assert(closureClass != null || | 533 assert(closureClass != null || |
| 563 (fieldCaptures.isEmpty && boxes.isEmpty)); | 534 (fieldCaptures.isEmpty && boxes.isEmpty)); |
| 564 | 535 |
| 565 void addClosureField(Local local, String name) { | 536 void addClosureField(Local local, String name) { |
| 566 ClosureFieldElement closureField = | 537 ClosureFieldElement closureField = |
| 567 new ClosureFieldElement(name, local, closureClass); | 538 new ClosureFieldElement(name, local, closureClass); |
| 568 closureClass.addField(closureField, compiler); | 539 closureClass.addField(closureField, compiler); |
| 569 data.setLocalVariableForClosureField(closureField, local); | 540 data.freeVariableMap[local] = closureField; |
| 570 data.setFreeVariableClosureField(local, closureField); | |
| 571 } | 541 } |
| 572 | 542 |
| 573 // Add the box elements first so we get the same ordering. | 543 // Add the box elements first so we get the same ordering. |
| 574 // TODO(sra): What is the canonical order of multiple boxes? | 544 // TODO(sra): What is the canonical order of multiple boxes? |
| 575 for (BoxLocal capturedElement in boxes) { | 545 for (BoxLocal capturedElement in boxes) { |
| 576 addClosureField(capturedElement, capturedElement.name); | 546 addClosureField(capturedElement, capturedElement.name); |
| 577 } | 547 } |
| 578 | 548 |
| 579 /// Comparator for locals. Position boxes before elements. | 549 /// Comparator for locals. Position boxes before elements. |
| 580 int compareLocals(a, b) { | 550 int compareLocals(a, b) { |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 | 992 |
| 1023 String get name => typeVariable.name; | 993 String get name => typeVariable.name; |
| 1024 | 994 |
| 1025 int get hashCode => typeVariable.hashCode; | 995 int get hashCode => typeVariable.hashCode; |
| 1026 | 996 |
| 1027 bool operator ==(other) { | 997 bool operator ==(other) { |
| 1028 if (other is! TypeVariableLocal) return false; | 998 if (other is! TypeVariableLocal) return false; |
| 1029 return typeVariable == other.typeVariable; | 999 return typeVariable == other.typeVariable; |
| 1030 } | 1000 } |
| 1031 } | 1001 } |
| OLD | NEW |