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 |