Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 dart_tree; | 5 library dart_tree; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
| 9 import '../util/util.dart'; | 9 import '../util/util.dart'; |
| 10 import '../elements/elements.dart' | 10 import '../elements/elements.dart' |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 accept(Visitor visitor) => visitor.visitSequence(this); | 82 accept(Visitor visitor) => visitor.visitSequence(this); |
| 83 } | 83 } |
| 84 | 84 |
| 85 /** | 85 /** |
| 86 * A local binding of a [Variable] to an [Expression]. | 86 * A local binding of a [Variable] to an [Expression]. |
| 87 * | 87 * |
| 88 * In contrast to the CPS-based IR, non-primitive expressions can be named | 88 * In contrast to the CPS-based IR, non-primitive expressions can be named |
| 89 * with let. | 89 * with let. |
| 90 */ | 90 */ |
| 91 class LetVal extends Expression { | 91 class LetVal extends Expression { |
| 92 final bool hasExactlyOneUse; | |
| 92 final Variable variable; | 93 final Variable variable; |
| 93 final Expression definition; | 94 Expression definition; |
| 94 final Expression body; | 95 Expression body; |
| 95 | 96 |
| 96 LetVal(this.variable, this.definition, this.body); | 97 LetVal(this.hasExactlyOneUse, this.variable, this.definition, this.body); |
|
floitsch
2014/04/10 17:24:46
I would put this last. It seems less important tha
Kevin Millikin (Google)
2014/04/11 08:31:23
Good reason, done.
| |
| 97 | 98 |
| 98 bool get isPure => definition.isPure && body.isPure; | 99 bool get isPure => definition.isPure && body.isPure; |
| 99 | 100 |
| 100 accept(Visitor visitor) => visitor.visitLetVal(this); | 101 accept(Visitor visitor) => visitor.visitLetVal(this); |
| 101 } | 102 } |
| 102 | 103 |
| 103 /** | 104 /** |
| 104 * A call to a static target. | 105 * A call to a static target. |
| 105 * | 106 * |
| 106 * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. | 107 * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 function = new FunctionDefinition(parameters, node.body.accept(this)); | 237 function = new FunctionDefinition(parameters, node.body.accept(this)); |
| 237 return null; | 238 return null; |
| 238 } | 239 } |
| 239 | 240 |
| 240 Expression visitLetPrim(ir.LetPrim node) { | 241 Expression visitLetPrim(ir.LetPrim node) { |
| 241 // LetPrim is translated to LetVal. | 242 // LetPrim is translated to LetVal. |
| 242 Expression definition = node.primitive.accept(this); | 243 Expression definition = node.primitive.accept(this); |
| 243 if (node.primitive.hasAtLeastOneUse) { | 244 if (node.primitive.hasAtLeastOneUse) { |
| 244 Variable variable = new Variable(null); | 245 Variable variable = new Variable(null); |
| 245 variables[node.primitive] = variable; | 246 variables[node.primitive] = variable; |
| 246 return new LetVal(variable, definition, node.body.accept(this)); | 247 return new LetVal(node.primitive.hasExactlyOneUse, variable, |
| 248 definition, node.body.accept(this)); | |
| 247 } else { | 249 } else { |
| 248 return new Sequence([definition, node.body.accept(this)]); | 250 return new Sequence([definition, node.body.accept(this)]); |
| 249 } | 251 } |
| 250 } | 252 } |
| 251 | 253 |
| 252 Expression visitLetCont(ir.LetCont node) { | 254 Expression visitLetCont(ir.LetCont node) { |
| 253 // TODO(kmillikin): Allow continuations to have multiple uses. This could | 255 // TODO(kmillikin): Allow continuations to have multiple uses. This could |
| 254 // arise due to the representation of local control flow or due to | 256 // arise due to the representation of local control flow or due to |
| 255 // optimization. | 257 // optimization. |
| 256 assert(node.continuation.hasAtMostOneUse); | 258 assert(node.continuation.hasAtMostOneUse); |
| 257 return node.body.accept(this); | 259 return node.body.accept(this); |
| 258 } | 260 } |
| 259 | 261 |
| 260 Expression visitInvokeStatic(ir.InvokeStatic node) { | 262 Expression visitInvokeStatic(ir.InvokeStatic node) { |
| 261 // Calls are translated to direct style. | 263 // Calls are translated to direct style. |
| 262 List<Expression> arguments = translateArguments(node.arguments); | 264 List<Expression> arguments = translateArguments(node.arguments); |
| 263 Expression invoke = new InvokeStatic(node.target, arguments); | 265 Expression invoke = new InvokeStatic(node.target, arguments); |
| 264 ir.Continuation cont = node.continuation.definition; | 266 ir.Continuation cont = node.continuation.definition; |
| 265 if (cont == returnContinuation) { | 267 if (cont == returnContinuation) { |
| 266 return new Return(invoke); | 268 return new Return(invoke); |
| 267 } else { | 269 } else { |
| 268 assert(cont.hasExactlyOneUse); | 270 assert(cont.hasExactlyOneUse); |
| 269 if (cont.parameter.hasAtLeastOneUse) { | 271 if (cont.parameter.hasAtLeastOneUse) { |
| 270 Variable variable = new Variable(null); | 272 Variable variable = new Variable(null); |
| 271 variables[cont.parameter] = variable; | 273 variables[cont.parameter] = variable; |
| 272 return new LetVal(variable, invoke, cont.body.accept(this)); | 274 return new LetVal(cont.parameter.hasExactlyOneUse, variable, |
| 275 invoke, cont.body.accept(this)); | |
| 273 } else { | 276 } else { |
| 274 return new Sequence([invoke, cont.body.accept(this)]); | 277 return new Sequence([invoke, cont.body.accept(this)]); |
| 275 } | 278 } |
| 276 } | 279 } |
| 277 } | 280 } |
| 278 | 281 |
| 279 Expression visitInvokeContinuation(ir.InvokeContinuation node) { | 282 Expression visitInvokeContinuation(ir.InvokeContinuation node) { |
| 280 // TODO(kmillikin): Support non-return continuations. These could arise | 283 // TODO(kmillikin): Support non-return continuations. These could arise |
| 281 // due to local control flow or due to inlining or other optimization. | 284 // due to local control flow or due to inlining or other optimization. |
| 282 assert(node.continuation.definition == returnContinuation); | 285 assert(node.continuation.definition == returnContinuation); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 | 349 |
| 347 // TODO(kmillikin): It's not always beneficial to propagate pure | 350 // TODO(kmillikin): It's not always beneficial to propagate pure |
| 348 // definitions---it can prevent propagation of their inputs. Implement | 351 // definitions---it can prevent propagation of their inputs. Implement |
| 349 // a heuristic to avoid this. | 352 // a heuristic to avoid this. |
| 350 | 353 |
| 351 // TODO(kmillikin): Replace linear search with something faster in | 354 // TODO(kmillikin): Replace linear search with something faster in |
| 352 // practice. | 355 // practice. |
| 353 bool seenImpure = false; | 356 bool seenImpure = false; |
| 354 for (int i = environment.length - 1; i >= 0; --i) { | 357 for (int i = environment.length - 1; i >= 0; --i) { |
| 355 if (environment[i].variable == node) { | 358 if (environment[i].variable == node) { |
| 356 if (!seenImpure || environment[i].definition.isPure) { | 359 if ((!seenImpure || environment[i].definition.isPure) |
| 360 && environment[i].hasExactlyOneUse) { | |
| 357 // Use the definition if it is pure or if it is the first impure | 361 // Use the definition if it is pure or if it is the first impure |
| 358 // definition (i.e., propagating past only pure expressions). | 362 // definition (i.e., propagating past only pure expressions). |
| 359 return environment.removeAt(i).definition.accept(this); | 363 return environment.removeAt(i).definition.accept(this); |
| 360 } | 364 } |
| 361 break; | 365 break; |
| 362 } else if (!environment[i].definition.isPure) { | 366 } else if (!environment[i].definition.isPure) { |
| 363 // Once the first impure definition is seen, impure definitions should | 367 // Once the first impure definition is seen, impure definitions should |
| 364 // no longer be propagated. Continue searching for a pure definition. | 368 // no longer be propagated. Continue searching for a pure definition. |
| 365 seenImpure = true; | 369 seenImpure = true; |
| 366 } | 370 } |
| 367 } | 371 } |
| 368 // If the definition could not be propagated, leave the variable use. | 372 // If the definition could not be propagated, leave the variable use. |
| 369 return node; | 373 return node; |
| 370 } | 374 } |
| 371 | 375 |
| 372 Expression visitSequence(Sequence node) { | 376 Expression visitSequence(Sequence node) { |
| 373 for (int i = 0; i < node.expressions.length; ++i) { | 377 for (int i = 0; i < node.expressions.length; ++i) { |
| 374 node.expressions[i] = node.expressions[i].accept(this); | 378 node.expressions[i] = node.expressions[i].accept(this); |
| 375 } | 379 } |
| 376 return node; | 380 return node; |
| 377 } | 381 } |
| 378 | 382 |
| 379 Expression visitLetVal(LetVal node) { | 383 Expression visitLetVal(LetVal node) { |
| 380 environment.add(node); | 384 environment.add(node); |
| 381 Expression body = node.body.accept(this); | 385 Expression body = node.body.accept(this); |
| 382 | 386 |
| 383 // TODO(kmillikin): Allow definitions that are not propagated. Currently, | 387 if (!environment.isEmpty && environment.last == node) { |
| 384 // the only bindings are anonymous intermediate values (which only have one | 388 // The definition could not be propagated. Residualize the let binding. |
| 385 // use in the absence of optimizations) and they are not reordered. | 389 node.body = body; |
| 390 environment.removeLast(); | |
| 391 node.definition = node.definition.accept(this); | |
| 392 return node; | |
| 393 } | |
| 386 assert(!environment.contains(node)); | 394 assert(!environment.contains(node)); |
| 387 return body; | 395 return body; |
| 388 } | 396 } |
| 389 | 397 |
| 390 Expression visitInvokeStatic(InvokeStatic node) { | 398 Expression visitInvokeStatic(InvokeStatic node) { |
| 391 // Process arguments right-to-left, the opposite of evaluation order. | 399 // Process arguments right-to-left, the opposite of evaluation order. |
| 392 for (int i = node.arguments.length - 1; i >= 0; --i) { | 400 for (int i = node.arguments.length - 1; i >= 0; --i) { |
| 393 node.arguments[i] = node.arguments[i].accept(this); | 401 node.arguments[i] = node.arguments[i].accept(this); |
| 394 } | 402 } |
| 395 return node; | 403 return node; |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 745 } | 753 } |
| 746 | 754 |
| 747 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { | 755 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { |
| 748 return unimplemented(); | 756 return unimplemented(); |
| 749 } | 757 } |
| 750 | 758 |
| 751 ast.Expression visitDummy(dart2js.DummyConstant constant) { | 759 ast.Expression visitDummy(dart2js.DummyConstant constant) { |
| 752 return unimplemented(); | 760 return unimplemented(); |
| 753 } | 761 } |
| 754 } | 762 } |
| OLD | NEW |