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
26 package com.sun.tools.javac.jvm;
27
28 import java.util.*;
29
30 import com.sun.tools.javac.util.*;
31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
32 import com.sun.tools.javac.util.List;
33 import com.sun.tools.javac.code.*;
34 import com.sun.tools.javac.code.Attribute.TypeCompound;
35 import com.sun.tools.javac.code.Symbol.VarSymbol;
36 import com.sun.tools.javac.comp.*;
37 import com.sun.tools.javac.tree.*;
38
39 import com.sun.tools.javac.code.Symbol.*;
40 import com.sun.tools.javac.code.Type.*;
41 import com.sun.tools.javac.jvm.Code.*;
42 import com.sun.tools.javac.jvm.Items.*;
43 import com.sun.tools.javac.tree.EndPosTable;
44 import com.sun.tools.javac.tree.JCTree.*;
45
46 import static com.sun.tools.javac.code.Flags.*;
47 import static com.sun.tools.javac.code.Kinds.Kind.*;
48 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
49 import static com.sun.tools.javac.code.TypeTag.*;
50 import static com.sun.tools.javac.jvm.ByteCodes.*;
51 import static com.sun.tools.javac.jvm.CRTFlags.*;
52 import static com.sun.tools.javac.main.Option.*;
53 import static com.sun.tools.javac.tree.JCTree.Tag.*;
54
55 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
56 *
57 * <p><b>This is NOT part of any supported API.
58 * If you write code that depends on this, you do so at your own risk.
59 * This code and its internal interfaces are subject to change or
60 * deletion without notice.</b>
61 */
62 public class Gen extends JCTree.Visitor {
63 protected static final Context.Key<Gen> genKey = new Context.Key<>();
64
65 private final Log log;
66 private final Symtab syms;
67 private final Check chk;
68 private final Resolve rs;
69 private final TreeMaker make;
70 private final Names names;
71 private final Target target;
72 private final Map<Type,Symbol> stringBufferAppend;
73 private Name accessDollar;
74 private final Types types;
75 private final Lower lower;
76 private final Flow flow;
77 private final Annotate annotate;
78
79 /** Format of stackmap tables to be generated. */
80 private final Code.StackMapFormat stackMap;
81
82 /** A type that serves as the expected type for all method expressions.
83 */
84 private final Type methodType;
85
86 public static Gen instance(Context context) {
87 Gen instance = context.get(genKey);
88 if (instance == null)
89 instance = new Gen(context);
90 return instance;
91 }
92
93 /** Constant pool, reset by genClass.
94 */
95 private Pool pool;
96
97 protected Gen(Context context) {
98 context.put(genKey, this);
99
100 names = Names.instance(context);
101 log = Log.instance(context);
102 syms = Symtab.instance(context);
103 chk = Check.instance(context);
104 rs = Resolve.instance(context);
105 make = TreeMaker.instance(context);
106 target = Target.instance(context);
107 types = Types.instance(context);
108 methodType = new MethodType(null, null, null, syms.methodClass);
109 stringBufferAppend = new HashMap<>();
110 accessDollar = names.
111 fromString("access" + target.syntheticNameChar());
112 flow = Flow.instance(context);
113 lower = Lower.instance(context);
114
115 Options options = Options.instance(context);
116 lineDebugInfo =
117 options.isUnset(G_CUSTOM) ||
118 options.isSet(G_CUSTOM, "lines");
119 varDebugInfo =
120 options.isUnset(G_CUSTOM)
121 ? options.isSet(G)
122 : options.isSet(G_CUSTOM, "vars");
123 genCrt = options.isSet(XJCOV);
124 debugCode = options.isSet("debugcode");
125 allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
126 allowBetterNullChecks = target.hasObjects();
127 pool = new Pool(types);
128
129 // ignore cldc because we cannot have both stackmap formats
736 code.resolve(cond.trueJumps);
737 CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
738 if (markBranches) first.tree = tree.truepart;
739 Chain falseJumps = first.jumpFalse();
740 code.resolve(first.trueJumps);
741 Chain trueJumps = code.branch(goto_);
742 code.resolve(secondJumps);
743 CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
744 CondItem result = items.makeCondItem(second.opcode,
745 Code.mergeChains(trueJumps, second.trueJumps),
746 Code.mergeChains(falseJumps, second.falseJumps));
747 if (markBranches) result.tree = tree.falsepart;
748 return result;
749 } else {
750 CondItem result = genExpr(_tree, syms.booleanType).mkCond();
751 if (markBranches) result.tree = _tree;
752 return result;
753 }
754 }
755
756 /** Visitor class for expressions which might be constant expressions.
757 * This class is a subset of TreeScanner. Intended to visit trees pruned by
758 * Lower as long as constant expressions looking for references to any
759 * ClassSymbol. Any such reference will be added to the constant pool so
760 * automated tools can detect class dependencies better.
761 */
762 class ClassReferenceVisitor extends JCTree.Visitor {
763
764 @Override
765 public void visitTree(JCTree tree) {}
766
767 @Override
768 public void visitBinary(JCBinary tree) {
769 tree.lhs.accept(this);
770 tree.rhs.accept(this);
771 }
772
773 @Override
774 public void visitSelect(JCFieldAccess tree) {
775 if (tree.selected.type.hasTag(CLASS)) {
1878 result = genExpr(tree.expr, tree.expr.type);
1879 }
1880
1881 public void visitAssign(JCAssign tree) {
1882 Item l = genExpr(tree.lhs, tree.lhs.type);
1883 genExpr(tree.rhs, tree.lhs.type).load();
1884 if (tree.rhs.type.hasTag(BOT)) {
1885 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
1886 for "regarding a reference as having some other type in a manner that can be proved
1887 correct at compile time."
1888 */
1889 code.state.forceStackTop(tree.lhs.type);
1890 }
1891 result = items.makeAssignItem(l);
1892 }
1893
1894 public void visitAssignop(JCAssignOp tree) {
1895 OperatorSymbol operator = (OperatorSymbol) tree.operator;
1896 Item l;
1897 if (operator.opcode == string_add) {
1898 // Generate code to make a string buffer
1899 makeStringBuffer(tree.pos());
1900
1901 // Generate code for first string, possibly save one
1902 // copy under buffer
1903 l = genExpr(tree.lhs, tree.lhs.type);
1904 if (l.width() > 0) {
1905 code.emitop0(dup_x1 + 3 * (l.width() - 1));
1906 }
1907
1908 // Load first string and append to buffer.
1909 l.load();
1910 appendString(tree.lhs);
1911
1912 // Append all other strings to buffer.
1913 appendStrings(tree.rhs);
1914
1915 // Convert buffer to string.
1916 bufferToString(tree.pos());
1917 } else {
1918 // Generate code for first expression
1919 l = genExpr(tree.lhs, tree.lhs.type);
1920
1921 // If we have an increment of -32768 to +32767 of a local
1922 // int variable we can use an incr instruction instead of
1923 // proceeding further.
1924 if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) &&
1925 l instanceof LocalItem &&
1926 tree.lhs.type.getTag().isSubRangeOf(INT) &&
1927 tree.rhs.type.getTag().isSubRangeOf(INT) &&
1928 tree.rhs.type.constValue() != null) {
1929 int ival = ((Number) tree.rhs.type.constValue()).intValue();
1930 if (tree.hasTag(MINUS_ASG)) ival = -ival;
1931 ((LocalItem)l).incr(ival);
1932 result = l;
1933 return;
1934 }
1935 // Otherwise, duplicate expression, load one copy
1936 // and complete binary operation.
2009 Assert.error();
2010 }
2011 }
2012 }
2013
2014 /** Generate a null check from the object value at stack top. */
2015 private void genNullCheck(DiagnosticPosition pos) {
2016 if (allowBetterNullChecks) {
2017 callMethod(pos, syms.objectsType, names.requireNonNull,
2018 List.of(syms.objectType), true);
2019 } else {
2020 callMethod(pos, syms.objectType, names.getClass,
2021 List.<Type>nil(), false);
2022 }
2023 code.emitop0(pop);
2024 }
2025
2026 public void visitBinary(JCBinary tree) {
2027 OperatorSymbol operator = (OperatorSymbol)tree.operator;
2028 if (operator.opcode == string_add) {
2029 // Create a string buffer.
2030 makeStringBuffer(tree.pos());
2031 // Append all strings to buffer.
2032 appendStrings(tree);
2033 // Convert buffer to string.
2034 bufferToString(tree.pos());
2035 result = items.makeStackItem(syms.stringType);
2036 } else if (tree.hasTag(AND)) {
2037 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2038 if (!lcond.isFalse()) {
2039 Chain falseJumps = lcond.jumpFalse();
2040 code.resolve(lcond.trueJumps);
2041 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2042 result = items.
2043 makeCondItem(rcond.opcode,
2044 rcond.trueJumps,
2045 Code.mergeChains(falseJumps,
2046 rcond.falseJumps));
2047 } else {
2048 result = lcond;
2049 }
2050 } else if (tree.hasTag(OR)) {
2051 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2052 if (!lcond.isTrue()) {
2053 Chain trueJumps = lcond.jumpTrue();
2054 code.resolve(lcond.falseJumps);
2055 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2056 result = items.
2057 makeCondItem(rcond.opcode,
2058 Code.mergeChains(trueJumps, rcond.trueJumps),
2059 rcond.falseJumps);
2060 } else {
2061 result = lcond;
2062 }
2063 } else {
2064 Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
2065 od.load();
2066 result = completeBinop(tree.lhs, tree.rhs, operator);
2067 }
2068 }
2069 //where
2070 /** Make a new string buffer.
2071 */
2072 void makeStringBuffer(DiagnosticPosition pos) {
2073 code.emitop2(new_, makeRef(pos, syms.stringBuilderType));
2074 code.emitop0(dup);
2075 callMethod(
2076 pos, syms.stringBuilderType, names.init, List.<Type>nil(), false);
2077 }
2078
2079 /** Append value (on tos) to string buffer (on tos - 1).
2080 */
2081 void appendString(JCTree tree) {
2082 Type t = tree.type.baseType();
2083 if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) {
2084 t = syms.objectType;
2085 }
2086 items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke();
2087 }
2088 Symbol getStringBufferAppend(JCTree tree, Type t) {
2089 Assert.checkNull(t.constValue());
2090 Symbol method = stringBufferAppend.get(t);
2091 if (method == null) {
2092 method = rs.resolveInternalMethod(tree.pos(),
2093 attrEnv,
2094 syms.stringBuilderType,
2095 names.append,
2096 List.of(t),
2097 null);
2098 stringBufferAppend.put(t, method);
2099 }
2100 return method;
2101 }
2102
2103 /** Add all strings in tree to string buffer.
2104 */
2105 void appendStrings(JCTree tree) {
2106 tree = TreeInfo.skipParens(tree);
2107 if (tree.hasTag(PLUS) && tree.type.constValue() == null) {
2108 JCBinary op = (JCBinary) tree;
2109 if (op.operator.kind == MTH &&
2110 ((OperatorSymbol) op.operator).opcode == string_add) {
2111 appendStrings(op.lhs);
2112 appendStrings(op.rhs);
2113 return;
2114 }
2115 }
2116 genExpr(tree, tree.type).load();
2117 appendString(tree);
2118 }
2119
2120 /** Convert string buffer on tos to string.
2121 */
2122 void bufferToString(DiagnosticPosition pos) {
2123 callMethod(
2124 pos,
2125 syms.stringBuilderType,
2126 names.toString,
2127 List.<Type>nil(),
2128 false);
2129 }
2130
2131 /** Complete generating code for operation, with left operand
2132 * already on stack.
2133 * @param lhs The tree representing the left operand.
2134 * @param rhs The tree representing the right operand.
2135 * @param operator The operator symbol.
2136 */
2137 Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) {
2138 MethodType optype = (MethodType)operator.type;
2139 int opcode = operator.opcode;
2140 if (opcode >= if_icmpeq && opcode <= if_icmple &&
2141 rhs.type.constValue() instanceof Number &&
2142 ((Number) rhs.type.constValue()).intValue() == 0) {
2143 opcode = opcode + (ifeq - if_icmpeq);
2144 } else if (opcode >= if_acmpeq && opcode <= if_acmpne &&
2145 TreeInfo.isNull(rhs)) {
2146 opcode = opcode + (if_acmp_null - if_acmpeq);
2147 } else {
2148 // The expected type of the right operand is
2149 // the second parameter type of the operator, except for
|
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
26 package com.sun.tools.javac.jvm;
27
28 import com.sun.tools.javac.util.*;
29 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
30 import com.sun.tools.javac.util.List;
31 import com.sun.tools.javac.code.*;
32 import com.sun.tools.javac.code.Attribute.TypeCompound;
33 import com.sun.tools.javac.code.Symbol.VarSymbol;
34 import com.sun.tools.javac.comp.*;
35 import com.sun.tools.javac.tree.*;
36
37 import com.sun.tools.javac.code.Symbol.*;
38 import com.sun.tools.javac.code.Type.*;
39 import com.sun.tools.javac.jvm.Code.*;
40 import com.sun.tools.javac.jvm.Items.*;
41 import com.sun.tools.javac.tree.EndPosTable;
42 import com.sun.tools.javac.tree.JCTree.*;
43
44 import static com.sun.tools.javac.code.Flags.*;
45 import static com.sun.tools.javac.code.Kinds.Kind.*;
46 import static com.sun.tools.javac.code.TypeTag.*;
47 import static com.sun.tools.javac.jvm.ByteCodes.*;
48 import static com.sun.tools.javac.jvm.CRTFlags.*;
49 import static com.sun.tools.javac.main.Option.*;
50 import static com.sun.tools.javac.tree.JCTree.Tag.*;
51
52 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
53 *
54 * <p><b>This is NOT part of any supported API.
55 * If you write code that depends on this, you do so at your own risk.
56 * This code and its internal interfaces are subject to change or
57 * deletion without notice.</b>
58 */
59 public class Gen extends JCTree.Visitor {
60 protected static final Context.Key<Gen> genKey = new Context.Key<>();
61
62 private final Log log;
63 private final Symtab syms;
64 private final Check chk;
65 private final Resolve rs;
66 private final TreeMaker make;
67 private final Names names;
68 private final Target target;
69 private Name accessDollar;
70 private final Types types;
71 private final Lower lower;
72 private final Flow flow;
73 private final Annotate annotate;
74 private final StringConcat concat;
75
76 /** Format of stackmap tables to be generated. */
77 private final Code.StackMapFormat stackMap;
78
79 /** A type that serves as the expected type for all method expressions.
80 */
81 private final Type methodType;
82
83 public static Gen instance(Context context) {
84 Gen instance = context.get(genKey);
85 if (instance == null)
86 instance = new Gen(context);
87 return instance;
88 }
89
90 /** Constant pool, reset by genClass.
91 */
92 private Pool pool;
93
94 protected Gen(Context context) {
95 context.put(genKey, this);
96
97 names = Names.instance(context);
98 log = Log.instance(context);
99 syms = Symtab.instance(context);
100 chk = Check.instance(context);
101 rs = Resolve.instance(context);
102 make = TreeMaker.instance(context);
103 target = Target.instance(context);
104 types = Types.instance(context);
105 concat = StringConcat.instance(context);
106
107 methodType = new MethodType(null, null, null, syms.methodClass);
108 accessDollar = names.
109 fromString("access" + target.syntheticNameChar());
110 flow = Flow.instance(context);
111 lower = Lower.instance(context);
112
113 Options options = Options.instance(context);
114 lineDebugInfo =
115 options.isUnset(G_CUSTOM) ||
116 options.isSet(G_CUSTOM, "lines");
117 varDebugInfo =
118 options.isUnset(G_CUSTOM)
119 ? options.isSet(G)
120 : options.isSet(G_CUSTOM, "vars");
121 genCrt = options.isSet(XJCOV);
122 debugCode = options.isSet("debugcode");
123 allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
124 allowBetterNullChecks = target.hasObjects();
125 pool = new Pool(types);
126
127 // ignore cldc because we cannot have both stackmap formats
734 code.resolve(cond.trueJumps);
735 CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
736 if (markBranches) first.tree = tree.truepart;
737 Chain falseJumps = first.jumpFalse();
738 code.resolve(first.trueJumps);
739 Chain trueJumps = code.branch(goto_);
740 code.resolve(secondJumps);
741 CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
742 CondItem result = items.makeCondItem(second.opcode,
743 Code.mergeChains(trueJumps, second.trueJumps),
744 Code.mergeChains(falseJumps, second.falseJumps));
745 if (markBranches) result.tree = tree.falsepart;
746 return result;
747 } else {
748 CondItem result = genExpr(_tree, syms.booleanType).mkCond();
749 if (markBranches) result.tree = _tree;
750 return result;
751 }
752 }
753
754 public Code getCode() {
755 return code;
756 }
757
758 public Items getItems() {
759 return items;
760 }
761
762 public Env<AttrContext> getAttrEnv() {
763 return attrEnv;
764 }
765
766 /** Visitor class for expressions which might be constant expressions.
767 * This class is a subset of TreeScanner. Intended to visit trees pruned by
768 * Lower as long as constant expressions looking for references to any
769 * ClassSymbol. Any such reference will be added to the constant pool so
770 * automated tools can detect class dependencies better.
771 */
772 class ClassReferenceVisitor extends JCTree.Visitor {
773
774 @Override
775 public void visitTree(JCTree tree) {}
776
777 @Override
778 public void visitBinary(JCBinary tree) {
779 tree.lhs.accept(this);
780 tree.rhs.accept(this);
781 }
782
783 @Override
784 public void visitSelect(JCFieldAccess tree) {
785 if (tree.selected.type.hasTag(CLASS)) {
1888 result = genExpr(tree.expr, tree.expr.type);
1889 }
1890
1891 public void visitAssign(JCAssign tree) {
1892 Item l = genExpr(tree.lhs, tree.lhs.type);
1893 genExpr(tree.rhs, tree.lhs.type).load();
1894 if (tree.rhs.type.hasTag(BOT)) {
1895 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
1896 for "regarding a reference as having some other type in a manner that can be proved
1897 correct at compile time."
1898 */
1899 code.state.forceStackTop(tree.lhs.type);
1900 }
1901 result = items.makeAssignItem(l);
1902 }
1903
1904 public void visitAssignop(JCAssignOp tree) {
1905 OperatorSymbol operator = (OperatorSymbol) tree.operator;
1906 Item l;
1907 if (operator.opcode == string_add) {
1908 l = concat.makeConcat(tree);
1909 } else {
1910 // Generate code for first expression
1911 l = genExpr(tree.lhs, tree.lhs.type);
1912
1913 // If we have an increment of -32768 to +32767 of a local
1914 // int variable we can use an incr instruction instead of
1915 // proceeding further.
1916 if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) &&
1917 l instanceof LocalItem &&
1918 tree.lhs.type.getTag().isSubRangeOf(INT) &&
1919 tree.rhs.type.getTag().isSubRangeOf(INT) &&
1920 tree.rhs.type.constValue() != null) {
1921 int ival = ((Number) tree.rhs.type.constValue()).intValue();
1922 if (tree.hasTag(MINUS_ASG)) ival = -ival;
1923 ((LocalItem)l).incr(ival);
1924 result = l;
1925 return;
1926 }
1927 // Otherwise, duplicate expression, load one copy
1928 // and complete binary operation.
2001 Assert.error();
2002 }
2003 }
2004 }
2005
2006 /** Generate a null check from the object value at stack top. */
2007 private void genNullCheck(DiagnosticPosition pos) {
2008 if (allowBetterNullChecks) {
2009 callMethod(pos, syms.objectsType, names.requireNonNull,
2010 List.of(syms.objectType), true);
2011 } else {
2012 callMethod(pos, syms.objectType, names.getClass,
2013 List.<Type>nil(), false);
2014 }
2015 code.emitop0(pop);
2016 }
2017
2018 public void visitBinary(JCBinary tree) {
2019 OperatorSymbol operator = (OperatorSymbol)tree.operator;
2020 if (operator.opcode == string_add) {
2021 result = concat.makeConcat(tree);
2022 } else if (tree.hasTag(AND)) {
2023 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2024 if (!lcond.isFalse()) {
2025 Chain falseJumps = lcond.jumpFalse();
2026 code.resolve(lcond.trueJumps);
2027 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2028 result = items.
2029 makeCondItem(rcond.opcode,
2030 rcond.trueJumps,
2031 Code.mergeChains(falseJumps,
2032 rcond.falseJumps));
2033 } else {
2034 result = lcond;
2035 }
2036 } else if (tree.hasTag(OR)) {
2037 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2038 if (!lcond.isTrue()) {
2039 Chain trueJumps = lcond.jumpTrue();
2040 code.resolve(lcond.falseJumps);
2041 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2042 result = items.
2043 makeCondItem(rcond.opcode,
2044 Code.mergeChains(trueJumps, rcond.trueJumps),
2045 rcond.falseJumps);
2046 } else {
2047 result = lcond;
2048 }
2049 } else {
2050 Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
2051 od.load();
2052 result = completeBinop(tree.lhs, tree.rhs, operator);
2053 }
2054 }
2055
2056
2057 /** Complete generating code for operation, with left operand
2058 * already on stack.
2059 * @param lhs The tree representing the left operand.
2060 * @param rhs The tree representing the right operand.
2061 * @param operator The operator symbol.
2062 */
2063 Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) {
2064 MethodType optype = (MethodType)operator.type;
2065 int opcode = operator.opcode;
2066 if (opcode >= if_icmpeq && opcode <= if_icmple &&
2067 rhs.type.constValue() instanceof Number &&
2068 ((Number) rhs.type.constValue()).intValue() == 0) {
2069 opcode = opcode + (ifeq - if_icmpeq);
2070 } else if (opcode >= if_acmpeq && opcode <= if_acmpne &&
2071 TreeInfo.isNull(rhs)) {
2072 opcode = opcode + (if_acmp_null - if_acmpeq);
2073 } else {
2074 // The expected type of the right operand is
2075 // the second parameter type of the operator, except for
|