| 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 '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| 10 import '../util/util.dart' show CURRENT_ELEMENT_SPANNABLE; | 10 import '../util/util.dart' show CURRENT_ELEMENT_SPANNABLE; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 | 47 |
| 48 final Map<cps_ir.Primitive, Variable> primitive2variable = | 48 final Map<cps_ir.Primitive, Variable> primitive2variable = |
| 49 <cps_ir.Primitive, Variable>{}; | 49 <cps_ir.Primitive, Variable>{}; |
| 50 final Map<cps_ir.MutableVariable, Variable> mutable2variable = | 50 final Map<cps_ir.MutableVariable, Variable> mutable2variable = |
| 51 <cps_ir.MutableVariable, Variable>{}; | 51 <cps_ir.MutableVariable, Variable>{}; |
| 52 | 52 |
| 53 // Continuations with more than one use are replaced with Tree labels. This | 53 // Continuations with more than one use are replaced with Tree labels. This |
| 54 // is the mapping from continuations to labels. | 54 // is the mapping from continuations to labels. |
| 55 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 55 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
| 56 | 56 |
| 57 /// A stack of singly-used labels that can be safely inlined at their use | |
| 58 /// site. | |
| 59 /// | |
| 60 /// Code for continuations with exactly one use is inlined at the use site. | |
| 61 /// This is not safe if the code is moved inside the scope of an exception | |
| 62 /// handler (i.e., into a try block). We keep a stack of singly-referenced | |
| 63 /// continuations that are in scope without crossing a binding for a handler. | |
| 64 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; | |
| 65 | |
| 66 ExecutableElement currentElement; | 57 ExecutableElement currentElement; |
| 67 /// The 'this' Parameter for currentElement or the enclosing method. | 58 /// The 'this' Parameter for currentElement or the enclosing method. |
| 68 cps_ir.Parameter thisParameter; | 59 cps_ir.Parameter thisParameter; |
| 69 cps_ir.Continuation returnContinuation; | 60 cps_ir.Continuation returnContinuation; |
| 70 | 61 |
| 71 Builder parent; | 62 Builder parent; |
| 72 | 63 |
| 73 Builder(this.internalError, [this.parent]); | 64 Builder(this.internalError, [this.parent]); |
| 74 | 65 |
| 75 Builder createInnerBuilder() { | 66 Builder createInnerBuilder() { |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 | 302 |
| 312 // Don't translate unused primitives. | 303 // Don't translate unused primitives. |
| 313 if (variable == null) return visit(node.body); | 304 if (variable == null) return visit(node.body); |
| 314 | 305 |
| 315 Expression value = visit(node.primitive); | 306 Expression value = visit(node.primitive); |
| 316 return Assign.makeStatement(variable, value, visit(node.body)); | 307 return Assign.makeStatement(variable, value, visit(node.body)); |
| 317 } | 308 } |
| 318 | 309 |
| 319 Statement visitLetCont(cps_ir.LetCont node) { | 310 Statement visitLetCont(cps_ir.LetCont node) { |
| 320 // Introduce labels for continuations that need them. | 311 // Introduce labels for continuations that need them. |
| 321 int safeForInliningLengthOnEntry = safeForInlining.length; | |
| 322 for (cps_ir.Continuation continuation in node.continuations) { | 312 for (cps_ir.Continuation continuation in node.continuations) { |
| 323 if (continuation.hasMultipleUses || continuation.isRecursive) { | 313 if (continuation.hasMultipleUses || continuation.isRecursive) { |
| 324 labels[continuation] = new Label(); | 314 labels[continuation] = new Label(); |
| 325 } else { | |
| 326 safeForInlining.add(continuation); | |
| 327 } | 315 } |
| 328 } | 316 } |
| 329 Statement body = visit(node.body); | 317 Statement body = visit(node.body); |
| 330 safeForInlining.length = safeForInliningLengthOnEntry; | |
| 331 // Continuations are bound at the same level, but they have to be | 318 // Continuations are bound at the same level, but they have to be |
| 332 // translated as if nested. This is because the body can invoke any | 319 // translated as if nested. This is because the body can invoke any |
| 333 // of them from anywhere, so it must be nested inside all of them. | 320 // of them from anywhere, so it must be nested inside all of them. |
| 334 // | 321 // |
| 335 // The continuation bodies are not always translated directly here because | 322 // The continuation bodies are not always translated directly here because |
| 336 // they may have been already translated: | 323 // they may have been already translated: |
| 337 // * For singly-used continuations, the continuation's body is | 324 // * For singly-used continuations, the continuation's body is |
| 338 // translated at the site of the continuation invocation. | 325 // translated at the site of the continuation invocation. |
| 339 // * For recursive continuations, there is a single non-recursive | 326 // * For recursive continuations, there is a single non-recursive |
| 340 // invocation. The continuation's body is translated at the site | 327 // invocation. The continuation's body is translated at the site |
| 341 // of the non-recursive continuation invocation. | 328 // of the non-recursive continuation invocation. |
| 342 // See visitInvokeContinuation for the implementation. | 329 // See visitInvokeContinuation for the implementation. |
| 343 Statement current = body; | 330 Statement current = body; |
| 344 for (cps_ir.Continuation continuation in node.continuations.reversed) { | 331 for (cps_ir.Continuation continuation in node.continuations.reversed) { |
| 345 Label label = labels[continuation]; | 332 Label label = labels[continuation]; |
| 346 if (label != null && !continuation.isRecursive) { | 333 if (label != null && !continuation.isRecursive) { |
| 347 current = | 334 current = |
| 348 new LabeledStatement(label, current, visit(continuation.body)); | 335 new LabeledStatement(label, current, visit(continuation.body)); |
| 349 } | 336 } |
| 350 } | 337 } |
| 351 return current; | 338 return current; |
| 352 } | 339 } |
| 353 | 340 |
| 354 Statement visitLetHandler(cps_ir.LetHandler node) { | 341 Statement visitLetHandler(cps_ir.LetHandler node) { |
| 355 List<cps_ir.Continuation> saved = safeForInlining; | |
| 356 safeForInlining = <cps_ir.Continuation>[]; | |
| 357 Statement tryBody = visit(node.body); | 342 Statement tryBody = visit(node.body); |
| 358 safeForInlining = saved; | |
| 359 List<Variable> catchParameters = | 343 List<Variable> catchParameters = |
| 360 node.handler.parameters.map(getVariable).toList(); | 344 node.handler.parameters.map(getVariable).toList(); |
| 361 Statement catchBody = visit(node.handler.body); | 345 Statement catchBody = visit(node.handler.body); |
| 362 return new Try(tryBody, catchParameters, catchBody); | 346 return new Try(tryBody, catchParameters, catchBody); |
| 363 } | 347 } |
| 364 | 348 |
| 365 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { | 349 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { |
| 366 // Calls are translated to direct style. | 350 // Calls are translated to direct style. |
| 367 List<Expression> arguments = translateArguments(node.arguments); | 351 List<Expression> arguments = translateArguments(node.arguments); |
| 368 Expression invoke = new InvokeStatic(node.target, node.selector, arguments, | 352 Expression invoke = new InvokeStatic(node.target, node.selector, arguments, |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 // - There is a single non-recursive invocation. Translate | 467 // - There is a single non-recursive invocation. Translate |
| 484 // the continuation body inline as a labeled loop at the | 468 // the continuation body inline as a labeled loop at the |
| 485 // invocation site. | 469 // invocation site. |
| 486 // - Translate the recursive invocations to Continue. | 470 // - Translate the recursive invocations to Continue. |
| 487 if (cont.isRecursive) { | 471 if (cont.isRecursive) { |
| 488 return node.isRecursive | 472 return node.isRecursive |
| 489 ? new Continue(labels[cont]) | 473 ? new Continue(labels[cont]) |
| 490 : new WhileTrue(labels[cont], visit(cont.body)); | 474 : new WhileTrue(labels[cont], visit(cont.body)); |
| 491 } else { | 475 } else { |
| 492 if (cont.hasExactlyOneUse) { | 476 if (cont.hasExactlyOneUse) { |
| 493 if (safeForInlining.contains(cont)) { | 477 if (!node.isEscapingTry) { |
| 494 return visit(cont.body); | 478 return visit(cont.body); |
| 495 } | 479 } |
| 496 labels[cont] = new Label(); | 480 labels[cont] = new Label(); |
| 497 } | 481 } |
| 498 return new Break(labels[cont]); | 482 return new Break(labels[cont]); |
| 499 } | 483 } |
| 500 }); | 484 }); |
| 501 } | 485 } |
| 502 } | 486 } |
| 503 | 487 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 return new ForeignStatement( | 607 return new ForeignStatement( |
| 624 node.codeTemplate, | 608 node.codeTemplate, |
| 625 node.type, | 609 node.type, |
| 626 node.arguments.map(getVariableUse).toList(growable: false), | 610 node.arguments.map(getVariableUse).toList(growable: false), |
| 627 node.nativeBehavior, | 611 node.nativeBehavior, |
| 628 node.dependency); | 612 node.dependency); |
| 629 } | 613 } |
| 630 } | 614 } |
| 631 } | 615 } |
| 632 | 616 |
| OLD | NEW |