BranchOptimizer.java revision 1197:20c3aef2b4cb
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.codegen; 27 28import static jdk.nashorn.internal.codegen.Condition.EQ; 29import static jdk.nashorn.internal.codegen.Condition.GE; 30import static jdk.nashorn.internal.codegen.Condition.GT; 31import static jdk.nashorn.internal.codegen.Condition.LE; 32import static jdk.nashorn.internal.codegen.Condition.LT; 33import static jdk.nashorn.internal.codegen.Condition.NE; 34 35import jdk.nashorn.internal.ir.BinaryNode; 36import jdk.nashorn.internal.ir.Expression; 37import jdk.nashorn.internal.ir.JoinPredecessorExpression; 38import jdk.nashorn.internal.ir.LocalVariableConversion; 39import jdk.nashorn.internal.ir.UnaryNode; 40 41/** 42 * Branch optimizer for CodeGenerator. Given a jump condition this helper 43 * class attempts to simplify the control flow 44 */ 45final class BranchOptimizer { 46 47 private final CodeGenerator codegen; 48 private final MethodEmitter method; 49 50 BranchOptimizer(final CodeGenerator codegen, final MethodEmitter method) { 51 this.codegen = codegen; 52 this.method = method; 53 } 54 55 void execute(final Expression node, final Label label, final boolean state) { 56 branchOptimizer(node, label, state); 57 } 58 59 private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { 60 final Expression rhs = unaryNode.getExpression(); 61 62 switch (unaryNode.tokenType()) { 63 case NOT: 64 branchOptimizer(rhs, label, !state); 65 return; 66 default: 67 if (unaryNode.getType().isBoolean()) { 68 branchOptimizer(rhs, label, state); 69 return; 70 } 71 break; 72 } 73 74 loadTestAndJump(unaryNode, label, state); 75 } 76 77 private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { 78 final Expression lhs = binaryNode.lhs(); 79 final Expression rhs = binaryNode.rhs(); 80 81 switch (binaryNode.tokenType()) { 82 case AND: 83 if (state) { 84 final Label skip = new Label("skip"); 85 optimizeLogicalOperand(lhs, skip, false, false); 86 optimizeLogicalOperand(rhs, label, true, true); 87 method.label(skip); 88 } else { 89 optimizeLogicalOperand(lhs, label, false, false); 90 optimizeLogicalOperand(rhs, label, false, true); 91 } 92 return; 93 94 case OR: 95 if (state) { 96 optimizeLogicalOperand(lhs, label, true, false); 97 optimizeLogicalOperand(rhs, label, true, true); 98 } else { 99 final Label skip = new Label("skip"); 100 optimizeLogicalOperand(lhs, skip, true, false); 101 optimizeLogicalOperand(rhs, label, false, true); 102 method.label(skip); 103 } 104 return; 105 106 case EQ: 107 case EQ_STRICT: 108 codegen.loadComparisonOperands(binaryNode); 109 method.conditionalJump(state ? EQ : NE, true, label); 110 return; 111 112 case NE: 113 case NE_STRICT: 114 codegen.loadComparisonOperands(binaryNode); 115 method.conditionalJump(state ? NE : EQ, true, label); 116 return; 117 118 case GE: 119 codegen.loadComparisonOperands(binaryNode); 120 method.conditionalJump(state ? GE : LT, false, label); 121 return; 122 123 case GT: 124 codegen.loadComparisonOperands(binaryNode); 125 method.conditionalJump(state ? GT : LE, false, label); 126 return; 127 128 case LE: 129 codegen.loadComparisonOperands(binaryNode); 130 method.conditionalJump(state ? LE : GT, true, label); 131 return; 132 133 case LT: 134 codegen.loadComparisonOperands(binaryNode); 135 method.conditionalJump(state ? LT : GE, true, label); 136 return; 137 138 default: 139 break; 140 } 141 142 loadTestAndJump(binaryNode, label, state); 143 } 144 145 private void optimizeLogicalOperand(final Expression expr, final Label label, final boolean state, final boolean isRhs) { 146 final JoinPredecessorExpression jpexpr = (JoinPredecessorExpression)expr; 147 if(LocalVariableConversion.hasLiveConversion(jpexpr)) { 148 final Label after = new Label("after"); 149 branchOptimizer(jpexpr.getExpression(), after, !state); 150 method.beforeJoinPoint(jpexpr); 151 method._goto(label); 152 method.label(after); 153 if(isRhs) { 154 method.beforeJoinPoint(jpexpr); 155 } 156 } else { 157 branchOptimizer(jpexpr.getExpression(), label, state); 158 } 159 } 160 private void branchOptimizer(final Expression node, final Label label, final boolean state) { 161 if (node instanceof BinaryNode) { 162 branchOptimizer((BinaryNode)node, label, state); 163 return; 164 } 165 166 if (node instanceof UnaryNode) { 167 branchOptimizer((UnaryNode)node, label, state); 168 return; 169 } 170 171 loadTestAndJump(node, label, state); 172 } 173 174 private void loadTestAndJump(final Expression node, final Label label, final boolean state) { 175 codegen.loadExpressionAsBoolean(node); 176 if (state) { 177 method.ifne(label); 178 } else { 179 method.ifeq(label); 180 } 181 } 182} 183