1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
29 final static int NO_OFFSET = -1;
30
31
32 final public static int opc_target = -1;
33
34
35 private int insnOpcode;
36
37
38 private int insnOffset = NO_OFFSET;
39
40
41 private Insn nextInsn = null;
42
43
44 private Insn prevInsn = null;
45
46
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
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
185
186
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
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
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
266
267
268
269
270
271
272
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">
286
287 abstract void print(PrintStream out, int indent);
288
289 abstract int store(byte[] buf, int index);
290
291
292
293
294
295 abstract int size();
296
297
298
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:
524 case opc_newarray:
525 return new InsnIntOp(op, insnEnv.getByte(), pc);
526
527 case opc_sipush:
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 }