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

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: Make this-capture work in the context of constructors. 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 assert(element !== null); 183 assert(element !== null);
181 declareLocal(element); 184 declareLocal(element);
182 } 185 }
183 // We still need to visit the right-hand sides of the init-assignments. 186 // We still need to visit the right-hand sides of the init-assignments.
184 // Simply visit all children. We will visit the locals again and make them 187 // Simply visit all children. We will visit the locals again and make them
185 // used, but that should not be a problem. 188 // used, but that should not be a problem.
186 node.visitChildren(this); 189 node.visitChildren(this);
187 } 190 }
188 191
189 visitIdentifier(Identifier node) { 192 visitIdentifier(Identifier node) {
190 // TODO(floitsch): handle 'this'. 193 if (node.isThis()) {
191 if (node.isThis() && insideClosure) { 194 useLocal(closureData.thisElement);
192 compiler.unimplemented("ClosureAnalyzer.visitIdentifier this-capture",
193 node: node);
194 } 195 }
195 node.visitChildren(this); 196 node.visitChildren(this);
196 } 197 }
197 198
198 visitSend(Send node) { 199 visitSend(Send node) {
199 Element element = elements[node]; 200 Element element = elements[node];
200 if (Elements.isLocal(element)) { 201 if (Elements.isLocal(element)) {
201 useLocal(element); 202 useLocal(element);
202 } else if (element === null && node.receiver === null) { 203 } else if (node.receiver === null &&
203 if (insideClosure) { 204 Elements.isInstanceSend(node, elements)) {
204 compiler.unimplemented("ClosureTranslator.visitSend this-capture"); 205 useLocal(closureData.thisElement);
205 }
206 } 206 }
207 node.visitChildren(this); 207 node.visitChildren(this);
208 } 208 }
209 209
210 // If variables that are declared in the [node] scope are captured and need 210 // If variables that are declared in the [node] scope are captured and need
211 // to be boxed create a box-element and update the [capturingScopes] in the 211 // to be boxed create a box-element and update the [capturingScopes] in the
212 // current [closureData]. 212 // current [closureData].
213 // The boxed variables are updated in the [capturedVariableMapping]. 213 // The boxed variables are updated in the [capturedVariableMapping].
214 void attachCapturedScopeVariables(Node node) { 214 void attachCapturedScopeVariables(Node node) {
215 Element box = null; 215 Element box = null;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 FunctionElement callElement = 256 FunctionElement callElement =
257 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, 257 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME,
258 element, 258 element,
259 globalizedElement); 259 globalizedElement);
260 globalizedElement.backendMembers = 260 globalizedElement.backendMembers =
261 const EmptyLink<Element>().prepend(callElement); 261 const EmptyLink<Element>().prepend(callElement);
262 globalizedElement.isResolved = true; 262 globalizedElement.isResolved = true;
263 ClassElement objectClass = 263 ClassElement objectClass =
264 compiler.coreLibrary.find(const SourceString('Object')); 264 compiler.coreLibrary.find(const SourceString('Object'));
265 globalizedElement.supertype = new SimpleType(Types.OBJECT, objectClass); 265 globalizedElement.supertype = new SimpleType(Types.OBJECT, objectClass);
266 return new ClosureData(globalizedElement, callElement); 266 // The nested function's 'this' is the same as the one for the outer
267 // function. It could be [null] if we are inside a static method.
268 Element thisElement = closureData.thisElement;
269 return new ClosureData(globalizedElement, callElement, thisElement);
267 } 270 }
268 271
269 visitFunctionExpression(FunctionExpression node) { 272 visitFunctionExpression(FunctionExpression node) {
273 FunctionElement element = elements[node];
270 bool isClosure = (closureData !== null); 274 bool isClosure = (closureData !== null);
271 275
272 if (isClosure) closures.add(node); 276 if (isClosure) closures.add(node);
273 277
274 bool oldInsideClosure = insideClosure; 278 bool oldInsideClosure = insideClosure;
275 FunctionElement oldFunctionElement = currentFunctionElement; 279 FunctionElement oldFunctionElement = currentFunctionElement;
276 ClosureData oldClosureData = closureData; 280 ClosureData oldClosureData = closureData;
277 List<Element> oldScopeVariables = scopeVariables; 281 List<Element> oldScopeVariables = scopeVariables;
278 282
279 283
280 insideClosure = isClosure; 284 insideClosure = isClosure;
281 currentFunctionElement = elements[node]; 285 currentFunctionElement = elements[node];
282 closureData = insideClosure ? 286 if (insideClosure) {
283 globalizeClosure(node) : 287 closureData = globalizeClosure(node);
284 new ClosureData(null, null); 288 } else {
289 Element thisElement = null;
290 // TODO(floitsch): we should not need to look for generative constructors.
291 // At the moment we store only one ClosureData for both the factory and
292 // the body.
293 if (element.isInstanceMember() ||
294 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
295 // TODO(floitsch): currently all variables are considered to be
296 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
297 Element thisEnclosingElement = element;
298 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
299 ConstructorBodyElement body = element;
300 thisEnclosingElement = body.constructor;
301 }
302 thisElement = new Element(const SourceString("this"),
303 ElementKind.PARAMETER,
304 thisEnclosingElement);
305 }
306 closureData = new ClosureData(null, null, thisElement);
307 }
285 scopeVariables = new List<Element>(); 308 scopeVariables = new List<Element>();
286 309
287 // TODO(floitsch): a named function is visible from inside itself. Add 310 // TODO(floitsch): a named function is visible from inside itself. Add
288 // the element to the block. 311 // the element to the block.
289 312
313 // We have to declare the implicit 'this' parameter.
314 if (!insideClosure && closureData.thisElement !== null) {
315 declareLocal(closureData.thisElement);
316 }
317
290 node.visitChildren(this); 318 node.visitChildren(this);
291 319
292 attachCapturedScopeVariables(node); 320 attachCapturedScopeVariables(node);
293 321
294 closureDataCache[node] = closureData; 322 closureDataCache[node] = closureData;
295 323
296 ClosureData savedClosureData = closureData; 324 ClosureData savedClosureData = closureData;
297 bool savedInsideClosure = insideClosure; 325 bool savedInsideClosure = insideClosure;
298 326
299 // Restore old values. 327 // Restore old values.
(...skipping 21 matching lines...) Expand all
321 } 349 }
322 } 350 }
323 351
324 visitTryStatement(TryStatement node) { 352 visitTryStatement(TryStatement node) {
325 // TODO(ngeoffray): implement finer grain state. 353 // TODO(ngeoffray): implement finer grain state.
326 inTryCatchOrFinally = true; 354 inTryCatchOrFinally = true;
327 node.visitChildren(this); 355 node.visitChildren(this);
328 inTryCatchOrFinally = false; 356 inTryCatchOrFinally = false;
329 } 357 }
330 } 358 }
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