| 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; |
| 11 | 11 |
| 12 String toString() => "ClosureFieldElement($name)"; | 12 String toString() => "ClosureFieldElement($name)"; |
| 13 } | 13 } |
| 14 | 14 |
| 15 class ClosureClassElement extends ClassElement { | 15 class ClosureClassElement extends ClassElement { |
| 16 ClosureClassElement(Compiler compiler, Element enclosingElement) | 16 ClosureClassElement(Compiler compiler, Element enclosingElement) |
| 17 : super(compiler.closureClass.name, enclosingElement) { | 17 : super(compiler.closureClass.name, enclosingElement) { |
| 18 isResolved = true; | 18 isResolved = true; |
| 19 compiler.closureClass.ensureResolved(compiler); | 19 compiler.closureClass.ensureResolved(compiler); |
| 20 supertype = compiler.closureClass.computeType(compiler); | 20 supertype = compiler.closureClass.computeType(compiler); |
| 21 } | 21 } |
| 22 } | 22 } |
| 23 | 23 |
| 24 class BoxElement extends Element { |
| 25 BoxElement(SourceString name, Element enclosingElement) |
| 26 : super(name, ElementKind.VARIABLE, enclosingElement); |
| 27 } |
| 28 |
| 29 class ThisElement extends Element { |
| 30 ThisElement(Element enclosing) |
| 31 : super(const SourceString('this'), ElementKind.PARAMETER, enclosing); |
| 32 |
| 33 bool isAssignable() => false; |
| 34 } |
| 35 |
| 24 // The box-element for a scope, and the captured variables that need to be | 36 // The box-element for a scope, and the captured variables that need to be |
| 25 // stored in the box. | 37 // stored in the box. |
| 26 class ClosureScope { | 38 class ClosureScope { |
| 27 Element boxElement; | 39 Element boxElement; |
| 28 Map<Element, Element> capturedVariableMapping; | 40 Map<Element, Element> capturedVariableMapping; |
| 29 // If the scope is attached to a [For] contains the variables that are | 41 // If the scope is attached to a [For] contains the variables that are |
| 30 // declared in the initializer of the [For] and that need to be boxed. | 42 // declared in the initializer of the [For] and that need to be boxed. |
| 31 // Otherwise contains the empty List. | 43 // Otherwise contains the empty List. |
| 32 List<Element> boxedLoopVariables; | 44 List<Element> boxedLoopVariables; |
| 33 | 45 |
| 34 ClosureScope(this.boxElement, this.capturedVariableMapping) | 46 ClosureScope(this.boxElement, this.capturedVariableMapping) |
| 35 : boxedLoopVariables = const <Element>[]; | 47 : boxedLoopVariables = const <Element>[]; |
| 36 | 48 |
| 37 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); | 49 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); |
| 38 } | 50 } |
| 39 | 51 |
| 40 class ClosureData { | 52 class ClosureData { |
| 41 // The closure's element before any translation. Will be null for methods. | 53 // The closure's element before any translation. Will be null for methods. |
| 42 final FunctionElement closureElement; | 54 final FunctionElement closureElement; |
| 43 // The closureClassElement will be null for methods that are not local | 55 // The closureClassElement will be null for methods that are not local |
| 44 // closures. | 56 // closures. |
| 45 final ClassElement closureClassElement; | 57 final ClassElement closureClassElement; |
| 46 // The callElement will be null for methods that are not local closures. | 58 // The callElement will be null for methods that are not local closures. |
| 47 final FunctionElement callElement; | 59 final FunctionElement callElement; |
| 48 // The [thisElement] makes handling 'this' easier by treating it like any | 60 // The [thisElement] makes handling 'this' easier by treating it like any |
| 49 // other argument. It is only set for instance-members. | 61 // other argument. It is only set for instance-members. |
| 50 final Element thisElement; | 62 final ThisElement thisElement; |
| 51 | 63 |
| 52 // Maps free locals, arguments and function elements to their captured | 64 // Maps free locals, arguments and function elements to their captured |
| 53 // copies. | 65 // copies. |
| 54 final Map<Element, Element> freeVariableMapping; | 66 final Map<Element, Element> freeVariableMapping; |
| 55 // Maps closure-fields to their captured elements. This is somehow the inverse | 67 // Maps closure-fields to their captured elements. This is somehow the inverse |
| 56 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does | 68 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does |
| 57 // not deal with boxes, here we map instance-fields (which might represent | 69 // not deal with boxes, here we map instance-fields (which might represent |
| 58 // boxes) to their boxElement. | 70 // boxes) to their boxElement. |
| 59 final Map<Element, Element> capturedFieldMapping; | 71 final Map<Element, Element> capturedFieldMapping; |
| 60 | 72 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 75 this.capturedFieldMapping = new Map<Element, Element>(), | 87 this.capturedFieldMapping = new Map<Element, Element>(), |
| 76 this.capturingScopes = new Map<Node, ClosureScope>(), | 88 this.capturingScopes = new Map<Node, ClosureScope>(), |
| 77 this.usedVariablesInTry = new Set<Element>(); | 89 this.usedVariablesInTry = new Set<Element>(); |
| 78 | 90 |
| 79 bool isClosure() => closureElement !== null; | 91 bool isClosure() => closureElement !== null; |
| 80 } | 92 } |
| 81 | 93 |
| 82 class ClosureTranslator extends AbstractVisitor { | 94 class ClosureTranslator extends AbstractVisitor { |
| 83 final Compiler compiler; | 95 final Compiler compiler; |
| 84 final TreeElements elements; | 96 final TreeElements elements; |
| 85 int boxCounter = 0; | 97 int closureFieldCounter = 0; |
| 86 bool inTryCatchOrFinally = false; | 98 bool inTryCatchOrFinally = false; |
| 87 final Map<Node, ClosureData> closureDataCache; | 99 final Map<Node, ClosureData> closureDataCache; |
| 88 | 100 |
| 89 // Map of captured variables. Initially they will map to themselves. If | 101 // Map of captured variables. Initially they will map to themselves. If |
| 90 // a variable needs to be boxed then the scope declaring the variable | 102 // a variable needs to be boxed then the scope declaring the variable |
| 91 // will update this mapping. | 103 // will update this mapping. |
| 92 Map<Element, Element> capturedVariableMapping; | 104 Map<Element, Element> capturedVariableMapping; |
| 93 // List of encountered closures. | 105 // List of encountered closures. |
| 94 List<FunctionExpression> closures; | 106 List<FunctionExpression> closures; |
| 95 | 107 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 } else { | 161 } else { |
| 150 // A boxed element. | 162 // A boxed element. |
| 151 freeVariableMapping[fromElement] = updatedElement; | 163 freeVariableMapping[fromElement] = updatedElement; |
| 152 Element boxElement = updatedElement.enclosingElement; | 164 Element boxElement = updatedElement.enclosingElement; |
| 153 assert(boxElement.kind == ElementKind.VARIABLE); | 165 assert(boxElement.kind == ElementKind.VARIABLE); |
| 154 fieldCaptures.add(boxElement); | 166 fieldCaptures.add(boxElement); |
| 155 } | 167 } |
| 156 }); | 168 }); |
| 157 ClassElement closureElement = data.closureClassElement; | 169 ClassElement closureElement = data.closureClassElement; |
| 158 assert(closureElement != null || fieldCaptures.isEmpty()); | 170 assert(closureElement != null || fieldCaptures.isEmpty()); |
| 159 for (Element boxElement in fieldCaptures) { | 171 for (Element capturedElement in fieldCaptures) { |
| 160 Element fieldElement = | 172 SourceString name; |
| 161 new ClosureFieldElement(boxElement.name, closureElement); | 173 if (capturedElement is BoxElement) { |
| 174 // The name is already mangled. |
| 175 name = capturedElement.name; |
| 176 } else { |
| 177 int id = closureFieldCounter++; |
| 178 name = new SourceString("${capturedElement.name.slowToString()}_$id"); |
| 179 } |
| 180 Element fieldElement = new ClosureFieldElement(name, closureElement); |
| 162 closureElement.backendMembers = | 181 closureElement.backendMembers = |
| 163 closureElement.backendMembers.prepend(fieldElement); | 182 closureElement.backendMembers.prepend(fieldElement); |
| 164 data.capturedFieldMapping[fieldElement] = boxElement; | 183 data.capturedFieldMapping[fieldElement] = capturedElement; |
| 165 freeVariableMapping[boxElement] = fieldElement; | 184 freeVariableMapping[capturedElement] = fieldElement; |
| 166 } | 185 } |
| 167 } | 186 } |
| 168 } | 187 } |
| 169 | 188 |
| 170 void useLocal(Element element) { | 189 void useLocal(Element element) { |
| 171 // TODO(floitsch): replace this with a general solution. | 190 // TODO(floitsch): replace this with a general solution. |
| 172 Element functionElement = currentFunctionElement; | 191 Element functionElement = currentFunctionElement; |
| 173 if (functionElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 192 if (functionElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
| 174 ConstructorBodyElement body = functionElement; | 193 ConstructorBodyElement body = functionElement; |
| 175 functionElement = body.constructor; | 194 functionElement = body.constructor; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 } | 252 } |
| 234 | 253 |
| 235 // If variables that are declared in the [node] scope are captured and need | 254 // If variables that are declared in the [node] scope are captured and need |
| 236 // to be boxed create a box-element and update the [capturingScopes] in the | 255 // to be boxed create a box-element and update the [capturingScopes] in the |
| 237 // current [closureData]. | 256 // current [closureData]. |
| 238 // The boxed variables are updated in the [capturedVariableMapping]. | 257 // The boxed variables are updated in the [capturedVariableMapping]. |
| 239 void attachCapturedScopeVariables(Node node) { | 258 void attachCapturedScopeVariables(Node node) { |
| 240 Element box = null; | 259 Element box = null; |
| 241 Map<Element, Element> scopeMapping = new Map<Element, Element>(); | 260 Map<Element, Element> scopeMapping = new Map<Element, Element>(); |
| 242 for (Element element in scopeVariables) { | 261 for (Element element in scopeVariables) { |
| 262 // No need to box non-assignable elements. |
| 263 if (!element.isAssignable()) continue; |
| 243 if (capturedVariableMapping.containsKey(element)) { | 264 if (capturedVariableMapping.containsKey(element)) { |
| 244 if (box == null) { | 265 if (box == null) { |
| 245 // TODO(floitsch): construct better box names. | 266 // TODO(floitsch): construct better box names. |
| 246 SourceString boxName = new SourceString("box${boxCounter++}"); | 267 SourceString boxName = |
| 247 box = new Element(boxName, | 268 new SourceString("box_${closureFieldCounter++}"); |
| 248 ElementKind.VARIABLE, | 269 box = new BoxElement(boxName, currentFunctionElement); |
| 249 currentFunctionElement); | |
| 250 } | 270 } |
| 251 // TODO(floitsch): construct better boxed names. | 271 // TODO(floitsch): construct better boxed names. |
| 252 String elementName = element.name.slowToString(); | 272 String elementName = element.name.slowToString(); |
| 253 // We are currently using the name in an HForeign which could replace | 273 // We are currently using the name in an HForeign which could replace |
| 254 // "$X" with something else. | 274 // "$X" with something else. |
| 255 String escaped = elementName.replaceAll("\$", "_"); | 275 String escaped = elementName.replaceAll("\$", "_"); |
| 256 SourceString boxedName = new SourceString("${escaped}_${boxCounter++}"); | 276 SourceString boxedName = |
| 277 new SourceString("${escaped}_${closureFieldCounter++}"); |
| 257 Element boxed = new Element(boxedName, ElementKind.FIELD, box); | 278 Element boxed = new Element(boxedName, ElementKind.FIELD, box); |
| 258 scopeMapping[element] = boxed; | 279 scopeMapping[element] = boxed; |
| 259 capturedVariableMapping[element] = boxed; | 280 capturedVariableMapping[element] = boxed; |
| 260 } | 281 } |
| 261 } | 282 } |
| 262 if (!scopeMapping.isEmpty()) { | 283 if (!scopeMapping.isEmpty()) { |
| 263 ClosureScope scope = new ClosureScope(box, scopeMapping); | 284 ClosureScope scope = new ClosureScope(box, scopeMapping); |
| 264 closureData.capturingScopes[node] = scope; | 285 closureData.capturingScopes[node] = scope; |
| 265 } | 286 } |
| 266 } | 287 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 // the body. | 360 // the body. |
| 340 if (element.isInstanceMember() || | 361 if (element.isInstanceMember() || |
| 341 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 362 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 342 // TODO(floitsch): currently all variables are considered to be | 363 // TODO(floitsch): currently all variables are considered to be |
| 343 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. | 364 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. |
| 344 Element thisEnclosingElement = element; | 365 Element thisEnclosingElement = element; |
| 345 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 366 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
| 346 ConstructorBodyElement body = element; | 367 ConstructorBodyElement body = element; |
| 347 thisEnclosingElement = body.constructor; | 368 thisEnclosingElement = body.constructor; |
| 348 } | 369 } |
| 349 thisElement = new Element(const SourceString("this"), | 370 thisElement = new ThisElement(thisEnclosingElement); |
| 350 ElementKind.PARAMETER, | |
| 351 thisEnclosingElement); | |
| 352 } | 371 } |
| 353 closureData = new ClosureData(null, null, null, thisElement); | 372 closureData = new ClosureData(null, null, null, thisElement); |
| 354 } | 373 } |
| 355 scopeVariables = new List<Element>(); | 374 scopeVariables = new List<Element>(); |
| 356 | 375 |
| 357 // TODO(floitsch): a named function is visible from inside itself. Add | |
| 358 // the element to the block. | |
| 359 | |
| 360 // We have to declare the implicit 'this' parameter. | 376 // We have to declare the implicit 'this' parameter. |
| 361 if (!insideClosure && closureData.thisElement !== null) { | 377 if (!insideClosure && closureData.thisElement !== null) { |
| 362 declareLocal(closureData.thisElement); | 378 declareLocal(closureData.thisElement); |
| 363 } | 379 } |
| 364 // If we are inside a named closure we have to declare ourselve. For | 380 // If we are inside a named closure we have to declare ourselve. For |
| 365 // simplicity we declare the local even if the closure does not have a name | 381 // simplicity we declare the local even if the closure does not have a name |
| 366 // It will simply not be used. | 382 // It will simply not be used. |
| 367 if (insideClosure) { | 383 if (insideClosure) { |
| 368 declareLocal(element); | 384 declareLocal(element); |
| 369 } | 385 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 declareLocal(elements[node]); | 424 declareLocal(elements[node]); |
| 409 } | 425 } |
| 410 | 426 |
| 411 visitTryStatement(TryStatement node) { | 427 visitTryStatement(TryStatement node) { |
| 412 // TODO(ngeoffray): implement finer grain state. | 428 // TODO(ngeoffray): implement finer grain state. |
| 413 inTryCatchOrFinally = true; | 429 inTryCatchOrFinally = true; |
| 414 node.visitChildren(this); | 430 node.visitChildren(this); |
| 415 inTryCatchOrFinally = false; | 431 inTryCatchOrFinally = false; |
| 416 } | 432 } |
| 417 } | 433 } |
| OLD | NEW |