KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > commons > GeneratorAdapter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package org.objectweb.asm.commons;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.List JavaDoc;
35
36 import org.objectweb.asm.ClassVisitor;
37 import org.objectweb.asm.Label;
38 import org.objectweb.asm.MethodVisitor;
39 import org.objectweb.asm.Opcodes;
40 import org.objectweb.asm.Type;
41
42 /**
43  * A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate
44  * code. For example, using this adapter, the class below
45  *
46  * <pre>
47  * public class Example {
48  * public static void main(String[] args) {
49  * System.out.println(&quot;Hello world!&quot;);
50  * }
51  * }
52  * </pre>
53  *
54  * can be generated as follows:
55  *
56  * <pre>
57  * ClassWriter cw = new ClassWriter(true);
58  * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
59  *
60  * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
61  * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
62  * mg.loadThis();
63  * mg.invokeConstructor(Type.getType(Object.class), m);
64  * mg.returnValue();
65  * mg.endMethod();
66  *
67  * m = Method.getMethod(&quot;void main (String[])&quot;);
68  * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
69  * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
70  * mg.push(&quot;Hello world!&quot;);
71  * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod(&quot;void println (String)&quot;));
72  * mg.returnValue();
73  * mg.endMethod();
74  *
75  * cw.visitEnd();
76  * </pre>
77  *
78  * @author Juozas Baliuka
79  * @author Chris Nokleberg
80  * @author Eric Bruneton
81  */

82 public class GeneratorAdapter extends LocalVariablesSorter {
83
84     private final static Type BYTE_TYPE = Type.getType("Ljava/lang/Byte;");
85
86     private final static Type BOOLEAN_TYPE = Type.getType("Ljava/lang/Boolean;");
87
88     private final static Type SHORT_TYPE = Type.getType("Ljava/lang/Short;");
89
90     private final static Type CHARACTER_TYPE = Type.getType("Ljava/lang/Character;");
91
92     private final static Type INTEGER_TYPE = Type.getType("Ljava/lang/Integer;");
93
94     private final static Type FLOAT_TYPE = Type.getType("Ljava/lang/Float;");
95
96     private final static Type LONG_TYPE = Type.getType("Ljava/lang/Long;");
97
98     private final static Type DOUBLE_TYPE = Type.getType("Ljava/lang/Double;");
99
100     private final static Type NUMBER_TYPE = Type.getType("Ljava/lang/Number;");
101
102     private final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
103
104     private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
105
106     private final static Method CHAR_VALUE = Method.getMethod("char charValue()");
107
108     private final static Method INT_VALUE = Method.getMethod("int intValue()");
109
110     private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()");
111
112     private final static Method LONG_VALUE = Method.getMethod("long longValue()");
113
114     private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
115
116     /**
117      * Constant for the {@link #math math} method.
118      */

119     public final static int ADD = Opcodes.IADD;
120
121     /**
122      * Constant for the {@link #math math} method.
123      */

124     public final static int SUB = Opcodes.ISUB;
125
126     /**
127      * Constant for the {@link #math math} method.
128      */

129     public final static int MUL = Opcodes.IMUL;
130
131     /**
132      * Constant for the {@link #math math} method.
133      */

134     public final static int DIV = Opcodes.IDIV;
135
136     /**
137      * Constant for the {@link #math math} method.
138      */

139     public final static int REM = Opcodes.IREM;
140
141     /**
142      * Constant for the {@link #math math} method.
143      */

144     public final static int NEG = Opcodes.INEG;
145
146     /**
147      * Constant for the {@link #math math} method.
148      */

149     public final static int SHL = Opcodes.ISHL;
150
151     /**
152      * Constant for the {@link #math math} method.
153      */

154     public final static int SHR = Opcodes.ISHR;
155
156     /**
157      * Constant for the {@link #math math} method.
158      */

159     public final static int USHR = Opcodes.IUSHR;
160
161     /**
162      * Constant for the {@link #math math} method.
163      */

164     public final static int AND = Opcodes.IAND;
165
166     /**
167      * Constant for the {@link #math math} method.
168      */

169     public final static int OR = Opcodes.IOR;
170
171     /**
172      * Constant for the {@link #math math} method.
173      */

174     public final static int XOR = Opcodes.IXOR;
175
176     /**
177      * Constant for the {@link #ifCmp ifCmp} method.
178      */

179     public final static int EQ = Opcodes.IFEQ;
180
181     /**
182      * Constant for the {@link #ifCmp ifCmp} method.
183      */

184     public final static int NE = Opcodes.IFNE;
185
186     /**
187      * Constant for the {@link #ifCmp ifCmp} method.
188      */

189     public final static int LT = Opcodes.IFLT;
190
191     /**
192      * Constant for the {@link #ifCmp ifCmp} method.
193      */

194     public final static int GE = Opcodes.IFGE;
195
196     /**
197      * Constant for the {@link #ifCmp ifCmp} method.
198      */

199     public final static int GT = Opcodes.IFGT;
200
201     /**
202      * Constant for the {@link #ifCmp ifCmp} method.
203      */

204     public final static int LE = Opcodes.IFLE;
205
206     /**
207      * Access flags of the method visited by this adapter.
208      */

209     private final int access;
210
211     /**
212      * Return type of the method visited by this adapter.
213      */

214     private final Type returnType;
215
216     /**
217      * Argument types of the method visited by this adapter.
218      */

219     private final Type[] argumentTypes;
220
221     /**
222      * Types of the local variables of the method visited by this adapter.
223      */

224     private final List JavaDoc localTypes;
225
226     /**
227      * Creates a new {@link GeneratorAdapter}.
228      *
229      * @param access access flags of the adapted method.
230      * @param method the adapted method.
231      * @param mv the method visitor to which this adapter delegates calls.
232      */

233     public GeneratorAdapter(
234         final int access,
235         final Method method,
236         final MethodVisitor mv)
237     {
238         super(access, method.getDescriptor(), mv);
239         this.access = access;
240         this.returnType = method.getReturnType();
241         this.argumentTypes = method.getArgumentTypes();
242         this.localTypes = new ArrayList JavaDoc();
243     }
244
245     /**
246      * Creates a new {@link GeneratorAdapter}.
247      *
248      * @param access access flags of the adapted method.
249      * @param method the adapted method.
250      * @param signature the signature of the adapted method (may be
251      * <tt>null</tt>).
252      * @param exceptions the exceptions thrown by the adapted method (may be
253      * <tt>null</tt>).
254      * @param cv the class visitor to which this adapter delegates calls.
255      */

256     public GeneratorAdapter(
257         final int access,
258         final Method method,
259         final String JavaDoc signature,
260         final Type[] exceptions,
261         final ClassVisitor cv)
262     {
263         this(access, method, cv.visitMethod(access,
264                 method.getName(),
265                 method.getDescriptor(),
266                 signature,
267                 getInternalNames(exceptions)));
268     }
269
270     /**
271      * Returns the internal names of the given types.
272      *
273      * @param types a set of types.
274      * @return the internal names of the given types.
275      */

276     private static String JavaDoc[] getInternalNames(final Type[] types) {
277         if (types == null) {
278             return null;
279         }
280         String JavaDoc[] names = new String JavaDoc[types.length];
281         for (int i = 0; i < names.length; ++i) {
282             names[i] = types[i].getInternalName();
283         }
284         return names;
285     }
286
287     // ------------------------------------------------------------------------
288
// Instructions to push constants on the stack
289
// ------------------------------------------------------------------------
290

291     /**
292      * Generates the instruction to push the given value on the stack.
293      *
294      * @param value the value to be pushed on the stack.
295      */

296     public void push(final boolean value) {
297         push(value ? 1 : 0);
298     }
299
300     /**
301      * Generates the instruction to push the given value on the stack.
302      *
303      * @param value the value to be pushed on the stack.
304      */

305     public void push(final int value) {
306         if (value >= -1 && value <= 5) {
307             mv.visitInsn(Opcodes.ICONST_0 + value);
308         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
309             mv.visitIntInsn(Opcodes.BIPUSH, value);
310         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
311             mv.visitIntInsn(Opcodes.SIPUSH, value);
312         } else {
313             mv.visitLdcInsn(new Integer JavaDoc(value));
314         }
315     }
316
317     /**
318      * Generates the instruction to push the given value on the stack.
319      *
320      * @param value the value to be pushed on the stack.
321      */

322     public void push(final long value) {
323         if (value == 0L || value == 1L) {
324             mv.visitInsn(Opcodes.LCONST_0 + (int) value);
325         } else {
326             mv.visitLdcInsn(new Long JavaDoc(value));
327         }
328     }
329
330     /**
331      * Generates the instruction to push the given value on the stack.
332      *
333      * @param value the value to be pushed on the stack.
334      */

335     public void push(final float value) {
336         int bits = Float.floatToIntBits(value);
337         if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
338
mv.visitInsn(Opcodes.FCONST_0 + (int) value);
339         } else {
340             mv.visitLdcInsn(new Float JavaDoc(value));
341         }
342     }
343
344     /**
345      * Generates the instruction to push the given value on the stack.
346      *
347      * @param value the value to be pushed on the stack.
348      */

349     public void push(final double value) {
350         long bits = Double.doubleToLongBits(value);
351         if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
352
mv.visitInsn(Opcodes.DCONST_0 + (int) value);
353         } else {
354             mv.visitLdcInsn(new Double JavaDoc(value));
355         }
356     }
357
358     /**
359      * Generates the instruction to push the given value on the stack.
360      *
361      * @param value the value to be pushed on the stack. May be <tt>null</tt>.
362      */

363     public void push(final String JavaDoc value) {
364         if (value == null) {
365             mv.visitInsn(Opcodes.ACONST_NULL);
366         } else {
367             mv.visitLdcInsn(value);
368         }
369     }
370
371     /**
372      * Generates the instruction to push the given value on the stack.
373      *
374      * @param value the value to be pushed on the stack.
375      */

376     public void push(final Type value) {
377         if (value == null) {
378             mv.visitInsn(Opcodes.ACONST_NULL);
379         } else {
380             mv.visitLdcInsn(value);
381         }
382     }
383
384     // ------------------------------------------------------------------------
385
// Instructions to load and store method arguments
386
// ------------------------------------------------------------------------
387

388     /**
389      * Returns the index of the given method argument in the frame's local
390      * variables array.
391      *
392      * @param arg the index of a method argument.
393      * @return the index of the given method argument in the frame's local
394      * variables array.
395      */

396     private int getArgIndex(final int arg) {
397         int index = ((access & Opcodes.ACC_STATIC) == 0 ? 1 : 0);
398         for (int i = 0; i < arg; i++) {
399             index += argumentTypes[i].getSize();
400         }
401         return index;
402     }
403
404     /**
405      * Generates the instruction to push a local variable on the stack.
406      *
407      * @param type the type of the local variable to be loaded.
408      * @param index an index in the frame's local variables array.
409      */

410     private void loadInsn(final Type type, final int index) {
411         mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
412     }
413
414     /**
415      * Generates the instruction to store the top stack value in a local
416      * variable.
417      *
418      * @param type the type of the local variable to be stored.
419      * @param index an index in the frame's local variables array.
420      */

421     private void storeInsn(final Type type, final int index) {
422         mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
423     }
424
425     /**
426      * Generates the instruction to load 'this' on the stack.
427      */

428     public void loadThis() {
429         if ((access & Opcodes.ACC_STATIC) != 0) {
430             throw new IllegalStateException JavaDoc("no 'this' pointer within static method");
431         }
432         mv.visitVarInsn(Opcodes.ALOAD, 0);
433     }
434
435     /**
436      * Generates the instruction to load the given method argument on the stack.
437      *
438      * @param arg the index of a method argument.
439      */

440     public void loadArg(final int arg) {
441         loadInsn(argumentTypes[arg], getArgIndex(arg));
442     }
443
444     /**
445      * Generates the instructions to load the given method arguments on the
446      * stack.
447      *
448      * @param arg the index of the first method argument to be loaded.
449      * @param count the number of method arguments to be loaded.
450      */

451     public void loadArgs(final int arg, final int count) {
452         int index = getArgIndex(arg);
453         for (int i = 0; i < count; ++i) {
454             Type t = argumentTypes[arg + i];
455             loadInsn(t, index);
456             index += t.getSize();
457         }
458     }
459
460     /**
461      * Generates the instructions to load all the method arguments on the stack.
462      */

463     public void loadArgs() {
464         loadArgs(0, argumentTypes.length);
465     }
466
467     /**
468      * Generates the instructions to load all the method arguments on the stack,
469      * as a single object array.
470      */

471     public void loadArgArray() {
472         push(argumentTypes.length);
473         newArray(OBJECT_TYPE);
474         for (int i = 0; i < argumentTypes.length; i++) {
475             dup();
476             push(i);
477             loadArg(i);
478             box(argumentTypes[i]);
479             arrayStore(OBJECT_TYPE);
480         }
481     }
482
483     /**
484      * Generates the instruction to store the top stack value in the given
485      * method argument.
486      *
487      * @param arg the index of a method argument.
488      */

489     public void storeArg(final int arg) {
490         storeInsn(argumentTypes[arg], getArgIndex(arg));
491     }
492
493     // ------------------------------------------------------------------------
494
// Instructions to load and store local variables
495
// ------------------------------------------------------------------------
496

497     /**
498      * Creates a new local variable of the given type.
499      *
500      * @param type the type of the local variable to be created.
501      * @return the identifier of the newly created local variable.
502      */

503     public int newLocal(final Type type) {
504         int local = super.newLocal(type.getSize());
505         setLocalType(local, type);
506         return local;
507     }
508
509     /**
510      * Returns the type of the given local variable.
511      *
512      * @param local a local variable identifier, as returned by {@link #newLocal
513      * newLocal}.
514      * @return the type of the given local variable.
515      */

516     public Type getLocalType(final int local) {
517         return (Type) localTypes.get(local - firstLocal);
518     }
519
520     /**
521      * Sets the current type of the given local variable.
522      *
523      * @param local a local variable identifier, as returned by {@link #newLocal
524      * newLocal}.
525      * @param type the type of the value being stored in the local variable
526      */

527     private void setLocalType(final int local, final Type type) {
528         int index = local - firstLocal;
529         while (localTypes.size() < index + 1)
530             localTypes.add(null);
531         localTypes.set(index, type);
532     }
533
534     /**
535      * Generates the instruction to load the given local variable on the stack.
536      *
537      * @param local a local variable identifier, as returned by {@link #newLocal
538      * newLocal}.
539      */

540     public void loadLocal(final int local) {
541         loadInsn(getLocalType(local), local);
542     }
543
544     /**
545      * Generates the instruction to load the given local variable on the stack.
546      *
547      * @param local a local variable identifier, as returned by {@link #newLocal
548      * newLocal}.
549      */

550     public void loadLocal(final int local, final Type type) {
551         setLocalType(local, type);
552         loadInsn(type, local);
553     }
554
555     /**
556      * Generates the instruction to store the top stack value in the given local
557      * variable.
558      *
559      * @param local a local variable identifier, as returned by {@link #newLocal
560      * newLocal}.
561      */

562     public void storeLocal(final int local) {
563         storeInsn(getLocalType(local), local);
564     }
565
566     /**
567      * Generates the instruction to store the top stack value in the given local
568      * variable.
569      *
570      * @param local a local variable identifier, as returned by {@link #newLocal
571      * newLocal}.
572      */

573     public void storeLocal(final int local, final Type type) {
574         setLocalType(local, type);
575         storeInsn(type, local);
576     }
577
578     /**
579      * Generates the instruction to load an element from an array.
580      *
581      * @param type the type of the array element to be loaded.
582      */

583     public void arrayLoad(final Type type) {
584         mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
585     }
586
587     /**
588      * Generates the instruction to store an element in an array.
589      *
590      * @param type the type of the array element to be stored.
591      */

592     public void arrayStore(final Type type) {
593         mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
594     }
595
596     // ------------------------------------------------------------------------
597
// Instructions to manage the stack
598
// ------------------------------------------------------------------------
599

600     /**
601      * Generates a POP instruction.
602      */

603     public void pop() {
604         mv.visitInsn(Opcodes.POP);
605     }
606
607     /**
608      * Generates a POP2 instruction.
609      */

610     public void pop2() {
611         mv.visitInsn(Opcodes.POP2);
612     }
613
614     /**
615      * Generates a DUP instruction.
616      */

617     public void dup() {
618         mv.visitInsn(Opcodes.DUP);
619     }
620
621     /**
622      * Generates a DUP2 instruction.
623      */

624     public void dup2() {
625         mv.visitInsn(Opcodes.DUP2);
626     }
627
628     /**
629      * Generates a DUP_X1 instruction.
630      */

631     public void dupX1() {
632         mv.visitInsn(Opcodes.DUP_X1);
633     }
634
635     /**
636      * Generates a DUP_X2 instruction.
637      */

638     public void dupX2() {
639         mv.visitInsn(Opcodes.DUP_X2);
640     }
641
642     /**
643      * Generates a DUP2_X1 instruction.
644      */

645     public void dup2X1() {
646         mv.visitInsn(Opcodes.DUP2_X1);
647     }
648
649     /**
650      * Generates a DUP2_X2 instruction.
651      */

652     public void dup2X2() {
653         mv.visitInsn(Opcodes.DUP2_X2);
654     }
655
656     /**
657      * Generates a SWAP instruction.
658      */

659     public void swap() {
660         mv.visitInsn(Opcodes.SWAP);
661     }
662
663     /**
664      * Generates the instructions to swap the top two stack values.
665      *
666      * @param prev type of the top - 1 stack value.
667      * @param type type of the top stack value.
668      */

669     public void swap(final Type prev, final Type type) {
670         if (type.getSize() == 1) {
671             if (prev.getSize() == 1) {
672                 swap(); // same as dupX1(), pop();
673
} else {
674                 dupX2();
675                 pop();
676             }
677         } else {
678             if (prev.getSize() == 1) {
679                 dup2X1();
680                 pop2();
681             } else {
682                 dup2X2();
683                 pop2();
684             }
685         }
686     }
687
688     // ------------------------------------------------------------------------
689
// Instructions to do mathematical and logical operations
690
// ------------------------------------------------------------------------
691

692     /**
693      * Generates the instruction to do the specified mathematical or logical
694      * operation.
695      *
696      * @param op a mathematical or logical operation. Must be one of ADD, SUB,
697      * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
698      * @param type the type of the operand(s) for this operation.
699      */

700     public void math(final int op, final Type type) {
701         mv.visitInsn(type.getOpcode(op));
702     }
703
704     /**
705      * Generates the instructions to compute the bitwise negation of the top
706      * stack value.
707      */

708     public void not() {
709         mv.visitInsn(Opcodes.ICONST_1);
710         mv.visitInsn(Opcodes.IXOR);
711     }
712
713     /**
714      * Generates the instruction to increment the given local variable.
715      *
716      * @param local the local variable to be incremented.
717      * @param amount the amount by which the local variable must be incremented.
718      */

719     public void iinc(final int local, final int amount) {
720         mv.visitIincInsn(local, amount);
721     }
722
723     /**
724      * Generates the instructions to cast a numerical value from one type to
725      * another.
726      *
727      * @param from the type of the top stack value
728      * @param to the type into which this value must be cast.
729      */

730     public void cast(final Type from, final Type to) {
731         if (from != to) {
732             if (from == Type.DOUBLE_TYPE) {
733                 if (to == Type.FLOAT_TYPE) {
734                     mv.visitInsn(Opcodes.D2F);
735                 } else if (to == Type.LONG_TYPE) {
736                     mv.visitInsn(Opcodes.D2L);
737                 } else {
738                     mv.visitInsn(Opcodes.D2I);
739                     cast(Type.INT_TYPE, to);
740                 }
741             } else if (from == Type.FLOAT_TYPE) {
742                 if (to == Type.DOUBLE_TYPE) {
743                     mv.visitInsn(Opcodes.F2D);
744                 } else if (to == Type.LONG_TYPE) {
745                     mv.visitInsn(Opcodes.F2L);
746                 } else {
747                     mv.visitInsn(Opcodes.F2I);
748                     cast(Type.INT_TYPE, to);
749                 }
750             } else if (from == Type.LONG_TYPE) {
751                 if (to == Type.DOUBLE_TYPE) {
752                     mv.visitInsn(Opcodes.L2D);
753                 } else if (to == Type.FLOAT_TYPE) {
754                     mv.visitInsn(Opcodes.L2F);
755                 } else {
756                     mv.visitInsn(Opcodes.L2I);
757                     cast(Type.INT_TYPE, to);
758                 }
759             } else {
760                 if (to == Type.BYTE_TYPE) {
761                     mv.visitInsn(Opcodes.I2B);
762                 } else if (to == Type.CHAR_TYPE) {
763                     mv.visitInsn(Opcodes.I2C);
764                 } else if (to == Type.DOUBLE_TYPE) {
765                     mv.visitInsn(Opcodes.I2D);
766                 } else if (to == Type.FLOAT_TYPE) {
767                     mv.visitInsn(Opcodes.I2F);
768                 } else if (to == Type.LONG_TYPE) {
769                     mv.visitInsn(Opcodes.I2L);
770                 } else if (to == Type.SHORT_TYPE) {
771                     mv.visitInsn(Opcodes.I2S);
772                 }
773             }
774         }
775     }
776
777     // ------------------------------------------------------------------------
778
// Instructions to do boxing and unboxing operations
779
// ------------------------------------------------------------------------
780

781     /**
782      * Generates the instructions to box the top stack value. This value is
783      * replaced by its boxed equivalent on top of the stack.
784      *
785      * @param type the type of the top stack value.
786      */

787     public void box(final Type type) {
788         if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
789             return;
790         }
791         if (type == Type.VOID_TYPE) {
792             push((String JavaDoc) null);
793         } else {
794             Type boxed = type;
795             switch (type.getSort()) {
796                 case Type.BYTE:
797                     boxed = BYTE_TYPE;
798                     break;
799                 case Type.BOOLEAN:
800                     boxed = BOOLEAN_TYPE;
801                     break;
802                 case Type.SHORT:
803                     boxed = SHORT_TYPE;
804                     break;
805                 case Type.CHAR:
806                     boxed = CHARACTER_TYPE;
807                     break;
808                 case Type.INT:
809                     boxed = INTEGER_TYPE;
810                     break;
811                 case Type.FLOAT:
812                     boxed = FLOAT_TYPE;
813                     break;
814                 case Type.LONG:
815                     boxed = LONG_TYPE;
816                     break;
817                 case Type.DOUBLE:
818                     boxed = DOUBLE_TYPE;
819                     break;
820             }
821             newInstance(boxed);
822             if (type.getSize() == 2) {
823                 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
824
dupX2();
825                 dupX2();
826                 pop();
827             } else {
828                 // p -> po -> opo -> oop -> o
829
dupX1();
830                 swap();
831             }
832             invokeConstructor(boxed, new Method("<init>",
833                     Type.VOID_TYPE,
834                     new Type[] { type }));
835         }
836     }
837
838     /**
839      * Generates the instructions to unbox the top stack value. This value is
840      * replaced by its unboxed equivalent on top of the stack.
841      *
842      * @param type the type of the top stack value.
843      */

844     public void unbox(final Type type) {
845         Type t = NUMBER_TYPE;
846         Method sig = null;
847         switch (type.getSort()) {
848             case Type.VOID:
849                 return;
850             case Type.CHAR:
851                 t = CHARACTER_TYPE;
852                 sig = CHAR_VALUE;
853                 break;
854             case Type.BOOLEAN:
855                 t = BOOLEAN_TYPE;
856                 sig = BOOLEAN_VALUE;
857                 break;
858             case Type.DOUBLE:
859                 sig = DOUBLE_VALUE;
860                 break;
861             case Type.FLOAT:
862                 sig = FLOAT_VALUE;
863                 break;
864             case Type.LONG:
865                 sig = LONG_VALUE;
866                 break;
867             case Type.INT:
868             case Type.SHORT:
869             case Type.BYTE:
870                 sig = INT_VALUE;
871         }
872         if (sig == null) {
873             checkCast(type);
874         } else {
875             checkCast(t);
876             invokeVirtual(t, sig);
877         }
878     }
879
880     // ------------------------------------------------------------------------
881
// Instructions to jump to other instructions
882
// ------------------------------------------------------------------------
883

884     /**
885      * Creates a new {@link Label}.
886      *
887      * @return a new {@link Label}.
888      */

889     public Label newLabel() {
890         return new Label();
891     }
892
893     /**
894      * Marks the current code position with the given label.
895      *
896      * @param label a label.
897      */

898     public void mark(final Label label) {
899         mv.visitLabel(label);
900     }
901
902     /**
903      * Marks the current code position with a new label.
904      *
905      * @return the label that was created to mark the current code position.
906      */

907     public Label mark() {
908         Label label = new Label();
909         mv.visitLabel(label);
910         return label;
911     }
912
913     /**
914      * Generates the instructions to jump to a label based on the comparison of
915      * the top two stack values.
916      *
917      * @param type the type of the top two stack values.
918      * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
919      * LE.
920      * @param label where to jump if the comparison result is <tt>true</tt>.
921      */

922     public void ifCmp(final Type type, final int mode, final Label label) {
923         int intOp = -1;
924         int jumpMode = mode;
925         switch (mode) {
926             case GE:
927                 jumpMode = LT;
928                 break;
929             case LE:
930                 jumpMode = GT;
931                 break;
932         }
933         switch (type.getSort()) {
934             case Type.LONG:
935                 mv.visitInsn(Opcodes.LCMP);
936                 break;
937             case Type.DOUBLE:
938                 mv.visitInsn(Opcodes.DCMPG);
939                 break;
940             case Type.FLOAT:
941                 mv.visitInsn(Opcodes.FCMPG);
942                 break;
943             case Type.ARRAY:
944             case Type.OBJECT:
945                 switch (mode) {
946                     case EQ:
947                         mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
948                         return;
949                     case NE:
950                         mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
951                         return;
952                 }
953                 throw new IllegalArgumentException JavaDoc("Bad comparison for type "
954                         + type);
955             default:
956                 switch (mode) {
957                     case EQ:
958                         intOp = Opcodes.IF_ICMPEQ;
959                         break;
960                     case NE:
961                         intOp = Opcodes.IF_ICMPNE;
962                         break;
963                     case GE:
964                         intOp = Opcodes.IF_ICMPGE;
965                         break;
966                     case LT:
967                         intOp = Opcodes.IF_ICMPLT;
968                         break;
969                     case LE:
970                         intOp = Opcodes.IF_ICMPLE;
971                         break;
972                     case GT:
973                         intOp = Opcodes.IF_ICMPGT;
974                         break;
975                 }
976                 mv.visitJumpInsn(intOp, label);
977                 return;
978         }
979         mv.visitJumpInsn(jumpMode, label);
980     }
981
982     /**
983      * Generates the instructions to jump to a label based on the comparison of
984      * the top two integer stack values.
985      *
986      * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
987      * LE.
988      * @param label where to jump if the comparison result is <tt>true</tt>.
989      */

990     public void ifICmp(final int mode, final Label label) {
991         ifCmp(Type.INT_TYPE, mode, label);
992     }
993
994     /**
995      * Generates the instructions to jump to a label based on the comparison of
996      * the top integer stack value with zero.
997      *
998      * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
999      * LE.
1000     * @param label where to jump if the comparison result is <tt>true</tt>.
1001     */

1002    public void ifZCmp(final int mode, final Label label) {
1003        mv.visitJumpInsn(mode, label);
1004    }
1005
1006    /**
1007     * Generates the instruction to jump to the given label if the top stack
1008     * value is null.
1009     *
1010     * @param label where to jump if the condition is <tt>true</tt>.
1011     */

1012    public void ifNull(final Label label) {
1013        mv.visitJumpInsn(Opcodes.IFNULL, label);
1014    }
1015
1016    /**
1017     * Generates the instruction to jump to the given label if the top stack
1018     * value is not null.
1019     *
1020     * @param label where to jump if the condition is <tt>true</tt>.
1021     */

1022    public void ifNonNull(final Label label) {
1023        mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1024    }
1025
1026    /**
1027     * Generates the instruction to jump to the given label.
1028     *
1029     * @param label where to jump if the condition is <tt>true</tt>.
1030     */

1031    public void goTo(final Label label) {
1032        mv.visitJumpInsn(Opcodes.GOTO, label);
1033    }
1034
1035    /**
1036     * Generates a RET instruction.
1037     *
1038     * @param local a local variable identifier, as returned by {@link #newLocal
1039     * newLocal}.
1040     */

1041    public void ret(final int local) {
1042        mv.visitVarInsn(Opcodes.RET, local);
1043    }
1044
1045    /**
1046     * Generates the instructions for a switch statement.
1047     *
1048     * @param keys the switch case keys.
1049     * @param generator a generator to generate the code for the switch cases.
1050     */

1051    public void tableSwitch(
1052        final int[] keys,
1053        final TableSwitchGenerator generator)
1054    {
1055        float density;
1056        if (keys.length == 0) {
1057            density = 0;
1058        } else {
1059            density = (float) keys.length
1060                    / (keys[keys.length - 1] - keys[0] + 1);
1061        }
1062        tableSwitch(keys, generator, density >= 0.5f);
1063    }
1064
1065    /**
1066     * Generates the instructions for a switch statement.
1067     *
1068     * @param keys the switch case keys.
1069     * @param generator a generator to generate the code for the switch cases.
1070     * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or
1071     * <tt>false</tt> to use a LOOKUPSWITCH instruction.
1072     */

1073    public void tableSwitch(
1074        final int[] keys,
1075        final TableSwitchGenerator generator,
1076        final boolean useTable)
1077    {
1078        for (int i = 1; i < keys.length; ++i) {
1079            if (keys[i] < keys[i - 1]) {
1080                throw new IllegalArgumentException JavaDoc("keys must be sorted ascending");
1081            }
1082        }
1083        Label def = newLabel();
1084        Label end = newLabel();
1085        if (keys.length > 0) {
1086            int len = keys.length;
1087            int min = keys[0];
1088            int max = keys[len - 1];
1089            int range = max - min + 1;
1090            if (useTable) {
1091                Label[] labels = new Label[range];
1092                Arrays.fill(labels, def);
1093                for (int i = 0; i < len; ++i) {
1094                    labels[keys[i] - min] = newLabel();
1095                }
1096                mv.visitTableSwitchInsn(min, max, def, labels);
1097                for (int i = 0; i < range; ++i) {
1098                    Label label = labels[i];
1099                    if (label != def) {
1100                        mark(label);
1101                        generator.generateCase(i + min, end);
1102                    }
1103                }
1104            } else {
1105                Label[] labels = new Label[len];
1106                for (int i = 0; i < len; ++i) {
1107                    labels[i] = newLabel();
1108                }
1109                mv.visitLookupSwitchInsn(def, keys, labels);
1110                for (int i = 0; i < len; ++i) {
1111                    mark(labels[i]);
1112                    generator.generateCase(keys[i], end);
1113                }
1114            }
1115        }
1116        mark(def);
1117        generator.generateDefault();
1118        mark(end);
1119    }
1120
1121    /**
1122     * Generates the instruction to return the top stack value to the caller.
1123     */

1124    public void returnValue() {
1125        mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1126    }
1127
1128    // ------------------------------------------------------------------------
1129
// Instructions to load and store fields
1130
// ------------------------------------------------------------------------
1131

1132    /**
1133     * Generates a get field or set field instruction.
1134     *
1135     * @param opcode the instruction's opcode.
1136     * @param ownerType the class in which the field is defined.
1137     * @param name the name of the field.
1138     * @param fieldType the type of the field.
1139     */

1140    private void fieldInsn(
1141        final int opcode,
1142        final Type ownerType,
1143        final String JavaDoc name,
1144        final Type fieldType)
1145    {
1146        mv.visitFieldInsn(opcode,
1147                ownerType.getInternalName(),
1148                name,
1149                fieldType.getDescriptor());
1150    }
1151
1152    /**
1153     * Generates the instruction to push the value of a static field on the
1154     * stack.
1155     *
1156     * @param owner the class in which the field is defined.
1157     * @param name the name of the field.
1158     * @param type the type of the field.
1159     */

1160    public void getStatic(final Type owner, final String JavaDoc name, final Type type)
1161    {
1162        fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1163    }
1164
1165    /**
1166     * Generates the instruction to store the top stack value in a static field.
1167     *
1168     * @param owner the class in which the field is defined.
1169     * @param name the name of the field.
1170     * @param type the type of the field.
1171     */

1172    public void putStatic(final Type owner, final String JavaDoc name, final Type type)
1173    {
1174        fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1175    }
1176
1177    /**
1178     * Generates the instruction to push the value of a non static field on the
1179     * stack.
1180     *
1181     * @param owner the class in which the field is defined.
1182     * @param name the name of the field.
1183     * @param type the type of the field.
1184     */

1185    public void getField(final Type owner, final String JavaDoc name, final Type type) {
1186        fieldInsn(Opcodes.GETFIELD, owner, name, type);
1187    }
1188
1189    /**
1190     * Generates the instruction to store the top stack value in a non static
1191     * field.
1192     *
1193     * @param owner the class in which the field is defined.
1194     * @param name the name of the field.
1195     * @param type the type of the field.
1196     */

1197    public void putField(final Type owner, final String JavaDoc name, final Type type) {
1198        fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1199    }
1200
1201    // ------------------------------------------------------------------------
1202
// Instructions to invoke methods
1203
// ------------------------------------------------------------------------
1204

1205    /**
1206     * Generates an invoke method instruction.
1207     *
1208     * @param opcode the instruction's opcode.
1209     * @param type the class in which the method is defined.
1210     * @param method the method to be invoked.
1211     */

1212    private void invokeInsn(
1213        final int opcode,
1214        final Type type,
1215        final Method method)
1216    {
1217        String JavaDoc owner = type.getSort() == Type.ARRAY
1218                ? type.getDescriptor()
1219                : type.getInternalName();
1220        mv.visitMethodInsn(opcode,
1221                owner,
1222                method.getName(),
1223                method.getDescriptor());
1224    }
1225
1226    /**
1227     * Generates the instruction to invoke a normal method.
1228     *
1229     * @param owner the class in which the method is defined.
1230     * @param method the method to be invoked.
1231     */

1232    public void invokeVirtual(final Type owner, final Method method) {
1233        invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);
1234    }
1235
1236    /**
1237     * Generates the instruction to invoke a constructor.
1238     *
1239     * @param type the class in which the constructor is defined.
1240     * @param method the constructor to be invoked.
1241     */

1242    public void invokeConstructor(final Type type, final Method method) {
1243        invokeInsn(Opcodes.INVOKESPECIAL, type, method);
1244    }
1245
1246    /**
1247     * Generates the instruction to invoke a static method.
1248     *
1249     * @param owner the class in which the method is defined.
1250     * @param method the method to be invoked.
1251     */

1252    public void invokeStatic(final Type owner, final Method method) {
1253        invokeInsn(Opcodes.INVOKESTATIC, owner, method);
1254    }
1255
1256    /**
1257     * Generates the instruction to invoke an interface method.
1258     *
1259     * @param owner the class in which the method is defined.
1260     * @param method the method to be invoked.
1261     */

1262    public void invokeInterface(final Type owner, final Method method) {
1263        invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);
1264    }
1265
1266    // ------------------------------------------------------------------------
1267
// Instructions to create objects and arrays
1268
// ------------------------------------------------------------------------
1269

1270    /**
1271     * Generates a type dependent instruction.
1272     *
1273     * @param opcode the instruction's opcode.
1274     * @param type the instruction's operand.
1275     */

1276    private void typeInsn(final int opcode, final Type type) {
1277        String JavaDoc desc;
1278        if (type.getSort() == Type.ARRAY) {
1279            desc = type.getDescriptor();
1280        } else {
1281            desc = type.getInternalName();
1282        }
1283        mv.visitTypeInsn(opcode, desc);
1284    }
1285
1286    /**
1287     * Generates the instruction to create a new object.
1288     *
1289     * @param type the class of the object to be created.
1290     */

1291    public void newInstance(final Type type) {
1292        typeInsn(Opcodes.NEW, type);
1293    }
1294
1295    /**
1296     * Generates the instruction to create a new array.
1297     *
1298     * @param type the type of the array elements.
1299     */

1300    public void newArray(final Type type) {
1301        int typ;
1302        switch (type.getSort()) {
1303            case Type.BOOLEAN:
1304                typ = Opcodes.T_BOOLEAN;
1305                break;
1306            case Type.CHAR:
1307                typ = Opcodes.T_CHAR;
1308                break;
1309            case Type.BYTE:
1310                typ = Opcodes.T_BYTE;
1311                break;
1312            case Type.SHORT:
1313                typ = Opcodes.T_SHORT;
1314                break;
1315            case Type.INT:
1316                typ = Opcodes.T_INT;
1317                break;
1318            case Type.FLOAT:
1319                typ = Opcodes.T_FLOAT;
1320                break;
1321            case Type.LONG:
1322                typ = Opcodes.T_LONG;
1323                break;
1324            case Type.DOUBLE:
1325                typ = Opcodes.T_DOUBLE;
1326                break;
1327            default:
1328                typeInsn(Opcodes.ANEWARRAY, type);
1329                return;
1330        }
1331        mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1332    }
1333
1334    // ------------------------------------------------------------------------
1335
// Miscelaneous instructions
1336
// ------------------------------------------------------------------------
1337

1338    /**
1339     * Generates the instruction to compute the length of an array.
1340     */

1341    public void arrayLength() {
1342        mv.visitInsn(Opcodes.ARRAYLENGTH);
1343    }
1344
1345    /**
1346     * Generates the instruction to throw an exception.
1347     */

1348    public void throwException() {
1349        mv.visitInsn(Opcodes.ATHROW);
1350    }
1351
1352    /**
1353     * Generates the instructions to create and throw an exception. The
1354     * exception class must have a constructor with a single String argument.
1355     *
1356     * @param type the class of the exception to be thrown.
1357     * @param msg the detailed message of the exception.
1358     */

1359    public void throwException(final Type type, final String JavaDoc msg) {
1360        newInstance(type);
1361        dup();
1362        push(msg);
1363        invokeConstructor(type, Method.getMethod("void <init> (String)"));
1364        throwException();
1365    }
1366
1367    /**
1368     * Generates the instruction to check that the top stack value is of the
1369     * given type.
1370     *
1371     * @param type a class or interface type.
1372     */

1373    public void checkCast(final Type type) {
1374        if (!type.equals(OBJECT_TYPE)) {
1375            typeInsn(Opcodes.CHECKCAST, type);
1376        }
1377    }
1378
1379    /**
1380     * Generates the instruction to test if the top stack value is of the given
1381     * type.
1382     *
1383     * @param type a class or interface type.
1384     */

1385    public void instanceOf(final Type type) {
1386        typeInsn(Opcodes.INSTANCEOF, type);
1387    }
1388
1389    /**
1390     * Generates the instruction to get the monitor of the top stack value.
1391     */

1392    public void monitorEnter() {
1393        mv.visitInsn(Opcodes.MONITORENTER);
1394    }
1395
1396    /**
1397     * Generates the instruction to release the monitor of the top stack value.
1398     */

1399    public void monitorExit() {
1400        mv.visitInsn(Opcodes.MONITOREXIT);
1401    }
1402
1403    // ------------------------------------------------------------------------
1404
// Non instructions
1405
// ------------------------------------------------------------------------
1406

1407    /**
1408     * Marks the end of the visited method.
1409     */

1410    public void endMethod() {
1411        if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1412            mv.visitMaxs(0, 0);
1413        }
1414    }
1415
1416    /**
1417     * Marks the start of an exception handler.
1418     *
1419     * @param start beginning of the exception handler's scope (inclusive).
1420     * @param end end of the exception handler's scope (exclusive).
1421     * @param exception internal name of the type of exceptions handled by the
1422     * handler.
1423     */

1424    public void catchException(
1425        final Label start,
1426        final Label end,
1427        final Type exception)
1428    {
1429        mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName());
1430    }
1431}
1432
Popular Tags