| 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("leg.dart"); | 8 #import("leg.dart"); |
| 9 #import("scanner/scannerlib.dart"); | 9 #import("scanner/scannerlib.dart"); |
| 10 #import("tree/tree.dart"); | 10 #import("tree/tree.dart"); |
| 11 #import("util/util.dart"); | 11 #import("util/util.dart"); |
| 12 | 12 |
| 13 class ClosureTask extends CompilerTask { | 13 class ClosureTask extends CompilerTask { |
| 14 Map<Node, ClosureClassMap> closureMappingCache; | 14 Map<Node, ClosureClassMap> closureMappingCache; |
| 15 ClosureTask(Compiler compiler) | 15 ClosureTask(Compiler compiler) |
| 16 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 16 : closureMappingCache = new Map<Node, ClosureClassMap>(), |
| 17 super(compiler); | 17 super(compiler); |
| 18 | 18 |
| 19 String get name => "Closure Simplifier"; | 19 String get name => "Closure Simplifier"; |
| 20 | 20 |
| 21 ClosureClassMap computeClosureToClassMapping(FunctionExpression node, | 21 ClosureClassMap computeClosureToClassMapping(FunctionExpression node, |
| 22 TreeElements elements) { | 22 TreeElements elements) { |
| 23 return measure(() { | 23 return measure(() { |
| 24 ClosureClassMap cached = closureMappingCache[node]; | 24 ClosureClassMap cached = closureMappingCache[node]; |
| 25 if (cached !== null) return cached; | 25 if (cached !== null) return cached; |
| 26 | 26 |
| 27 ClosureTranslator translator = | 27 ClosureTranslator translator = |
| 28 new ClosureTranslator(compiler, elements, closureMappingCache); | 28 new ClosureTranslator(compiler, elements, closureMappingCache); |
| 29 // The translator will store the computed closure-mappings inside the | 29 // The translator will store the computed closure-mappings inside the |
| 30 // cache. One for given method and one for each nested closure. | 30 // cache. One for given method and one for each nested closure. |
| 31 translator.translate(node); | 31 translator.translate(node); |
| 32 assert(closureMappingCache[node] != null); | 32 assert(closureMappingCache[node] != null); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 134 |
| 135 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their | 135 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their |
| 136 // [ClosureScope] which contains their box and the | 136 // [ClosureScope] which contains their box and the |
| 137 // captured variables that are stored in the box. | 137 // captured variables that are stored in the box. |
| 138 // This map will be empty if the method/closure of this [ClosureData] does not | 138 // This map will be empty if the method/closure of this [ClosureData] does not |
| 139 // contain any nested closure. | 139 // contain any nested closure. |
| 140 final Map<Node, ClosureScope> capturingScopes; | 140 final Map<Node, ClosureScope> capturingScopes; |
| 141 | 141 |
| 142 final Set<Element> usedVariablesInTry; | 142 final Set<Element> usedVariablesInTry; |
| 143 | 143 |
| 144 // A map from the parameter element to the variable element that |
| 145 // holds the sentinel check. |
| 146 final Map<Element, Element> parametersWithSentinel; |
| 147 |
| 144 ClosureClassMap(this.closureElement, | 148 ClosureClassMap(this.closureElement, |
| 145 this.closureClassElement, | 149 this.closureClassElement, |
| 146 this.callElement, | 150 this.callElement, |
| 147 this.thisElement) | 151 this.thisElement) |
| 148 : this.freeVariableMapping = new Map<Element, Element>(), | 152 : this.freeVariableMapping = new Map<Element, Element>(), |
| 149 this.capturedFieldMapping = new Map<Element, Element>(), | 153 this.capturedFieldMapping = new Map<Element, Element>(), |
| 150 this.capturingScopes = new Map<Node, ClosureScope>(), | 154 this.capturingScopes = new Map<Node, ClosureScope>(), |
| 151 this.usedVariablesInTry = new Set<Element>(); | 155 this.usedVariablesInTry = new Set<Element>(), |
| 156 this.parametersWithSentinel = new Map<Element, Element>(); |
| 152 | 157 |
| 153 bool isClosure() => closureElement !== null; | 158 bool isClosure() => closureElement !== null; |
| 154 } | 159 } |
| 155 | 160 |
| 156 class ClosureTranslator extends AbstractVisitor { | 161 class ClosureTranslator extends AbstractVisitor { |
| 157 final Compiler compiler; | 162 final Compiler compiler; |
| 158 final TreeElements elements; | 163 final TreeElements elements; |
| 159 int closureFieldCounter = 0; | 164 int closureFieldCounter = 0; |
| 160 bool inTryStatement = false; | 165 bool inTryStatement = false; |
| 161 final Map<Node, ClosureClassMap> closureMappingCache; | 166 final Map<Node, ClosureClassMap> closureMappingCache; |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 | 310 |
| 306 visitSend(Send node) { | 311 visitSend(Send node) { |
| 307 Element element = elements[node]; | 312 Element element = elements[node]; |
| 308 if (Elements.isLocal(element)) { | 313 if (Elements.isLocal(element)) { |
| 309 useLocal(element); | 314 useLocal(element); |
| 310 } else if (node.receiver === null && | 315 } else if (node.receiver === null && |
| 311 Elements.isInstanceSend(node, elements)) { | 316 Elements.isInstanceSend(node, elements)) { |
| 312 useLocal(closureData.thisElement); | 317 useLocal(closureData.thisElement); |
| 313 } else if (node.isSuperCall) { | 318 } else if (node.isSuperCall) { |
| 314 useLocal(closureData.thisElement); | 319 useLocal(closureData.thisElement); |
| 320 } else if (node.isOperator |
| 321 && node.argumentsNode is Prefix |
| 322 && node.selector.source.stringValue == '?') { |
| 323 Element parameter = elements[node.receiver]; |
| 324 FunctionElement enclosing = parameter.enclosingElement; |
| 325 FunctionExpression function = enclosing.parseNode(compiler); |
| 326 ClosureClassMap cached = closureMappingCache[function]; |
| 327 if (!cached.parametersWithSentinel.containsKey(parameter)) { |
| 328 SourceString parameterName = parameter.name; |
| 329 String name = '${parameterName.slowToString()}_check'; |
| 330 Element newElement = new Element(new SourceString(name), |
| 331 ElementKind.VARIABLE, |
| 332 enclosing); |
| 333 useLocal(newElement); |
| 334 cached.parametersWithSentinel[parameter] = newElement; |
| 335 } |
| 315 } | 336 } |
| 316 node.visitChildren(this); | 337 node.visitChildren(this); |
| 317 } | 338 } |
| 318 | 339 |
| 319 visitSendSet(SendSet node) { | 340 visitSendSet(SendSet node) { |
| 320 Element element = elements[node]; | 341 Element element = elements[node]; |
| 321 if (Elements.isLocal(element)) { | 342 if (Elements.isLocal(element)) { |
| 322 mutatedVariables.add(element); | 343 mutatedVariables.add(element); |
| 323 } | 344 } |
| 324 super.visitSendSet(node); | 345 super.visitSendSet(node); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. | 492 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. |
| 472 Element thisEnclosingElement = element; | 493 Element thisEnclosingElement = element; |
| 473 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 494 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
| 474 ConstructorBodyElement body = element; | 495 ConstructorBodyElement body = element; |
| 475 thisEnclosingElement = body.constructor; | 496 thisEnclosingElement = body.constructor; |
| 476 } | 497 } |
| 477 thisElement = new ThisElement(thisEnclosingElement); | 498 thisElement = new ThisElement(thisEnclosingElement); |
| 478 } | 499 } |
| 479 closureData = new ClosureClassMap(null, null, null, thisElement); | 500 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 480 } | 501 } |
| 502 closureMappingCache[node] = closureData; |
| 481 | 503 |
| 482 inNewScope(node, () { | 504 inNewScope(node, () { |
| 483 // We have to declare the implicit 'this' parameter. | 505 // We have to declare the implicit 'this' parameter. |
| 484 if (!insideClosure && closureData.thisElement !== null) { | 506 if (!insideClosure && closureData.thisElement !== null) { |
| 485 declareLocal(closureData.thisElement); | 507 declareLocal(closureData.thisElement); |
| 486 } | 508 } |
| 487 // If we are inside a named closure we have to declare ourselve. For | 509 // If we are inside a named closure we have to declare ourselve. For |
| 488 // simplicity we declare the local even if the closure does not have a | 510 // simplicity we declare the local even if the closure does not have a |
| 489 // name. | 511 // name. |
| 490 // It will simply not be used. | 512 // It will simply not be used. |
| 491 if (insideClosure) { | 513 if (insideClosure) { |
| 492 declareLocal(element); | 514 declareLocal(element); |
| 493 } | 515 } |
| 494 | 516 |
| 495 // TODO(ahe): This is problematic. The backend should not repeat | 517 // TODO(ahe): This is problematic. The backend should not repeat |
| 496 // the work of the resolver. It is the resolver's job to create | 518 // the work of the resolver. It is the resolver's job to create |
| 497 // parameters, etc. Other phases should only visit statements. | 519 // parameters, etc. Other phases should only visit statements. |
| 498 // TODO(floitsch): we avoid visiting the initializers on purpose so that | 520 // TODO(floitsch): we avoid visiting the initializers on purpose so that |
| 499 // we get an error-message later in the builder. | 521 // we get an error-message later in the builder. |
| 500 if (node.parameters !== null) node.parameters.accept(this); | 522 if (node.parameters !== null) node.parameters.accept(this); |
| 501 if (node.body !== null) node.body.accept(this); | 523 if (node.body !== null) node.body.accept(this); |
| 502 }); | 524 }); |
| 503 | 525 |
| 504 closureMappingCache[node] = closureData; | |
| 505 | 526 |
| 506 ClosureClassMap savedClosureData = closureData; | 527 ClosureClassMap savedClosureData = closureData; |
| 507 bool savedInsideClosure = insideClosure; | 528 bool savedInsideClosure = insideClosure; |
| 508 | 529 |
| 509 // Restore old values. | 530 // Restore old values. |
| 510 insideClosure = oldInsideClosure; | 531 insideClosure = oldInsideClosure; |
| 511 closureData = oldClosureData; | 532 closureData = oldClosureData; |
| 512 currentFunctionElement = oldFunctionElement; | 533 currentFunctionElement = oldFunctionElement; |
| 513 | 534 |
| 514 // Mark all free variables as captured and use them in the outer function. | 535 // Mark all free variables as captured and use them in the outer function. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 531 } | 552 } |
| 532 | 553 |
| 533 visitTryStatement(TryStatement node) { | 554 visitTryStatement(TryStatement node) { |
| 534 // TODO(ngeoffray): implement finer grain state. | 555 // TODO(ngeoffray): implement finer grain state. |
| 535 bool oldInTryStatement = inTryStatement; | 556 bool oldInTryStatement = inTryStatement; |
| 536 inTryStatement = true; | 557 inTryStatement = true; |
| 537 node.visitChildren(this); | 558 node.visitChildren(this); |
| 538 inTryStatement = oldInTryStatement; | 559 inTryStatement = oldInTryStatement; |
| 539 } | 560 } |
| 540 } | 561 } |
| OLD | NEW |