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