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

Side by Side Diff: lib/compiler/implementation/closure.dart

Issue 10855146: Make the closure-to-class translator more accessible. It can now be (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments Created 8 years, 4 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 | « no previous file | lib/compiler/implementation/compiler.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 #library("closureToClassMapper");
6
7 #import("elements/elements.dart");
8 #import("leg.dart");
9 #import("scanner/scannerlib.dart");
10 #import("tree/tree.dart");
11 #import("util/util.dart");
12
13 class ClosureTask extends CompilerTask {
14 Map<Node, ClosureClassMap> closureMappingCache;
15 ClosureTask(Compiler compiler)
16 : closureMappingCache = new Map<Node, ClosureClassMap>(),
17 super(compiler);
18
19 String get name() => "Closure Simplifier";
20
21 ClosureClassMap computeClosureToClassMapping(FunctionExpression node,
22 TreeElements elements) {
23 return measure(() {
24 ClosureClassMap cached = closureMappingCache[node];
25 if (cached !== null) return cached;
26
27 ClosureTranslator translator =
28 new ClosureTranslator(compiler, elements, closureMappingCache);
29 // The translator will store the computed closure-mappings inside the
30 // cache. One for given method and one for each nested closure.
31 translator.translate(node);
32 assert(closureMappingCache[node] != null);
33 return closureMappingCache[node];
34 });
35 }
36
37 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) {
38 return measure(() {
39 ClosureClassMap nestedClosureData = closureMappingCache[node];
40 if (nestedClosureData === null) {
41 // TODO(floitsch): we can only assume that the reason for not having a
42 // closure data here is, because the function is inside an initializer.
43 compiler.unimplemented("Closures inside initializers", node: node);
44 }
45 return nestedClosureData;
46 });
47 }
48 }
49
5 class ClosureFieldElement extends Element { 50 class ClosureFieldElement extends Element {
6 ClosureFieldElement(SourceString name, ClassElement enclosing) 51 ClosureFieldElement(SourceString name, ClassElement enclosing)
7 : super(name, ElementKind.FIELD, enclosing); 52 : super(name, ElementKind.FIELD, enclosing);
8 53
9 bool isInstanceMember() => true; 54 bool isInstanceMember() => true;
10 bool isAssignable() => false; 55 bool isAssignable() => false;
11 56
12 String toString() => "ClosureFieldElement($name)"; 57 String toString() => "ClosureFieldElement($name)";
13 } 58 }
14 59
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 // declared in the initializer of the [For] and that need to be boxed. 102 // declared in the initializer of the [For] and that need to be boxed.
58 // Otherwise contains the empty List. 103 // Otherwise contains the empty List.
59 List<Element> boxedLoopVariables; 104 List<Element> boxedLoopVariables;
60 105
61 ClosureScope(this.boxElement, this.capturedVariableMapping) 106 ClosureScope(this.boxElement, this.capturedVariableMapping)
62 : boxedLoopVariables = const <Element>[]; 107 : boxedLoopVariables = const <Element>[];
63 108
64 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); 109 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty();
65 } 110 }
66 111
67 class ClosureData { 112 class ClosureClassMap {
68 // The closure's element before any translation. Will be null for methods. 113 // The closure's element before any translation. Will be null for methods.
69 final FunctionElement closureElement; 114 final FunctionElement closureElement;
70 // The closureClassElement will be null for methods that are not local 115 // The closureClassElement will be null for methods that are not local
71 // closures. 116 // closures.
72 final ClassElement closureClassElement; 117 final ClassElement closureClassElement;
73 // The callElement will be null for methods that are not local closures. 118 // The callElement will be null for methods that are not local closures.
74 final FunctionElement callElement; 119 final FunctionElement callElement;
75 // The [thisElement] makes handling 'this' easier by treating it like any 120 // The [thisElement] makes handling 'this' easier by treating it like any
76 // other argument. It is only set for instance-members. 121 // other argument. It is only set for instance-members.
77 final ThisElement thisElement; 122 final ThisElement thisElement;
78 123
79 // Maps free locals, arguments and function elements to their captured 124 // Maps free locals, arguments and function elements to their captured
80 // copies. 125 // copies.
81 final Map<Element, Element> freeVariableMapping; 126 final Map<Element, Element> freeVariableMapping;
82 // Maps closure-fields to their captured elements. This is somehow the inverse 127 // Maps closure-fields to their captured elements. This is somehow the inverse
83 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does 128 // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does
84 // not deal with boxes, here we map instance-fields (which might represent 129 // not deal with boxes, here we map instance-fields (which might represent
85 // boxes) to their boxElement. 130 // boxes) to their boxElement.
86 final Map<Element, Element> capturedFieldMapping; 131 final Map<Element, Element> capturedFieldMapping;
87 132
88 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their 133 // Maps scopes ([Loop] and [FunctionExpression] nodes) to their
89 // [ClosureScope] which contains their box and the 134 // [ClosureScope] which contains their box and the
90 // captured variables that are stored in the box. 135 // captured variables that are stored in the box.
91 // This map will be empty if the method/closure of this [ClosureData] does not 136 // This map will be empty if the method/closure of this [ClosureData] does not
92 // contain any nested closure. 137 // contain any nested closure.
93 final Map<Node, ClosureScope> capturingScopes; 138 final Map<Node, ClosureScope> capturingScopes;
94 139
95 final Set<Element> usedVariablesInTry; 140 final Set<Element> usedVariablesInTry;
96 141
97 ClosureData(this.closureElement, 142 ClosureClassMap(this.closureElement,
98 this.closureClassElement, 143 this.closureClassElement,
99 this.callElement, 144 this.callElement,
100 this.thisElement) 145 this.thisElement)
101 : this.freeVariableMapping = new Map<Element, Element>(), 146 : this.freeVariableMapping = new Map<Element, Element>(),
102 this.capturedFieldMapping = new Map<Element, Element>(), 147 this.capturedFieldMapping = new Map<Element, Element>(),
103 this.capturingScopes = new Map<Node, ClosureScope>(), 148 this.capturingScopes = new Map<Node, ClosureScope>(),
104 this.usedVariablesInTry = new Set<Element>(); 149 this.usedVariablesInTry = new Set<Element>();
105 150
106 bool isClosure() => closureElement !== null; 151 bool isClosure() => closureElement !== null;
107 } 152 }
108 153
109 class ClosureTranslator extends AbstractVisitor { 154 class ClosureTranslator extends AbstractVisitor {
110 final SsaBuilder builder; 155 final Compiler compiler;
111 final TreeElements elements; 156 final TreeElements elements;
112 int closureFieldCounter = 0; 157 int closureFieldCounter = 0;
113 bool inTryStatement = false; 158 bool inTryStatement = false;
114 final Map<Node, ClosureData> closureDataCache; 159 final Map<Node, ClosureClassMap> closureMappingCache;
115 160
116 // Map of captured variables. Initially they will map to themselves. If 161 // Map of captured variables. Initially they will map to themselves. If
117 // a variable needs to be boxed then the scope declaring the variable 162 // a variable needs to be boxed then the scope declaring the variable
118 // will update this mapping. 163 // will update this mapping.
119 Map<Element, Element> capturedVariableMapping; 164 Map<Element, Element> capturedVariableMapping;
120 // List of encountered closures. 165 // List of encountered closures.
121 List<FunctionExpression> closures; 166 List<FunctionExpression> closures;
122 167
123 // The variables that have been declared in the current scope. 168 // The variables that have been declared in the current scope.
124 List<Element> scopeVariables; 169 List<Element> scopeVariables;
125 170
126 // Keep track of the mutated variables so that we don't need to box 171 // Keep track of the mutated variables so that we don't need to box
127 // non-mutated variables. 172 // non-mutated variables.
128 Set<Element> mutatedVariables; 173 Set<Element> mutatedVariables;
129 174
130 FunctionElement currentFunctionElement; 175 FunctionElement currentFunctionElement;
131 // The closureData of the currentFunctionElement. 176 // The closureData of the currentFunctionElement.
132 ClosureData closureData; 177 ClosureClassMap closureData;
133 178
134 bool insideClosure = false; 179 bool insideClosure = false;
135 180
136 Compiler get compiler() => builder.compiler; 181 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache)
182 : capturedVariableMapping = new Map<Element, Element>(),
183 closures = <FunctionExpression>[],
184 mutatedVariables = new Set<Element>();
137 185
138 ClosureTranslator(SsaBuilder builder) 186 void translate(Node node) {
139 : this.builder = builder,
140 this.elements = builder.elements,
141 capturedVariableMapping = new Map<Element, Element>(),
142 closures = <FunctionExpression>[],
143 mutatedVariables = new Set<Element>(),
144 this.closureDataCache = builder.builder.closureDataCache;
145
146 ClosureData translate(Node node) {
147 // Closures have already been analyzed when visiting the surrounding
148 // method/function. This also shortcuts for bailout functions.
149 ClosureData cached = closureDataCache[node];
150 if (cached !== null) return cached;
151
152 visit(node); 187 visit(node);
153 // When variables need to be boxed their [capturedVariableMapping] is 188 // When variables need to be boxed their [capturedVariableMapping] is
154 // updated, but we delay updating the similar freeVariableMapping in the 189 // updated, but we delay updating the similar freeVariableMapping in the
155 // closure datas that capture these variables. 190 // closure datas that capture these variables.
156 // The closures don't have their fields (in the closure class) set, either. 191 // The closures don't have their fields (in the closure class) set, either.
157 updateClosures(); 192 updateClosures();
158
159 return closureDataCache[node];
160 } 193 }
161 194
162 // This function runs through all of the existing closures and updates their 195 // This function runs through all of the existing closures and updates their
163 // free variables to the boxed value. It also adds the field-elements to the 196 // free variables to the boxed value. It also adds the field-elements to the
164 // class representing the closure. At the same time it fills the 197 // class representing the closure. At the same time it fills the
165 // [capturedFieldMapping]. 198 // [capturedFieldMapping].
166 void updateClosures() { 199 void updateClosures() {
167 for (FunctionExpression closure in closures) { 200 for (FunctionExpression closure in closures) {
168 // The captured variables that need to be stored in a field of the closure 201 // The captured variables that need to be stored in a field of the closure
169 // class. 202 // class.
170 Set<Element> fieldCaptures = new Set<Element>(); 203 Set<Element> fieldCaptures = new Set<Element>();
171 ClosureData data = closureDataCache[closure]; 204 ClosureClassMap data = closureMappingCache[closure];
172 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; 205 Map<Element, Element> freeVariableMapping = data.freeVariableMapping;
173 // We get a copy of the keys and iterate over it, to avoid modifications 206 // We get a copy of the keys and iterate over it, to avoid modifications
174 // to the map while iterating over it. 207 // to the map while iterating over it.
175 freeVariableMapping.getKeys().forEach((Element fromElement) { 208 freeVariableMapping.getKeys().forEach((Element fromElement) {
176 assert(fromElement == freeVariableMapping[fromElement]); 209 assert(fromElement == freeVariableMapping[fromElement]);
177 Element updatedElement = capturedVariableMapping[fromElement]; 210 Element updatedElement = capturedVariableMapping[fromElement];
178 assert(updatedElement !== null); 211 assert(updatedElement !== null);
179 if (fromElement == updatedElement) { 212 if (fromElement == updatedElement) {
180 assert(freeVariableMapping[fromElement] == updatedElement); 213 assert(freeVariableMapping[fromElement] == updatedElement);
181 assert(Elements.isLocal(updatedElement)); 214 assert(Elements.isLocal(updatedElement));
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 link = link.tail) { 389 link = link.tail) {
357 Node definition = link.head; 390 Node definition = link.head;
358 Element element = elements[definition]; 391 Element element = elements[definition];
359 if (capturedVariableMapping.containsKey(element)) { 392 if (capturedVariableMapping.containsKey(element)) {
360 result.add(element); 393 result.add(element);
361 }; 394 };
362 } 395 }
363 scopeData.boxedLoopVariables = result; 396 scopeData.boxedLoopVariables = result;
364 } 397 }
365 398
366 ClosureData globalizeClosure(FunctionExpression node, Element element) { 399 ClosureClassMap globalizeClosure(FunctionExpression node, Element element) {
367 SourceString closureName = 400 SourceString closureName =
368 new SourceString(compiler.namer.closureName(element)); 401 new SourceString(compiler.namer.closureName(element));
369 ClassElement globalizedElement = new ClosureClassElement( 402 ClassElement globalizedElement = new ClosureClassElement(
370 closureName, compiler, element.getCompilationUnit()); 403 closureName, compiler, element.getCompilationUnit());
371 FunctionElement callElement = 404 FunctionElement callElement =
372 new FunctionElement.from(compiler.namer.CLOSURE_INVOCATION_NAME, 405 new FunctionElement.from(compiler.namer.CLOSURE_INVOCATION_NAME,
373 element, 406 element,
374 globalizedElement); 407 globalizedElement);
375 globalizedElement.backendMembers = 408 globalizedElement.backendMembers =
376 const EmptyLink<Element>().prepend(callElement); 409 const EmptyLink<Element>().prepend(callElement);
377 // The nested function's 'this' is the same as the one for the outer 410 // The nested function's 'this' is the same as the one for the outer
378 // function. It could be [null] if we are inside a static method. 411 // function. It could be [null] if we are inside a static method.
379 Element thisElement = closureData.thisElement; 412 Element thisElement = closureData.thisElement;
380 return new ClosureData(element, globalizedElement, 413 return new ClosureClassMap(element, globalizedElement,
381 callElement, thisElement); 414 callElement, thisElement);
382 } 415 }
383 416
384 visitFunctionExpression(FunctionExpression node) { 417 visitFunctionExpression(FunctionExpression node) {
385 Element element = elements[node]; 418 Element element = elements[node];
386 if (element.kind === ElementKind.PARAMETER) { 419 if (element.kind === ElementKind.PARAMETER) {
387 // TODO(ahe): This is a hack. This method should *not* call 420 // TODO(ahe): This is a hack. This method should *not* call
388 // visitChildren. 421 // visitChildren.
389 return node.name.accept(this); 422 return node.name.accept(this);
390 } 423 }
391 bool isClosure = (closureData !== null); 424 bool isClosure = (closureData !== null);
392 425
393 if (isClosure) closures.add(node); 426 if (isClosure) closures.add(node);
394 427
395 bool oldInsideClosure = insideClosure; 428 bool oldInsideClosure = insideClosure;
396 FunctionElement oldFunctionElement = currentFunctionElement; 429 FunctionElement oldFunctionElement = currentFunctionElement;
397 ClosureData oldClosureData = closureData; 430 ClosureClassMap oldClosureData = closureData;
398 431
399 insideClosure = isClosure; 432 insideClosure = isClosure;
400 currentFunctionElement = elements[node]; 433 currentFunctionElement = elements[node];
401 if (insideClosure) { 434 if (insideClosure) {
402 closureData = globalizeClosure(node, element); 435 closureData = globalizeClosure(node, element);
403 } else { 436 } else {
404 Element thisElement = null; 437 Element thisElement = null;
405 // TODO(floitsch): we should not need to look for generative constructors. 438 // TODO(floitsch): we should not need to look for generative constructors.
406 // At the moment we store only one ClosureData for both the factory and 439 // At the moment we store only one ClosureData for both the factory and
407 // the body. 440 // the body.
408 if (element.isInstanceMember() || 441 if (element.isInstanceMember() ||
409 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { 442 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
410 // TODO(floitsch): currently all variables are considered to be 443 // TODO(floitsch): currently all variables are considered to be
411 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. 444 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
412 Element thisEnclosingElement = element; 445 Element thisEnclosingElement = element;
413 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { 446 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
414 ConstructorBodyElement body = element; 447 ConstructorBodyElement body = element;
415 thisEnclosingElement = body.constructor; 448 thisEnclosingElement = body.constructor;
416 } 449 }
417 thisElement = new ThisElement(thisEnclosingElement); 450 thisElement = new ThisElement(thisEnclosingElement);
418 } 451 }
419 closureData = new ClosureData(null, null, null, thisElement); 452 closureData = new ClosureClassMap(null, null, null, thisElement);
420 } 453 }
421 454
422 inNewScope(node, () { 455 inNewScope(node, () {
423 // We have to declare the implicit 'this' parameter. 456 // We have to declare the implicit 'this' parameter.
424 if (!insideClosure && closureData.thisElement !== null) { 457 if (!insideClosure && closureData.thisElement !== null) {
425 declareLocal(closureData.thisElement); 458 declareLocal(closureData.thisElement);
426 } 459 }
427 // If we are inside a named closure we have to declare ourselve. For 460 // If we are inside a named closure we have to declare ourselve. For
428 // simplicity we declare the local even if the closure does not have a 461 // simplicity we declare the local even if the closure does not have a
429 // name. 462 // name.
430 // It will simply not be used. 463 // It will simply not be used.
431 if (insideClosure) { 464 if (insideClosure) {
432 declareLocal(element); 465 declareLocal(element);
433 } 466 }
434 467
435 // TODO(ahe): This is problematic. The backend should not repeat 468 // TODO(ahe): This is problematic. The backend should not repeat
436 // the work of the resolver. It is the resolver's job to create 469 // the work of the resolver. It is the resolver's job to create
437 // parameters, etc. Other phases should only visit statements. 470 // parameters, etc. Other phases should only visit statements.
438 // TODO(floitsch): we avoid visiting the initializers on purpose so that 471 // TODO(floitsch): we avoid visiting the initializers on purpose so that
439 // we get an error-message later in the builder. 472 // we get an error-message later in the builder.
440 if (node.parameters !== null) node.parameters.accept(this); 473 if (node.parameters !== null) node.parameters.accept(this);
441 if (node.body !== null) node.body.accept(this); 474 if (node.body !== null) node.body.accept(this);
442 }); 475 });
443 476
444 closureDataCache[node] = closureData; 477 closureMappingCache[node] = closureData;
445 478
446 ClosureData savedClosureData = closureData; 479 ClosureClassMap savedClosureData = closureData;
447 bool savedInsideClosure = insideClosure; 480 bool savedInsideClosure = insideClosure;
448 481
449 // Restore old values. 482 // Restore old values.
450 insideClosure = oldInsideClosure; 483 insideClosure = oldInsideClosure;
451 closureData = oldClosureData; 484 closureData = oldClosureData;
452 currentFunctionElement = oldFunctionElement; 485 currentFunctionElement = oldFunctionElement;
453 486
454 // Mark all free variables as captured and use them in the outer function. 487 // Mark all free variables as captured and use them in the outer function.
455 List<Element> freeVariables = 488 List<Element> freeVariables =
456 savedClosureData.freeVariableMapping.getKeys(); 489 savedClosureData.freeVariableMapping.getKeys();
(...skipping 14 matching lines...) Expand all
471 } 504 }
472 505
473 visitTryStatement(TryStatement node) { 506 visitTryStatement(TryStatement node) {
474 // TODO(ngeoffray): implement finer grain state. 507 // TODO(ngeoffray): implement finer grain state.
475 bool oldInTryStatement = inTryStatement; 508 bool oldInTryStatement = inTryStatement;
476 inTryStatement = true; 509 inTryStatement = true;
477 node.visitChildren(this); 510 node.visitChildren(this);
478 inTryStatement = oldInTryStatement; 511 inTryStatement = oldInTryStatement;
479 } 512 }
480 } 513 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698