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 if (currentFunctionElement != enclosing) { | |
326 // If the parameter is from an outer function, we need to put | |
327 // the check in a field of the closure class. | |
328 FunctionExpression node = enclosing.parseNode(compiler); | |
329 ClosureClassMap cached = closureMappingCache[node]; | |
330 if (!cached.parametersWithSentinel.containsKey(parameter)) { | |
331 SourceString parameterName = parameter.name; | |
332 String name = '${parameterName.slowToString()}_check'; | |
kasperl
2012/09/04 10:50:08
Is it a problem if this conflicts with other param
ngeoffray
2012/09/04 10:53:44
No, the namer will disambiguate the elements.
| |
333 Element newElement = new Element(new SourceString(name), | |
334 ElementKind.VARIABLE, | |
335 enclosing); | |
336 useLocal(newElement); | |
337 cached.parametersWithSentinel[parameter] = newElement; | |
338 } | |
339 } | |
315 } | 340 } |
316 node.visitChildren(this); | 341 node.visitChildren(this); |
317 } | 342 } |
318 | 343 |
319 visitSendSet(SendSet node) { | 344 visitSendSet(SendSet node) { |
320 Element element = elements[node]; | 345 Element element = elements[node]; |
321 if (Elements.isLocal(element)) { | 346 if (Elements.isLocal(element)) { |
322 mutatedVariables.add(element); | 347 mutatedVariables.add(element); |
323 } | 348 } |
324 super.visitSendSet(node); | 349 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'. | 496 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. |
472 Element thisEnclosingElement = element; | 497 Element thisEnclosingElement = element; |
473 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 498 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
474 ConstructorBodyElement body = element; | 499 ConstructorBodyElement body = element; |
475 thisEnclosingElement = body.constructor; | 500 thisEnclosingElement = body.constructor; |
476 } | 501 } |
477 thisElement = new ThisElement(thisEnclosingElement); | 502 thisElement = new ThisElement(thisEnclosingElement); |
478 } | 503 } |
479 closureData = new ClosureClassMap(null, null, null, thisElement); | 504 closureData = new ClosureClassMap(null, null, null, thisElement); |
480 } | 505 } |
506 closureMappingCache[node] = closureData; | |
481 | 507 |
482 inNewScope(node, () { | 508 inNewScope(node, () { |
483 // We have to declare the implicit 'this' parameter. | 509 // We have to declare the implicit 'this' parameter. |
484 if (!insideClosure && closureData.thisElement !== null) { | 510 if (!insideClosure && closureData.thisElement !== null) { |
485 declareLocal(closureData.thisElement); | 511 declareLocal(closureData.thisElement); |
486 } | 512 } |
487 // If we are inside a named closure we have to declare ourselve. For | 513 // 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 | 514 // simplicity we declare the local even if the closure does not have a |
489 // name. | 515 // name. |
490 // It will simply not be used. | 516 // It will simply not be used. |
491 if (insideClosure) { | 517 if (insideClosure) { |
492 declareLocal(element); | 518 declareLocal(element); |
493 } | 519 } |
494 | 520 |
495 // TODO(ahe): This is problematic. The backend should not repeat | 521 // TODO(ahe): This is problematic. The backend should not repeat |
496 // the work of the resolver. It is the resolver's job to create | 522 // the work of the resolver. It is the resolver's job to create |
497 // parameters, etc. Other phases should only visit statements. | 523 // parameters, etc. Other phases should only visit statements. |
498 // TODO(floitsch): we avoid visiting the initializers on purpose so that | 524 // TODO(floitsch): we avoid visiting the initializers on purpose so that |
499 // we get an error-message later in the builder. | 525 // we get an error-message later in the builder. |
500 if (node.parameters !== null) node.parameters.accept(this); | 526 if (node.parameters !== null) node.parameters.accept(this); |
501 if (node.body !== null) node.body.accept(this); | 527 if (node.body !== null) node.body.accept(this); |
502 }); | 528 }); |
503 | 529 |
504 closureMappingCache[node] = closureData; | |
505 | 530 |
506 ClosureClassMap savedClosureData = closureData; | 531 ClosureClassMap savedClosureData = closureData; |
507 bool savedInsideClosure = insideClosure; | 532 bool savedInsideClosure = insideClosure; |
508 | 533 |
509 // Restore old values. | 534 // Restore old values. |
510 insideClosure = oldInsideClosure; | 535 insideClosure = oldInsideClosure; |
511 closureData = oldClosureData; | 536 closureData = oldClosureData; |
512 currentFunctionElement = oldFunctionElement; | 537 currentFunctionElement = oldFunctionElement; |
513 | 538 |
514 // Mark all free variables as captured and use them in the outer function. | 539 // Mark all free variables as captured and use them in the outer function. |
(...skipping 16 matching lines...) Expand all Loading... | |
531 } | 556 } |
532 | 557 |
533 visitTryStatement(TryStatement node) { | 558 visitTryStatement(TryStatement node) { |
534 // TODO(ngeoffray): implement finer grain state. | 559 // TODO(ngeoffray): implement finer grain state. |
535 bool oldInTryStatement = inTryStatement; | 560 bool oldInTryStatement = inTryStatement; |
536 inTryStatement = true; | 561 inTryStatement = true; |
537 node.visitChildren(this); | 562 node.visitChildren(this); |
538 inTryStatement = oldInTryStatement; | 563 inTryStatement = oldInTryStatement; |
539 } | 564 } |
540 } | 565 } |
OLD | NEW |