1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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 */
21package proguard.classfile.instruction;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.CodeAttribute;
25import proguard.classfile.instruction.visitor.InstructionVisitor;
26
27/**
28 * Base class for representing instructions.
29 *
30 * @author Eric Lafortune
31 */
32public 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, // unused
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, // unused
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, // unused
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     */
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     */
677    public abstract Instruction shrink();
678
679
680
681    /**
682     * Writes the Instruction at the given offset in the given code attribute.
683     */
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     */
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     */
713    protected boolean isWide()
714    {
715        return false;
716    }
717
718
719    /**
720     * Reads the data following the instruction opcode.
721     */
722    protected abstract void readInfo(byte[] code, int offset);
723
724
725    /**
726     * Writes data following the instruction opcode.
727     */
728    protected abstract void writeInfo(byte[] code, int offset);
729
730
731    /**
732     * Returns the length in bytes of the instruction.
733     */
734    public abstract int length(int offset);
735
736
737    /**
738     * Accepts the given visitor.
739     */
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     */
746    public String toString(int offset)
747    {
748        return "["+offset+"] "+ this.toString();
749    }
750
751
752    /**
753     * Returns the name of the instruction.
754     */
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     */
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     */
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     */
785    public int stackPushCount(Clazz clazz)
786    {
787        return STACK_PUSH_COUNTS[opcode & 0xff];
788    }
789
790
791    // Small utility methods.
792
793    protected static int readByte(byte[] code, int offset)
794    {
795        return code[offset] & 0xff;
796    }
797
798    protected static int readShort(byte[] code, int offset)
799    {
800        return ((code[offset++] & 0xff) << 8) |
801               ( code[offset  ] & 0xff      );
802    }
803
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
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
824    protected static int readSignedByte(byte[] code, int offset)
825    {
826        return code[offset];
827    }
828
829    protected static int readSignedShort(byte[] code, int offset)
830    {
831        return (code[offset++] <<   8) |
832               (code[offset  ] & 0xff);
833    }
834
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
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
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
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
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
888    protected static void writeSignedByte(byte[] code, int offset, int value)
889    {
890        if (value << 24 >> 24 != value)
891        {
892            throw new IllegalArgumentException("Signed byte value out of range ["+value+"]");
893        }
894
895        code[offset] = (byte)value;
896    }
897
898    protected static void writeSignedShort(byte[] code, int offset, int value)
899    {
900        if (value << 16 >> 16 != 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
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