1 cananian 1.3.2.4 // InGen.java, created Sun Sep 13 22:49:20 1998 by cananian
  2 cananian 1.2     // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.2     // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1     package harpoon.IR.Bytecode;
  5 cananian 1.1     
  6 cananian 1.3.2.3 import harpoon.ClassFile.HClass;
  7 cananian 1.1     import harpoon.Util.Util;
  8 cananian 1.1     
  9 cananian 1.1     /**
 10 cananian 1.1      * <code>InGen</code> is used for non-branching instructions.
 11 cananian 1.1      * An <code>InGen</code> has an opcode and optional operands.
 12 cananian 1.1      * An <code>InGen</code> has exactly one predecessor and exactly
 13 cananian 1.1      * one successor.<p>
 14 cananian 1.1      * Note that <code>InGen</code> contain <code>Operand</code> objects
 15 cananian 1.1      * for all <b>relevant</b>, explicit or implicit operands of the
 16 cananian 1.1      * bytecode instruction.  This means that, for example, an 
 17 cananian 1.1      * <code>iload_0</code> will be given an <Code>OpLocalVariable</code>
 18 cananian 1.1      * operand corresponding to the implicit '0', and conversely that
 19 cananian 1.1      * <code>invokeinterface</code> will <b>not</b> contain operands for
 20 cananian 1.1      * the <code>nargs</code> operand (which is obvious from the method
 21 cananian 1.1      * signature) nor for the dummy placeholder value which trails the
 22 cananian 1.1      * opcode in the raw bytecode array.
 23 cananian 1.1      *
 24 cananian 1.3.2.6  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 25 cananian 1.4      * @version $Id: InGen.java,v 1.4 2002/02/25 21:04:17 cananian Exp $
 26 cananian 1.1      */
 27 cananian 1.1     public class InGen extends Instr {
 28 cananian 1.3.2.2   final byte opcode;
 29 cananian 1.3.2.2   final Operand operands[];
 30 cananian 1.1     
 31 cananian 1.1       /** Create an <code>InGen</code> from a chunk of bytecode starting at
 32 cananian 1.1        *  offset <code>pc</code>. <code>parent</code> is used to lookup
 33 cananian 1.1        *  <code>constant_pool</code> references. */
 34 cananian 1.1       public InGen(String sourcefile, int linenumber, 
 35 cananian 1.1                    byte[] code, int pc, Code parent) {
 36 cananian 1.1         super(sourcefile, linenumber);
 37 cananian 1.3.2.2     this.opcode = (code[pc]==Op.WIDE)?code[pc+1]:code[pc];
 38 cananian 1.1         // Make operands, if necessary.
 39 cananian 1.1         switch(code[pc]) {
 40 cananian 1.1           // Constant local variable index 0:
 41 cananian 1.1         case Op.ALOAD_0:
 42 cananian 1.1         case Op.ASTORE_0:
 43 cananian 1.1         case Op.DLOAD_0:
 44 cananian 1.1         case Op.DSTORE_0:
 45 cananian 1.1         case Op.FLOAD_0:
 46 cananian 1.1         case Op.FSTORE_0:
 47 cananian 1.1         case Op.ILOAD_0:
 48 cananian 1.1         case Op.ISTORE_0:
 49 cananian 1.1         case Op.LLOAD_0:
 50 cananian 1.1         case Op.LSTORE_0:
 51 cananian 1.1           operands = new Operand[] { new OpLocalVariable(0) };
 52 cananian 1.1           break;
 53 cananian 1.1           // Constant local variable index 1:
 54 cananian 1.1         case Op.ALOAD_1:
 55 cananian 1.1         case Op.ASTORE_1:
 56 cananian 1.1         case Op.DLOAD_1:
 57 cananian 1.1         case Op.DSTORE_1:
 58 cananian 1.1         case Op.FLOAD_1:
 59 cananian 1.1         case Op.FSTORE_1:
 60 cananian 1.1         case Op.ILOAD_1:
 61 cananian 1.1         case Op.ISTORE_1:
 62 cananian 1.1         case Op.LLOAD_1:
 63 cananian 1.1         case Op.LSTORE_1:
 64 cananian 1.1           operands = new Operand[] { new OpLocalVariable(1) };
 65 cananian 1.1           break;
 66 cananian 1.1           // Constant local variable index 2:
 67 cananian 1.1         case Op.ALOAD_2:
 68 cananian 1.1         case Op.ASTORE_2:
 69 cananian 1.1         case Op.DLOAD_2:
 70 cananian 1.1         case Op.DSTORE_2:
 71 cananian 1.1         case Op.FLOAD_2:
 72 cananian 1.1         case Op.FSTORE_2:
 73 cananian 1.1         case Op.ILOAD_2:
 74 cananian 1.1         case Op.ISTORE_2:
 75 cananian 1.1         case Op.LLOAD_2:
 76 cananian 1.1         case Op.LSTORE_2:
 77 cananian 1.1           operands = new Operand[] { new OpLocalVariable(2) };
 78 cananian 1.1           break;
 79 cananian 1.1           // Constant local variable index 3:
 80 cananian 1.1         case Op.ALOAD_3:
 81 cananian 1.1         case Op.ASTORE_3:
 82 cananian 1.1         case Op.DLOAD_3:
 83 cananian 1.1         case Op.DSTORE_3:
 84 cananian 1.1         case Op.FLOAD_3:
 85 cananian 1.1         case Op.FSTORE_3:
 86 cananian 1.1         case Op.ILOAD_3:
 87 cananian 1.1         case Op.ISTORE_3:
 88 cananian 1.1         case Op.LLOAD_3:
 89 cananian 1.1         case Op.LSTORE_3:
 90 cananian 1.1           operands = new Operand[] { new OpLocalVariable(3) };
 91 cananian 1.1           break;
 92 cananian 1.1           // Local variable index
 93 cananian 1.1         case Op.ALOAD:
 94 cananian 1.1         case Op.ASTORE:
 95 cananian 1.1         case Op.DLOAD:
 96 cananian 1.1         case Op.DSTORE:
 97 cananian 1.1         case Op.FLOAD:
 98 cananian 1.1         case Op.FSTORE:
 99 cananian 1.1         case Op.ILOAD:
100 cananian 1.1         case Op.ISTORE:
101 cananian 1.1         case Op.LLOAD:
102 cananian 1.1         case Op.LSTORE:
103 cananian 1.1           operands = new Operand[] { new OpLocalVariable(u1(code,pc+1)) };
104 cananian 1.1           break;
105 cananian 1.1           // Class
106 cananian 1.1         case Op.ANEWARRAY:
107 cananian 1.1         case Op.CHECKCAST:
108 cananian 1.1         case Op.INSTANCEOF:
109 cananian 1.1         case Op.NEW:
110 cananian 1.1           operands = new Operand[] { new OpClass(parent, u2(code,pc+1)) };
111 cananian 1.1           break;
112 cananian 1.1           // Field
113 cananian 1.1         case Op.GETFIELD:
114 cananian 1.1         case Op.GETSTATIC:
115 cananian 1.1         case Op.PUTFIELD:
116 cananian 1.1         case Op.PUTSTATIC:
117 cananian 1.1           operands = new Operand[] { new OpField(parent, u2(code,pc+1)) };
118 cananian 1.1           break;
119 cananian 1.1           // Method
120 cananian 1.1         case Op.INVOKESPECIAL:
121 cananian 1.1         case Op.INVOKESTATIC:
122 cananian 1.1         case Op.INVOKEVIRTUAL:
123 cananian 1.1         case Op.INVOKEINTERFACE: // note that we discard an unnecessary operand.
124 cananian 1.1           operands = new Operand[] { new OpMethod(parent, u2(code,pc+1)) };
125 cananian 1.1           break;
126 cananian 1.1           // Byte
127 cananian 1.1         case Op.BIPUSH:
128 cananian 1.1         case Op.NEWARRAY:
129 cananian 1.1           operands = new Operand[] { 
130 cananian 1.1             new OpConstant(new Byte(code[pc+1]), HClass.Byte)
131 cananian 1.1           };
132 cananian 1.1           break;
133 cananian 1.1           // Short
134 cananian 1.1         case Op.SIPUSH:
135 cananian 1.1           operands = new Operand[] { 
136 cananian 1.1             new OpConstant(new Short((short)u2(code,pc+1)), HClass.Short)
137 cananian 1.1           };
138 cananian 1.1           break;
139 cananian 1.1           // Integer constant.
140 cananian 1.1         case Op.ICONST_M1:
141 cananian 1.1         case Op.ICONST_0:
142 cananian 1.1         case Op.ICONST_1:
143 cananian 1.1         case Op.ICONST_2:
144 cananian 1.1         case Op.ICONST_3:
145 cananian 1.1         case Op.ICONST_4:
146 cananian 1.1         case Op.ICONST_5:
147 cananian 1.1           operands = new Operand[] {
148 cananian 1.1             new OpConstant(new Integer((int)(code[pc]-Op.ICONST_0)), HClass.Int)
149 cananian 1.1           };
150 cananian 1.1           break;
151 cananian 1.1           // Long constant.
152 cananian 1.1         case Op.LCONST_0:
153 cananian 1.1         case Op.LCONST_1:
154 cananian 1.1           operands = new Operand[] {
155 cananian 1.1             new OpConstant(new Long((long)(code[pc]-Op.LCONST_0)), HClass.Long)
156 cananian 1.1           };
157 cananian 1.1           break;
158 cananian 1.1           // Floating-point constant.
159 cananian 1.1         case Op.FCONST_0:
160 cananian 1.1         case Op.FCONST_1:
161 cananian 1.1         case Op.FCONST_2:
162 cananian 1.1           operands = new Operand[] {
163 cananian 1.1             new OpConstant(new Float((float)(code[pc]-Op.FCONST_0)), HClass.Float)
164 cananian 1.3           };
165 cananian 1.3           break;
166 cananian 1.3           // Double constant.
167 cananian 1.3         case Op.DCONST_0:
168 cananian 1.3         case Op.DCONST_1:
169 cananian 1.3           operands = new Operand[] {
170 cananian 1.3             new OpConstant(new Double((double)(code[pc]-Op.DCONST_0)),
171 cananian 1.3                            HClass.Double)
172 cananian 1.1           };
173 cananian 1.1           break;
174 cananian 1.1           // General constant.
175 cananian 1.1         case Op.LDC:
176 cananian 1.1           operands = new Operand[] { new OpConstant(parent, u1(code,pc+1)) };
177 cananian 1.1           break;
178 cananian 1.1         case Op.LDC_W:
179 cananian 1.1         case Op.LDC2_W:
180 cananian 1.1           operands = new Operand[] { new OpConstant(parent, u2(code,pc+1)) };
181 cananian 1.1           break;
182 cananian 1.1           // Odd-balls
183 cananian 1.1         case Op.IINC:
184 cananian 1.1           operands = new Operand[] {
185 cananian 1.1             new OpLocalVariable(u1(code,pc+1)),
186 cananian 1.1             new OpConstant(new Integer((int)code[pc+2]), HClass.Int)
187 cananian 1.1           };
188 cananian 1.1           break;
189 cananian 1.1         case Op.MULTIANEWARRAY:
190 cananian 1.1           operands = new Operand[] {
191 cananian 1.1             new OpClass(parent, u2(code,pc+1)),
192 cananian 1.1             new OpConstant(new Integer(u1(code,pc+3)), HClass.Int)
193 cananian 1.1           };
194 cananian 1.1           break;
195 cananian 1.1         case Op.RET:
196 cananian 1.1           operands = new Operand[] { 
197 cananian 1.1             new OpConstant(new Integer(u1(code,pc+1)), HClass.Int)
198 cananian 1.1           };
199 cananian 1.1           break;
200 cananian 1.1         case Op.WIDE: // this is evil.
201 cananian 1.1           if (code[pc+1]==Op.IINC) // very evil.
202 cananian 1.1             operands = new Operand[] { 
203 cananian 1.3.2.2           new OpLocalVariable(u2(code, pc+2)),
204 cananian 1.3.2.5           new OpConstant(new Integer(s2(code,pc+4)), HClass.Int) 
205 cananian 1.1             };
206 cananian 1.3.2.2       else
207 cananian 1.3.2.2           operands = new Operand[] { new OpLocalVariable(u2(code, pc+2)) };
208 cananian 1.1           break;
209 cananian 1.1           // Takes an operand, but don't belong:
210 cananian 1.1         case Op.GOTO:
211 cananian 1.1         case Op.GOTO_W:
212 cananian 1.1         case Op.IF_ACMPEQ:
213 cananian 1.1         case Op.IF_ACMPNE:
214 cananian 1.1         case Op.IF_ICMPEQ:
215 cananian 1.1         case Op.IF_ICMPNE:
216 cananian 1.1         case Op.IF_ICMPLT:
217 cananian 1.1         case Op.IF_ICMPGE:
218 cananian 1.1         case Op.IF_ICMPGT:
219 cananian 1.1         case Op.IF_ICMPLE:
220 cananian 1.1         case Op.IFEQ:
221 cananian 1.1         case Op.IFNE:
222 cananian 1.1         case Op.IFLT:
223 cananian 1.1         case Op.IFGE:
224 cananian 1.1         case Op.IFGT:
225 cananian 1.1         case Op.IFLE:
226 cananian 1.1         case Op.IFNONNULL:
227 cananian 1.1         case Op.IFNULL:
228 cananian 1.1         case Op.JSR:
229 cananian 1.1         case Op.JSR_W:
230 cananian 1.1         case Op.LOOKUPSWITCH:
231 cananian 1.1         case Op.TABLESWITCH:
232 cananian 1.1           throw new Error("Branch operations are not InGen's.");
233 cananian 1.1         default:
234 cananian 1.1           operands = new Operand[0];
235 cananian 1.1           break;
236 cananian 1.1         }
237 cananian 1.1         // done.  yay.
238 cananian 1.1       }
239 cananian 1.1       /** Create an integer from an unsigned byte. */
240 cananian 1.1       static int u1(byte[] code, int pc) {
241 cananian 1.1         return ((int) code[pc]) & 0xFF;
242 cananian 1.1       }
243 cananian 1.1       /** Create an integer from an unsigned two-byte quantity (big-endian). */
244 cananian 1.1       static int u2(byte[] code, int pc) {
245 cananian 1.1         return (u1(code,pc) << 8) | u1(code,pc+1);
246 cananian 1.1       }
247 cananian 1.3.2.5   /** Create an integer from a signed two-byte quantity (big-endian). */
248 cananian 1.3.2.5   static int s2(byte[] code, int pc) {
249 cananian 1.3.2.5     int s = u2(code, pc);
250 cananian 1.3.2.5     return (s&0x8000)==0 ? s : (s | ~0xFFFF);
251 cananian 1.1       }
252 cananian 1.1     
253 cananian 1.1       /** Return the bytecode opcode of this instruction.
254 cananian 1.1        *  @see Op */
255 cananian 1.1       public byte getOpcode() { return opcode; }
256 cananian 1.1       /** Return a specific operand of this instruction. */
257 cananian 1.1       public Operand getOperand(int i) { return operands[i]; }
258 cananian 1.1       /** Get all the operands of this instruction. */
259 cananian 1.3.2.1   public Operand[] getOperands() { 
260 cananian 1.3.2.1     return (Operand[]) Util.safeCopy(Operand.arrayFactory, operands);
261 cananian 1.3.2.1   }
262 cananian 1.1     
263 cananian 1.1       // provide run-time checks on arity.
264 cananian 1.1       /** @see Instr#addPrev */
265 cananian 1.1       void addPrev(Instr prev) {
266 cananian 1.1         if (this.prev.size()>=1)
267 cananian 1.1           throw new Error("Only one predecessor for InGen allowed.");
268 cananian 1.1         super.addPrev(prev);
269 cananian 1.1       }
270 cananian 1.1       /** @see Instr#addNext */
271 cananian 1.1       void addNext(Instr next) {
272 cananian 1.1         if (this.next.size()>=1)
273 cananian 1.1           throw new Error("Only one successor for InGen allowed.");
274 cananian 1.1         super.addNext(next);
275 cananian 1.1       }
276 cananian 1.1     
277 cananian 1.1       /** Return human-readable instruction string. */
278 cananian 1.1       public String toString() {
279 cananian 1.1         StringBuffer sb = new StringBuffer(Op.toString(opcode));
280 cananian 1.1         sb.append(' ');
281 cananian 1.1         for (int i=0; i<operands.length; i++) {
282 cananian 1.1           sb.append(operands[i].toString());
283 cananian 1.1           if (i<operands.length-1)
284 cananian 1.1             sb.append(", ");
285 cananian 1.1         }
286 cananian 1.1         return sb.toString();
287 cananian 1.1       }
288 cananian 1.1     
289 cananian 1.1     }