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

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

Issue 10692122: Don't box variables for closures that are assigned only once. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 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 | tests/co19/co19-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;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 // Map of captured variables. Initially they will map to themselves. If 106 // Map of captured variables. Initially they will map to themselves. If
107 // a variable needs to be boxed then the scope declaring the variable 107 // a variable needs to be boxed then the scope declaring the variable
108 // will update this mapping. 108 // will update this mapping.
109 Map<Element, Element> capturedVariableMapping; 109 Map<Element, Element> capturedVariableMapping;
110 // List of encountered closures. 110 // List of encountered closures.
111 List<FunctionExpression> closures; 111 List<FunctionExpression> closures;
112 112
113 // The variables that have been declared in the current scope. 113 // The variables that have been declared in the current scope.
114 List<Element> scopeVariables; 114 List<Element> scopeVariables;
115 115
116 // Keep track of the mutated variables so that we don't need to box
117 // non-mutated variables.
118 Set<Element> mutatedVariables;
119
116 FunctionElement currentFunctionElement; 120 FunctionElement currentFunctionElement;
117 // The closureData of the currentFunctionElement. 121 // The closureData of the currentFunctionElement.
118 ClosureData closureData; 122 ClosureData closureData;
119 123
120 bool insideClosure = false; 124 bool insideClosure = false;
121 125
122 Compiler get compiler() => builder.compiler; 126 Compiler get compiler() => builder.compiler;
123 127
124 ClosureTranslator(SsaBuilder builder) 128 ClosureTranslator(SsaBuilder builder)
125 : this.builder = builder, 129 : this.builder = builder,
126 this.elements = builder.elements, 130 this.elements = builder.elements,
127 capturedVariableMapping = new Map<Element, Element>(), 131 capturedVariableMapping = new Map<Element, Element>(),
128 closures = <FunctionExpression>[], 132 closures = <FunctionExpression>[],
133 mutatedVariables = new Set<Element>(),
129 this.closureDataCache = builder.builder.closureDataCache; 134 this.closureDataCache = builder.builder.closureDataCache;
130 135
131 ClosureData translate(Node node) { 136 ClosureData translate(Node node) {
132 // Closures have already been analyzed when visiting the surrounding 137 // Closures have already been analyzed when visiting the surrounding
133 // method/function. This also shortcuts for bailout functions. 138 // method/function. This also shortcuts for bailout functions.
134 ClosureData cached = closureDataCache[node]; 139 ClosureData cached = closureDataCache[node];
135 if (cached !== null) return cached; 140 if (cached !== null) return cached;
136 141
137 visit(node); 142 visit(node);
138 // When variables need to be boxed their [capturedVariableMapping] is 143 // When variables need to be boxed their [capturedVariableMapping] is
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 visitNode(Node node) => node.visitChildren(this); 232 visitNode(Node node) => node.visitChildren(this);
228 233
229 visitVariableDefinitions(VariableDefinitions node) { 234 visitVariableDefinitions(VariableDefinitions node) {
230 for (Link<Node> link = node.definitions.nodes; 235 for (Link<Node> link = node.definitions.nodes;
231 !link.isEmpty(); 236 !link.isEmpty();
232 link = link.tail) { 237 link = link.tail) {
233 Node definition = link.head; 238 Node definition = link.head;
234 Element element = elements[definition]; 239 Element element = elements[definition];
235 assert(element !== null); 240 assert(element !== null);
236 declareLocal(element); 241 declareLocal(element);
242 // We still need to visit the right-hand sides of the init-assignments.
243 // For SendSets don't visit the left again. Otherwise it would be marked
244 // as mutated.
245 if (definition is SendSet) {
246 SendSet assignment = definition;
247 visit(assignment.argumentsNode);
248 } else {
249 visit(definition);
250 }
237 } 251 }
238 // We still need to visit the right-hand sides of the init-assignments.
239 // Simply visit all children. We will visit the locals again and make them
240 // used, but that should not be a problem.
241 node.visitChildren(this);
242 } 252 }
243 253
244 visitIdentifier(Identifier node) { 254 visitIdentifier(Identifier node) {
245 if (node.isThis()) { 255 if (node.isThis()) {
246 useLocal(closureData.thisElement); 256 useLocal(closureData.thisElement);
247 } 257 }
248 node.visitChildren(this); 258 node.visitChildren(this);
249 } 259 }
250 260
251 visitSend(Send node) { 261 visitSend(Send node) {
252 Element element = elements[node]; 262 Element element = elements[node];
253 if (Elements.isLocal(element)) { 263 if (Elements.isLocal(element)) {
254 useLocal(element); 264 useLocal(element);
255 } else if (node.receiver === null && 265 } else if (node.receiver === null &&
256 Elements.isInstanceSend(node, elements)) { 266 Elements.isInstanceSend(node, elements)) {
257 useLocal(closureData.thisElement); 267 useLocal(closureData.thisElement);
258 } else if (node.isSuperCall) { 268 } else if (node.isSuperCall) {
259 useLocal(closureData.thisElement); 269 useLocal(closureData.thisElement);
260 } 270 }
261 node.visitChildren(this); 271 node.visitChildren(this);
262 } 272 }
263 273
274 visitSendSet(SendSet node) {
275 Element element = elements[node];
276 if (Elements.isLocal(element)) {
277 mutatedVariables.add(element);
278 }
279 super.visitSendSet(node);
280 }
281
264 // If variables that are declared in the [node] scope are captured and need 282 // If variables that are declared in the [node] scope are captured and need
265 // to be boxed create a box-element and update the [capturingScopes] in the 283 // to be boxed create a box-element and update the [capturingScopes] in the
266 // current [closureData]. 284 // current [closureData].
267 // The boxed variables are updated in the [capturedVariableMapping]. 285 // The boxed variables are updated in the [capturedVariableMapping].
268 void attachCapturedScopeVariables(Node node) { 286 void attachCapturedScopeVariables(Node node) {
269 Element box = null; 287 Element box = null;
270 Map<Element, Element> scopeMapping = new Map<Element, Element>(); 288 Map<Element, Element> scopeMapping = new Map<Element, Element>();
271 for (Element element in scopeVariables) { 289 for (Element element in scopeVariables) {
272 // No need to box non-assignable elements. 290 // No need to box non-assignable elements.
273 if (!element.isAssignable()) continue; 291 if (!element.isAssignable()) continue;
292 if (!mutatedVariables.contains(element)) continue;
274 if (capturedVariableMapping.containsKey(element)) { 293 if (capturedVariableMapping.containsKey(element)) {
275 if (box == null) { 294 if (box == null) {
276 // TODO(floitsch): construct better box names. 295 // TODO(floitsch): construct better box names.
277 SourceString boxName = 296 SourceString boxName =
278 new SourceString("box_${closureFieldCounter++}"); 297 new SourceString("box_${closureFieldCounter++}");
279 box = new BoxElement(boxName, currentFunctionElement); 298 box = new BoxElement(boxName, currentFunctionElement);
280 } 299 }
281 // TODO(floitsch): construct better boxed names. 300 // TODO(floitsch): construct better boxed names.
282 String elementName = element.name.slowToString(); 301 String elementName = element.name.slowToString();
283 // We are currently using the name in an HForeign which could replace 302 // We are currently using the name in an HForeign which could replace
284 // "$X" with something else. 303 // "$X" with something else.
285 String escaped = elementName.replaceAll("\$", "_"); 304 String escaped = elementName.replaceAll("\$", "_");
286 SourceString boxedName = 305 SourceString boxedName =
287 new SourceString("${escaped}_${closureFieldCounter++}"); 306 new SourceString("${escaped}_${closureFieldCounter++}");
288 Element boxed = new Element(boxedName, ElementKind.FIELD, box); 307 Element boxed = new Element(boxedName, ElementKind.FIELD, box);
289 scopeMapping[element] = boxed; 308 scopeMapping[element] = boxed;
290 capturedVariableMapping[element] = boxed; 309 capturedVariableMapping[element] = boxed;
291 } 310 }
292 } 311 }
293 if (!scopeMapping.isEmpty()) { 312 if (!scopeMapping.isEmpty()) {
294 ClosureScope scope = new ClosureScope(box, scopeMapping); 313 ClosureScope scope = new ClosureScope(box, scopeMapping);
295 closureData.capturingScopes[node] = scope; 314 closureData.capturingScopes[node] = scope;
296 } 315 }
297 } 316 }
298 317
299 visitLoop(Loop node) { 318 void inNewScope(Node node, Function action) {
300 List<Element> oldScopeVariables = scopeVariables; 319 List<Element> oldScopeVariables = scopeVariables;
301 scopeVariables = new List<Element>(); 320 scopeVariables = new List<Element>();
302 node.visitChildren(this); 321 action();
303 attachCapturedScopeVariables(node); 322 attachCapturedScopeVariables(node);
323 for (Element element in scopeVariables) {
324 mutatedVariables.remove(element);
325 }
304 scopeVariables = oldScopeVariables; 326 scopeVariables = oldScopeVariables;
305 } 327 }
306 328
329 visitLoop(Loop node) {
330 inNewScope(node, () {
331 node.visitChildren(this);
332 });
333 }
334
307 visitFor(For node) { 335 visitFor(For node) {
308 visitLoop(node); 336 visitLoop(node);
309 // See if we have declared loop variables that need to be boxed. 337 // See if we have declared loop variables that need to be boxed.
310 if (node.initializer === null) return; 338 if (node.initializer === null) return;
311 VariableDefinitions definitions = node.initializer.asVariableDefinitions(); 339 VariableDefinitions definitions = node.initializer.asVariableDefinitions();
312 if (definitions == null) return; 340 if (definitions == null) return;
313 ClosureScope scopeData = closureData.capturingScopes[node]; 341 ClosureScope scopeData = closureData.capturingScopes[node];
314 if (scopeData === null) return; 342 if (scopeData === null) return;
315 List<Element> result = <Element>[]; 343 List<Element> result = <Element>[];
316 for (Link<Node> link = definitions.definitions.nodes; 344 for (Link<Node> link = definitions.definitions.nodes;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 // visitChildren. 377 // visitChildren.
350 return node.name.accept(this); 378 return node.name.accept(this);
351 } 379 }
352 bool isClosure = (closureData !== null); 380 bool isClosure = (closureData !== null);
353 381
354 if (isClosure) closures.add(node); 382 if (isClosure) closures.add(node);
355 383
356 bool oldInsideClosure = insideClosure; 384 bool oldInsideClosure = insideClosure;
357 FunctionElement oldFunctionElement = currentFunctionElement; 385 FunctionElement oldFunctionElement = currentFunctionElement;
358 ClosureData oldClosureData = closureData; 386 ClosureData oldClosureData = closureData;
359 List<Element> oldScopeVariables = scopeVariables;
360
361 387
362 insideClosure = isClosure; 388 insideClosure = isClosure;
363 currentFunctionElement = elements[node]; 389 currentFunctionElement = elements[node];
364 if (insideClosure) { 390 if (insideClosure) {
365 closureData = globalizeClosure(node); 391 closureData = globalizeClosure(node);
366 } else { 392 } else {
367 Element thisElement = null; 393 Element thisElement = null;
368 // TODO(floitsch): we should not need to look for generative constructors. 394 // TODO(floitsch): we should not need to look for generative constructors.
369 // At the moment we store only one ClosureData for both the factory and 395 // At the moment we store only one ClosureData for both the factory and
370 // the body. 396 // the body.
371 if (element.isInstanceMember() || 397 if (element.isInstanceMember() ||
372 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { 398 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
373 // TODO(floitsch): currently all variables are considered to be 399 // TODO(floitsch): currently all variables are considered to be
374 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'. 400 // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
375 Element thisEnclosingElement = element; 401 Element thisEnclosingElement = element;
376 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { 402 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
377 ConstructorBodyElement body = element; 403 ConstructorBodyElement body = element;
378 thisEnclosingElement = body.constructor; 404 thisEnclosingElement = body.constructor;
379 } 405 }
380 thisElement = new ThisElement(thisEnclosingElement); 406 thisElement = new ThisElement(thisEnclosingElement);
381 } 407 }
382 closureData = new ClosureData(null, null, null, thisElement); 408 closureData = new ClosureData(null, null, null, thisElement);
383 } 409 }
384 scopeVariables = new List<Element>();
385 410
386 // We have to declare the implicit 'this' parameter. 411 inNewScope(node, () {
387 if (!insideClosure && closureData.thisElement !== null) { 412 // We have to declare the implicit 'this' parameter.
388 declareLocal(closureData.thisElement); 413 if (!insideClosure && closureData.thisElement !== null) {
389 } 414 declareLocal(closureData.thisElement);
390 // If we are inside a named closure we have to declare ourselve. For 415 }
391 // simplicity we declare the local even if the closure does not have a name 416 // If we are inside a named closure we have to declare ourselve. For
392 // It will simply not be used. 417 // simplicity we declare the local even if the closure does not have a
393 if (insideClosure) { 418 // name.
394 declareLocal(element); 419 // It will simply not be used.
395 } 420 if (insideClosure) {
421 declareLocal(element);
422 }
396 423
397 // TODO(ahe): This is problematic. The backend should not repeat 424 // TODO(ahe): This is problematic. The backend should not repeat
398 // the work of the resolver. It is the resolver's job to create 425 // the work of the resolver. It is the resolver's job to create
399 // parameters, etc. Other phases should only visit statements. 426 // parameters, etc. Other phases should only visit statements.
400 // TODO(floitsch): we avoid visiting the initializers on purpose so that we 427 // TODO(floitsch): we avoid visiting the initializers on purpose so that
401 // get an error-message later in the builder. 428 // we get an error-message later in the builder.
402 if (node.parameters !== null) node.parameters.accept(this); 429 if (node.parameters !== null) node.parameters.accept(this);
403 if (node.body !== null) node.body.accept(this); 430 if (node.body !== null) node.body.accept(this);
404 431 });
405 attachCapturedScopeVariables(node);
406 432
407 closureDataCache[node] = closureData; 433 closureDataCache[node] = closureData;
408 434
409 ClosureData savedClosureData = closureData; 435 ClosureData savedClosureData = closureData;
410 bool savedInsideClosure = insideClosure; 436 bool savedInsideClosure = insideClosure;
411 437
412 // Restore old values. 438 // Restore old values.
413 scopeVariables = oldScopeVariables;
414 insideClosure = oldInsideClosure; 439 insideClosure = oldInsideClosure;
415 closureData = oldClosureData; 440 closureData = oldClosureData;
416 currentFunctionElement = oldFunctionElement; 441 currentFunctionElement = oldFunctionElement;
417 442
418 // Mark all free variables as captured and use them in the outer function. 443 // Mark all free variables as captured and use them in the outer function.
419 List<Element> freeVariables = 444 List<Element> freeVariables =
420 savedClosureData.freeVariableMapping.getKeys(); 445 savedClosureData.freeVariableMapping.getKeys();
421 assert(freeVariables.isEmpty() || savedInsideClosure); 446 assert(freeVariables.isEmpty() || savedInsideClosure);
422 for (Element freeElement in freeVariables) { 447 for (Element freeElement in freeVariables) {
423 if (capturedVariableMapping[freeElement] != null && 448 if (capturedVariableMapping[freeElement] != null &&
(...skipping 11 matching lines...) Expand all
435 } 460 }
436 461
437 visitTryStatement(TryStatement node) { 462 visitTryStatement(TryStatement node) {
438 // TODO(ngeoffray): implement finer grain state. 463 // TODO(ngeoffray): implement finer grain state.
439 bool oldInTryStatement = inTryStatement; 464 bool oldInTryStatement = inTryStatement;
440 inTryStatement = true; 465 inTryStatement = true;
441 node.visitChildren(this); 466 node.visitChildren(this);
442 inTryStatement = oldInTryStatement; 467 inTryStatement = oldInTryStatement;
443 } 468 }
444 } 469 }
OLDNEW
« no previous file with comments | « no previous file | tests/co19/co19-leg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698