Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: frog/leg/ssa/closure.dart

Issue 9359011: Capture this. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed comments and fixed bug. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « frog/leg/ssa/builder.dart ('k') | frog/tests/leg_only/src/ClosureCapture3Test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « frog/leg/ssa/builder.dart ('k') | frog/tests/leg_only/src/ClosureCapture3Test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698