BranchOptimizer.java revision 1262:ee849fe4b32d
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; 34import static jdk.nashorn.internal.parser.TokenType.NOT; 35 36import jdk.nashorn.internal.ir.BinaryNode; 37import jdk.nashorn.internal.ir.Expression; 38import jdk.nashorn.internal.ir.JoinPredecessorExpression; 39import jdk.nashorn.internal.ir.LocalVariableConversion; 40import jdk.nashorn.internal.ir.UnaryNode; 41 42/** 43 * Branch optimizer for CodeGenerator. Given a jump condition this helper 44 * class attempts to simplify the control flow 45 */ 46final class BranchOptimizer { 47 48 private final CodeGenerator codegen; 49 private final MethodEmitter method; 50 51 BranchOptimizer(final CodeGenerator codegen, final MethodEmitter method) { 52 this.codegen = codegen; 53 this.method = method; 54 } 55 56 void execute(final Expression node, final Label label, final boolean state) { 57 branchOptimizer(node, label, state); 58 } 59 60 private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { 61 if (unaryNode.isTokenType(NOT)) { 62 branchOptimizer(unaryNode.getExpression(), label, !state); 63 } else { 64 loadTestAndJump(unaryNode, label, state); 65 } 66 } 67 68 private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { 69 final Expression lhs = binaryNode.lhs(); 70 final Expression rhs = binaryNode.rhs(); 71 72 switch (binaryNode.tokenType()) { 73 case AND: 74 if (state) { 75 final Label skip = new Label("skip"); 76 optimizeLogicalOperand(lhs, skip, false, false); 77 optimizeLogicalOperand(rhs, label, true, true); 78 method.label(skip); 79 } else { 80 optimizeLogicalOperand(lhs, label, false, false); 81 optimizeLogicalOperand(rhs, label, false, true); 82 } 83 return; 84 85 case OR: 86 if (state) { 87 optimizeLogicalOperand(lhs, label, true, false); 88 optimizeLogicalOperand(rhs, label, true, true); 89 } else { 90 final Label skip = new Label("skip"); 91 optimizeLogicalOperand(lhs, skip, true, false); 92 optimizeLogicalOperand(rhs, label, false, true); 93 method.label(skip); 94 } 95 return; 96 97 case EQ: 98 case EQ_STRICT: 99 codegen.loadComparisonOperands(binaryNode); 100 method.conditionalJump(state ? EQ : NE, true, label); 101 return; 102 103 case NE: 104 case NE_STRICT: 105 codegen.loadComparisonOperands(binaryNode); 106 method.conditionalJump(state ? NE : EQ, true, label); 107 return; 108 109 case GE: 110 codegen.loadComparisonOperands(binaryNode); 111 method.conditionalJump(state ? GE : LT, false, label); 112 return; 113 114 case GT: 115 codegen.loadComparisonOperands(binaryNode); 116 method.conditionalJump(state ? GT : LE, false, label); 117 return; 118 119 case LE: 120 codegen.loadComparisonOperands(binaryNode); 121 method.conditionalJump(state ? LE : GT, true, label); 122 return; 123 124 case LT: 125 codegen.loadComparisonOperands(binaryNode); 126 method.conditionalJump(state ? LT : GE, true, label); 127 return; 128 129 default: 130 break; 131 } 132 133 loadTestAndJump(binaryNode, label, state); 134 } 135 136 private void optimizeLogicalOperand(final Expression expr, final Label label, final boolean state, final boolean isRhs) { 137 final JoinPredecessorExpression jpexpr = (JoinPredecessorExpression)expr; 138 if(LocalVariableConversion.hasLiveConversion(jpexpr)) { 139 final Label after = new Label("after"); 140 branchOptimizer(jpexpr.getExpression(), after, !state); 141 method.beforeJoinPoint(jpexpr); 142 method._goto(label); 143 method.label(after); 144 if(isRhs) { 145 method.beforeJoinPoint(jpexpr); 146 } 147 } else { 148 branchOptimizer(jpexpr.getExpression(), label, state); 149 } 150 } 151 private void branchOptimizer(final Expression node, final Label label, final boolean state) { 152 if (node instanceof BinaryNode) { 153 branchOptimizer((BinaryNode)node, label, state); 154 return; 155 } 156 157 if (node instanceof UnaryNode) { 158 branchOptimizer((UnaryNode)node, label, state); 159 return; 160 } 161 162 loadTestAndJump(node, label, state); 163 } 164 165 private void loadTestAndJump(final Expression node, final Label label, final boolean state) { 166 codegen.loadExpressionAsBoolean(node); 167 if (state) { 168 method.ifne(label); 169 } else { 170 method.ifeq(label); 171 } 172 } 173} 174