001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.classfile.instruction;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.attribute.CodeAttribute;
025: import proguard.classfile.instruction.visitor.InstructionVisitor;
026:
027: /**
028: * Base class for representing instructions.
029: *
030: * @author Eric Lafortune
031: */
032: public abstract class Instruction {
033: // An array for marking Category 2 instructions.
034: private static final boolean[] IS_CATEGORY2 = new boolean[] {
035: false, // nop
036: false, // aconst_null
037: false, // iconst_m1
038: false, // iconst_0
039: false, // iconst_1
040: false, // iconst_2
041: false, // iconst_3
042: false, // iconst_4
043: false, // iconst_5
044: true, // lconst_0
045: true, // lconst_1
046: false, // fconst_0
047: false, // fconst_1
048: false, // fconst_2
049: true, // dconst_0
050: true, // dconst_1
051: false, // bipush
052: false, // sipush
053: false, // ldc
054: false, // ldc_w
055: true, // ldc2_w
056: false, // iload
057: true, // lload
058: false, // fload
059: true, // dload
060: false, // aload
061: false, // iload_0
062: false, // iload_1
063: false, // iload_2
064: false, // iload_3
065: true, // lload_0
066: true, // lload_1
067: true, // lload_2
068: true, // lload_3
069: false, // fload_0
070: false, // fload_1
071: false, // fload_2
072: false, // fload_3
073: true, // dload_0
074: true, // dload_1
075: true, // dload_2
076: true, // dload_3
077: false, // aload_0
078: false, // aload_1
079: false, // aload_2
080: false, // aload_3
081: false, // iaload
082: true, // laload
083: false, // faload
084: true, // daload
085: false, // aaload
086: false, // baload
087: false, // caload
088: false, // saload
089: false, // istore
090: true, // lstore
091: false, // fstore
092: true, // dstore
093: false, // astore
094: false, // istore_0
095: false, // istore_1
096: false, // istore_2
097: false, // istore_3
098: true, // lstore_0
099: true, // lstore_1
100: true, // lstore_2
101: true, // lstore_3
102: false, // fstore_0
103: false, // fstore_1
104: false, // fstore_2
105: false, // fstore_3
106: true, // dstore_0
107: true, // dstore_1
108: true, // dstore_2
109: true, // dstore_3
110: false, // astore_0
111: false, // astore_1
112: false, // astore_2
113: false, // astore_3
114: false, // iastore
115: true, // lastore
116: false, // fastore
117: true, // dastore
118: false, // aastore
119: false, // bastore
120: false, // castore
121: false, // sastore
122: false, // pop
123: true, // pop2
124: false, // dup
125: false, // dup_x1
126: false, // dup_x2
127: true, // dup2
128: true, // dup2_x1
129: true, // dup2_x2
130: false, // swap
131: false, // iadd
132: true, // ladd
133: false, // fadd
134: true, // dadd
135: false, // isub
136: true, // lsub
137: false, // fsub
138: true, // dsub
139: false, // imul
140: true, // lmul
141: false, // fmul
142: true, // dmul
143: false, // idiv
144: true, // ldiv
145: false, // fdiv
146: true, // ddiv
147: false, // irem
148: true, // lrem
149: false, // frem
150: true, // drem
151: false, // ineg
152: true, // lneg
153: false, // fneg
154: true, // dneg
155: false, // ishl
156: true, // lshl
157: false, // ishr
158: true, // lshr
159: false, // iushr
160: true, // lushr
161: false, // iand
162: true, // land
163: false, // ior
164: true, // lor
165: false, // ixor
166: true, // lxor
167: false, // iinc
168: false, // i2l
169: false, // i2f
170: false, // i2d
171: true, // l2i
172: true, // l2f
173: true, // l2d
174: false, // f2i
175: false, // f2l
176: false, // f2d
177: true, // d2i
178: true, // d2l
179: true, // d2f
180: false, // i2b
181: false, // i2c
182: false, // i2s
183: true, // lcmp
184: false, // fcmpl
185: false, // fcmpg
186: true, // dcmpl
187: true, // dcmpg
188: false, // ifeq
189: false, // ifne
190: false, // iflt
191: false, // ifge
192: false, // ifgt
193: false, // ifle
194: false, // ificmpeq
195: false, // ificmpne
196: false, // ificmplt
197: false, // ificmpge
198: false, // ificmpgt
199: false, // ificmple
200: false, // ifacmpeq
201: false, // ifacmpne
202: false, // goto
203: false, // jsr
204: false, // ret
205: false, // tableswitch
206: false, // lookupswitch
207: false, // ireturn
208: true, // lreturn
209: false, // freturn
210: true, // dreturn
211: false, // areturn
212: false, // return
213: false, // getstatic
214: false, // putstatic
215: false, // getfield
216: false, // putfield
217: false, // invokevirtual
218: false, // invokespecial
219: false, // invokestatic
220: false, // invokeinterface
221: false, // unused
222: false, // new
223: false, // newarray
224: false, // anewarray
225: false, // arraylength
226: false, // athrow
227: false, // checkcast
228: false, // instanceof
229: false, // monitorenter
230: false, // monitorexit
231: false, // wide
232: false, // multianewarray
233: false, // ifnull
234: false, // ifnonnull
235: false, // goto_w
236: false, // jsr_w
237: };
238:
239: // An array containing the fixed number of entries popped from the stack,
240: // for all instructions.
241: private static final int[] STACK_POP_COUNTS = new int[] { 0, // nop
242: 0, // aconst_null
243: 0, // iconst_m1
244: 0, // iconst_0
245: 0, // iconst_1
246: 0, // iconst_2
247: 0, // iconst_3
248: 0, // iconst_4
249: 0, // iconst_5
250: 0, // lconst_0
251: 0, // lconst_1
252: 0, // fconst_0
253: 0, // fconst_1
254: 0, // fconst_2
255: 0, // dconst_0
256: 0, // dconst_1
257: 0, // bipush
258: 0, // sipush
259: 0, // ldc
260: 0, // ldc_w
261: 0, // ldc2_w
262: 0, // iload
263: 0, // lload
264: 0, // fload
265: 0, // dload
266: 0, // aload
267: 0, // iload_0
268: 0, // iload_1
269: 0, // iload_2
270: 0, // iload_3
271: 0, // lload_0
272: 0, // lload_1
273: 0, // lload_2
274: 0, // lload_3
275: 0, // fload_0
276: 0, // fload_1
277: 0, // fload_2
278: 0, // fload_3
279: 0, // dload_0
280: 0, // dload_1
281: 0, // dload_2
282: 0, // dload_3
283: 0, // aload_0
284: 0, // aload_1
285: 0, // aload_2
286: 0, // aload_3
287: 2, // iaload
288: 2, // laload
289: 2, // faload
290: 2, // daload
291: 2, // aaload
292: 2, // baload
293: 2, // caload
294: 2, // saload
295: 1, // istore
296: 2, // lstore
297: 1, // fstore
298: 2, // dstore
299: 1, // astore
300: 1, // istore_0
301: 1, // istore_1
302: 1, // istore_2
303: 1, // istore_3
304: 2, // lstore_0
305: 2, // lstore_1
306: 2, // lstore_2
307: 2, // lstore_3
308: 1, // fstore_0
309: 1, // fstore_1
310: 1, // fstore_2
311: 1, // fstore_3
312: 2, // dstore_0
313: 2, // dstore_1
314: 2, // dstore_2
315: 2, // dstore_3
316: 1, // astore_0
317: 1, // astore_1
318: 1, // astore_2
319: 1, // astore_3
320: 3, // iastore
321: 4, // lastore
322: 3, // fastore
323: 4, // dastore
324: 3, // aastore
325: 3, // bastore
326: 3, // castore
327: 3, // sastore
328: 1, // pop
329: 2, // pop2
330: 1, // dup
331: 2, // dup_x1
332: 3, // dup_x2
333: 2, // dup2
334: 3, // dup2_x1
335: 4, // dup2_x2
336: 2, // swap
337: 2, // iadd
338: 4, // ladd
339: 2, // fadd
340: 4, // dadd
341: 2, // isub
342: 4, // lsub
343: 2, // fsub
344: 4, // dsub
345: 2, // imul
346: 4, // lmul
347: 2, // fmul
348: 4, // dmul
349: 2, // idiv
350: 4, // ldiv
351: 2, // fdiv
352: 4, // ddiv
353: 2, // irem
354: 4, // lrem
355: 2, // frem
356: 4, // drem
357: 1, // ineg
358: 2, // lneg
359: 1, // fneg
360: 2, // dneg
361: 2, // ishl
362: 3, // lshl
363: 2, // ishr
364: 3, // lshr
365: 2, // iushr
366: 3, // lushr
367: 2, // iand
368: 4, // land
369: 2, // ior
370: 4, // lor
371: 2, // ixor
372: 4, // lxor
373: 0, // iinc
374: 1, // i2l
375: 1, // i2f
376: 1, // i2d
377: 2, // l2i
378: 2, // l2f
379: 2, // l2d
380: 1, // f2i
381: 1, // f2l
382: 1, // f2d
383: 2, // d2i
384: 2, // d2l
385: 2, // d2f
386: 1, // i2b
387: 1, // i2c
388: 1, // i2s
389: 4, // lcmp
390: 2, // fcmpl
391: 2, // fcmpg
392: 4, // dcmpl
393: 4, // dcmpg
394: 1, // ifeq
395: 1, // ifne
396: 1, // iflt
397: 1, // ifge
398: 1, // ifgt
399: 1, // ifle
400: 2, // ificmpeq
401: 2, // ificmpne
402: 2, // ificmplt
403: 2, // ificmpge
404: 2, // ificmpgt
405: 2, // ificmple
406: 2, // ifacmpeq
407: 2, // ifacmpne
408: 0, // goto
409: 0, // jsr
410: 0, // ret
411: 1, // tableswitch
412: 1, // lookupswitch
413: 1, // ireturn
414: 2, // lreturn
415: 1, // freturn
416: 2, // dreturn
417: 1, // areturn
418: 0, // return
419: 0, // getstatic
420: 0, // putstatic
421: 1, // getfield
422: 1, // putfield
423: 1, // invokevirtual
424: 1, // invokespecial
425: 0, // invokestatic
426: 1, // invokeinterface
427: 0, // unused
428: 0, // new
429: 1, // newarray
430: 1, // anewarray
431: 1, // arraylength
432: 1, // athrow
433: 1, // checkcast
434: 1, // instanceof
435: 1, // monitorenter
436: 1, // monitorexit
437: 0, // wide
438: 0, // multianewarray
439: 1, // ifnull
440: 1, // ifnonnull
441: 0, // goto_w
442: 0, // jsr_w
443: };
444:
445: // An array containing the fixed number of entries pushed onto the stack,
446: // for all instructions.
447: private static final int[] STACK_PUSH_COUNTS = new int[] { 0, // nop
448: 1, // aconst_null
449: 1, // iconst_m1
450: 1, // iconst_0
451: 1, // iconst_1
452: 1, // iconst_2
453: 1, // iconst_3
454: 1, // iconst_4
455: 1, // iconst_5
456: 2, // lconst_0
457: 2, // lconst_1
458: 1, // fconst_0
459: 1, // fconst_1
460: 1, // fconst_2
461: 2, // dconst_0
462: 2, // dconst_1
463: 1, // bipush
464: 1, // sipush
465: 1, // ldc
466: 1, // ldc_w
467: 2, // ldc2_w
468: 1, // iload
469: 2, // lload
470: 1, // fload
471: 2, // dload
472: 1, // aload
473: 1, // iload_0
474: 1, // iload_1
475: 1, // iload_2
476: 1, // iload_3
477: 2, // lload_0
478: 2, // lload_1
479: 2, // lload_2
480: 2, // lload_3
481: 1, // fload_0
482: 1, // fload_1
483: 1, // fload_2
484: 1, // fload_3
485: 2, // dload_0
486: 2, // dload_1
487: 2, // dload_2
488: 2, // dload_3
489: 1, // aload_0
490: 1, // aload_1
491: 1, // aload_2
492: 1, // aload_3
493: 1, // iaload
494: 2, // laload
495: 1, // faload
496: 2, // daload
497: 1, // aaload
498: 1, // baload
499: 1, // caload
500: 1, // saload
501: 0, // istore
502: 0, // lstore
503: 0, // fstore
504: 0, // dstore
505: 0, // astore
506: 0, // istore_0
507: 0, // istore_1
508: 0, // istore_2
509: 0, // istore_3
510: 0, // lstore_0
511: 0, // lstore_1
512: 0, // lstore_2
513: 0, // lstore_3
514: 0, // fstore_0
515: 0, // fstore_1
516: 0, // fstore_2
517: 0, // fstore_3
518: 0, // dstore_0
519: 0, // dstore_1
520: 0, // dstore_2
521: 0, // dstore_3
522: 0, // astore_0
523: 0, // astore_1
524: 0, // astore_2
525: 0, // astore_3
526: 0, // iastore
527: 0, // lastore
528: 0, // fastore
529: 0, // dastore
530: 0, // aastore
531: 0, // bastore
532: 0, // castore
533: 0, // sastore
534: 0, // pop
535: 0, // pop2
536: 2, // dup
537: 3, // dup_x1
538: 4, // dup_x2
539: 4, // dup2
540: 5, // dup2_x1
541: 6, // dup2_x2
542: 2, // swap
543: 1, // iadd
544: 2, // ladd
545: 1, // fadd
546: 2, // dadd
547: 1, // isub
548: 2, // lsub
549: 1, // fsub
550: 2, // dsub
551: 1, // imul
552: 2, // lmul
553: 1, // fmul
554: 2, // dmul
555: 1, // idiv
556: 2, // ldiv
557: 1, // fdiv
558: 2, // ddiv
559: 1, // irem
560: 2, // lrem
561: 1, // frem
562: 2, // drem
563: 1, // ineg
564: 2, // lneg
565: 1, // fneg
566: 2, // dneg
567: 1, // ishl
568: 2, // lshl
569: 1, // ishr
570: 2, // lshr
571: 1, // iushr
572: 2, // lushr
573: 1, // iand
574: 2, // land
575: 1, // ior
576: 2, // lor
577: 1, // ixor
578: 2, // lxor
579: 0, // iinc
580: 2, // i2l
581: 1, // i2f
582: 2, // i2d
583: 1, // l2i
584: 1, // l2f
585: 2, // l2d
586: 1, // f2i
587: 2, // f2l
588: 2, // f2d
589: 1, // d2i
590: 2, // d2l
591: 1, // d2f
592: 1, // i2b
593: 1, // i2c
594: 1, // i2s
595: 1, // lcmp
596: 1, // fcmpl
597: 1, // fcmpg
598: 1, // dcmpl
599: 1, // dcmpg
600: 0, // ifeq
601: 0, // ifne
602: 0, // iflt
603: 0, // ifge
604: 0, // ifgt
605: 0, // ifle
606: 0, // ificmpeq
607: 0, // ificmpne
608: 0, // ificmplt
609: 0, // ificmpge
610: 0, // ificmpgt
611: 0, // ificmple
612: 0, // ifacmpeq
613: 0, // ifacmpne
614: 0, // goto
615: 1, // jsr
616: 0, // ret
617: 0, // tableswitch
618: 0, // lookupswitch
619: 0, // ireturn
620: 0, // lreturn
621: 0, // freturn
622: 0, // dreturn
623: 0, // areturn
624: 0, // return
625: 0, // getstatic
626: 0, // putstatic
627: 0, // getfield
628: 0, // putfield
629: 0, // invokevirtual
630: 0, // invokespecial
631: 0, // invokestatic
632: 0, // invokeinterface
633: 0, // unused
634: 1, // new
635: 1, // newarray
636: 1, // anewarray
637: 1, // arraylength
638: 0, // athrow
639: 1, // checkcast
640: 1, // instanceof
641: 0, // monitorenter
642: 0, // monitorexit
643: 0, // wide
644: 1, // multianewarray
645: 0, // ifnull
646: 0, // ifnonnull
647: 0, // goto_w
648: 1, // jsr_w
649: };
650:
651: public byte opcode;
652:
653: /**
654: * Returns the canonical opcode of this instruction, i.e. typically the
655: * opcode whose extension has been removed.
656: */
657: public byte canonicalOpcode() {
658: return opcode;
659: }
660:
661: /**
662: * Shrinks this instruction to its shortest possible form.
663: * @return this instruction.
664: */
665: public abstract Instruction shrink();
666:
667: /**
668: * Writes the Instruction at the given offset in the given code attribute.
669: */
670: public final void write(CodeAttribute codeAttribute, int offset) {
671: write(codeAttribute.code, offset);
672: }
673:
674: /**
675: * Writes the Instruction at the given offset in the given code array.
676: */
677: public final void write(byte[] code, int offset) {
678: // Write the wide opcode, if necessary.
679: if (isWide()) {
680: code[offset++] = InstructionConstants.OP_WIDE;
681: }
682:
683: // Write the opcode.
684: code[offset++] = opcode;
685:
686: // Write any additional arguments.
687: writeInfo(code, offset);
688: }
689:
690: /**
691: * Returns whether the instruction is wide, index.e. preceded by a wide opcode.
692: * With the current specifications, only variable instructions can be wide.
693: */
694: protected boolean isWide() {
695: return false;
696: }
697:
698: /**
699: * Reads the data following the instruction opcode.
700: */
701: protected abstract void readInfo(byte[] code, int offset);
702:
703: /**
704: * Writes data following the instruction opcode.
705: */
706: protected abstract void writeInfo(byte[] code, int offset);
707:
708: /**
709: * Returns the length in bytes of the instruction.
710: */
711: public abstract int length(int offset);
712:
713: /**
714: * Accepts the given visitor.
715: */
716: public abstract void accept(Clazz clazz, Method method,
717: CodeAttribute codeAttribute, int offset,
718: InstructionVisitor instructionVisitor);
719:
720: /**
721: * Returns a description of the instruction, at the given offset.
722: */
723: public String toString(int offset) {
724: return "[" + offset + "] " + this .toString();
725: }
726:
727: /**
728: * Returns the name of the instruction.
729: */
730: public String getName() {
731: return InstructionConstants.NAMES[opcode & 0xff];
732: }
733:
734: /**
735: * Returns whether the instruction is a Category 2 instruction. This means
736: * that it operates on long or double arguments.
737: */
738: public boolean isCategory2() {
739: return IS_CATEGORY2[opcode & 0xff];
740: }
741:
742: /**
743: * Returns the number of entries popped from the stack during the execution
744: * of the instruction.
745: */
746: public int stackPopCount(Clazz clazz) {
747: return STACK_POP_COUNTS[opcode & 0xff];
748: }
749:
750: /**
751: * Returns the number of entries pushed onto the stack during the execution
752: * of the instruction.
753: */
754: public int stackPushCount(Clazz clazz) {
755: return STACK_PUSH_COUNTS[opcode & 0xff];
756: }
757:
758: // Small utility methods.
759:
760: protected static int readByte(byte[] code, int offset) {
761: return code[offset] & 0xff;
762: }
763:
764: protected static int readShort(byte[] code, int offset) {
765: return ((code[offset++] & 0xff) << 8) | (code[offset] & 0xff);
766: }
767:
768: protected static int readInt(byte[] code, int offset) {
769: return (code[offset++] << 24) | ((code[offset++] & 0xff) << 16)
770: | ((code[offset++] & 0xff) << 8)
771: | (code[offset] & 0xff);
772: }
773:
774: protected static int readValue(byte[] code, int offset,
775: int valueSize) {
776: switch (valueSize) {
777: case 0:
778: return 0;
779: case 1:
780: return readByte(code, offset);
781: case 2:
782: return readShort(code, offset);
783: case 4:
784: return readInt(code, offset);
785: default:
786: throw new IllegalArgumentException(
787: "Unsupported value size [" + valueSize + "]");
788: }
789: }
790:
791: protected static int readSignedByte(byte[] code, int offset) {
792: return code[offset];
793: }
794:
795: protected static int readSignedShort(byte[] code, int offset) {
796: return (code[offset++] << 8) | (code[offset] & 0xff);
797: }
798:
799: protected static int readSignedValue(byte[] code, int offset,
800: int valueSize) {
801: switch (valueSize) {
802: case 0:
803: return 0;
804: case 1:
805: return readSignedByte(code, offset);
806: case 2:
807: return readSignedShort(code, offset);
808: case 4:
809: return readInt(code, offset);
810: default:
811: throw new IllegalArgumentException(
812: "Unsupported value size [" + valueSize + "]");
813: }
814: }
815:
816: protected static void writeByte(byte[] code, int offset, int value) {
817: if (value > 0xff) {
818: throw new IllegalArgumentException(
819: "Unsigned byte value larger than 0xff [" + value
820: + "]");
821: }
822:
823: code[offset] = (byte) value;
824: }
825:
826: protected static void writeShort(byte[] code, int offset, int value) {
827: if (value > 0xffff) {
828: throw new IllegalArgumentException(
829: "Unsigned short value larger than 0xffff [" + value
830: + "]");
831: }
832:
833: code[offset++] = (byte) (value >> 8);
834: code[offset] = (byte) (value);
835: }
836:
837: protected static void writeInt(byte[] code, int offset, int value) {
838: code[offset++] = (byte) (value >> 24);
839: code[offset++] = (byte) (value >> 16);
840: code[offset++] = (byte) (value >> 8);
841: code[offset] = (byte) (value);
842: }
843:
844: protected static void writeValue(byte[] code, int offset,
845: int value, int valueSize) {
846: switch (valueSize) {
847: case 0:
848: break;
849: case 1:
850: writeByte(code, offset, value);
851: break;
852: case 2:
853: writeShort(code, offset, value);
854: break;
855: case 4:
856: writeInt(code, offset, value);
857: break;
858: default:
859: throw new IllegalArgumentException(
860: "Unsupported value size [" + valueSize + "]");
861: }
862: }
863:
864: protected static void writeSignedByte(byte[] code, int offset,
865: int value) {
866: if (value << 24 >> 24 != value) {
867: throw new IllegalArgumentException(
868: "Signed byte value out of range [" + value + "]");
869: }
870:
871: code[offset] = (byte) value;
872: }
873:
874: protected static void writeSignedShort(byte[] code, int offset,
875: int value) {
876: if (value << 16 >> 16 != value) {
877: throw new IllegalArgumentException(
878: "Signed short value out of range [" + value + "]");
879: }
880:
881: code[offset++] = (byte) (value >> 8);
882: code[offset] = (byte) (value);
883: }
884:
885: protected static void writeSignedValue(byte[] code, int offset,
886: int value, int valueSize) {
887: switch (valueSize) {
888: case 0:
889: break;
890: case 1:
891: writeSignedByte(code, offset, value);
892: break;
893: case 2:
894: writeSignedShort(code, offset, value);
895: break;
896: case 4:
897: writeInt(code, offset, value);
898: break;
899: default:
900: throw new IllegalArgumentException(
901: "Unsupported value size [" + valueSize + "]");
902: }
903: }
904: }
|