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 // The box-element for a scope, and the captured variables that need to be | 15 // The box-element for a scope, and the captured variables that need to be |
16 // stored in the box. | 16 // stored in the box. |
17 class ClosureScope { | 17 class ClosureScope { |
18 Element boxElement; | 18 Element boxElement; |
19 Map<Element, Element> capturedVariableMapping; | 19 Map<Element, Element> capturedVariableMapping; |
20 | 20 |
21 ClosureScope(this.boxElement, this.capturedVariableMapping); | 21 ClosureScope(this.boxElement, this.capturedVariableMapping); |
22 } | 22 } |
23 | 23 |
24 class ClosureData { | 24 class ClosureData { |
25 // The globalizedClosureElement will be null for methods that are not local | 25 // The globalizedClosureElement will be null for methods that are not local |
26 // closures. | 26 // closures. |
27 final ClassElement globalizedClosureElement; | 27 final ClassElement globalizedClosureElement; |
28 // The callElement will be null for methods that are not local closures. | 28 // The callElement will be null for methods that are not local closures. |
29 final FunctionElement callElement; | 29 final FunctionElement callElement; |
30 // The [thisElement] makes handling 'this' easier by treating it like any | |
31 // other argument. It is only set for instance-members. | |
32 final Element thisElement; | |
30 | 33 |
31 // Maps free locals, arguments and function elements to their captured | 34 // Maps free locals, arguments and function elements to their captured |
32 // copies. | 35 // copies. |
33 final Map<Element, Element> freeVariableMapping; | 36 final Map<Element, Element> freeVariableMapping; |
34 // Maps closure-fields to their captured elements. This is somehow the inverse | 37 // Maps closure-fields to their captured elements. This is somehow the inverse |
35 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does | 38 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does |
36 // not deal with boxes, here we map instance-fields (which might represent | 39 // not deal with boxes, here we map instance-fields (which might represent |
37 // boxes) to their boxElement. | 40 // boxes) to their boxElement. |
38 final Map<Element, Element> capturedFieldMapping; | 41 final Map<Element, Element> capturedFieldMapping; |
39 | 42 |
40 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their | 43 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their |
41 // [ClosureScope] which contains their box and the | 44 // [ClosureScope] which contains their box and the |
42 // captured variables that are stored in the box. | 45 // captured variables that are stored in the box. |
43 // This map will be empty if the method/closure of this [ClosureData] does not | 46 // This map will be empty if the method/closure of this [ClosureData] does not |
44 // contain any nested closure. | 47 // contain any nested closure. |
45 final Map<Node, ClosureScope> capturingScopes; | 48 final Map<Node, ClosureScope> capturingScopes; |
46 | 49 |
47 final Set<Element> usedVariablesInTry; | 50 final Set<Element> usedVariablesInTry; |
48 | 51 |
49 ClosureData(this.globalizedClosureElement, this.callElement) | 52 ClosureData(this.globalizedClosureElement, this.callElement, this.thisElement) |
50 : this.freeVariableMapping = new Map<Element, Element>(), | 53 : this.freeVariableMapping = new Map<Element, Element>(), |
51 this.capturedFieldMapping = new Map<Element, Element>(), | 54 this.capturedFieldMapping = new Map<Element, Element>(), |
52 this.capturingScopes = new Map<Node, ClosureScope>(), | 55 this.capturingScopes = new Map<Node, ClosureScope>(), |
53 this.usedVariablesInTry = new Set<Element>(); | 56 this.usedVariablesInTry = new Set<Element>(); |
54 } | 57 } |
55 | 58 |
56 Map<Node, ClosureData> _closureDataCache; | 59 Map<Node, ClosureData> _closureDataCache; |
57 Map<Node, ClosureData> get closureDataCache() { | 60 Map<Node, ClosureData> get closureDataCache() { |
58 if (_closureDataCache === null) { | 61 if (_closureDataCache === null) { |
59 _closureDataCache = new HashMap<Node, ClosureData>(); | 62 _closureDataCache = new HashMap<Node, ClosureData>(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 assert(element !== null); | 177 assert(element !== null); |
175 declareLocal(element); | 178 declareLocal(element); |
176 } | 179 } |
177 // We still need to visit the right-hand sides of the init-assignments. | 180 // We still need to visit the right-hand sides of the init-assignments. |
178 // Simply visit all children. We will visit the locals again and make them | 181 // Simply visit all children. We will visit the locals again and make them |
179 // used, but that should not be a problem. | 182 // used, but that should not be a problem. |
180 node.visitChildren(this); | 183 node.visitChildren(this); |
181 } | 184 } |
182 | 185 |
183 visitIdentifier(Identifier node) { | 186 visitIdentifier(Identifier node) { |
184 // TODO(floitsch): handle 'this'. | 187 if (node.isThis()) { |
185 if (node.isThis() && insideClosure) { | 188 useLocal(closureData.thisElement); |
186 compiler.unimplemented("ClosureAnalyzer.visitIdentifier this-capture", | |
187 node: node); | |
188 } | 189 } |
189 node.visitChildren(this); | 190 node.visitChildren(this); |
190 } | 191 } |
191 | 192 |
192 visitSend(Send node) { | 193 visitSend(Send node) { |
193 Element element = elements[node]; | 194 Element element = elements[node]; |
194 if (Elements.isLocal(element)) { | 195 if (Elements.isLocal(element)) { |
195 useLocal(element); | 196 useLocal(element); |
196 } else if (element === null && node.receiver === null) { | 197 } else if (node.receiver === null && |
197 if (insideClosure) { | 198 Elements.isInstanceSend(node, elements)) { |
ngeoffray
2012/02/08 13:31:24
How about isThisSend in that case? It could also c
floitsch
2012/02/08 14:36:53
I prefer keeping it the way it is.
| |
198 compiler.unimplemented("ClosureTranslator.visitSend this-capture"); | 199 useLocal(closureData.thisElement); |
199 } | |
200 } | 200 } |
201 node.visitChildren(this); | 201 node.visitChildren(this); |
202 } | 202 } |
203 | 203 |
204 // If variables that are declared in the [node] scope are captured and need | 204 // If variables that are declared in the [node] scope are captured and need |
205 // to be boxed create a box-element and update the [capturingScopes] in the | 205 // to be boxed create a box-element and update the [capturingScopes] in the |
206 // current [closureData]. | 206 // current [closureData]. |
207 // The boxed variables are updated in the [capturedVariableMapping]. | 207 // The boxed variables are updated in the [capturedVariableMapping]. |
208 void attachCapturedScopeVariables(Node node) { | 208 void attachCapturedScopeVariables(Node node) { |
209 Element box = null; | 209 Element box = null; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 FunctionElement callElement = | 250 FunctionElement callElement = |
251 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, | 251 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, |
252 element, | 252 element, |
253 globalizedElement); | 253 globalizedElement); |
254 globalizedElement.backendMembers = | 254 globalizedElement.backendMembers = |
255 const EmptyLink<Element>().prepend(callElement); | 255 const EmptyLink<Element>().prepend(callElement); |
256 globalizedElement.isResolved = true; | 256 globalizedElement.isResolved = true; |
257 ClassElement objectClass = | 257 ClassElement objectClass = |
258 compiler.coreLibrary.find(const SourceString('Object')); | 258 compiler.coreLibrary.find(const SourceString('Object')); |
259 globalizedElement.supertype = new SimpleType(Types.OBJECT, objectClass); | 259 globalizedElement.supertype = new SimpleType(Types.OBJECT, objectClass); |
260 return new ClosureData(globalizedElement, callElement); | 260 // The nested function's 'this' is the same as the one for the outer |
261 // function. It could be [null] if we are inside a static method. | |
262 Element thisElement = closureData.thisElement; | |
263 return new ClosureData(globalizedElement, callElement, thisElement); | |
261 } | 264 } |
262 | 265 |
263 visitFunctionExpression(FunctionExpression node) { | 266 visitFunctionExpression(FunctionExpression node) { |
267 FunctionElement element = elements[node]; | |
264 bool isClosure = (closureData !== null); | 268 bool isClosure = (closureData !== null); |
265 | 269 |
266 if (isClosure) closures.add(node); | 270 if (isClosure) closures.add(node); |
267 | 271 |
268 bool oldInsideClosure = insideClosure; | 272 bool oldInsideClosure = insideClosure; |
269 FunctionElement oldFunctionElement = currentFunctionElement; | 273 FunctionElement oldFunctionElement = currentFunctionElement; |
270 ClosureData oldClosureData = closureData; | 274 ClosureData oldClosureData = closureData; |
271 List<Element> oldScopeVariables = scopeVariables; | 275 List<Element> oldScopeVariables = scopeVariables; |
272 | 276 |
273 | 277 |
274 insideClosure = isClosure; | 278 insideClosure = isClosure; |
275 currentFunctionElement = elements[node]; | 279 currentFunctionElement = elements[node]; |
276 closureData = insideClosure ? | 280 if (insideClosure) { |
277 globalizeClosure(node) : | 281 closureData = globalizeClosure(node); |
278 new ClosureData(null, null); | 282 } else { |
283 Element thisElement = null; | |
284 // TODO(floitsch): we should not need to look for generative constructors. | |
ngeoffray
2012/02/08 13:31:24
Improve comment?
floitsch
2012/02/08 14:36:53
Done.
| |
285 if (element.isInstanceMember() || | |
286 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
287 thisElement = new Element(const SourceString("this"), | |
288 ElementKind.PARAMETER, | |
289 element); | |
290 } | |
291 closureData = new ClosureData(null, null, thisElement); | |
292 } | |
279 scopeVariables = new List<Element>(); | 293 scopeVariables = new List<Element>(); |
280 | 294 |
281 // TODO(floitsch): a named function is visible from inside itself. Add | 295 // TODO(floitsch): a named function is visible from inside itself. Add |
282 // the element to the block. | 296 // the element to the block. |
283 | 297 |
298 // We have to declare the implicit 'this' parameter. | |
299 if (!insideClosure && closureData.thisElement !== null) { | |
300 declareLocal(closureData.thisElement); | |
301 } | |
302 | |
284 node.visitChildren(this); | 303 node.visitChildren(this); |
285 | 304 |
286 attachCapturedScopeVariables(node); | 305 attachCapturedScopeVariables(node); |
287 | 306 |
288 closureDataCache[node] = closureData; | 307 closureDataCache[node] = closureData; |
289 | 308 |
290 ClosureData savedClosureData = closureData; | 309 ClosureData savedClosureData = closureData; |
291 bool savedInsideClosure = insideClosure; | 310 bool savedInsideClosure = insideClosure; |
292 | 311 |
293 // Restore old values. | 312 // Restore old values. |
(...skipping 21 matching lines...) Expand all Loading... | |
315 } | 334 } |
316 } | 335 } |
317 | 336 |
318 visitTryStatement(TryStatement node) { | 337 visitTryStatement(TryStatement node) { |
319 // TODO(ngeoffray): implement finer grain state. | 338 // TODO(ngeoffray): implement finer grain state. |
320 inTryCatchOrFinally = true; | 339 inTryCatchOrFinally = true; |
321 node.visitChildren(this); | 340 node.visitChildren(this); |
322 inTryCatchOrFinally = false; | 341 inTryCatchOrFinally = false; |
323 } | 342 } |
324 } | 343 } |
OLD | NEW |