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