| 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 "tree/tree.dart"; | 9 import "tree/tree.dart"; |
| 10 import "util/util.dart"; | 10 import "util/util.dart"; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 Element boxElement; | 108 Element boxElement; |
| 109 Map<Element, Element> capturedVariableMapping; | 109 Map<Element, Element> capturedVariableMapping; |
| 110 // If the scope is attached to a [For] contains the variables that are | 110 // If the scope is attached to a [For] contains the variables that are |
| 111 // declared in the initializer of the [For] and that need to be boxed. | 111 // declared in the initializer of the [For] and that need to be boxed. |
| 112 // Otherwise contains the empty List. | 112 // Otherwise contains the empty List. |
| 113 List<Element> boxedLoopVariables; | 113 List<Element> boxedLoopVariables; |
| 114 | 114 |
| 115 ClosureScope(this.boxElement, this.capturedVariableMapping) | 115 ClosureScope(this.boxElement, this.capturedVariableMapping) |
| 116 : boxedLoopVariables = const <Element>[]; | 116 : boxedLoopVariables = const <Element>[]; |
| 117 | 117 |
| 118 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); | 118 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
| 119 } | 119 } |
| 120 | 120 |
| 121 class ClosureClassMap { | 121 class ClosureClassMap { |
| 122 // The closure's element before any translation. Will be null for methods. | 122 // The closure's element before any translation. Will be null for methods. |
| 123 final Element closureElement; | 123 final Element closureElement; |
| 124 // The closureClassElement will be null for methods that are not local | 124 // The closureClassElement will be null for methods that are not local |
| 125 // closures. | 125 // closures. |
| 126 final ClassElement closureClassElement; | 126 final ClassElement closureClassElement; |
| 127 // The callElement will be null for methods that are not local closures. | 127 // The callElement will be null for methods that are not local closures. |
| 128 final FunctionElement callElement; | 128 final FunctionElement callElement; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 fieldCaptures.add(updatedElement); | 243 fieldCaptures.add(updatedElement); |
| 244 } else { | 244 } else { |
| 245 // A boxed element. | 245 // A boxed element. |
| 246 freeVariableMapping[fromElement] = updatedElement; | 246 freeVariableMapping[fromElement] = updatedElement; |
| 247 Element boxElement = updatedElement.enclosingElement; | 247 Element boxElement = updatedElement.enclosingElement; |
| 248 assert(boxElement.kind == ElementKind.VARIABLE); | 248 assert(boxElement.kind == ElementKind.VARIABLE); |
| 249 fieldCaptures.add(boxElement); | 249 fieldCaptures.add(boxElement); |
| 250 } | 250 } |
| 251 }); | 251 }); |
| 252 ClassElement closureElement = data.closureClassElement; | 252 ClassElement closureElement = data.closureClassElement; |
| 253 assert(closureElement != null || fieldCaptures.isEmpty()); | 253 assert(closureElement != null || fieldCaptures.isEmpty); |
| 254 for (Element capturedElement in fieldCaptures) { | 254 for (Element capturedElement in fieldCaptures) { |
| 255 SourceString name; | 255 SourceString name; |
| 256 if (capturedElement is BoxElement) { | 256 if (capturedElement is BoxElement) { |
| 257 // The name is already mangled. | 257 // The name is already mangled. |
| 258 name = capturedElement.name; | 258 name = capturedElement.name; |
| 259 } else { | 259 } else { |
| 260 int id = closureFieldCounter++; | 260 int id = closureFieldCounter++; |
| 261 name = new SourceString("${capturedElement.name.slowToString()}_$id"); | 261 name = new SourceString("${capturedElement.name.slowToString()}_$id"); |
| 262 } | 262 } |
| 263 Element fieldElement = new ClosureFieldElement(name, closureElement); | 263 Element fieldElement = new ClosureFieldElement(name, closureElement); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 void declareLocal(Element element) { | 295 void declareLocal(Element element) { |
| 296 scopeVariables.add(element); | 296 scopeVariables.add(element); |
| 297 } | 297 } |
| 298 | 298 |
| 299 visit(Node node) => node.accept(this); | 299 visit(Node node) => node.accept(this); |
| 300 | 300 |
| 301 visitNode(Node node) => node.visitChildren(this); | 301 visitNode(Node node) => node.visitChildren(this); |
| 302 | 302 |
| 303 visitVariableDefinitions(VariableDefinitions node) { | 303 visitVariableDefinitions(VariableDefinitions node) { |
| 304 for (Link<Node> link = node.definitions.nodes; | 304 for (Link<Node> link = node.definitions.nodes; |
| 305 !link.isEmpty(); | 305 !link.isEmpty; |
| 306 link = link.tail) { | 306 link = link.tail) { |
| 307 Node definition = link.head; | 307 Node definition = link.head; |
| 308 Element element = elements[definition]; | 308 Element element = elements[definition]; |
| 309 assert(element != null); | 309 assert(element != null); |
| 310 declareLocal(element); | 310 declareLocal(element); |
| 311 // We still need to visit the right-hand sides of the init-assignments. | 311 // We still need to visit the right-hand sides of the init-assignments. |
| 312 // For SendSets don't visit the left again. Otherwise it would be marked | 312 // For SendSets don't visit the left again. Otherwise it would be marked |
| 313 // as mutated. | 313 // as mutated. |
| 314 if (definition is Send) { | 314 if (definition is Send) { |
| 315 Send assignment = definition; | 315 Send assignment = definition; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 // We are currently using the name in an HForeign which could replace | 429 // We are currently using the name in an HForeign which could replace |
| 430 // "$X" with something else. | 430 // "$X" with something else. |
| 431 String escaped = elementName.replaceAll("\$", "_"); | 431 String escaped = elementName.replaceAll("\$", "_"); |
| 432 SourceString boxedName = | 432 SourceString boxedName = |
| 433 new SourceString("${escaped}_${closureFieldCounter++}"); | 433 new SourceString("${escaped}_${closureFieldCounter++}"); |
| 434 Element boxed = new Element(boxedName, ElementKind.FIELD, box); | 434 Element boxed = new Element(boxedName, ElementKind.FIELD, box); |
| 435 scopeMapping[element] = boxed; | 435 scopeMapping[element] = boxed; |
| 436 capturedVariableMapping[element] = boxed; | 436 capturedVariableMapping[element] = boxed; |
| 437 } | 437 } |
| 438 } | 438 } |
| 439 if (!scopeMapping.isEmpty()) { | 439 if (!scopeMapping.isEmpty) { |
| 440 ClosureScope scope = new ClosureScope(box, scopeMapping); | 440 ClosureScope scope = new ClosureScope(box, scopeMapping); |
| 441 closureData.capturingScopes[node] = scope; | 441 closureData.capturingScopes[node] = scope; |
| 442 } | 442 } |
| 443 } | 443 } |
| 444 | 444 |
| 445 void inNewScope(Node node, Function action) { | 445 void inNewScope(Node node, Function action) { |
| 446 List<Element> oldScopeVariables = scopeVariables; | 446 List<Element> oldScopeVariables = scopeVariables; |
| 447 scopeVariables = new List<Element>(); | 447 scopeVariables = new List<Element>(); |
| 448 action(); | 448 action(); |
| 449 attachCapturedScopeVariables(node); | 449 attachCapturedScopeVariables(node); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 462 visitFor(For node) { | 462 visitFor(For node) { |
| 463 visitLoop(node); | 463 visitLoop(node); |
| 464 // See if we have declared loop variables that need to be boxed. | 464 // See if we have declared loop variables that need to be boxed. |
| 465 if (node.initializer == null) return; | 465 if (node.initializer == null) return; |
| 466 VariableDefinitions definitions = node.initializer.asVariableDefinitions(); | 466 VariableDefinitions definitions = node.initializer.asVariableDefinitions(); |
| 467 if (definitions == null) return; | 467 if (definitions == null) return; |
| 468 ClosureScope scopeData = closureData.capturingScopes[node]; | 468 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 469 if (scopeData == null) return; | 469 if (scopeData == null) return; |
| 470 List<Element> result = <Element>[]; | 470 List<Element> result = <Element>[]; |
| 471 for (Link<Node> link = definitions.definitions.nodes; | 471 for (Link<Node> link = definitions.definitions.nodes; |
| 472 !link.isEmpty(); | 472 !link.isEmpty; |
| 473 link = link.tail) { | 473 link = link.tail) { |
| 474 Node definition = link.head; | 474 Node definition = link.head; |
| 475 Element element = elements[definition]; | 475 Element element = elements[definition]; |
| 476 if (capturedVariableMapping.containsKey(element)) { | 476 if (capturedVariableMapping.containsKey(element)) { |
| 477 result.add(element); | 477 result.add(element); |
| 478 }; | 478 }; |
| 479 } | 479 } |
| 480 scopeData.boxedLoopVariables = result; | 480 scopeData.boxedLoopVariables = result; |
| 481 } | 481 } |
| 482 | 482 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 bool savedInsideClosure = insideClosure; | 580 bool savedInsideClosure = insideClosure; |
| 581 | 581 |
| 582 // Restore old values. | 582 // Restore old values. |
| 583 insideClosure = oldInsideClosure; | 583 insideClosure = oldInsideClosure; |
| 584 closureData = oldClosureData; | 584 closureData = oldClosureData; |
| 585 currentElement = oldFunctionElement; | 585 currentElement = oldFunctionElement; |
| 586 | 586 |
| 587 // Mark all free variables as captured and use them in the outer function. | 587 // Mark all free variables as captured and use them in the outer function. |
| 588 List<Element> freeVariables = | 588 List<Element> freeVariables = |
| 589 savedClosureData.freeVariableMapping.getKeys(); | 589 savedClosureData.freeVariableMapping.getKeys(); |
| 590 assert(freeVariables.isEmpty() || savedInsideClosure); | 590 assert(freeVariables.isEmpty || savedInsideClosure); |
| 591 for (Element freeElement in freeVariables) { | 591 for (Element freeElement in freeVariables) { |
| 592 if (capturedVariableMapping[freeElement] != null && | 592 if (capturedVariableMapping[freeElement] != null && |
| 593 capturedVariableMapping[freeElement] != freeElement) { | 593 capturedVariableMapping[freeElement] != freeElement) { |
| 594 compiler.internalError('In closure analyzer', node: node); | 594 compiler.internalError('In closure analyzer', node: node); |
| 595 } | 595 } |
| 596 capturedVariableMapping[freeElement] = freeElement; | 596 capturedVariableMapping[freeElement] = freeElement; |
| 597 useLocal(freeElement); | 597 useLocal(freeElement); |
| 598 } | 598 } |
| 599 } | 599 } |
| 600 | 600 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 624 } | 624 } |
| 625 | 625 |
| 626 visitTryStatement(TryStatement node) { | 626 visitTryStatement(TryStatement node) { |
| 627 // TODO(ngeoffray): implement finer grain state. | 627 // TODO(ngeoffray): implement finer grain state. |
| 628 bool oldInTryStatement = inTryStatement; | 628 bool oldInTryStatement = inTryStatement; |
| 629 inTryStatement = true; | 629 inTryStatement = true; |
| 630 node.visitChildren(this); | 630 node.visitChildren(this); |
| 631 inTryStatement = oldInTryStatement; | 631 inTryStatement = oldInTryStatement; |
| 632 } | 632 } |
| 633 } | 633 } |
| OLD | NEW |