| 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 class ClosureFieldElement extends Element { | 5 class ClosureFieldElement extends Element { |
| 6 ClosureFieldElement(SourceString name, ClassElement enclosing) | 6 ClosureFieldElement(SourceString name, ClassElement enclosing) |
| 7 : super(name, ElementKind.FIELD, enclosing); | 7 : super(name, ElementKind.FIELD, enclosing); |
| 8 | 8 |
| 9 bool isInstanceMember() => true; | 9 bool isInstanceMember() => true; |
| 10 bool isAssignable() => false; | 10 bool isAssignable() => false; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 this.callElement, | 63 this.callElement, |
| 64 this.thisElement) | 64 this.thisElement) |
| 65 : this.freeVariableMapping = new Map<Element, Element>(), | 65 : this.freeVariableMapping = new Map<Element, Element>(), |
| 66 this.capturedFieldMapping = new Map<Element, Element>(), | 66 this.capturedFieldMapping = new Map<Element, Element>(), |
| 67 this.capturingScopes = new Map<Node, ClosureScope>(), | 67 this.capturingScopes = new Map<Node, ClosureScope>(), |
| 68 this.usedVariablesInTry = new Set<Element>(); | 68 this.usedVariablesInTry = new Set<Element>(); |
| 69 | 69 |
| 70 bool isClosure() => closureElement !== null; | 70 bool isClosure() => closureElement !== null; |
| 71 } | 71 } |
| 72 | 72 |
| 73 Map<Node, ClosureData> _closureDataCache; | |
| 74 Map<Node, ClosureData> get closureDataCache() { | |
| 75 if (_closureDataCache === null) { | |
| 76 _closureDataCache = new HashMap<Node, ClosureData>(); | |
| 77 } | |
| 78 return _closureDataCache; | |
| 79 } | |
| 80 | |
| 81 class ClosureTranslator extends AbstractVisitor { | 73 class ClosureTranslator extends AbstractVisitor { |
| 82 final Compiler compiler; | 74 final Compiler compiler; |
| 83 final TreeElements elements; | 75 final TreeElements elements; |
| 84 int boxCounter = 0; | 76 int boxCounter = 0; |
| 85 bool inTryCatchOrFinally = false; | 77 bool inTryCatchOrFinally = false; |
| 86 | 78 |
| 87 // Map of captured variables. Initially they will map to themselves. If | 79 // Map of captured variables. Initially they will map to themselves. If |
| 88 // a variable needs to be boxed then the scope declaring the variable | 80 // a variable needs to be boxed then the scope declaring the variable |
| 89 // will update this mapping. | 81 // will update this mapping. |
| 90 Map<Element, Element> capturedVariableMapping; | 82 Map<Element, Element> capturedVariableMapping; |
| 91 // List of encountered closures. | 83 // List of encountered closures. |
| 92 List<FunctionExpression> closures; | 84 List<FunctionExpression> closures; |
| 93 | 85 |
| 94 // The variables that have been declared in the current scope. | 86 // The variables that have been declared in the current scope. |
| 95 List<Element> scopeVariables; | 87 List<Element> scopeVariables; |
| 96 | 88 |
| 97 FunctionElement currentFunctionElement; | 89 FunctionElement currentFunctionElement; |
| 98 // The closureData of the currentFunctionElement. | 90 // The closureData of the currentFunctionElement. |
| 99 ClosureData closureData; | 91 ClosureData closureData; |
| 100 | 92 |
| 101 bool insideClosure = false; | 93 bool insideClosure = false; |
| 102 | 94 |
| 103 ClosureTranslator(this.compiler, this.elements) | 95 ClosureTranslator(this.compiler, this.elements) |
| 104 : capturedVariableMapping = new Map<Element, Element>(), | 96 : capturedVariableMapping = new Map<Element, Element>(), |
| 105 closures = <FunctionExpression>[]; | 97 closures = <FunctionExpression>[]; |
| 106 | 98 |
| 107 ClosureData translate(Node node) { | 99 ClosureData translate(Node node) { |
| 108 // Closures have already been analyzed when visiting the surrounding | 100 // Closures have already been analyzed when visiting the surrounding |
| 109 // method/function. This also shortcuts for bailout functions. | 101 // method/function. This also shortcuts for bailout functions. |
| 110 ClosureData cached = closureDataCache[node]; | 102 ClosureData cached = compiler.closureDataCache[node]; |
| 111 if (cached !== null) return cached; | 103 if (cached !== null) return cached; |
| 112 | 104 |
| 113 visit(node); | 105 visit(node); |
| 114 // When variables need to be boxed their [capturedVariableMapping] is | 106 // When variables need to be boxed their [capturedVariableMapping] is |
| 115 // updated, but we delay updating the similar freeVariableMapping in the | 107 // updated, but we delay updating the similar freeVariableMapping in the |
| 116 // closure datas that capture these variables. | 108 // closure datas that capture these variables. |
| 117 // The closures don't have their fields (in the closure class) set, either. | 109 // The closures don't have their fields (in the closure class) set, either. |
| 118 updateClosures(); | 110 updateClosures(); |
| 119 | 111 |
| 120 return closureDataCache[node]; | 112 return compiler.closureDataCache[node]; |
| 121 } | 113 } |
| 122 | 114 |
| 123 // This function runs through all of the existing closures and updates their | 115 // This function runs through all of the existing closures and updates their |
| 124 // free variables to the boxed value. It also adds the field-elements to the | 116 // free variables to the boxed value. It also adds the field-elements to the |
| 125 // class representing the closure. At the same time it fills the | 117 // class representing the closure. At the same time it fills the |
| 126 // [capturedFieldMapping]. | 118 // [capturedFieldMapping]. |
| 127 void updateClosures() { | 119 void updateClosures() { |
| 128 for (FunctionExpression closure in closures) { | 120 for (FunctionExpression closure in closures) { |
| 129 // The captured variables that need to be stored in a field of the closure | 121 // The captured variables that need to be stored in a field of the closure |
| 130 // class. | 122 // class. |
| 131 Set<Element> fieldCaptures = new Set<Element>(); | 123 Set<Element> fieldCaptures = new Set<Element>(); |
| 132 ClosureData data = closureDataCache[closure]; | 124 ClosureData data = compiler.closureDataCache[closure]; |
| 133 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; | 125 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; |
| 134 // We get a copy of the keys and iterate over it, to avoid modifications | 126 // We get a copy of the keys and iterate over it, to avoid modifications |
| 135 // to the map while iterating over it. | 127 // to the map while iterating over it. |
| 136 freeVariableMapping.getKeys().forEach((Element fromElement) { | 128 freeVariableMapping.getKeys().forEach((Element fromElement) { |
| 137 assert(fromElement == freeVariableMapping[fromElement]); | 129 assert(fromElement == freeVariableMapping[fromElement]); |
| 138 Element updatedElement = capturedVariableMapping[fromElement]; | 130 Element updatedElement = capturedVariableMapping[fromElement]; |
| 139 assert(updatedElement !== null); | 131 assert(updatedElement !== null); |
| 140 if (fromElement == updatedElement) { | 132 if (fromElement == updatedElement) { |
| 141 assert(freeVariableMapping[fromElement] == updatedElement); | 133 assert(freeVariableMapping[fromElement] == updatedElement); |
| 142 assert(Elements.isLocal(updatedElement)); | 134 assert(Elements.isLocal(updatedElement)); |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 declareLocal(element); | 362 declareLocal(element); |
| 371 } | 363 } |
| 372 | 364 |
| 373 // TODO(ahe): This is problematic. The backend should not repeat | 365 // TODO(ahe): This is problematic. The backend should not repeat |
| 374 // the work of the resolver. It is the resolver's job to create | 366 // the work of the resolver. It is the resolver's job to create |
| 375 // parameters, etc. Other phases should only visit statements. | 367 // parameters, etc. Other phases should only visit statements. |
| 376 node.visitChildren(this); | 368 node.visitChildren(this); |
| 377 | 369 |
| 378 attachCapturedScopeVariables(node); | 370 attachCapturedScopeVariables(node); |
| 379 | 371 |
| 380 closureDataCache[node] = closureData; | 372 compiler.closureDataCache[node] = closureData; |
| 381 | 373 |
| 382 ClosureData savedClosureData = closureData; | 374 ClosureData savedClosureData = closureData; |
| 383 bool savedInsideClosure = insideClosure; | 375 bool savedInsideClosure = insideClosure; |
| 384 | 376 |
| 385 // Restore old values. | 377 // Restore old values. |
| 386 scopeVariables = oldScopeVariables; | 378 scopeVariables = oldScopeVariables; |
| 387 insideClosure = oldInsideClosure; | 379 insideClosure = oldInsideClosure; |
| 388 closureData = oldClosureData; | 380 closureData = oldClosureData; |
| 389 currentFunctionElement = oldFunctionElement; | 381 currentFunctionElement = oldFunctionElement; |
| 390 | 382 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 409 // TODO(ngeoffray): implement finer grain state. | 401 // TODO(ngeoffray): implement finer grain state. |
| 410 inTryCatchOrFinally = true; | 402 inTryCatchOrFinally = true; |
| 411 node.visitChildren(this); | 403 node.visitChildren(this); |
| 412 inTryCatchOrFinally = false; | 404 inTryCatchOrFinally = false; |
| 413 } | 405 } |
| 414 | 406 |
| 415 visitLiteralMap(LiteralMap node) { | 407 visitLiteralMap(LiteralMap node) { |
| 416 // TODO(ahe): Remove this method. | 408 // TODO(ahe): Remove this method. |
| 417 } | 409 } |
| 418 } | 410 } |
| OLD | NEW |