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