| 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 tree_ir_builder; | 5 library tree_ir_builder; |
| 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 '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 /// This is not safe if the code is moved inside the scope of an exception | 62 /// This is not safe if the code is moved inside the scope of an exception |
| 63 /// handler (i.e., into a try block). We keep a stack of singly-referenced | 63 /// handler (i.e., into a try block). We keep a stack of singly-referenced |
| 64 /// continuations that are in scope without crossing a binding for a handler. | 64 /// continuations that are in scope without crossing a binding for a handler. |
| 65 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; | 65 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; |
| 66 | 66 |
| 67 ExecutableElement currentElement; | 67 ExecutableElement currentElement; |
| 68 /// The 'this' Parameter for currentElement or the enclosing method. | 68 /// The 'this' Parameter for currentElement or the enclosing method. |
| 69 cps_ir.Parameter thisParameter; | 69 cps_ir.Parameter thisParameter; |
| 70 cps_ir.Continuation returnContinuation; | 70 cps_ir.Continuation returnContinuation; |
| 71 | 71 |
| 72 /// Number of loops enclosing the currently visited node. |
| 73 int enclosingLoops = 0; |
| 74 |
| 72 Builder parent; | 75 Builder parent; |
| 73 | 76 |
| 74 Builder(this.internalError, [this.parent]); | 77 Builder(this.internalError, [this.parent]); |
| 75 | 78 |
| 76 Builder createInnerBuilder() { | 79 Builder createInnerBuilder() { |
| 77 return new Builder(internalError, this); | 80 return new Builder(internalError, this); |
| 78 } | 81 } |
| 79 | 82 |
| 80 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 83 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
| 81 /// variables. | 84 /// variables. |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 210 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
| 208 return new List<Expression>.generate(args.length, | 211 return new List<Expression>.generate(args.length, |
| 209 (int index) => getVariableUse(args[index]), | 212 (int index) => getVariableUse(args[index]), |
| 210 growable: false); | 213 growable: false); |
| 211 } | 214 } |
| 212 | 215 |
| 213 Statement buildContinuationAssignment( | 216 Statement buildContinuationAssignment( |
| 214 cps_ir.Parameter parameter, | 217 cps_ir.Parameter parameter, |
| 215 Expression argument, | 218 Expression argument, |
| 216 Statement buildRest()) { | 219 Statement buildRest()) { |
| 217 Statement assignment; | 220 Expression expr; |
| 218 if (parameter.hasAtLeastOneUse) { | 221 if (parameter.hasAtLeastOneUse) { |
| 219 Variable variable = getVariable(parameter); | 222 expr = new Assign(getVariable(parameter), argument); |
| 220 assignment = new Assign(variable, argument, null); | |
| 221 } else { | 223 } else { |
| 222 assignment = new ExpressionStatement(argument, null); | 224 expr = argument; |
| 223 } | 225 } |
| 224 assignment.next = buildRest(); | 226 return new ExpressionStatement(expr, buildRest()); |
| 225 return assignment; | |
| 226 } | 227 } |
| 227 | 228 |
| 228 /// Simultaneously assigns each argument to the corresponding parameter, | 229 /// Simultaneously assigns each argument to the corresponding parameter, |
| 229 /// then continues at the statement created by [buildRest]. | 230 /// then continues at the statement created by [buildRest]. |
| 230 Statement buildPhiAssignments( | 231 Statement buildPhiAssignments( |
| 231 List<cps_ir.Parameter> parameters, | 232 List<cps_ir.Parameter> parameters, |
| 232 List<Expression> arguments, | 233 List<Expression> arguments, |
| 233 Statement buildRest()) { | 234 Statement buildRest()) { |
| 234 assert(parameters.length == arguments.length); | 235 assert(parameters.length == arguments.length); |
| 235 // We want a parallel assignment to all parameters simultaneously. | 236 // We want a parallel assignment to all parameters simultaneously. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 257 } | 258 } |
| 258 list.add(i); | 259 list.add(i); |
| 259 } else { | 260 } else { |
| 260 // v1 = this; | 261 // v1 = this; |
| 261 } | 262 } |
| 262 } | 263 } |
| 263 | 264 |
| 264 Statement first, current; | 265 Statement first, current; |
| 265 void addAssignment(Variable dst, Expression src) { | 266 void addAssignment(Variable dst, Expression src) { |
| 266 if (first == null) { | 267 if (first == null) { |
| 267 first = current = new Assign(dst, src, null); | 268 first = current = Assign.makeStatement(dst, src); |
| 268 } else { | 269 } else { |
| 269 current = current.next = new Assign(dst, src, null); | 270 current = current.next = Assign.makeStatement(dst, src); |
| 270 } | 271 } |
| 271 } | 272 } |
| 272 | 273 |
| 273 List<Expression> assignmentSrc = new List<Expression>(parameters.length); | 274 List<Expression> assignmentSrc = new List<Expression>(parameters.length); |
| 274 List<bool> done = new List<bool>.filled(parameters.length, false); | 275 List<bool> done = new List<bool>.filled(parameters.length, false); |
| 275 void visitAssignment(int i) { | 276 void visitAssignment(int i) { |
| 276 if (done[i]) { | 277 if (done[i]) { |
| 277 return; | 278 return; |
| 278 } | 279 } |
| 279 Variable param = getVariable(parameters[i]); | 280 Variable param = getVariable(parameters[i]); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 if (variable == null) return visit(node.body); | 365 if (variable == null) return visit(node.body); |
| 365 | 366 |
| 366 Node definition = visit(node.primitive); | 367 Node definition = visit(node.primitive); |
| 367 | 368 |
| 368 // visitPrimitive returns a Statement without successor if it cannot occur | 369 // visitPrimitive returns a Statement without successor if it cannot occur |
| 369 // in expression context (currently only the case for FunctionDeclarations). | 370 // in expression context (currently only the case for FunctionDeclarations). |
| 370 if (definition is Statement) { | 371 if (definition is Statement) { |
| 371 definition.next = visit(node.body); | 372 definition.next = visit(node.body); |
| 372 return definition; | 373 return definition; |
| 373 } else { | 374 } else { |
| 374 return new Assign(variable, definition, visit(node.body)); | 375 return Assign.makeStatement(variable, definition, visit(node.body)); |
| 375 } | 376 } |
| 376 } | 377 } |
| 377 | 378 |
| 378 Statement visitBody(cps_ir.Body node) { | 379 Statement visitBody(cps_ir.Body node) { |
| 379 return visit(node.body); | 380 return visit(node.body); |
| 380 } | 381 } |
| 381 | 382 |
| 382 Statement visitLetCont(cps_ir.LetCont node) { | 383 Statement visitLetCont(cps_ir.LetCont node) { |
| 383 // Introduce labels for continuations that need them. | 384 // Introduce labels for continuations that need them. |
| 384 int safeForInliningLengthOnEntry = safeForInlining.length; | 385 int safeForInliningLengthOnEntry = safeForInlining.length; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 nextBuilder); | 468 nextBuilder); |
| 468 } | 469 } |
| 469 } | 470 } |
| 470 | 471 |
| 471 Statement visitLetMutable(cps_ir.LetMutable node) { | 472 Statement visitLetMutable(cps_ir.LetMutable node) { |
| 472 Variable variable = addMutableVariable(node.variable); | 473 Variable variable = addMutableVariable(node.variable); |
| 473 Expression value = getVariableUse(node.value); | 474 Expression value = getVariableUse(node.value); |
| 474 Statement body = visit(node.body); | 475 Statement body = visit(node.body); |
| 475 // If the variable was captured by an inner function in the body, this | 476 // If the variable was captured by an inner function in the body, this |
| 476 // must be declared here so we assign to a fresh copy of the variable. | 477 // must be declared here so we assign to a fresh copy of the variable. |
| 477 bool needsDeclaration = variable.isCaptured; | 478 if (variable.isCaptured && enclosingLoops > 0) { |
| 478 return new Assign(variable, value, body, isDeclaration: needsDeclaration); | 479 return new VariableDeclaration(variable, value, body); |
| 480 } |
| 481 return Assign.makeStatement(variable, value, body); |
| 479 } | 482 } |
| 480 | 483 |
| 481 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { | 484 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { |
| 482 return getMutableVariableUse(node.variable); | 485 return getMutableVariableUse(node.variable); |
| 483 } | 486 } |
| 484 | 487 |
| 485 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { | 488 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { |
| 486 Variable variable = getMutableVariable(node.variable.definition); | 489 Variable variable = getMutableVariable(node.variable.definition); |
| 487 Expression value = getVariableUse(node.value); | 490 Expression value = getVariableUse(node.value); |
| 488 return new Assign(variable, value, visit(node.body)); | 491 return Assign.makeStatement(variable, value, visit(node.body)); |
| 489 } | 492 } |
| 490 | 493 |
| 491 Statement visitDeclareFunction(cps_ir.DeclareFunction node) { | 494 Statement visitDeclareFunction(cps_ir.DeclareFunction node) { |
| 492 Variable variable = addMutableVariable(node.variable); | 495 Variable variable = addMutableVariable(node.variable); |
| 493 FunctionDefinition function = makeSubFunction(node.definition); | 496 FunctionDefinition function = makeSubFunction(node.definition); |
| 494 return new FunctionDeclaration(variable, function, visit(node.body)); | 497 return new FunctionDeclaration(variable, function, visit(node.body)); |
| 495 } | 498 } |
| 496 | 499 |
| 497 Statement visitTypeOperator(cps_ir.TypeOperator node) { | 500 Statement visitTypeOperator(cps_ir.TypeOperator node) { |
| 498 Expression receiver = getVariableUse(node.receiver); | 501 Expression receiver = getVariableUse(node.receiver); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 // inline at the invocation site. | 535 // inline at the invocation site. |
| 533 // - If there are multiple uses, translate to Break. | 536 // - If there are multiple uses, translate to Break. |
| 534 // * Recursive continuations | 537 // * Recursive continuations |
| 535 // - There is a single non-recursive invocation. Translate | 538 // - There is a single non-recursive invocation. Translate |
| 536 // the continuation body inline as a labeled loop at the | 539 // the continuation body inline as a labeled loop at the |
| 537 // invocation site. | 540 // invocation site. |
| 538 // - Translate the recursive invocations to Continue. | 541 // - Translate the recursive invocations to Continue. |
| 539 if (cont.isRecursive) { | 542 if (cont.isRecursive) { |
| 540 return node.isRecursive | 543 return node.isRecursive |
| 541 ? new Continue(labels[cont]) | 544 ? new Continue(labels[cont]) |
| 542 : new WhileTrue(labels[cont], visit(cont.body)); | 545 : new WhileTrue(labels[cont], makeLoopBody(cont.body)); |
| 543 } else { | 546 } else { |
| 544 if (cont.hasExactlyOneUse) { | 547 if (cont.hasExactlyOneUse) { |
| 545 if (safeForInlining.contains(cont)) { | 548 if (safeForInlining.contains(cont)) { |
| 546 return visit(cont.body); | 549 return visit(cont.body); |
| 547 } | 550 } |
| 548 labels[cont] = new Label(); | 551 labels[cont] = new Label(); |
| 549 } | 552 } |
| 550 return new Break(labels[cont]); | 553 return new Break(labels[cont]); |
| 551 } | 554 } |
| 552 }); | 555 }); |
| 553 } | 556 } |
| 554 } | 557 } |
| 555 | 558 |
| 559 Statement makeLoopBody(cps_ir.Expression body) { |
| 560 ++enclosingLoops; |
| 561 Statement result = visit(body); |
| 562 --enclosingLoops; |
| 563 return result; |
| 564 } |
| 565 |
| 556 Statement visitBranch(cps_ir.Branch node) { | 566 Statement visitBranch(cps_ir.Branch node) { |
| 557 Expression condition = visit(node.condition); | 567 Expression condition = visit(node.condition); |
| 558 Statement thenStatement, elseStatement; | 568 Statement thenStatement, elseStatement; |
| 559 cps_ir.Continuation cont = node.trueContinuation.definition; | 569 cps_ir.Continuation cont = node.trueContinuation.definition; |
| 560 assert(cont.parameters.isEmpty); | 570 assert(cont.parameters.isEmpty); |
| 561 thenStatement = | 571 thenStatement = |
| 562 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); | 572 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); |
| 563 cont = node.falseContinuation.definition; | 573 cont = node.falseContinuation.definition; |
| 564 assert(cont.parameters.isEmpty); | 574 assert(cont.parameters.isEmpty); |
| 565 elseStatement = | 575 elseStatement = |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 } | 650 } |
| 641 | 651 |
| 642 @override | 652 @override |
| 643 Node visitTypeExpression(cps_ir.TypeExpression node) { | 653 Node visitTypeExpression(cps_ir.TypeExpression node) { |
| 644 return new TypeExpression( | 654 return new TypeExpression( |
| 645 node.dartType, | 655 node.dartType, |
| 646 node.arguments.map(getVariableUse).toList()); | 656 node.arguments.map(getVariableUse).toList()); |
| 647 } | 657 } |
| 648 } | 658 } |
| 649 | 659 |
| OLD | NEW |