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' show FunctionElement, FunctionSignature; | 10 import '../elements/elements.dart' show FunctionElement, FunctionSignature; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 identifier = Emitter.makeIdentifier(name); | 58 identifier = Emitter.makeIdentifier(name); |
| 59 return identifier; | 59 return identifier; |
| 60 } | 60 } |
| 61 | 61 |
| 62 final bool isPure = true; | 62 final bool isPure = true; |
| 63 | 63 |
| 64 accept(Visitor visitor) => visitor.visitVariable(this); | 64 accept(Visitor visitor) => visitor.visitVariable(this); |
| 65 } | 65 } |
| 66 | 66 |
| 67 /** | 67 /** |
| 68 * A sequence of expressions. | |
| 69 * | |
| 70 * The value of the sequence is the value of the last expression. All but | |
|
Kevin Millikin (Google)
2014/04/03 12:00:56
I'm going to remove this comment about the semanti
| |
| 71 * the last are evaluated for their effect. | |
| 72 */ | |
| 73 class Sequence extends Expression { | |
| 74 final List<Expression> expressions; | |
| 75 | |
| 76 Sequence(this.expressions); | |
| 77 | |
| 78 bool get isPure => expressions.every((e) => e.isPure); | |
|
floitsch
2014/04/03 12:31:16
Probably not an issue yet, but should we cache it?
| |
| 79 | |
| 80 accept(Visitor visitor) => visitor.visitSequence(this); | |
| 81 } | |
| 82 | |
| 83 /** | |
| 68 * A local binding of a [Variable] to an [Expression]. | 84 * A local binding of a [Variable] to an [Expression]. |
| 69 * | 85 * |
| 70 * In contrast to the CPS-based IR, non-primitive expressions can be named | 86 * In contrast to the CPS-based IR, non-primitive expressions can be named |
| 71 * with let. | 87 * with let. |
| 72 */ | 88 */ |
| 73 class LetVal extends Expression { | 89 class LetVal extends Expression { |
| 74 final Variable variable; | 90 final Variable variable; |
| 75 final Expression definition; | 91 final Expression definition; |
| 76 final Expression body; | 92 final Expression body; |
| 77 | 93 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 accept(Visitor visitor) => visitor.visitConstant(this); | 143 accept(Visitor visitor) => visitor.visitConstant(this); |
| 128 } | 144 } |
| 129 | 145 |
| 130 abstract class Visitor<T> { | 146 abstract class Visitor<T> { |
| 131 // Abstract classes. | 147 // Abstract classes. |
| 132 T visitNode(Node node) => node.accept(this); | 148 T visitNode(Node node) => node.accept(this); |
| 133 T visitExpression(Expression node) => visitNode(node); | 149 T visitExpression(Expression node) => visitNode(node); |
| 134 | 150 |
| 135 // Concrete classes. | 151 // Concrete classes. |
| 136 T visitVariable(Variable node) => visitExpression(node); | 152 T visitVariable(Variable node) => visitExpression(node); |
| 153 T visitSequence(Sequence node) => visitExpression(node); | |
| 137 T visitLetVal(LetVal node) => visitExpression(node); | 154 T visitLetVal(LetVal node) => visitExpression(node); |
| 138 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); | 155 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); |
| 139 T visitReturn(Return node) => visitExpression(node); | 156 T visitReturn(Return node) => visitExpression(node); |
| 140 T visitConstant(Constant node) => visitExpression(node); | 157 T visitConstant(Constant node) => visitExpression(node); |
| 141 } | 158 } |
| 142 | 159 |
| 143 /** | 160 /** |
| 144 * Builder translates from CPS-based IR to direct-style Tree. | 161 * Builder translates from CPS-based IR to direct-style Tree. |
| 145 * | 162 * |
| 146 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced | 163 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 | 207 |
| 191 Expression visitFunction(ir.Function node) { | 208 Expression visitFunction(ir.Function node) { |
| 192 // Functions are simplistically translated to their bodies. For now this | 209 // Functions are simplistically translated to their bodies. For now this |
| 193 // is good enough. | 210 // is good enough. |
| 194 returnContinuation = node.returnContinuation; | 211 returnContinuation = node.returnContinuation; |
| 195 return node.body.accept(this); | 212 return node.body.accept(this); |
| 196 } | 213 } |
| 197 | 214 |
| 198 Expression visitLetPrim(ir.LetPrim node) { | 215 Expression visitLetPrim(ir.LetPrim node) { |
| 199 // LetPrim is translated to LetVal. | 216 // LetPrim is translated to LetVal. |
| 200 Variable variable = new Variable(); | |
| 201 Expression definition = node.primitive.accept(this); | 217 Expression definition = node.primitive.accept(this); |
| 202 variables[node.primitive] = variable; | 218 if (node.primitive.hasAtLeastOneUse) { |
|
floitsch
2014/04/03 12:31:16
Should we create a helper function?
The code here
| |
| 203 return new LetVal(variable, definition, node.body.accept(this)); | 219 Variable variable = new Variable(); |
| 220 variables[node.primitive] = variable; | |
| 221 return new LetVal(variable, definition, node.body.accept(this)); | |
| 222 } else { | |
| 223 return new Sequence([definition, node.body.accept(this)]); | |
| 224 } | |
| 204 } | 225 } |
| 205 | 226 |
| 206 Expression visitLetCont(ir.LetCont node) { | 227 Expression visitLetCont(ir.LetCont node) { |
| 207 // TODO(kmillikin): Allow continuations to have multiple uses. This could | 228 // TODO(kmillikin): Allow continuations to have multiple uses. This could |
| 208 // arise due to the representation of local control flow or due to | 229 // arise due to the representation of local control flow or due to |
| 209 // optimization. | 230 // optimization. |
| 210 assert(node.continuation.hasAtMostOneUse); | 231 assert(node.continuation.hasAtMostOneUse); |
| 211 return node.body.accept(this); | 232 return node.body.accept(this); |
| 212 } | 233 } |
| 213 | 234 |
| 214 Expression visitInvokeStatic(ir.InvokeStatic node) { | 235 Expression visitInvokeStatic(ir.InvokeStatic node) { |
| 215 // Calls are translated to direct style. | 236 // Calls are translated to direct style. |
| 216 List<Expression> arguments = translateArguments(node.arguments); | 237 List<Expression> arguments = translateArguments(node.arguments); |
| 217 Expression invoke = new InvokeStatic(node.target, arguments); | 238 Expression invoke = new InvokeStatic(node.target, arguments); |
| 218 ir.Continuation cont = node.continuation.definition; | 239 ir.Continuation cont = node.continuation.definition; |
| 219 if (cont == returnContinuation) { | 240 if (cont == returnContinuation) { |
| 220 return new Return(invoke); | 241 return new Return(invoke); |
| 221 } else { | 242 } else { |
| 222 assert(cont.hasExactlyOneUse); | 243 assert(cont.hasExactlyOneUse); |
| 223 Variable variable = new Variable(); | 244 if (cont.parameter.hasAtLeastOneUse) { |
| 224 variables[cont.parameter] = variable; | 245 Variable variable = new Variable(); |
| 225 return new LetVal(variable, invoke, cont.body.accept(this)); | 246 variables[cont.parameter] = variable; |
| 247 return new LetVal(variable, invoke, cont.body.accept(this)); | |
| 248 } else { | |
| 249 return new Sequence([invoke, cont.body.accept(this)]); | |
| 250 } | |
| 226 } | 251 } |
| 227 } | 252 } |
| 228 | 253 |
| 229 Expression visitInvokeContinuation(ir.InvokeContinuation node) { | 254 Expression visitInvokeContinuation(ir.InvokeContinuation node) { |
| 230 // TODO(kmillikin): Support non-return continuations. These could arise | 255 // TODO(kmillikin): Support non-return continuations. These could arise |
| 231 // due to local control flow or due to inlining or other optimization. | 256 // due to local control flow or due to inlining or other optimization. |
| 232 assert(node.continuation.definition == returnContinuation); | 257 assert(node.continuation.definition == returnContinuation); |
| 233 return new Return(variables[node.argument.definition]); | 258 return new Return(variables[node.argument.definition]); |
| 234 } | 259 } |
| 235 | 260 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 313 } else if (!environment[i].definition.isPure) { | 338 } else if (!environment[i].definition.isPure) { |
| 314 // Once the first impure definition is seen, impure definitions should | 339 // Once the first impure definition is seen, impure definitions should |
| 315 // no longer be propagated. Continue searching for a pure definition. | 340 // no longer be propagated. Continue searching for a pure definition. |
| 316 seenImpure = true; | 341 seenImpure = true; |
| 317 } | 342 } |
| 318 } | 343 } |
| 319 // If the definition could not be propagated, leave the variable use. | 344 // If the definition could not be propagated, leave the variable use. |
| 320 return node; | 345 return node; |
| 321 } | 346 } |
| 322 | 347 |
| 348 Expression visitSequence(Sequence node) { | |
| 349 for (int i = 0; i < node.expressions.length; ++i) { | |
| 350 node.expressions[i] = node.expressions[i].accept(this); | |
| 351 } | |
| 352 return node; | |
| 353 } | |
| 354 | |
| 323 Expression visitLetVal(LetVal node) { | 355 Expression visitLetVal(LetVal node) { |
| 324 environment.add(node); | 356 environment.add(node); |
| 325 Expression body = node.body.accept(this); | 357 Expression body = node.body.accept(this); |
| 326 | 358 |
| 327 // TODO(kmillikin): Allow definitions that are not propagated. Currently, | 359 // TODO(kmillikin): Allow definitions that are not propagated. Currently, |
| 328 // the only bindings are anonymous intermediate values (which only have one | 360 // the only bindings are anonymous intermediate values (which only have one |
| 329 // use in the absence of optimizations) and they are not reordered. | 361 // use in the absence of optimizations) and they are not reordered. |
| 330 assert(!environment.contains(node)); | 362 assert(!environment.contains(node)); |
| 331 return body; | 363 return body; |
| 332 } | 364 } |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 ast.Expression value = (body as ast.Return).expression; | 504 ast.Expression value = (body as ast.Return).expression; |
| 473 if (value is ast.LiteralNull) { | 505 if (value is ast.LiteralNull) { |
| 474 // '{ return null; }' is '{}'. | 506 // '{ return null; }' is '{}'. |
| 475 body = makeBlock([]); | 507 body = makeBlock([]); |
| 476 } else { | 508 } else { |
| 477 // '{ return e; }' is '=> e;'. | 509 // '{ return e; }' is '=> e;'. |
| 478 body = new ast.Return(new SymbolToken(FUNCTION_INFO, -1), | 510 body = new ast.Return(new SymbolToken(FUNCTION_INFO, -1), |
| 479 semicolon, | 511 semicolon, |
| 480 value); | 512 value); |
| 481 } | 513 } |
| 514 } else if (body is ast.Block) { | |
| 515 // Remove a final 'return null' that ends the body block. | |
| 516 List<ast.Node> statements = | |
| 517 (body as ast.Block).statements.nodes.toList(); | |
| 518 statements.removeLast(); | |
|
floitsch
2014/04/03 12:31:16
assert that it's a Return null.
Kevin Millikin (Google)
2014/04/03 12:52:46
Ack, that's just a bug. Thanks for catching it.
| |
| 519 body = makeBlock(statements); | |
| 482 } | 520 } |
| 483 | 521 |
| 484 return new ast.FunctionExpression(name, parameters, body, returnType, | 522 return new ast.FunctionExpression(name, parameters, body, returnType, |
| 485 ast.Modifiers.EMPTY, null, null); | 523 ast.Modifiers.EMPTY, null, null); |
| 486 } | 524 } |
| 487 | 525 |
| 488 /** | 526 /** |
| 489 * Translate a list of arguments to an AST NodeList. | 527 * Translate a list of arguments to an AST NodeList. |
| 490 */ | 528 */ |
| 491 ast.NodeList translateArguments(List<Expression> args) { | 529 ast.NodeList translateArguments(List<Expression> args) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 new ast.NodeList(openBrace, statements.toLink(), closeBrace)); | 565 new ast.NodeList(openBrace, statements.toLink(), closeBrace)); |
| 528 } | 566 } |
| 529 | 567 |
| 530 ast.Node visitVariable(Variable node) { | 568 ast.Node visitVariable(Variable node) { |
| 531 // The scope of variables is the body of their binding, so a name has | 569 // The scope of variables is the body of their binding, so a name has |
| 532 // already been generated when we visit a variable. | 570 // already been generated when we visit a variable. |
| 533 assert(node.identifier != null); | 571 assert(node.identifier != null); |
| 534 return new ast.Send(null, node.identifier); | 572 return new ast.Send(null, node.identifier); |
| 535 } | 573 } |
| 536 | 574 |
| 575 ast.Node visitSequence(Sequence node) { | |
| 576 return node.expressions.map((e) => e.accept(this)).reduce(concatenate); | |
| 577 } | |
| 578 | |
| 537 ast.Node visitLetVal(LetVal node) { | 579 ast.Node visitLetVal(LetVal node) { |
| 538 // Let bindings translate into assignments. | 580 // Let bindings translate into assignments. |
| 539 ast.Identifier identifier = node.variable.assignIdentifier(); | 581 ast.Identifier identifier = node.variable.assignIdentifier(); |
| 540 variables.add(identifier); | 582 variables.add(identifier); |
| 541 | 583 |
| 542 ast.Expression expression = node.definition.accept(this); | 584 ast.Expression expression = node.definition.accept(this); |
| 543 ast.Expression assignment = makeAssignment(identifier, expression); | 585 ast.Expression assignment = makeAssignment(identifier, expression); |
| 544 | 586 |
| 545 ast.Node rest = node.body.accept(this); | 587 ast.Node rest = node.body.accept(this); |
| 546 return concatenate(assignment, rest); | 588 return concatenate(assignment, rest); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 669 } | 711 } |
| 670 | 712 |
| 671 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { | 713 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { |
| 672 return unimplemented(); | 714 return unimplemented(); |
| 673 } | 715 } |
| 674 | 716 |
| 675 ast.Expression visitDummy(dart2js.DummyConstant constant) { | 717 ast.Expression visitDummy(dart2js.DummyConstant constant) { |
| 676 return unimplemented(); | 718 return unimplemented(); |
| 677 } | 719 } |
| 678 } | 720 } |
| OLD | NEW |