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

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

Issue 9969212: Reapplies (again) "Don't try to box immutable objects." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Apply fix. Created 8 years, 8 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 | samples/tests/samples/samples-leg.status » ('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 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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | samples/tests/samples/samples-leg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698