View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.jdo.impl.enhancer.classfile;
19  
20  import java.io.PrintStream;
21  import java.util.Stack;
22  
23  /***
24   * Insn is an abstract class which represents a java VM instruction in a
25   * sequence of instructions.
26   */
27  abstract public class Insn implements VMConstants {
28      /* An instruction with no pc defined yet */
29      final static int NO_OFFSET = -1;
30  
31      /* A special magic opcode for branch target pseudo instructions */
32      final public static int opc_target = -1;
33  
34      /* The opcode of this instruction */
35      private int insnOpcode;
36  
37      /* The pc of this instruction within the containing code sequence */
38      private int insnOffset = NO_OFFSET;
39  
40      /* The next instruction in the code sequence */
41      private Insn nextInsn = null;
42  
43      /* The previous instruction in the code sequence */
44      private Insn prevInsn = null;
45  
46      /* public accessors */
47  
48      /***
49       * Returns the next instruction in the code sequence
50       */
51      public Insn next() {
52          return nextInsn;
53      }
54  
55      /***
56       * Returns the previous instruction in the code sequence
57       */
58      public Insn prev() {
59          return prevInsn;
60      }
61  
62      /***
63       * Removes the current instruction from it's embedding sequence.
64       */
65      //@olsen: added method
66      public void remove() {
67          if (nextInsn != null)
68              nextInsn.prevInsn = prevInsn;
69  
70          if (prevInsn != null)
71              prevInsn.nextInsn = nextInsn;
72  
73          prevInsn = null;
74          nextInsn = null;
75      }
76  
77      /***
78       * Insert the single instruction in the code sequence after this 
79       * instruction.
80       * Returns the inserted instruction.
81       */
82      public Insn setNext(Insn i) {
83          if (nextInsn != null)
84              nextInsn.prevInsn = i;
85  
86          if (i != null) {
87              i.nextInsn = nextInsn;
88              i.prevInsn = this;
89          }
90          nextInsn = i;
91          return i;
92      }
93  
94      /***
95       * Insert an instruction sequence in the code sequence after this 
96       * instruction.
97       * Returns the final instruction.
98       */
99      public Insn insert(Insn i) {
100         if (i == null)
101             return this;
102 
103         Insn theNextInsn = nextInsn;
104         nextInsn = i;
105         i.prevInsn = this;
106 
107         while (i.nextInsn != null)
108             i = i.nextInsn;
109         i.nextInsn = theNextInsn;
110         if (theNextInsn != null)
111             theNextInsn.prevInsn = i;
112         return i;
113     }
114 
115     /***
116      * Append an instruction sequence at the end of this instruction
117      * sequence. 
118      * Returns the final instruction.
119      */
120     public Insn append(Insn i) {
121         Insn thisInsn = this;
122         while (thisInsn.nextInsn != null)
123             thisInsn = thisInsn.nextInsn;
124         return thisInsn.insert(i);
125     }
126 
127     /***
128      * Return the opcode for this instruction
129      */
130     public int opcode() {
131         return insnOpcode;
132     }
133 
134     /***
135      * Return the offset of this instruction in the containing code sequence
136      */
137     public int offset() {
138         return insnOffset;
139     }
140 
141     /***
142      * How many words of stack operands does this instruction take?
143      */
144     abstract public int nStackArgs();
145 
146     /***
147      * How many words of stack results does this instruction deposit?
148      */
149     abstract public int nStackResults();
150 
151     /***
152      * What are the types of the stack operands ?
153      */
154     abstract public String argTypes();
155 
156     /***
157      * What are the types of the stack results?
158      */
159     abstract public String resultTypes();
160 
161     /***
162      * Does this instruction branch?
163      */
164     abstract public boolean branches();
165 
166     /***
167      * Mark possible branch targets
168      */
169     public void markTargets() {
170     }
171 
172     /***
173      * Return the name of the operation for a given opcode
174      */
175     public static String opName(int opcode) {
176         if (opcode == opc_target)
177             return "target:";
178         if (opcode >=0 && opcode <= VMOp.ops.length)
179             return VMOp.ops[opcode].name();
180         else
181             throw new InsnError("invalid opcode for opName: " + opcode);
182     }
183 
184     /* Instruction creation interfaces - these should be used for all
185      * instructions except opc_iinc, opc_tableswitch, opc_lookupswitch,
186      * opc_multidimarraynew, and opc_invokeinterface.
187      */
188 
189     /***
190      * Create an instruction which requires no immediate operands
191      */
192     public static Insn create(int theOpCode) {
193         return new InsnSingle(theOpCode);
194     }
195 
196     /***
197      * Create an instruction which requires a single constant from the 
198      * constant pool as an immediate operand.
199      */
200     public static Insn create(int theOpCode, ConstBasic constValue) {
201         return new InsnConstOp(theOpCode, constValue);
202     }
203 
204     /***
205      * Create an instruction which requires a single integral constant
206      * as an immediate operand.
207      */
208     public static Insn create(int theOpCode, int intValue) {
209         return new InsnIntOp(theOpCode, intValue);
210     }
211 
212     /***
213      * Create an instruction which requires a single branch offset
214      * as an immediate operand.
215      */
216     public static Insn create(int theOpCode, InsnTarget target) {
217         return new InsnTargetOp(theOpCode, target);
218     }
219 
220     /***
221      * Print the sequence of instructions to the output stream
222      */
223     public void printList(PrintStream out) {
224         Insn insn = this;
225         while (insn != null) {
226             insn.print(out, 0);
227             insn = insn.next();
228         }
229     }
230 
231     /***
232      * Print this instruction to the output stream
233      */
234     public void printInsn(PrintStream out) {
235         print(out, 0);
236     }
237 
238     /***
239      * Compares this instance with another for structural equality.
240      */
241     //@olsen: added method
242     public boolean isEqual(Stack msg, Object obj) {
243         if (!(obj instanceof Insn)) {
244             msg.push("obj/obj.getClass() = "
245                      + (obj == null ? null : obj.getClass()));
246             msg.push("this.getClass() = "
247                      + this.getClass());
248             return false;
249         }
250         Insn other = (Insn)obj;
251 
252         if (this.insnOpcode != other.insnOpcode) {
253             // be tolerant against opc_ldc vs. opc_ldc_w
254             if (!((this.insnOpcode == opc_ldc
255                    || this.insnOpcode == opc_ldc_w)
256                   && (other.insnOpcode == opc_ldc
257                       || other.insnOpcode == opc_ldc_w))) {
258                 msg.push(String.valueOf("insnOpcode = "
259                                         + other.insnOpcode));
260                 msg.push(String.valueOf("insnOpcode = "
261                                         + this.insnOpcode));
262                 return false;
263             }
264         }
265         // offsets may differ due to different byte length
266         // (e.g. opc_ldc vs. opc_ldc_w)
267         //if (this.insnOffset != other.insnOffset) {
268         //    msg.push(String.valueOf("insnOffset = "
269         //                            + other.insnOffset));
270         //    msg.push(String.valueOf("insnOffset = "
271         //                            + this.insnOffset));
272         //    return false;
273         //}
274         return true;
275     }
276 
277     /***
278      * A printable representation 
279      */
280     public String toString() {
281         return ("Insn: " + "insnOpcode(" + opName(insnOpcode) + ")"
282                 + "  insnOffset(" + insnOffset + ")");
283     }
284 
285     /* package local methods *//package-summary/html">class="comment"> package local methods *//package-summary.html">/* package local methods *//package-summary.html">class="comment"> package local methods */
286 
287     abstract void print(PrintStream out, int indent);
288 
289     abstract int store(byte[] buf, int index);
290 
291     /* return the size of the instruction in bytes
292      * Note: some instructions are unable to answer correctly until their
293      * start offset is known
294      */
295     abstract int size();
296 
297     /* Set the offset of the instruction and return the offset of the
298        following instruction */
299 
300     final int resolveOffset(int pc) {
301         insnOffset = pc;
302         return pc + size();
303     }
304 
305     Insn(int theOpcode, int theOffset) {
306         insnOpcode = theOpcode;
307         insnOffset = theOffset;
308     }
309 
310     static int storeInt(byte buf[], int index, int v) {
311         buf[index++] = (byte) (v >> 24);
312         buf[index++] = (byte) ((v >> 16) & 0xff);
313         buf[index++] = (byte) ((v >> 8) & 0xff);
314         buf[index++] = (byte) (v & 0xff);
315         return index;
316     }
317 
318 
319     static int storeShort(byte buf[], int index, short v) {
320         buf[index++] = (byte) ((v >> 8) & 0xff);
321         buf[index++] = (byte) (v & 0xff);
322         return index;
323     }
324 
325     static Insn read(InsnReadEnv insnEnv) {
326         boolean widen = false;
327         int pc = insnEnv.currentPC();
328 
329         int op = insnEnv.getUByte();
330         if (op == opc_wide) {
331             widen = true;
332             op = insnEnv.getUByte();
333         }
334 
335         switch (op) {
336         case opc_nop:
337         case opc_aconst_null:
338         case opc_iconst_m1:
339         case opc_iconst_0:
340         case opc_iconst_1:
341         case opc_iconst_2:
342         case opc_iconst_3:
343         case opc_iconst_4:
344         case opc_iconst_5:
345         case opc_lconst_0:
346         case opc_lconst_1:
347         case opc_fconst_0:
348         case opc_fconst_1:
349         case opc_fconst_2:
350         case opc_dconst_0:
351         case opc_dconst_1:
352         case opc_iload_0:
353         case opc_iload_1:
354         case opc_iload_2:
355         case opc_iload_3:
356         case opc_lload_0:
357         case opc_lload_1:
358         case opc_lload_2:
359         case opc_lload_3:
360         case opc_fload_0:
361         case opc_fload_1:
362         case opc_fload_2:
363         case opc_fload_3:
364         case opc_dload_0:
365         case opc_dload_1:
366         case opc_dload_2:
367         case opc_dload_3:
368         case opc_aload_0:
369         case opc_aload_1:
370         case opc_aload_2:
371         case opc_aload_3:
372         case opc_iaload:
373         case opc_laload:
374         case opc_faload:
375         case opc_daload:
376         case opc_aaload:
377         case opc_baload:
378         case opc_caload:
379         case opc_saload:
380         case opc_istore_0:
381         case opc_istore_1:
382         case opc_istore_2:
383         case opc_istore_3:
384         case opc_lstore_0:
385         case opc_lstore_1:
386         case opc_lstore_2:
387         case opc_lstore_3:
388         case opc_fstore_0:
389         case opc_fstore_1:
390         case opc_fstore_2:
391         case opc_fstore_3:
392         case opc_dstore_0:
393         case opc_dstore_1:
394         case opc_dstore_2:
395         case opc_dstore_3:
396         case opc_astore_0:
397         case opc_astore_1:
398         case opc_astore_2:
399         case opc_astore_3:
400         case opc_iastore:
401         case opc_lastore:
402         case opc_fastore:
403         case opc_dastore:
404         case opc_aastore:
405         case opc_bastore:
406         case opc_castore:
407         case opc_sastore:
408         case opc_pop:
409         case opc_pop2:
410         case opc_dup:
411         case opc_dup_x1:
412         case opc_dup_x2:
413         case opc_dup2:
414         case opc_dup2_x1:
415         case opc_dup2_x2:
416         case opc_swap:
417         case opc_iadd:
418         case opc_ladd:
419         case opc_fadd:
420         case opc_dadd:
421         case opc_isub:
422         case opc_lsub:
423         case opc_fsub:
424         case opc_dsub:
425         case opc_imul:
426         case opc_lmul:
427         case opc_fmul:
428         case opc_dmul:
429         case opc_idiv:
430         case opc_ldiv:
431         case opc_fdiv:
432         case opc_ddiv:
433         case opc_irem:
434         case opc_lrem:
435         case opc_frem:
436         case opc_drem:
437         case opc_ineg:
438         case opc_lneg:
439         case opc_fneg:
440         case opc_dneg:
441         case opc_ishl:
442         case opc_lshl:
443         case opc_ishr:
444         case opc_lshr:
445         case opc_iushr:
446         case opc_lushr:
447         case opc_iand:
448         case opc_land:
449         case opc_ior:
450         case opc_lor:
451         case opc_ixor:
452         case opc_lxor:
453         case opc_i2l:
454         case opc_i2f:
455         case opc_i2d:
456         case opc_l2i:
457         case opc_l2f:
458         case opc_l2d:
459         case opc_f2i:
460         case opc_f2l:
461         case opc_f2d:
462         case opc_d2i:
463         case opc_d2l:
464         case opc_d2f:
465         case opc_i2b:
466         case opc_i2c:
467         case opc_i2s:
468         case opc_lcmp:
469         case opc_fcmpl:
470         case opc_fcmpg:
471         case opc_dcmpl:
472         case opc_dcmpg:
473         case opc_ireturn:
474         case opc_lreturn:
475         case opc_freturn:
476         case opc_dreturn:
477         case opc_areturn:
478         case opc_return:
479         case opc_xxxunusedxxx:
480         case opc_arraylength:
481         case opc_athrow:
482         case opc_monitorenter:
483         case opc_monitorexit:
484             return new InsnSingle(op, pc);
485       
486         case opc_ldc:
487             return new InsnConstOp(op, insnEnv.pool().constantAt(insnEnv.getUByte()),
488                                    pc);
489       
490         case opc_ldc_w:
491         case opc_ldc2_w:
492         case opc_getstatic:
493         case opc_putstatic:
494         case opc_getfield:
495         case opc_putfield:
496         case opc_invokevirtual:
497         case opc_invokespecial:
498         case opc_invokestatic:
499         case opc_new:
500         case opc_anewarray:
501         case opc_checkcast:
502         case opc_instanceof:
503             return new InsnConstOp(op,
504                                    insnEnv.pool().constantAt(insnEnv.getUShort()),
505                                    pc);
506       
507         case opc_iload:
508         case opc_lload:
509         case opc_fload:
510         case opc_dload:
511         case opc_aload:
512         case opc_istore:
513         case opc_lstore:
514         case opc_fstore:
515         case opc_dstore:
516         case opc_astore:
517         case opc_ret:
518             if (widen)
519                 return new InsnIntOp(op, insnEnv.getShort(), pc);
520             else
521                 return new InsnIntOp(op, insnEnv.getByte(), pc);
522 
523         case opc_bipush: /* a byte constant */
524         case opc_newarray:
525             return new InsnIntOp(op, insnEnv.getByte(), pc);
526 
527         case opc_sipush: /* a short constant */
528             return new InsnIntOp(op, insnEnv.getShort(), pc);
529 
530         case opc_iinc:
531             if (widen)
532                 return new InsnIInc(insnEnv.getUShort(), insnEnv.getShort(), pc);
533             else
534                 return new InsnIInc(insnEnv.getUByte(), insnEnv.getByte(), pc);
535 
536         case opc_ifeq:
537         case opc_ifne:
538         case opc_iflt:
539         case opc_ifge:
540         case opc_ifgt:
541         case opc_ifle:
542         case opc_if_icmpeq:
543         case opc_if_icmpne:
544         case opc_if_icmplt:
545         case opc_if_icmpge:
546         case opc_if_icmpgt:
547         case opc_if_icmple:
548         case opc_if_acmpeq:
549         case opc_if_acmpne:
550         case opc_goto:
551         case opc_jsr:
552         case opc_ifnull:
553         case opc_ifnonnull:
554             return new InsnTargetOp(op, insnEnv.getTarget(insnEnv.getShort()+pc), pc);
555 
556         case opc_goto_w:
557         case opc_jsr_w:
558             return new InsnTargetOp(op, insnEnv.getTarget(insnEnv.getInt()+pc), pc);
559 
560         case opc_tableswitch:
561             return InsnTableSwitch.read(insnEnv, pc);
562 
563         case opc_lookupswitch:
564             return InsnLookupSwitch.read(insnEnv, pc);
565 
566         case opc_invokeinterface:
567             return InsnInterfaceInvoke.read(insnEnv, pc);
568 
569         case opc_multianewarray:
570             return InsnMultiDimArrayNew.read(insnEnv, pc);
571         }
572         throw new InsnError("Invalid byte code (" + op + ")");
573     }
574 
575     /***
576      * Return the type of value manipulated by the load/store instruction
577      */
578     public static final int loadStoreDataType(int opcode) {
579         switch(opcode) {
580         case opc_iload:
581         case opc_iload_0:
582         case opc_iload_1:
583         case opc_iload_2:
584         case opc_iload_3:
585         case opc_istore:
586         case opc_istore_0:
587         case opc_istore_1:
588         case opc_istore_2:
589         case opc_istore_3:
590         case opc_iaload:
591         case opc_baload:
592         case opc_caload:
593         case opc_saload:
594         case opc_iastore:
595         case opc_bastore:
596         case opc_castore:
597         case opc_sastore:
598             return T_INT;
599 
600         case opc_lload:
601         case opc_lload_0:
602         case opc_lload_1:
603         case opc_lload_2:
604         case opc_lload_3:
605         case opc_lstore:
606         case opc_lstore_0:
607         case opc_lstore_1:
608         case opc_lstore_2:
609         case opc_lstore_3:
610         case opc_laload:
611         case opc_lastore:
612             return T_LONG;
613 
614         case opc_fload:
615         case opc_fload_0:
616         case opc_fload_1:
617         case opc_fload_2:
618         case opc_fload_3:
619         case opc_fstore:
620         case opc_fstore_0:
621         case opc_fstore_1:
622         case opc_fstore_2:
623         case opc_fstore_3:
624         case opc_faload:
625         case opc_fastore:
626             return T_FLOAT;
627 
628         case opc_dload:
629         case opc_dload_0:
630         case opc_dload_1:
631         case opc_dload_2:
632         case opc_dload_3:
633         case opc_dstore:
634         case opc_dstore_0:
635         case opc_dstore_1:
636         case opc_dstore_2:
637         case opc_dstore_3:
638         case opc_daload:
639         case opc_dastore:
640             return T_DOUBLE;
641 
642         case opc_aload:
643         case opc_aload_0:
644         case opc_aload_1:
645         case opc_aload_2:
646         case opc_aload_3:
647         case opc_astore:
648         case opc_astore_0:
649         case opc_astore_1:
650         case opc_astore_2:
651         case opc_astore_3:
652         case opc_aaload:
653         case opc_aastore:
654             return TC_OBJECT;
655 
656         default:
657             throw new InsnError("not a load/store");
658         }
659     }
660 }