1 /* 2 * Copyright (c) 1994, 2003, 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 26 package sun.tools.tree; 27 28 import sun.tools.java.*; 29 import sun.tools.asm.Assembler; 30 import java.io.PrintStream; 31 import java.util.Hashtable; 32 33 /** 34 * WARNING: The contents of this source file are not part of any 35 * supported API. Code that depends on them does so at its own risk: 36 * they are subject to change or removal without notice. 37 */ 38 public abstract 39 class AssignOpExpression extends BinaryAssignExpression { 40 protected Type itype; // Type of intermediate result, before assigning 41 final int NOINC = Integer.MAX_VALUE; 42 43 protected FieldUpdater updater = null; // Used also in 'AssignAddExpression'. 44 45 /** 46 * Constructor 47 */ AssignOpExpression(int op, long where, Expression left, Expression right)48 public AssignOpExpression(int op, long where, Expression left, Expression right) { 49 super(op, where, left, right); 50 } 51 52 /** 53 * Select the type 54 * 55 */ 56 @SuppressWarnings("fallthrough") selectType(Environment env, Context ctx, int tm)57 final void selectType(Environment env, Context ctx, int tm) { 58 Type rtype = null; // special conversion type for RHS 59 switch(op) { 60 case ASGADD: 61 if (left.type == Type.tString) { 62 if (right.type == Type.tVoid) { 63 // The type of the right hand side can be 64 // anything except void. Fix for 4119864. 65 env.error(where, "incompatible.type", 66 opNames[op], Type.tVoid, Type.tString); 67 type = Type.tError; 68 } else { 69 type = itype = Type.tString; 70 } 71 return; 72 } 73 /* Fall through */ 74 case ASGDIV: case ASGMUL: case ASGSUB: case ASGREM: 75 if ((tm & TM_DOUBLE) != 0) { 76 itype = Type.tDouble; 77 } else if ((tm & TM_FLOAT) != 0) { 78 itype = Type.tFloat; 79 } else if ((tm & TM_LONG) != 0) { 80 itype = Type.tLong; 81 } else { 82 itype = Type.tInt; 83 } 84 break; 85 86 case ASGBITAND: case ASGBITOR: case ASGBITXOR: 87 if ((tm & TM_BOOLEAN) != 0) { 88 itype = Type.tBoolean; 89 } else if ((tm & TM_LONG) != 0) { 90 itype = Type.tLong; 91 } else { 92 itype = Type.tInt; 93 } 94 break; 95 96 case ASGLSHIFT: case ASGRSHIFT: case ASGURSHIFT: 97 rtype = Type.tInt; 98 99 // Fix for bug 4134459. 100 // We allow any integral type (even long) to 101 // be the right hand side of a shift operation. 102 if (right.type.inMask(TM_INTEGER)) { 103 right = new ConvertExpression(where, Type.tInt, right); 104 } 105 // The intermediate type of the expression is the 106 // type of the left hand side after undergoing 107 // unary (not binary) type promotion. We ignore 108 // tm -- it contains information about both left 109 // and right hand sides -- and we compute the 110 // type only from the type of the lhs. 111 if (left.type == Type.tLong) { 112 itype = Type.tLong; 113 } else { 114 itype = Type.tInt; 115 } 116 117 break; 118 119 default: 120 throw new CompilerError("Bad assignOp type: " + op); 121 } 122 if (rtype == null) { 123 rtype = itype; 124 } 125 right = convert(env, ctx, rtype, right); 126 // The result is always the type of the left operand. 127 128 type = left.type; 129 } 130 131 132 /** 133 * Get the increment, return NOINC if an increment is not possible 134 */ getIncrement()135 int getIncrement() { 136 if ((left.op == IDENT) && type.isType(TC_INT) && (right.op == INTVAL)) 137 if ((op == ASGADD) || (op == ASGSUB)) 138 if (((IdentifierExpression)left).field.isLocal()) { 139 int val = ((IntExpression)right).value; 140 if (op == ASGSUB) 141 val = -val; 142 if (val == (short)val) 143 return val; 144 } 145 return NOINC; 146 } 147 148 149 /** 150 * Check an assignment expression 151 */ checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)152 public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp) { 153 vset = left.checkAssignOp(env, ctx, vset, exp, this); 154 vset = right.checkValue(env, ctx, vset, exp); 155 int tm = left.type.getTypeMask() | right.type.getTypeMask(); 156 if ((tm & TM_ERROR) != 0) { 157 return vset; 158 } 159 selectType(env, ctx, tm); 160 if (!type.isType(TC_ERROR)) { 161 convert(env, ctx, itype, left); 162 } 163 updater = left.getUpdater(env, ctx); // Must be called after 'checkAssignOp'. 164 return vset; 165 } 166 167 /** 168 * Inline 169 */ inlineValue(Environment env, Context ctx)170 public Expression inlineValue(Environment env, Context ctx) { 171 // Why not inlineLHS? But that does not work. 172 left = left.inlineValue(env, ctx); 173 right = right.inlineValue(env, ctx); 174 if (updater != null) { 175 updater = updater.inline(env, ctx); 176 } 177 return this; 178 } 179 180 /** 181 * Create a copy of the expression for method inlining 182 */ copyInline(Context ctx)183 public Expression copyInline(Context ctx) { 184 AssignOpExpression e = (AssignOpExpression)clone(); 185 e.left = left.copyInline(ctx); 186 e.right = right.copyInline(ctx); 187 if (updater != null) { 188 e.updater = updater.copyInline(ctx); 189 } 190 return e; 191 } 192 193 /** 194 * The cost of inlining this statement 195 */ costInline(int thresh, Environment env, Context ctx)196 public int costInline(int thresh, Environment env, Context ctx) { 197 /*----------* 198 return (getIncrement() != NOINC) 199 ? 2 200 : (3 + super.costInline(thresh, env, ctx)); 201 *----------*/ 202 if (updater == null) { 203 return (getIncrement() != NOINC) 204 // Increment variable in place. Count 3 bytes for 'iinc'. 205 ? 3 206 // Cost of rhs expression + cost of lhs expression + cost 207 // of load/op/store instructions. E.g.: iload = 1 or 2, 208 // istore = 1 or 2, iadd = 1. Cost could be higher if 209 // getfield/putfield or conversions needed, lower if rhs is 210 // a small constant. Costs are highly approximate. 211 : right.costInline(thresh, env, ctx) + 212 left.costInline(thresh, env, ctx) + 4; 213 } else { 214 // Cost of rhs expression + (2 * cost of access method call) + 215 // cost of operator. Does not account for cost of conversions, 216 // or duplications in value-needed context. 217 return right.costInline(thresh, env, ctx) + 218 updater.costInline(thresh, env, ctx, true) + 1; 219 } 220 } 221 222 /** 223 * Code 224 */ code(Environment env, Context ctx, Assembler asm, boolean valNeeded)225 void code(Environment env, Context ctx, Assembler asm, boolean valNeeded) { 226 227 // Handle cases in which a '+=' or '-=' operator can be optimized using 228 // the 'iinc' instruction. See also 'IncDecExpression.codeIncDec'. 229 // The 'iinc' instruction cannot be used if an access method call is required. 230 int val = getIncrement(); 231 if (val != NOINC && updater == null) { 232 int v = ((LocalMember)((IdentifierExpression)left).field).number; 233 int[] operands = { v, val }; 234 asm.add(where, opc_iinc, operands); 235 if (valNeeded) { 236 left.codeValue(env, ctx, asm); 237 } 238 return; 239 } 240 241 if (updater == null) { 242 // Field is directly accessible. 243 int depth = left.codeLValue(env, ctx, asm); 244 codeDup(env, ctx, asm, depth, 0); 245 left.codeLoad(env, ctx, asm); 246 codeConversion(env, ctx, asm, left.type, itype); 247 right.codeValue(env, ctx, asm); 248 codeOperation(env, ctx, asm); 249 codeConversion(env, ctx, asm, itype, type); 250 if (valNeeded) { 251 codeDup(env, ctx, asm, type.stackSize(), depth); 252 } 253 left.codeStore(env, ctx, asm); 254 } else { 255 // Must use access methods. 256 updater.startUpdate(env, ctx, asm, false); 257 codeConversion(env, ctx, asm, left.type, itype); 258 right.codeValue(env, ctx, asm); 259 codeOperation(env, ctx, asm); 260 codeConversion(env, ctx, asm, itype, type); 261 updater.finishUpdate(env, ctx, asm, valNeeded); 262 } 263 } 264 codeValue(Environment env, Context ctx, Assembler asm)265 public void codeValue(Environment env, Context ctx, Assembler asm) { 266 code(env, ctx, asm, true); 267 } code(Environment env, Context ctx, Assembler asm)268 public void code(Environment env, Context ctx, Assembler asm) { 269 code(env, ctx, asm, false); 270 } 271 272 /** 273 * Print 274 */ print(PrintStream out)275 public void print(PrintStream out) { 276 out.print("(" + opNames[op] + " "); 277 left.print(out); 278 out.print(" "); 279 right.print(out); 280 out.print(")"); 281 } 282 } 283