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