Chromium Code Reviews| Index: pkg/compiler/lib/src/ssa/builder.dart |
| diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart |
| index c9ef7eeb36a8334be1988372ff04a6645a278c72..a5216b263946051f88fd851b264e95851d397826 100644 |
| --- a/pkg/compiler/lib/src/ssa/builder.dart |
| +++ b/pkg/compiler/lib/src/ssa/builder.dart |
| @@ -4,6 +4,7 @@ |
| import 'dart:collection'; |
| +import 'package:compiler/src/ssa/ssa_branch_builder.dart'; |
| import 'package:js_runtime/shared/embedded_names.dart'; |
| import '../closure.dart'; |
| @@ -411,8 +412,6 @@ class SsaBuilder extends ast.Visitor |
| */ |
| final List<Element> sourceElementStack = <Element>[]; |
| - LocalsHandler localsHandler; |
| - |
| HInstruction rethrowableException; |
| Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
| @@ -1907,7 +1906,8 @@ class SsaBuilder extends ast.Visitor |
| push(attachPosition(instruction, node)); |
| } |
| - HInstruction popBoolified() { |
| + @override |
| + HBoolify popBoolified() { |
| HInstruction value = pop(); |
| if (_checkOrTrustTypes) { |
| return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, |
| @@ -2537,31 +2537,75 @@ class SsaBuilder extends ast.Visitor |
| void visitThen(), |
| void visitElse(), |
| SourceInformation sourceInformation}) { |
| - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
| + SsaBranchBuilder branchBuilder = |
| + new SsaBranchBuilder(this, compiler, diagnosticNode); |
| branchBuilder.handleIf(visitCondition, visitThen, visitElse, |
| sourceInformation: sourceInformation); |
| } |
| @override |
| void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleIfNull(() => visit(left), () => visit(right)); |
| } |
| @override |
| void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
| - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| - branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
| - visit(right); |
| - }, isAnd: true); |
| + SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
| + |
| + // This method is similar to [SsaBranchBuilder.handleLogicalAndOr] but |
| + // optimizes the case where left is a logical "and". |
| + // |
| + // For example (x && y) && z is transformed into x && (y && z): |
| + // t0 = boolify(x); |
| + // if (t0) { |
| + // t1 = boolify(y); |
| + // if (t1) { |
| + // t2 = boolify(z); |
| + // } |
| + // t3 = phi(t2, false); |
| + // } |
| + // result = phi(t3, false); |
| + void handleLogicalAndWithLeftNode(ast.Node left, void visitRight()) { |
| + ast.Send send = left.asSend(); |
| + if (send != null && send.isLogicalAnd) { |
| + ast.Node newLeft = send.receiver; |
| + Link<ast.Node> link = send.argumentsNode.nodes; |
| + assert(link.tail.isEmpty); |
| + ast.Node middle = link.head; |
| + handleLogicalAndWithLeftNode( |
| + newLeft, () => handleLogicalAndWithLeftNode(middle, visitRight)); |
| + } else { |
| + branchBuilder.handleLogicalAndOr(() => visit(left), visitRight, |
| + isAnd: true); |
| + } |
| + } |
| + |
| + handleLogicalAndWithLeftNode(left, () => visit(right)); |
| } |
| @override |
| void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
| - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| - branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
| - visit(right); |
| - }, isAnd: false); |
| + SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
| + |
| + // This method is similar to [SsaBranchBuilder.handleLogicalAndOr] but |
| + // optimizes the case where left is a logical "or". |
| + void handleLogicalOrWithLeftNode(ast.Node left, void visitRight()) { |
|
Siggi Cherem (dart-lang)
2016/09/01 23:51:21
what if we keep the handleLogicalAndOrWithLeftNode
Harry Terkelsen
2016/09/02 17:52:27
Done.
|
| + ast.Send send = left.asSend(); |
| + if (send != null && send.isLogicalOr) { |
| + ast.Node newLeft = send.receiver; |
| + Link<ast.Node> link = send.argumentsNode.nodes; |
| + assert(link.tail.isEmpty); |
| + ast.Node middle = link.head; |
| + handleLogicalOrWithLeftNode( |
| + newLeft, () => handleLogicalOrWithLeftNode(middle, visitRight)); |
| + } else { |
| + branchBuilder.handleLogicalAndOr(() => visit(left), visitRight, |
| + isAnd: true); |
|
Siggi Cherem (dart-lang)
2016/09/01 23:51:21
shouldn't this be "false"?
Harry Terkelsen
2016/09/02 17:52:27
oops! good catch
|
| + } |
| + } |
| + |
| + handleLogicalOrWithLeftNode(left, () => visit(right)); |
| } |
| @override |
| @@ -2819,7 +2863,7 @@ class SsaBuilder extends ast.Visitor |
| // we will be able to later compress it as: |
| // t1 || t1.x |
| HInstruction expression; |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleConditional( |
| () { |
| expression = visitAndPop(receiver); |
| @@ -2835,7 +2879,7 @@ class SsaBuilder extends ast.Visitor |
| }); |
| } |
| - /// Pushes a boolean checking [expression] against null. |
| + @override |
| pushCheckNull(HInstruction expression) { |
| push(new HIdentity( |
| expression, graph.addConstantNull(compiler), null, backend.boolType)); |
| @@ -3202,7 +3246,7 @@ class SsaBuilder extends ast.Visitor |
| ast.NodeList arguments, Selector selector, _) { |
| /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` |
| HInstruction receiver; |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleConditional(() { |
| receiver = generateInstanceSendReceiver(node); |
| pushCheckNull(receiver); |
| @@ -5008,7 +5052,7 @@ class SsaBuilder extends ast.Visitor |
| } |
| if (node.isIfNullAssignment) { |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| addDynamicSendArgumentsToList(node, setterInputs); |
| generateSuperSendSet(); |
| @@ -5328,7 +5372,7 @@ class SsaBuilder extends ast.Visitor |
| // if (t1 == null) |
| // t1 = x[i] = e; |
| // result = t1 |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| visit(arguments.head); |
| HInstruction value = pop(); |
| @@ -5376,7 +5420,7 @@ class SsaBuilder extends ast.Visitor |
| // else |
| // result = e.x = e2 |
| HInstruction receiverInstruction; |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleConditional( |
| () { |
| receiverInstruction = generateInstanceSendReceiver(node); |
| @@ -5549,7 +5593,8 @@ class SsaBuilder extends ast.Visitor |
| receiver); |
| HInstruction getterInstruction = pop(); |
| if (node.isIfNullAssignment) { |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = |
| + new SsaBranchBuilder(this, compiler, node); |
| brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| visit(node.arguments.head); |
| generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
| @@ -5570,7 +5615,7 @@ class SsaBuilder extends ast.Visitor |
| // t1 = e |
| // t1 == null ? t1 : (t1.x = t1.x op e2); |
| HInstruction receiver; |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleConditional(() { |
| receiver = generateInstanceSendReceiver(node); |
| pushCheckNull(receiver); |
| @@ -5596,7 +5641,7 @@ class SsaBuilder extends ast.Visitor |
| } |
| HInstruction getterInstruction = pop(); |
| if (node.isIfNullAssignment) { |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| visit(node.arguments.head); |
| generateNonInstanceSetter(node, element, pop()); |
| @@ -6006,7 +6051,7 @@ class SsaBuilder extends ast.Visitor |
| } |
| visitConditional(ast.Conditional node) { |
| - SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
| brancher.handleConditional(() => visit(node.condition), |
| () => visit(node.thenExpression), () => visit(node.elseExpression)); |
| } |
| @@ -7478,252 +7523,6 @@ class AstInliningState extends InliningState { |
| : super(function); |
| } |
| -class SsaBranch { |
| - final SsaBranchBuilder branchBuilder; |
| - final HBasicBlock block; |
| - LocalsHandler startLocals; |
| - LocalsHandler exitLocals; |
| - SubGraph graph; |
| - |
| - SsaBranch(this.branchBuilder) : block = new HBasicBlock(); |
| -} |
| - |
| -class SsaBranchBuilder { |
| - final SsaBuilder builder; |
| - final ast.Node diagnosticNode; |
| - |
| - SsaBranchBuilder(this.builder, [this.diagnosticNode]); |
| - |
| - Compiler get compiler => builder.compiler; |
| - |
| - void checkNotAborted() { |
| - if (builder.isAborted()) { |
| - compiler.unimplemented(diagnosticNode, "aborted control flow"); |
| - } |
| - } |
| - |
| - void buildCondition( |
| - void visitCondition(), |
| - SsaBranch conditionBranch, |
| - SsaBranch thenBranch, |
| - SsaBranch elseBranch, |
| - SourceInformation sourceInformation) { |
| - startBranch(conditionBranch); |
| - visitCondition(); |
| - checkNotAborted(); |
| - assert(identical(builder.current, builder.lastOpenedBlock)); |
| - HInstruction conditionValue = builder.popBoolified(); |
| - HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; |
| - HBasicBlock conditionExitBlock = builder.current; |
| - builder.close(branch); |
| - conditionBranch.exitLocals = builder.localsHandler; |
| - conditionExitBlock.addSuccessor(thenBranch.block); |
| - conditionExitBlock.addSuccessor(elseBranch.block); |
| - bool conditionBranchLocalsCanBeReused = |
| - mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); |
| - mergeLocals(conditionBranch, elseBranch, |
| - mayReuseFromLocals: conditionBranchLocalsCanBeReused); |
| - |
| - conditionBranch.graph = |
| - new SubExpression(conditionBranch.block, conditionExitBlock); |
| - } |
| - |
| - /** |
| - * Returns true if the locals of the [fromBranch] may be reused. A [:true:] |
| - * return value implies that [mayReuseFromLocals] was set to [:true:]. |
| - */ |
| - bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, |
| - {bool mayReuseFromLocals}) { |
| - LocalsHandler fromLocals = fromBranch.exitLocals; |
| - if (toBranch.startLocals == null) { |
| - if (mayReuseFromLocals) { |
| - toBranch.startLocals = fromLocals; |
| - return false; |
| - } else { |
| - toBranch.startLocals = new LocalsHandler.from(fromLocals); |
| - return true; |
| - } |
| - } else { |
| - toBranch.startLocals.mergeWith(fromLocals, toBranch.block); |
| - return true; |
| - } |
| - } |
| - |
| - void startBranch(SsaBranch branch) { |
| - builder.graph.addBlock(branch.block); |
| - builder.localsHandler = branch.startLocals; |
| - builder.open(branch.block); |
| - } |
| - |
| - HInstruction buildBranch(SsaBranch branch, void visitBranch(), |
| - SsaBranch joinBranch, bool isExpression) { |
| - startBranch(branch); |
| - visitBranch(); |
| - branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); |
| - branch.exitLocals = builder.localsHandler; |
| - if (!builder.isAborted()) { |
| - builder.goto(builder.current, joinBranch.block); |
| - mergeLocals(branch, joinBranch, mayReuseFromLocals: true); |
| - } |
| - if (isExpression) { |
| - checkNotAborted(); |
| - return builder.pop(); |
| - } |
| - return null; |
| - } |
| - |
| - handleIf(void visitCondition(), void visitThen(), void visitElse(), |
| - {SourceInformation sourceInformation}) { |
| - if (visitElse == null) { |
| - // Make sure to have an else part to avoid a critical edge. A |
| - // critical edge is an edge that connects a block with multiple |
| - // successors to a block with multiple predecessors. We avoid |
| - // such edges because they prevent inserting copies during code |
| - // generation of phi instructions. |
| - visitElse = () {}; |
| - } |
| - |
| - _handleDiamondBranch(visitCondition, visitThen, visitElse, |
| - isExpression: false, sourceInformation: sourceInformation); |
| - } |
| - |
| - handleConditional(void visitCondition(), void visitThen(), void visitElse()) { |
| - assert(visitElse != null); |
| - _handleDiamondBranch(visitCondition, visitThen, visitElse, |
| - isExpression: true); |
| - } |
| - |
| - handleIfNull(void left(), void right()) { |
| - // x ?? y is transformed into: x == null ? y : x |
| - HInstruction leftExpression; |
| - handleConditional(() { |
| - left(); |
| - leftExpression = builder.pop(); |
| - builder.pushCheckNull(leftExpression); |
| - }, right, () => builder.stack.add(leftExpression)); |
| - } |
| - |
| - void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { |
| - // x && y is transformed into: |
| - // t0 = boolify(x); |
| - // if (t0) { |
| - // t1 = boolify(y); |
| - // } |
| - // result = phi(t1, false); |
| - // |
| - // x || y is transformed into: |
| - // t0 = boolify(x); |
| - // if (not(t0)) { |
| - // t1 = boolify(y); |
| - // } |
| - // result = phi(t1, true); |
| - HInstruction boolifiedLeft; |
| - HInstruction boolifiedRight; |
| - |
| - void visitCondition() { |
| - left(); |
| - boolifiedLeft = builder.popBoolified(); |
| - builder.stack.add(boolifiedLeft); |
| - if (!isAnd) { |
| - builder.push(new HNot(builder.pop(), builder.backend.boolType)); |
| - } |
| - } |
| - |
| - void visitThen() { |
| - right(); |
| - boolifiedRight = builder.popBoolified(); |
| - } |
| - |
| - handleIf(visitCondition, visitThen, null); |
| - HConstant notIsAnd = |
| - builder.graph.addConstantBool(!isAnd, builder.compiler); |
| - JavaScriptBackend backend = builder.backend; |
| - HPhi result = new HPhi.manyInputs( |
| - null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); |
| - builder.current.addPhi(result); |
| - builder.stack.add(result); |
| - } |
| - |
| - void handleLogicalAndOrWithLeftNode(ast.Node left, void visitRight(), |
| - {bool isAnd}) { |
| - // This method is similar to [handleLogicalAndOr] but optimizes the case |
| - // where left is a logical "and" or logical "or". |
| - // |
| - // For example (x && y) && z is transformed into x && (y && z): |
| - // t0 = boolify(x); |
| - // if (t0) { |
| - // t1 = boolify(y); |
| - // if (t1) { |
| - // t2 = boolify(z); |
| - // } |
| - // t3 = phi(t2, false); |
| - // } |
| - // result = phi(t3, false); |
| - |
| - ast.Send send = left.asSend(); |
| - if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { |
| - ast.Node newLeft = send.receiver; |
| - Link<ast.Node> link = send.argumentsNode.nodes; |
| - assert(link.tail.isEmpty); |
| - ast.Node middle = link.head; |
| - handleLogicalAndOrWithLeftNode( |
| - newLeft, |
| - () => |
| - handleLogicalAndOrWithLeftNode(middle, visitRight, isAnd: isAnd), |
| - isAnd: isAnd); |
| - } else { |
| - handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); |
| - } |
| - } |
| - |
| - void _handleDiamondBranch( |
| - void visitCondition(), void visitThen(), void visitElse(), |
| - {bool isExpression, SourceInformation sourceInformation}) { |
| - SsaBranch conditionBranch = new SsaBranch(this); |
| - SsaBranch thenBranch = new SsaBranch(this); |
| - SsaBranch elseBranch = new SsaBranch(this); |
| - SsaBranch joinBranch = new SsaBranch(this); |
| - |
| - conditionBranch.startLocals = builder.localsHandler; |
| - builder.goto(builder.current, conditionBranch.block); |
| - |
| - buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, |
| - sourceInformation); |
| - HInstruction thenValue = |
| - buildBranch(thenBranch, visitThen, joinBranch, isExpression); |
| - HInstruction elseValue = |
| - buildBranch(elseBranch, visitElse, joinBranch, isExpression); |
| - |
| - if (isExpression) { |
| - assert(thenValue != null && elseValue != null); |
| - JavaScriptBackend backend = builder.backend; |
| - HPhi phi = new HPhi.manyInputs( |
| - null, <HInstruction>[thenValue, elseValue], backend.dynamicType); |
| - joinBranch.block.addPhi(phi); |
| - builder.stack.add(phi); |
| - } |
| - |
| - HBasicBlock joinBlock; |
| - // If at least one branch did not abort, open the joinBranch. |
| - if (!joinBranch.block.predecessors.isEmpty) { |
| - startBranch(joinBranch); |
| - joinBlock = joinBranch.block; |
| - } |
| - |
| - HIfBlockInformation info = new HIfBlockInformation( |
| - new HSubExpressionBlockInformation(conditionBranch.graph), |
| - new HSubGraphBlockInformation(thenBranch.graph), |
| - new HSubGraphBlockInformation(elseBranch.graph)); |
| - |
| - HBasicBlock conditionStartBlock = conditionBranch.block; |
| - conditionStartBlock.setBlockFlow(info, joinBlock); |
| - SubGraph conditionGraph = conditionBranch.graph; |
| - HIf branch = conditionGraph.end.last; |
| - assert(branch is HIf); |
| - branch.blockInformation = conditionStartBlock.blockFlow; |
| - } |
| -} |
| - |
| class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
| final ClassWorld classWorld; |