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 '../elements/elements.dart' | 8 import '../elements/elements.dart' |
| 9 show Element, FunctionElement, FunctionSignature, ParameterElement, | 9 show Element, FunctionElement, FunctionSignature, ParameterElement, |
| 10 ClassElement; | 10 ClassElement; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 int breakCount = 0; | 76 int breakCount = 0; |
| 77 | 77 |
| 78 /// The [LabeledStatement] binding this label. | 78 /// The [LabeledStatement] binding this label. |
| 79 LabeledStatement binding; | 79 LabeledStatement binding; |
| 80 } | 80 } |
| 81 | 81 |
| 82 /** | 82 /** |
| 83 * Variables are [Expression]s. | 83 * Variables are [Expression]s. |
| 84 */ | 84 */ |
| 85 class Variable extends Expression { | 85 class Variable extends Expression { |
| 86 // A counter used to generate names. The counter is reset to 0 for each | 86 Element element; |
| 87 // function emitted. | 87 int index; |
|
sigurdm
2014/06/04 07:51:56
Maybe have a comment explaining what the index ind
asgerf
2014/06/04 09:40:51
It was an akward field to have in the first place,
| |
| 88 static int counter = 0; | |
| 89 static String _newName() => 'v${counter++}'; | |
| 90 | 88 |
| 91 Element element; | 89 int readCount = 0; |
| 92 String cachedName; | 90 int writeCount = 0; |
| 93 | 91 |
| 94 String get name { | 92 Variable(this.element, this.index); |
| 95 if (cachedName != null) return cachedName; | |
| 96 return cachedName = ((element == null) ? _newName() : element.name); | |
| 97 } | |
| 98 | |
| 99 Variable(this.element); | |
| 100 | 93 |
| 101 accept(Visitor visitor) => visitor.visitVariable(this); | 94 accept(Visitor visitor) => visitor.visitVariable(this); |
| 102 } | 95 } |
| 103 | 96 |
| 104 /** | 97 /** |
| 105 * Common interface for invocations with arguments. | 98 * Common interface for invocations with arguments. |
| 106 */ | 99 */ |
| 107 abstract class Invoke { | 100 abstract class Invoke { |
| 108 List<Expression> get arguments; | 101 List<Expression> get arguments; |
| 109 Selector get selector; | 102 Selector get selector; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 /** | 244 /** |
| 252 * An assignments of an [Expression] to a [Variable]. | 245 * An assignments of an [Expression] to a [Variable]. |
| 253 * | 246 * |
| 254 * In contrast to the CPS-based IR, non-primitive expressions can be assigned | 247 * In contrast to the CPS-based IR, non-primitive expressions can be assigned |
| 255 * to variables. | 248 * to variables. |
| 256 */ | 249 */ |
| 257 class Assign extends Statement { | 250 class Assign extends Statement { |
| 258 Statement next; | 251 Statement next; |
| 259 final Variable variable; | 252 final Variable variable; |
| 260 Expression definition; | 253 Expression definition; |
| 261 final bool hasExactlyOneUse; | |
| 262 | 254 |
| 263 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); | 255 Assign(this.variable, this.definition, this.next) { |
| 256 ++variable.writeCount; | |
| 257 } | |
| 258 | |
| 259 bool get hasExactlyOneUse => variable.readCount == 1; | |
| 264 | 260 |
| 265 accept(Visitor visitor) => visitor.visitAssign(this); | 261 accept(Visitor visitor) => visitor.visitAssign(this); |
| 266 } | 262 } |
| 267 | 263 |
| 268 /** | 264 /** |
| 269 * A return exit from the function. | 265 * A return exit from the function. |
| 270 * | 266 * |
| 271 * In contrast to the CPS-based IR, the return value is an arbitrary | 267 * In contrast to the CPS-based IR, the return value is an arbitrary |
| 272 * expression. | 268 * expression. |
| 273 */ | 269 */ |
| 274 class Return extends Statement { | 270 class Return extends Statement { |
| 275 /// Should not be null. Use [Constant] with [NullConstant] for void returns. | 271 /// Should not be null. Use [Constant] with [NullConstant] for void returns. |
| 276 Expression value; | 272 Expression value; |
| 277 | 273 |
| 278 Statement get next => null; | 274 Statement get next => null; |
| 279 void set next(Statement s) => throw 'UNREACHABLE'; | 275 void set next(Statement s) => throw 'UNREACHABLE'; |
| 280 | 276 |
| 281 Return(this.value); | 277 Return(this.value); |
| 282 | 278 |
| 283 accept(Visitor visitor) => visitor.visitReturn(this); | 279 accept(Visitor visitor) => visitor.visitReturn(this); |
| 284 } | 280 } |
| 285 | 281 |
| 286 /** | 282 /** |
| 287 * A break from an enclosing [LabeledStatement]. The break targets the | 283 * A break from an enclosing [LabeledStatement]. The break targets the |
| 288 * labeled statement's successor statement. | 284 * labeled statement's successor statement. |
| 289 */ | 285 */ |
| 290 class Break extends Statement { | 286 class Break extends Statement { |
| 291 Label _target; | 287 Label target; |
| 292 | |
| 293 Label get target => _target; | |
| 294 void set target(Label newTarget) { | |
| 295 ++newTarget.breakCount; | |
| 296 --_target.breakCount; | |
| 297 _target = newTarget; | |
| 298 } | |
| 299 | 288 |
| 300 Statement get next => null; | 289 Statement get next => null; |
| 301 void set next(Statement s) => throw 'UNREACHABLE'; | 290 void set next(Statement s) => throw 'UNREACHABLE'; |
| 302 | 291 |
| 303 Break(this._target) { | 292 Break(this.target) { |
| 304 ++target.breakCount; | 293 ++target.breakCount; |
| 305 } | 294 } |
| 306 | 295 |
| 307 accept(Visitor visitor) => visitor.visitBreak(this); | 296 accept(Visitor visitor) => visitor.visitBreak(this); |
| 308 } | 297 } |
| 309 | 298 |
| 310 /** | 299 /** |
| 311 * A continue to an enclosing [While] loop. The continue targets the | 300 * A continue to an enclosing [While] loop. The continue targets the |
| 312 * loop's body. | 301 * loop's body. |
| 313 */ | 302 */ |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree | 412 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree |
| 424 * control-flow recognition. | 413 * control-flow recognition. |
| 425 * | 414 * |
| 426 * Otherwise, the output of Builder looks very much like the input. In | 415 * Otherwise, the output of Builder looks very much like the input. In |
| 427 * particular, intermediate values and blocks used for local control flow are | 416 * particular, intermediate values and blocks used for local control flow are |
| 428 * still all named. | 417 * still all named. |
| 429 */ | 418 */ |
| 430 class Builder extends ir.Visitor<Node> { | 419 class Builder extends ir.Visitor<Node> { |
| 431 final dart2js.Compiler compiler; | 420 final dart2js.Compiler compiler; |
| 432 | 421 |
| 433 // Uses of IR primitives are replaced with Tree variables. This is the | 422 /// Maps variable/parameter elements to the Tree variables that represent it. |
| 434 // mapping from primitives to variables. | 423 final Map<Element, List<Variable>> element2variables = <Element,List>{}; |
|
sigurdm
2014/06/04 07:51:56
Is there a reason not to use <Element, List<Variab
asgerf
2014/06/04 09:40:51
No, fixed it.
| |
| 435 final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{}; | |
| 436 | 424 |
| 437 // Continuations with more than one use are replaced with Tree labels. This | 425 // Continuations with more than one use are replaced with Tree labels. This |
| 438 // is the mapping from continuations to labels. | 426 // is the mapping from continuations to labels. |
| 439 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; | 427 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; |
| 440 | 428 |
| 441 FunctionDefinition function; | 429 FunctionDefinition function; |
| 442 ir.Continuation returnContinuation; | 430 ir.Continuation returnContinuation; |
| 443 | 431 |
| 444 Builder(this.compiler); | 432 Builder(this.compiler); |
| 445 | 433 |
| 434 /// Obtains the variable representing the given primitive. Returns null for | |
| 435 /// primitives that have no reference and do not need a variable. | |
| 436 Variable getVariable(ir.Primitive primitive) { | |
| 437 if (primitive.registerIndex == null) { | |
| 438 return null; // variable is unused | |
| 439 } | |
| 440 List<Variable> variables = element2variables[primitive.element]; | |
| 441 if (variables == null) { | |
| 442 variables = <Variable>[]; | |
| 443 element2variables[primitive.element] = variables; | |
| 444 } | |
| 445 while (variables.length <= primitive.registerIndex) { | |
| 446 variables.add(new Variable(primitive.element, variables.length)); | |
| 447 } | |
| 448 return variables[primitive.registerIndex]; | |
| 449 } | |
| 450 | |
| 451 /// Obtains a reference to the tree Variable corresponding to the IR primitive | |
| 452 /// referred to by [reference]. | |
| 453 /// This increments the reference count for the given variable, so the | |
| 454 /// returned expression must be used in the tree. | |
| 455 Expression getVariableReference(ir.Reference reference) { | |
| 456 Variable variable = getVariable(reference.definition); | |
| 457 if (variable == null) { | |
| 458 compiler.internalError( | |
| 459 compiler.currentElement, | |
| 460 "Reference to ${reference.definition} has no register"); | |
| 461 } | |
| 462 ++variable.readCount; | |
| 463 return variable; | |
| 464 } | |
| 465 | |
| 446 FunctionDefinition build(ir.FunctionDefinition node) { | 466 FunctionDefinition build(ir.FunctionDefinition node) { |
| 467 new ir.RegisterAllocator().visit(node); | |
| 447 visit(node); | 468 visit(node); |
| 448 return function; | 469 return function; |
| 449 } | 470 } |
| 450 | 471 |
| 451 List<Expression> translateArguments(List<ir.Reference> args) { | 472 List<Expression> translateArguments(List<ir.Reference> args) { |
| 452 return new List<Expression>.generate(args.length, | 473 return new List<Expression>.generate(args.length, |
| 453 (int index) => variables[args[index].definition]); | 474 (int index) => getVariableReference(args[index])); |
| 454 } | 475 } |
| 455 | 476 |
| 456 Statement buildParameterAssignments( | 477 Statement buildParameterAssignments( |
| 457 List<ir.Parameter> parameters, | 478 List<ir.Parameter> parameters, |
| 458 List<Expression> arguments, | 479 List<Expression> arguments, |
| 459 Statement buildRest()) { | 480 Statement buildRest()) { |
| 460 assert(parameters.length == arguments.length); | 481 assert(parameters.length == arguments.length); |
| 461 Statement first, current; | 482 Statement first, current; |
| 462 for (int i = 0; i < parameters.length; ++i) { | 483 for (int i = 0; i < parameters.length; ++i) { |
| 484 Expression argument = arguments[i]; | |
| 463 ir.Parameter parameter = parameters[i]; | 485 ir.Parameter parameter = parameters[i]; |
| 464 Statement assignment; | 486 Statement assignment; |
| 465 if (parameter.hasAtLeastOneUse) { | 487 Variable variable = getVariable(parameter); |
| 466 assignment = new Assign(variables[parameter], arguments[i], null, | 488 if (variable == null || variable == arguments[i]) { |
| 467 parameter.hasExactlyOneUse); | 489 if (argument is Variable) { |
| 490 assignment = null; // ignore pure expression | |
| 491 --argument.readCount; // kill unused argument | |
| 492 } else { | |
| 493 assignment = new ExpressionStatement(argument, null); | |
| 494 } | |
| 468 } else { | 495 } else { |
| 469 assignment = new ExpressionStatement(arguments[i], null); | 496 assignment = new Assign(variable, argument, null); |
| 470 } | 497 } |
| 471 | 498 |
| 472 if (first == null) { | 499 if (assignment != null) { |
| 473 current = first = assignment; | 500 if (first == null) { |
| 474 } else { | 501 current = first = assignment; |
| 475 current = current.next = assignment; | 502 } else { |
| 503 current = current.next = assignment; | |
| 504 } | |
| 476 } | 505 } |
| 477 } | 506 } |
| 478 | 507 |
| 479 if (first == null) { | 508 if (first == null) { |
| 480 first = buildRest(); | 509 first = buildRest(); |
| 481 } else { | 510 } else { |
| 482 current.next = buildRest(); | 511 current.next = buildRest(); |
| 483 } | 512 } |
| 484 return first; | 513 return first; |
| 485 } | 514 } |
| 486 | 515 |
| 487 Expression visitFunctionDefinition(ir.FunctionDefinition node) { | 516 Expression visitFunctionDefinition(ir.FunctionDefinition node) { |
| 488 returnContinuation = node.returnContinuation; | 517 returnContinuation = node.returnContinuation; |
| 489 List<Variable> parameters = <Variable>[]; | 518 List<Variable> parameters = <Variable>[]; |
| 490 for (ir.Parameter p in node.parameters) { | 519 for (ir.Parameter p in node.parameters) { |
| 491 Variable parameter = new Variable(p.element); | 520 Variable parameter = getVariable(p); |
| 521 assert(parameter != null); | |
| 492 parameters.add(parameter); | 522 parameters.add(parameter); |
| 493 variables[p] = parameter; | |
| 494 } | 523 } |
| 495 function = new FunctionDefinition(parameters, visit(node.body)); | 524 function = new FunctionDefinition(parameters, visit(node.body)); |
| 496 return null; | 525 return null; |
| 497 } | 526 } |
| 498 | 527 |
| 499 Statement visitLetPrim(ir.LetPrim node) { | 528 Statement visitLetPrim(ir.LetPrim node) { |
| 500 // LetPrim is translated to LetVal. | 529 // LetPrim is translated to Assign. |
| 501 Expression definition = visit(node.primitive); | 530 Expression definition = visit(node.primitive); |
| 502 if (node.primitive.hasAtLeastOneUse) { | 531 Variable variable = getVariable(node.primitive); |
| 503 Variable variable = new Variable(null); | 532 if (variable != null) { // variable is null if primitive is unused |
| 504 variables[node.primitive] = variable; | 533 return new Assign(variable, definition, node.body.accept(this)); |
| 505 return new Assign(variable, definition, visit(node.body), | |
| 506 node.primitive.hasExactlyOneUse); | |
| 507 } else if (node.primitive is ir.Constant) { | 534 } else if (node.primitive is ir.Constant) { |
| 508 // TODO(kmillikin): Implement more systematic treatment of pure CPS | 535 // TODO(kmillikin): Implement more systematic treatment of pure CPS |
| 509 // values (e.g., as part of a shrinking reductions pass). | 536 // values (e.g., as part of a shrinking reductions pass). |
| 510 return visit(node.body); | 537 return visit(node.body); |
| 511 } else { | 538 } else { |
| 512 return new ExpressionStatement(definition, visit(node.body)); | 539 return new ExpressionStatement(definition, visit(node.body)); |
| 513 } | 540 } |
| 514 } | 541 } |
| 515 | 542 |
| 516 Statement visitLetCont(ir.LetCont node) { | 543 Statement visitLetCont(ir.LetCont node) { |
| 517 Label label; | 544 Label label; |
| 518 if (node.continuation.hasMultipleUses) { | 545 if (node.continuation.hasMultipleUses) { |
| 519 label = new Label(); | 546 label = new Label(); |
| 520 labels[node.continuation] = label; | 547 labels[node.continuation] = label; |
| 521 } | 548 } |
| 522 node.continuation.parameters.forEach((p) { | |
| 523 if (p.hasAtLeastOneUse) variables[p] = new Variable(null); | |
| 524 }); | |
| 525 Statement body = visit(node.body); | 549 Statement body = visit(node.body); |
| 526 // The continuation's body is not always translated directly here because | 550 // The continuation's body is not always translated directly here because |
| 527 // it may have been already translated: | 551 // it may have been already translated: |
| 528 // * For singly-used continuations, the continuation's body is | 552 // * For singly-used continuations, the continuation's body is |
| 529 // translated at the site of the continuation invocation. | 553 // translated at the site of the continuation invocation. |
| 530 // * For recursive continuations, there is a single non-recursive | 554 // * For recursive continuations, there is a single non-recursive |
| 531 // invocation. The continuation's body is translated at the site | 555 // invocation. The continuation's body is translated at the site |
| 532 // of the non-recursive continuation invocation. | 556 // of the non-recursive continuation invocation. |
| 533 // See visitInvokeContinuation for the implementation. | 557 // See visitInvokeContinuation for the implementation. |
| 534 if (label == null || node.continuation.isRecursive) return body; | 558 if (label == null || node.continuation.isRecursive) return body; |
| 535 return new LabeledStatement(label, body, visit(node.continuation.body)); | 559 return new LabeledStatement(label, body, visit(node.continuation.body)); |
| 536 } | 560 } |
| 537 | 561 |
| 538 Statement visitInvokeStatic(ir.InvokeStatic node) { | 562 Statement visitInvokeStatic(ir.InvokeStatic node) { |
| 539 // Calls are translated to direct style. | 563 // Calls are translated to direct style. |
| 540 List<Expression> arguments = translateArguments(node.arguments); | 564 List<Expression> arguments = translateArguments(node.arguments); |
| 541 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); | 565 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); |
| 542 ir.Continuation cont = node.continuation.definition; | 566 ir.Continuation cont = node.continuation.definition; |
| 543 if (cont == returnContinuation) { | 567 if (cont == returnContinuation) { |
| 544 return new Return(invoke); | 568 return new Return(invoke); |
| 545 } else { | 569 } else { |
| 546 assert(cont.hasExactlyOneUse); | 570 assert(cont.hasExactlyOneUse); |
| 547 assert(cont.parameters.length == 1); | 571 assert(cont.parameters.length == 1); |
| 548 return buildParameterAssignments(cont.parameters, [invoke], | 572 return buildParameterAssignments(cont.parameters, [invoke], |
| 549 () => visit(cont.body)); | 573 () => visit(cont.body)); |
| 550 } | 574 } |
| 551 } | 575 } |
| 552 | 576 |
| 553 Statement visitInvokeMethod(ir.InvokeMethod node) { | 577 Statement visitInvokeMethod(ir.InvokeMethod node) { |
| 554 Variable receiver = variables[node.receiver.definition]; | 578 Expression receiver = getVariableReference(node.receiver); |
| 555 List<Expression> arguments = translateArguments(node.arguments); | 579 List<Expression> arguments = translateArguments(node.arguments); |
| 556 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); | 580 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); |
| 557 ir.Continuation cont = node.continuation.definition; | 581 ir.Continuation cont = node.continuation.definition; |
| 558 if (cont == returnContinuation) { | 582 if (cont == returnContinuation) { |
| 559 return new Return(invoke); | 583 return new Return(invoke); |
| 560 } else { | 584 } else { |
| 561 assert(cont.hasExactlyOneUse); | 585 assert(cont.hasExactlyOneUse); |
| 562 assert(cont.parameters.length == 1); | 586 assert(cont.parameters.length == 1); |
| 563 return buildParameterAssignments(cont.parameters, [invoke], | 587 return buildParameterAssignments(cont.parameters, [invoke], |
| 564 () => visit(cont.body)); | 588 () => visit(cont.body)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 596 | 620 |
| 597 Statement visitInvokeContinuation(ir.InvokeContinuation node) { | 621 Statement visitInvokeContinuation(ir.InvokeContinuation node) { |
| 598 // Invocations of the return continuation are translated to returns. | 622 // Invocations of the return continuation are translated to returns. |
| 599 // Other continuation invocations are replaced with assignments of the | 623 // Other continuation invocations are replaced with assignments of the |
| 600 // arguments to formal parameter variables, followed by the body if | 624 // arguments to formal parameter variables, followed by the body if |
| 601 // the continuation is singly reference or a break if it is multiply | 625 // the continuation is singly reference or a break if it is multiply |
| 602 // referenced. | 626 // referenced. |
| 603 ir.Continuation cont = node.continuation.definition; | 627 ir.Continuation cont = node.continuation.definition; |
| 604 if (cont == returnContinuation) { | 628 if (cont == returnContinuation) { |
| 605 assert(node.arguments.length == 1); | 629 assert(node.arguments.length == 1); |
| 606 return new Return(variables[node.arguments[0].definition]); | 630 return new Return(getVariableReference(node.arguments[0])); |
| 607 } else { | 631 } else { |
| 608 List<Expression> arguments = translateArguments(node.arguments); | 632 List<Expression> arguments = translateArguments(node.arguments); |
| 609 return buildParameterAssignments(cont.parameters, arguments, | 633 return buildParameterAssignments(cont.parameters, arguments, |
| 610 () { | 634 () { |
| 611 // Translate invocations of recursive and non-recursive | 635 // Translate invocations of recursive and non-recursive |
| 612 // continuations differently. | 636 // continuations differently. |
| 613 // * Non-recursive continuations | 637 // * Non-recursive continuations |
| 614 // - If there is one use, translate the continuation body | 638 // - If there is one use, translate the continuation body |
| 615 // inline at the invocation site. | 639 // inline at the invocation site. |
| 616 // - If there are multiple uses, translate to Break. | 640 // - If there are multiple uses, translate to Break. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 668 } | 692 } |
| 669 | 693 |
| 670 Expression visitContinuation(ir.Continuation node) { | 694 Expression visitContinuation(ir.Continuation node) { |
| 671 // Until continuations with multiple uses are supported, they are not | 695 // Until continuations with multiple uses are supported, they are not |
| 672 // visited. | 696 // visited. |
| 673 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); | 697 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); |
| 674 return null; | 698 return null; |
| 675 } | 699 } |
| 676 | 700 |
| 677 Expression visitIsTrue(ir.IsTrue node) { | 701 Expression visitIsTrue(ir.IsTrue node) { |
| 678 return variables[node.value.definition]; | 702 return getVariableReference(node.value); |
| 679 } | 703 } |
| 680 } | 704 } |
| 681 | 705 |
| 682 /** | 706 /** |
| 683 * Performs the following transformations on the tree: | 707 * Performs the following transformations on the tree: |
| 684 * - Assignment propagation | 708 * - Assignment propagation |
| 685 * - If-to-conditional conversion | 709 * - If-to-conditional conversion |
| 686 * - Flatten nested ifs | 710 * - Flatten nested ifs |
| 687 * - Break inlining | 711 * - Break inlining |
| 688 * - Redirect breaks | 712 * - Redirect breaks |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 | 931 |
| 908 Statement visitLabeledStatement(LabeledStatement node) { | 932 Statement visitLabeledStatement(LabeledStatement node) { |
| 909 if (node.next is Break) { | 933 if (node.next is Break) { |
| 910 // Eliminate label if next is just a break statement | 934 // Eliminate label if next is just a break statement |
| 911 // Breaks to this label are redirected to the outer label. | 935 // Breaks to this label are redirected to the outer label. |
| 912 // Note that breakCount for the two labels is updated proactively here | 936 // Note that breakCount for the two labels is updated proactively here |
| 913 // so breaks can reliably tell if they should inline their target. | 937 // so breaks can reliably tell if they should inline their target. |
| 914 Break next = node.next; | 938 Break next = node.next; |
| 915 Label newTarget = redirect(next.target); | 939 Label newTarget = redirect(next.target); |
| 916 labelRedirects[node.label] = newTarget; | 940 labelRedirects[node.label] = newTarget; |
| 917 newTarget.breakCount += node.label.breakCount; | 941 newTarget.breakCount += node.label.breakCount - 1; |
| 918 node.label.breakCount = 0; | 942 node.label.breakCount = 0; |
| 919 Statement result = visitStatement(node.body); | 943 Statement result = visitStatement(node.body); |
| 920 labelRedirects.remove(node.label); // Save some space. | 944 labelRedirects.remove(node.label); // Save some space. |
| 921 return result; | 945 return result; |
| 922 } | 946 } |
| 923 | 947 |
| 924 node.body = visitStatement(node.body); | 948 node.body = visitStatement(node.body); |
| 925 | 949 |
| 926 if (node.label.breakCount == 0) { | 950 if (node.label.breakCount == 0) { |
| 927 // Eliminate the label if next was inlined at a break | 951 // Eliminate the label if next was inlined at a break |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1032 static Statement combineStatementsWithSubexpressions( | 1056 static Statement combineStatementsWithSubexpressions( |
| 1033 Statement s, | 1057 Statement s, |
| 1034 Statement t, | 1058 Statement t, |
| 1035 Expression combine(Expression s, Expression t)) { | 1059 Expression combine(Expression s, Expression t)) { |
| 1036 if (s is Return && t is Return) { | 1060 if (s is Return && t is Return) { |
| 1037 return new Return(combine(s.value, t.value)); | 1061 return new Return(combine(s.value, t.value)); |
| 1038 } | 1062 } |
| 1039 if (s is Assign && t is Assign && s.variable == t.variable) { | 1063 if (s is Assign && t is Assign && s.variable == t.variable) { |
| 1040 Statement next = combineStatements(s.next, t.next); | 1064 Statement next = combineStatements(s.next, t.next); |
| 1041 if (next != null) { | 1065 if (next != null) { |
| 1066 --t.variable.writeCount; // Two assignments become one | |
| 1042 return new Assign(s.variable, | 1067 return new Assign(s.variable, |
| 1043 combine(s.definition, t.definition), | 1068 combine(s.definition, t.definition), |
| 1044 next, | 1069 next); |
| 1045 s.hasExactlyOneUse); | |
| 1046 } | 1070 } |
| 1047 } | 1071 } |
| 1048 if (s is ExpressionStatement && t is ExpressionStatement) { | 1072 if (s is ExpressionStatement && t is ExpressionStatement) { |
| 1049 Statement next = combineStatements(s.next, t.next); | 1073 Statement next = combineStatements(s.next, t.next); |
| 1050 if (next != null) { | 1074 if (next != null) { |
| 1051 return new ExpressionStatement(combine(s.expression, t.expression), | 1075 return new ExpressionStatement(combine(s.expression, t.expression), |
| 1052 next); | 1076 next); |
| 1053 } | 1077 } |
| 1054 } | 1078 } |
| 1055 return null; | 1079 return null; |
| 1056 } | 1080 } |
| 1057 | 1081 |
| 1058 /// Returns a statement equivalent to both [s] and [t], or null if [s] and | 1082 /// Returns a statement equivalent to both [s] and [t], or null if [s] and |
| 1059 /// [t] are incompatible. | 1083 /// [t] are incompatible. |
| 1060 /// If non-null is returned, the caller MUST discard [s] and [t] and use | 1084 /// If non-null is returned, the caller MUST discard [s] and [t] and use |
| 1061 /// the returned statement instead. | 1085 /// the returned statement instead. |
| 1062 /// If two breaks are combined, the label's break counter will be decremented. | 1086 /// If two breaks are combined, the label's break counter will be decremented. |
| 1063 static Statement combineStatements(Statement s, Statement t) { | 1087 static Statement combineStatements(Statement s, Statement t) { |
| 1064 if (s is Break && t is Break && s.target == t.target) { | 1088 if (s is Break && t is Break && s.target == t.target) { |
| 1065 --t.target.breakCount; // Two breaks become one. | 1089 --t.target.breakCount; // Two breaks become one. |
| 1066 return s; | 1090 return s; |
| 1067 } | 1091 } |
| 1068 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { | 1092 if (s is Return && t is Return) { |
| 1069 return s; | 1093 Expression e = combineExpressions(s.value, t.value); |
| 1094 if (e != null) { | |
| 1095 return new Return(e); | |
| 1096 } | |
| 1070 } | 1097 } |
| 1071 return null; | 1098 return null; |
| 1072 } | 1099 } |
| 1073 | 1100 |
| 1074 /// True if the two expressions both syntactically and semantically | 1101 /// Returns an expression equivalent to both [e1] and [e2]. |
| 1075 /// equivalent. | 1102 /// If non-null is returned, the caller must discard [e1] and [e2] and use |
| 1076 static bool equivalentExpressions(Expression e1, Expression e2) { | 1103 /// the resulting expression in the tree. |
| 1077 if (e1 == e2) { // Detect same variable reference | 1104 static Expression combineExpressions(Expression e1, Expression e2) { |
| 1078 // TODO(asgerf): This might turn the variable into a single-use, | 1105 if (e1 is Variable && e1 == e2) { |
| 1079 // but we currently don't discover this. | 1106 --e1.readCount; // Two references become one. |
| 1080 return true; | 1107 return e1; |
| 1081 } | 1108 } |
| 1082 if (e1 is Constant && e2 is Constant) { | 1109 if (e1 is Constant && e2 is Constant && e1.value == e2.value) { |
| 1083 return e1.value == e2.value; | 1110 return e1; |
| 1084 } | 1111 } |
| 1085 return false; | 1112 return null; |
| 1086 } | 1113 } |
| 1087 | 1114 |
| 1088 /// Try to collapse nested ifs using && and || expressions. | 1115 /// Try to collapse nested ifs using && and || expressions. |
| 1089 /// For example: | 1116 /// For example: |
| 1090 /// | 1117 /// |
| 1091 /// if (E1) { if (E2) S else break L } else break L | 1118 /// if (E1) { if (E2) S else break L } else break L |
| 1092 /// ==> | 1119 /// ==> |
| 1093 /// if (E1 && E2) S else break L | 1120 /// if (E1 && E2) S else break L |
| 1094 /// | 1121 /// |
| 1095 /// [branch1] and [branch2] control the position of the S statement. | 1122 /// [branch1] and [branch2] control the position of the S statement. |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1571 } | 1598 } |
| 1572 } | 1599 } |
| 1573 | 1600 |
| 1574 /// Destructively updates each entry of [l] with the result of visiting it. | 1601 /// Destructively updates each entry of [l] with the result of visiting it. |
| 1575 void _rewriteList(List<Expression> l) { | 1602 void _rewriteList(List<Expression> l) { |
| 1576 for (int i = 0; i < l.length; i++) { | 1603 for (int i = 0; i < l.length; i++) { |
| 1577 l[i] = visitExpression(l[i]); | 1604 l[i] = visitExpression(l[i]); |
| 1578 } | 1605 } |
| 1579 } | 1606 } |
| 1580 } | 1607 } |
| OLD | NEW |