View Javadoc

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