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