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 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{}; | 50 final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{}; |
| 51 | 51 |
| 52 /// Like [local2variables], except for mutable variables. | 52 /// Like [local2variables], except for mutable variables. |
| 53 final Map<cps_ir.MutableVariable, Variable> local2mutable = | 53 final Map<cps_ir.MutableVariable, Variable> local2mutable = |
| 54 <cps_ir.MutableVariable, Variable>{}; | 54 <cps_ir.MutableVariable, Variable>{}; |
| 55 | 55 |
| 56 // Continuations with more than one use are replaced with Tree labels. This | 56 // Continuations with more than one use are replaced with Tree labels. This |
| 57 // is the mapping from continuations to labels. | 57 // is the mapping from continuations to labels. |
| 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
| 59 | 59 |
| 60 // Code for continuations with exactly one use is inlined at the use site. | |
|
karlklose
2015/02/16 10:15:48
Use '///'.
| |
| 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> safeForHandlers = <cps_ir.Continuation>[]; | |
| 65 | |
| 60 ExecutableElement currentElement; | 66 ExecutableElement currentElement; |
| 61 cps_ir.Continuation returnContinuation; | 67 cps_ir.Continuation returnContinuation; |
| 62 | 68 |
| 63 Builder parent; | 69 Builder parent; |
| 64 | 70 |
| 65 Builder(this.internalError, [this.parent]); | 71 Builder(this.internalError, [this.parent]); |
| 66 | 72 |
| 67 Builder createInnerBuilder() { | 73 Builder createInnerBuilder() { |
| 68 return new Builder(internalError, this); | 74 return new Builder(internalError, this); |
| 69 } | 75 } |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 return new Assign(variable, definition, visit(node.body)); | 369 return new Assign(variable, definition, visit(node.body)); |
| 364 } | 370 } |
| 365 } | 371 } |
| 366 | 372 |
| 367 Statement visitRunnableBody(cps_ir.RunnableBody node) { | 373 Statement visitRunnableBody(cps_ir.RunnableBody node) { |
| 368 return visit(node.body); | 374 return visit(node.body); |
| 369 } | 375 } |
| 370 | 376 |
| 371 Statement visitLetCont(cps_ir.LetCont node) { | 377 Statement visitLetCont(cps_ir.LetCont node) { |
| 372 // Introduce labels for continuations that need them. | 378 // Introduce labels for continuations that need them. |
| 379 int safeForHandlersLengthOnEntry = safeForHandlers.length; | |
| 373 for (cps_ir.Continuation continuation in node.continuations) { | 380 for (cps_ir.Continuation continuation in node.continuations) { |
| 374 if (continuation.hasMultipleUses) { | 381 if (continuation.hasMultipleUses) { |
| 375 labels[continuation] = new Label(); | 382 labels[continuation] = new Label(); |
| 383 } else { | |
| 384 safeForHandlers.add(continuation); | |
| 376 } | 385 } |
| 377 } | 386 } |
| 378 Statement body = visit(node.body); | 387 Statement body = visit(node.body); |
| 388 safeForHandlers.length = safeForHandlersLengthOnEntry; | |
| 379 // Continuations are bound at the same level, but they have to be | 389 // Continuations are bound at the same level, but they have to be |
| 380 // translated as if nested. This is because the body can invoke any | 390 // translated as if nested. This is because the body can invoke any |
| 381 // of them from anywhere, so it must be nested inside all of them. | 391 // of them from anywhere, so it must be nested inside all of them. |
| 382 // | 392 // |
| 383 // The continuation bodies are not always translated directly here because | 393 // The continuation bodies are not always translated directly here because |
| 384 // they may have been already translated: | 394 // they may have been already translated: |
| 385 // * For singly-used continuations, the continuation's body is | 395 // * For singly-used continuations, the continuation's body is |
| 386 // translated at the site of the continuation invocation. | 396 // translated at the site of the continuation invocation. |
| 387 // * For recursive continuations, there is a single non-recursive | 397 // * For recursive continuations, there is a single non-recursive |
| 388 // invocation. The continuation's body is translated at the site | 398 // invocation. The continuation's body is translated at the site |
| 389 // of the non-recursive continuation invocation. | 399 // of the non-recursive continuation invocation. |
| 390 // See visitInvokeContinuation for the implementation. | 400 // See visitInvokeContinuation for the implementation. |
| 391 Statement current = body; | 401 Statement current = body; |
| 392 for (cps_ir.Continuation continuation in node.continuations.reversed) { | 402 for (cps_ir.Continuation continuation in node.continuations.reversed) { |
| 393 Label label = labels[continuation]; | 403 Label label = labels[continuation]; |
| 394 if (label != null && !continuation.isRecursive) { | 404 if (label != null && !continuation.isRecursive) { |
| 395 current = | 405 current = |
| 396 new LabeledStatement(label, current, visit(continuation.body)); | 406 new LabeledStatement(label, current, visit(continuation.body)); |
| 397 } | 407 } |
| 398 } | 408 } |
| 399 return current; | 409 return current; |
| 400 } | 410 } |
| 401 | 411 |
| 412 Statement visitLetHandler(cps_ir.LetHandler node) { | |
| 413 List<cps_ir.Continuation> saved = safeForHandlers; | |
| 414 safeForHandlers = <cps_ir.Continuation>[]; | |
| 415 Statement tryBody = visit(node.body); | |
| 416 safeForHandlers = saved; | |
| 417 List<Variable> catchParameters = | |
| 418 node.handler.parameters.map(getVariable).toList(); | |
| 419 Statement catchBody = visit(node.handler.body); | |
| 420 return new TryStatement(tryBody, catchParameters, catchBody); | |
| 421 } | |
| 422 | |
| 402 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { | 423 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { |
| 403 // Calls are translated to direct style. | 424 // Calls are translated to direct style. |
| 404 List<Expression> arguments = translateArguments(node.arguments); | 425 List<Expression> arguments = translateArguments(node.arguments); |
| 405 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); | 426 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); |
| 406 return continueWithExpression(node.continuation, invoke); | 427 return continueWithExpression(node.continuation, invoke); |
| 407 } | 428 } |
| 408 | 429 |
| 409 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { | 430 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { |
| 410 Expression invoke = new InvokeMethod(getVariableReference(node.receiver), | 431 Expression invoke = new InvokeMethod(getVariableReference(node.receiver), |
| 411 node.selector, | 432 node.selector, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 // * Recursive continuations | 521 // * Recursive continuations |
| 501 // - There is a single non-recursive invocation. Translate | 522 // - There is a single non-recursive invocation. Translate |
| 502 // the continuation body inline as a labeled loop at the | 523 // the continuation body inline as a labeled loop at the |
| 503 // invocation site. | 524 // invocation site. |
| 504 // - Translate the recursive invocations to Continue. | 525 // - Translate the recursive invocations to Continue. |
| 505 if (cont.isRecursive) { | 526 if (cont.isRecursive) { |
| 506 return node.isRecursive | 527 return node.isRecursive |
| 507 ? new Continue(labels[cont]) | 528 ? new Continue(labels[cont]) |
| 508 : new WhileTrue(labels[cont], visit(cont.body)); | 529 : new WhileTrue(labels[cont], visit(cont.body)); |
| 509 } else { | 530 } else { |
| 510 return cont.hasExactlyOneUse | 531 if (cont.hasExactlyOneUse) { |
| 511 ? visit(cont.body) | 532 if (safeForHandlers.contains(cont)) { |
| 512 : new Break(labels[cont]); | 533 return visit(cont.body); |
| 534 } | |
| 535 labels[cont] = new Label(); | |
|
asgerf
2015/02/20 10:10:08
I think you should create the Label inside visitLe
Kevin Millikin (Google)
2015/02/25 11:06:36
I agree that the whole thing is complicated.
* Th
asgerf
2015/02/25 11:55:11
I guess we could also just let the statement rewri
| |
| 536 } | |
| 537 return new Break(labels[cont]); | |
| 513 } | 538 } |
| 514 }); | 539 }); |
| 515 } | 540 } |
| 516 } | 541 } |
| 517 | 542 |
| 518 Statement visitBranch(cps_ir.Branch node) { | 543 Statement visitBranch(cps_ir.Branch node) { |
| 519 Expression condition = visit(node.condition); | 544 Expression condition = visit(node.condition); |
| 520 Statement thenStatement, elseStatement; | 545 Statement thenStatement, elseStatement; |
| 521 cps_ir.Continuation cont = node.trueContinuation.definition; | 546 cps_ir.Continuation cont = node.trueContinuation.definition; |
| 522 assert(cont.parameters.isEmpty); | 547 assert(cont.parameters.isEmpty); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 587 // visited. | 612 // visited. |
| 588 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node.'); | 613 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node.'); |
| 589 return null; | 614 return null; |
| 590 } | 615 } |
| 591 | 616 |
| 592 Expression visitIsTrue(cps_ir.IsTrue node) { | 617 Expression visitIsTrue(cps_ir.IsTrue node) { |
| 593 return getVariableReference(node.value); | 618 return getVariableReference(node.value); |
| 594 } | 619 } |
| 595 } | 620 } |
| 596 | 621 |
| OLD | NEW |