blob: 972b2ffcb8c6c05e335ca91cc7bc5a56aef3775d [file] [log] [blame]
Clement Escoffier042a0ec2007-06-24 15:11:33 +00001/***
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 */
30package org.objectweb.asm.commons;
31
32import java.util.ArrayList;
33import java.util.Arrays;
34import java.util.List;
35
36import org.objectweb.asm.ClassVisitor;
37import org.objectweb.asm.Label;
38import org.objectweb.asm.MethodVisitor;
39import org.objectweb.asm.Opcodes;
40import 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 */
82public class GeneratorAdapter extends LocalVariablesSorter {
83
84 private final static Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
85
86 private final static Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
87
88 private final static Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
89
90 private final static Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
91
92 private final static Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
93
94 private final static Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
95
96 private final static Type LONG_TYPE = Type.getObjectType("java/lang/Long");
97
98 private final static Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
99
100 private final static Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
101
102 private final static Type OBJECT_TYPE = Type.getObjectType("java/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 localTypes = new ArrayList();
225
226 /**
227 * Creates a new {@link GeneratorAdapter}.
228 *
229 * @param mv the method visitor to which this adapter delegates calls.
230 * @param access the method's access flags (see {@link Opcodes}).
231 * @param name the method's name.
232 * @param desc the method's descriptor (see {@link Type Type}).
233 */
234 public GeneratorAdapter(
235 final MethodVisitor mv,
236 final int access,
237 final String name,
238 final String desc)
239 {
240 super(access, desc, mv);
241 this.access = access;
242 this.returnType = Type.getReturnType(desc);
243 this.argumentTypes = Type.getArgumentTypes(desc);
244 }
245
246 /**
247 * Creates a new {@link GeneratorAdapter}.
248 *
249 * @param access access flags of the adapted method.
250 * @param method the adapted method.
251 * @param mv the method visitor to which this adapter delegates calls.
252 */
253 public GeneratorAdapter(
254 final int access,
255 final Method method,
256 final MethodVisitor mv)
257 {
258 super(access, method.getDescriptor(), mv);
259 this.access = access;
260 this.returnType = method.getReturnType();
261 this.argumentTypes = method.getArgumentTypes();
262 }
263
264 /**
265 * Creates a new {@link GeneratorAdapter}.
266 *
267 * @param access access flags of the adapted method.
268 * @param method the adapted method.
269 * @param signature the signature of the adapted method (may be
270 * <tt>null</tt>).
271 * @param exceptions the exceptions thrown by the adapted method (may be
272 * <tt>null</tt>).
273 * @param cv the class visitor to which this adapter delegates calls.
274 */
275 public GeneratorAdapter(
276 final int access,
277 final Method method,
278 final String signature,
279 final Type[] exceptions,
280 final ClassVisitor cv)
281 {
282 this(access, method, cv.visitMethod(access,
283 method.getName(),
284 method.getDescriptor(),
285 signature,
286 getInternalNames(exceptions)));
287 }
288
289 /**
290 * Returns the internal names of the given types.
291 *
292 * @param types a set of types.
293 * @return the internal names of the given types.
294 */
295 private static String[] getInternalNames(final Type[] types) {
296 if (types == null) {
297 return null;
298 }
299 String[] names = new String[types.length];
300 for (int i = 0; i < names.length; ++i) {
301 names[i] = types[i].getInternalName();
302 }
303 return names;
304 }
305
306 // ------------------------------------------------------------------------
307 // Instructions to push constants on the stack
308 // ------------------------------------------------------------------------
309
310 /**
311 * Generates the instruction to push the given value on the stack.
312 *
313 * @param value the value to be pushed on the stack.
314 */
315 public void push(final boolean value) {
316 push(value ? 1 : 0);
317 }
318
319 /**
320 * Generates the instruction to push the given value on the stack.
321 *
322 * @param value the value to be pushed on the stack.
323 */
324 public void push(final int value) {
325 if (value >= -1 && value <= 5) {
326 mv.visitInsn(Opcodes.ICONST_0 + value);
327 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
328 mv.visitIntInsn(Opcodes.BIPUSH, value);
329 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
330 mv.visitIntInsn(Opcodes.SIPUSH, value);
331 } else {
332 mv.visitLdcInsn(new Integer(value));
333 }
334 }
335
336 /**
337 * Generates the instruction to push the given value on the stack.
338 *
339 * @param value the value to be pushed on the stack.
340 */
341 public void push(final long value) {
342 if (value == 0L || value == 1L) {
343 mv.visitInsn(Opcodes.LCONST_0 + (int) value);
344 } else {
345 mv.visitLdcInsn(new Long(value));
346 }
347 }
348
349 /**
350 * Generates the instruction to push the given value on the stack.
351 *
352 * @param value the value to be pushed on the stack.
353 */
354 public void push(final float value) {
355 int bits = Float.floatToIntBits(value);
356 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
357 mv.visitInsn(Opcodes.FCONST_0 + (int) value);
358 } else {
359 mv.visitLdcInsn(new Float(value));
360 }
361 }
362
363 /**
364 * Generates the instruction to push the given value on the stack.
365 *
366 * @param value the value to be pushed on the stack.
367 */
368 public void push(final double value) {
369 long bits = Double.doubleToLongBits(value);
370 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
371 mv.visitInsn(Opcodes.DCONST_0 + (int) value);
372 } else {
373 mv.visitLdcInsn(new Double(value));
374 }
375 }
376
377 /**
378 * Generates the instruction to push the given value on the stack.
379 *
380 * @param value the value to be pushed on the stack. May be <tt>null</tt>.
381 */
382 public void push(final String value) {
383 if (value == null) {
384 mv.visitInsn(Opcodes.ACONST_NULL);
385 } else {
386 mv.visitLdcInsn(value);
387 }
388 }
389
390 /**
391 * Generates the instruction to push the given value on the stack.
392 *
393 * @param value the value to be pushed on the stack.
394 */
395 public void push(final Type value) {
396 if (value == null) {
397 mv.visitInsn(Opcodes.ACONST_NULL);
398 } else {
399 mv.visitLdcInsn(value);
400 }
401 }
402
403 // ------------------------------------------------------------------------
404 // Instructions to load and store method arguments
405 // ------------------------------------------------------------------------
406
407 /**
408 * Returns the index of the given method argument in the frame's local
409 * variables array.
410 *
411 * @param arg the index of a method argument.
412 * @return the index of the given method argument in the frame's local
413 * variables array.
414 */
415 private int getArgIndex(final int arg) {
416 int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
417 for (int i = 0; i < arg; i++) {
418 index += argumentTypes[i].getSize();
419 }
420 return index;
421 }
422
423 /**
424 * Generates the instruction to push a local variable on the stack.
425 *
426 * @param type the type of the local variable to be loaded.
427 * @param index an index in the frame's local variables array.
428 */
429 private void loadInsn(final Type type, final int index) {
430 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
431 }
432
433 /**
434 * Generates the instruction to store the top stack value in a local
435 * variable.
436 *
437 * @param type the type of the local variable to be stored.
438 * @param index an index in the frame's local variables array.
439 */
440 private void storeInsn(final Type type, final int index) {
441 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
442 }
443
444 /**
445 * Generates the instruction to load 'this' on the stack.
446 */
447 public void loadThis() {
448 if ((access & Opcodes.ACC_STATIC) != 0) {
449 throw new IllegalStateException("no 'this' pointer within static method");
450 }
451 mv.visitVarInsn(Opcodes.ALOAD, 0);
452 }
453
454 /**
455 * Generates the instruction to load the given method argument on the stack.
456 *
457 * @param arg the index of a method argument.
458 */
459 public void loadArg(final int arg) {
460 loadInsn(argumentTypes[arg], getArgIndex(arg));
461 }
462
463 /**
464 * Generates the instructions to load the given method arguments on the
465 * stack.
466 *
467 * @param arg the index of the first method argument to be loaded.
468 * @param count the number of method arguments to be loaded.
469 */
470 public void loadArgs(final int arg, final int count) {
471 int index = getArgIndex(arg);
472 for (int i = 0; i < count; ++i) {
473 Type t = argumentTypes[arg + i];
474 loadInsn(t, index);
475 index += t.getSize();
476 }
477 }
478
479 /**
480 * Generates the instructions to load all the method arguments on the stack.
481 */
482 public void loadArgs() {
483 loadArgs(0, argumentTypes.length);
484 }
485
486 /**
487 * Generates the instructions to load all the method arguments on the stack,
488 * as a single object array.
489 */
490 public void loadArgArray() {
491 push(argumentTypes.length);
492 newArray(OBJECT_TYPE);
493 for (int i = 0; i < argumentTypes.length; i++) {
494 dup();
495 push(i);
496 loadArg(i);
497 box(argumentTypes[i]);
498 arrayStore(OBJECT_TYPE);
499 }
500 }
501
502 /**
503 * Generates the instruction to store the top stack value in the given
504 * method argument.
505 *
506 * @param arg the index of a method argument.
507 */
508 public void storeArg(final int arg) {
509 storeInsn(argumentTypes[arg], getArgIndex(arg));
510 }
511
512 // ------------------------------------------------------------------------
513 // Instructions to load and store local variables
514 // ------------------------------------------------------------------------
515
516 /**
517 * Returns the type of the given local variable.
518 *
519 * @param local a local variable identifier, as returned by
520 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
521 * @return the type of the given local variable.
522 */
523 public Type getLocalType(final int local) {
524 return (Type) localTypes.get(local - firstLocal);
525 }
526
527 protected void setLocalType(final int local, final Type type) {
528 int index = local - firstLocal;
529 while (localTypes.size() < index + 1) {
530 localTypes.add(null);
531 }
532 localTypes.set(index, type);
533 }
534
535 /**
536 * Generates the instruction to load the given local variable on the stack.
537 *
538 * @param local a local variable identifier, as returned by
539 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
540 */
541 public void loadLocal(final int local) {
542 loadInsn(getLocalType(local), local);
543 }
544
545 /**
546 * Generates the instruction to load the given local variable on the stack.
547 *
548 * @param local a local variable identifier, as returned by
549 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
550 * @param type the type of this local variable.
551 */
552 public void loadLocal(final int local, final Type type) {
553 setLocalType(local, type);
554 loadInsn(type, local);
555 }
556
557 /**
558 * Generates the instruction to store the top stack value in the given local
559 * variable.
560 *
561 * @param local a local variable identifier, as returned by
562 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
563 */
564 public void storeLocal(final int local) {
565 storeInsn(getLocalType(local), local);
566 }
567
568 /**
569 * Generates the instruction to store the top stack value in the given local
570 * variable.
571 *
572 * @param local a local variable identifier, as returned by
573 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
574 * @param type the type of this local variable.
575 */
576 public void storeLocal(final int local, final Type type) {
577 setLocalType(local, type);
578 storeInsn(type, local);
579 }
580
581 /**
582 * Generates the instruction to load an element from an array.
583 *
584 * @param type the type of the array element to be loaded.
585 */
586 public void arrayLoad(final Type type) {
587 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
588 }
589
590 /**
591 * Generates the instruction to store an element in an array.
592 *
593 * @param type the type of the array element to be stored.
594 */
595 public void arrayStore(final Type type) {
596 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
597 }
598
599 // ------------------------------------------------------------------------
600 // Instructions to manage the stack
601 // ------------------------------------------------------------------------
602
603 /**
604 * Generates a POP instruction.
605 */
606 public void pop() {
607 mv.visitInsn(Opcodes.POP);
608 }
609
610 /**
611 * Generates a POP2 instruction.
612 */
613 public void pop2() {
614 mv.visitInsn(Opcodes.POP2);
615 }
616
617 /**
618 * Generates a DUP instruction.
619 */
620 public void dup() {
621 mv.visitInsn(Opcodes.DUP);
622 }
623
624 /**
625 * Generates a DUP2 instruction.
626 */
627 public void dup2() {
628 mv.visitInsn(Opcodes.DUP2);
629 }
630
631 /**
632 * Generates a DUP_X1 instruction.
633 */
634 public void dupX1() {
635 mv.visitInsn(Opcodes.DUP_X1);
636 }
637
638 /**
639 * Generates a DUP_X2 instruction.
640 */
641 public void dupX2() {
642 mv.visitInsn(Opcodes.DUP_X2);
643 }
644
645 /**
646 * Generates a DUP2_X1 instruction.
647 */
648 public void dup2X1() {
649 mv.visitInsn(Opcodes.DUP2_X1);
650 }
651
652 /**
653 * Generates a DUP2_X2 instruction.
654 */
655 public void dup2X2() {
656 mv.visitInsn(Opcodes.DUP2_X2);
657 }
658
659 /**
660 * Generates a SWAP instruction.
661 */
662 public void swap() {
663 mv.visitInsn(Opcodes.SWAP);
664 }
665
666 /**
667 * Generates the instructions to swap the top two stack values.
668 *
669 * @param prev type of the top - 1 stack value.
670 * @param type type of the top stack value.
671 */
672 public void swap(final Type prev, final Type type) {
673 if (type.getSize() == 1) {
674 if (prev.getSize() == 1) {
675 swap(); // same as dupX1(), pop();
676 } else {
677 dupX2();
678 pop();
679 }
680 } else {
681 if (prev.getSize() == 1) {
682 dup2X1();
683 pop2();
684 } else {
685 dup2X2();
686 pop2();
687 }
688 }
689 }
690
691 // ------------------------------------------------------------------------
692 // Instructions to do mathematical and logical operations
693 // ------------------------------------------------------------------------
694
695 /**
696 * Generates the instruction to do the specified mathematical or logical
697 * operation.
698 *
699 * @param op a mathematical or logical operation. Must be one of ADD, SUB,
700 * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
701 * @param type the type of the operand(s) for this operation.
702 */
703 public void math(final int op, final Type type) {
704 mv.visitInsn(type.getOpcode(op));
705 }
706
707 /**
708 * Generates the instructions to compute the bitwise negation of the top
709 * stack value.
710 */
711 public void not() {
712 mv.visitInsn(Opcodes.ICONST_1);
713 mv.visitInsn(Opcodes.IXOR);
714 }
715
716 /**
717 * Generates the instruction to increment the given local variable.
718 *
719 * @param local the local variable to be incremented.
720 * @param amount the amount by which the local variable must be incremented.
721 */
722 public void iinc(final int local, final int amount) {
723 mv.visitIincInsn(local, amount);
724 }
725
726 /**
727 * Generates the instructions to cast a numerical value from one type to
728 * another.
729 *
730 * @param from the type of the top stack value
731 * @param to the type into which this value must be cast.
732 */
733 public void cast(final Type from, final Type to) {
734 if (from != to) {
735 if (from == Type.DOUBLE_TYPE) {
736 if (to == Type.FLOAT_TYPE) {
737 mv.visitInsn(Opcodes.D2F);
738 } else if (to == Type.LONG_TYPE) {
739 mv.visitInsn(Opcodes.D2L);
740 } else {
741 mv.visitInsn(Opcodes.D2I);
742 cast(Type.INT_TYPE, to);
743 }
744 } else if (from == Type.FLOAT_TYPE) {
745 if (to == Type.DOUBLE_TYPE) {
746 mv.visitInsn(Opcodes.F2D);
747 } else if (to == Type.LONG_TYPE) {
748 mv.visitInsn(Opcodes.F2L);
749 } else {
750 mv.visitInsn(Opcodes.F2I);
751 cast(Type.INT_TYPE, to);
752 }
753 } else if (from == Type.LONG_TYPE) {
754 if (to == Type.DOUBLE_TYPE) {
755 mv.visitInsn(Opcodes.L2D);
756 } else if (to == Type.FLOAT_TYPE) {
757 mv.visitInsn(Opcodes.L2F);
758 } else {
759 mv.visitInsn(Opcodes.L2I);
760 cast(Type.INT_TYPE, to);
761 }
762 } else {
763 if (to == Type.BYTE_TYPE) {
764 mv.visitInsn(Opcodes.I2B);
765 } else if (to == Type.CHAR_TYPE) {
766 mv.visitInsn(Opcodes.I2C);
767 } else if (to == Type.DOUBLE_TYPE) {
768 mv.visitInsn(Opcodes.I2D);
769 } else if (to == Type.FLOAT_TYPE) {
770 mv.visitInsn(Opcodes.I2F);
771 } else if (to == Type.LONG_TYPE) {
772 mv.visitInsn(Opcodes.I2L);
773 } else if (to == Type.SHORT_TYPE) {
774 mv.visitInsn(Opcodes.I2S);
775 }
776 }
777 }
778 }
779
780 // ------------------------------------------------------------------------
781 // Instructions to do boxing and unboxing operations
782 // ------------------------------------------------------------------------
783
784 /**
785 * Generates the instructions to box the top stack value. This value is
786 * replaced by its boxed equivalent on top of the stack.
787 *
788 * @param type the type of the top stack value.
789 */
790 public void box(final Type type) {
791 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
792 return;
793 }
794 if (type == Type.VOID_TYPE) {
795 push((String) null);
796 } else {
797 Type boxed = type;
798 switch (type.getSort()) {
799 case Type.BYTE:
800 boxed = BYTE_TYPE;
801 break;
802 case Type.BOOLEAN:
803 boxed = BOOLEAN_TYPE;
804 break;
805 case Type.SHORT:
806 boxed = SHORT_TYPE;
807 break;
808 case Type.CHAR:
809 boxed = CHARACTER_TYPE;
810 break;
811 case Type.INT:
812 boxed = INTEGER_TYPE;
813 break;
814 case Type.FLOAT:
815 boxed = FLOAT_TYPE;
816 break;
817 case Type.LONG:
818 boxed = LONG_TYPE;
819 break;
820 case Type.DOUBLE:
821 boxed = DOUBLE_TYPE;
822 break;
823 }
824 newInstance(boxed);
825 if (type.getSize() == 2) {
826 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
827 dupX2();
828 dupX2();
829 pop();
830 } else {
831 // p -> po -> opo -> oop -> o
832 dupX1();
833 swap();
834 }
835 invokeConstructor(boxed, new Method("<init>",
836 Type.VOID_TYPE,
837 new Type[] { type }));
838 }
839 }
840
841 /**
842 * Generates the instructions to unbox the top stack value. This value is
843 * replaced by its unboxed equivalent on top of the stack.
844 *
845 * @param type the type of the top stack value.
846 */
847 public void unbox(final Type type) {
848 Type t = NUMBER_TYPE;
849 Method sig = null;
850 switch (type.getSort()) {
851 case Type.VOID:
852 return;
853 case Type.CHAR:
854 t = CHARACTER_TYPE;
855 sig = CHAR_VALUE;
856 break;
857 case Type.BOOLEAN:
858 t = BOOLEAN_TYPE;
859 sig = BOOLEAN_VALUE;
860 break;
861 case Type.DOUBLE:
862 sig = DOUBLE_VALUE;
863 break;
864 case Type.FLOAT:
865 sig = FLOAT_VALUE;
866 break;
867 case Type.LONG:
868 sig = LONG_VALUE;
869 break;
870 case Type.INT:
871 case Type.SHORT:
872 case Type.BYTE:
873 sig = INT_VALUE;
874 }
875 if (sig == null) {
876 checkCast(type);
877 } else {
878 checkCast(t);
879 invokeVirtual(t, sig);
880 }
881 }
882
883 // ------------------------------------------------------------------------
884 // Instructions to jump to other instructions
885 // ------------------------------------------------------------------------
886
887 /**
888 * Creates a new {@link Label}.
889 *
890 * @return a new {@link Label}.
891 */
892 public Label newLabel() {
893 return new Label();
894 }
895
896 /**
897 * Marks the current code position with the given label.
898 *
899 * @param label a label.
900 */
901 public void mark(final Label label) {
902 mv.visitLabel(label);
903 }
904
905 /**
906 * Marks the current code position with a new label.
907 *
908 * @return the label that was created to mark the current code position.
909 */
910 public Label mark() {
911 Label label = new Label();
912 mv.visitLabel(label);
913 return label;
914 }
915
916 /**
917 * Generates the instructions to jump to a label based on the comparison of
918 * the top two stack values.
919 *
920 * @param type the type of the top two stack values.
921 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
922 * LE.
923 * @param label where to jump if the comparison result is <tt>true</tt>.
924 */
925 public void ifCmp(final Type type, final int mode, final Label label) {
926 int intOp = -1;
927 switch (type.getSort()) {
928 case Type.LONG:
929 mv.visitInsn(Opcodes.LCMP);
930 break;
931 case Type.DOUBLE:
932 mv.visitInsn(Opcodes.DCMPG);
933 break;
934 case Type.FLOAT:
935 mv.visitInsn(Opcodes.FCMPG);
936 break;
937 case Type.ARRAY:
938 case Type.OBJECT:
939 switch (mode) {
940 case EQ:
941 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
942 return;
943 case NE:
944 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
945 return;
946 }
947 throw new IllegalArgumentException("Bad comparison for type "
948 + type);
949 default:
950 switch (mode) {
951 case EQ:
952 intOp = Opcodes.IF_ICMPEQ;
953 break;
954 case NE:
955 intOp = Opcodes.IF_ICMPNE;
956 break;
957 case GE:
958 intOp = Opcodes.IF_ICMPGE;
959 break;
960 case LT:
961 intOp = Opcodes.IF_ICMPLT;
962 break;
963 case LE:
964 intOp = Opcodes.IF_ICMPLE;
965 break;
966 case GT:
967 intOp = Opcodes.IF_ICMPGT;
968 break;
969 }
970 mv.visitJumpInsn(intOp, label);
971 return;
972 }
973 int jumpMode = mode;
974 switch (mode) {
975 case GE:
976 jumpMode = LT;
977 break;
978 case LE:
979 jumpMode = GT;
980 break;
981 }
982 mv.visitJumpInsn(jumpMode, label);
983 }
984
985 /**
986 * Generates the instructions to jump to a label based on the comparison of
987 * the top two integer stack values.
988 *
989 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
990 * LE.
991 * @param label where to jump if the comparison result is <tt>true</tt>.
992 */
993 public void ifICmp(final int mode, final Label label) {
994 ifCmp(Type.INT_TYPE, mode, label);
995 }
996
997 /**
998 * Generates the instructions to jump to a label based on the comparison of
999 * the top integer stack value with zero.
1000 *
1001 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
1002 * LE.
1003 * @param label where to jump if the comparison result is <tt>true</tt>.
1004 */
1005 public void ifZCmp(final int mode, final Label label) {
1006 mv.visitJumpInsn(mode, label);
1007 }
1008
1009 /**
1010 * Generates the instruction to jump to the given label if the top stack
1011 * value is null.
1012 *
1013 * @param label where to jump if the condition is <tt>true</tt>.
1014 */
1015 public void ifNull(final Label label) {
1016 mv.visitJumpInsn(Opcodes.IFNULL, label);
1017 }
1018
1019 /**
1020 * Generates the instruction to jump to the given label if the top stack
1021 * value is not null.
1022 *
1023 * @param label where to jump if the condition is <tt>true</tt>.
1024 */
1025 public void ifNonNull(final Label label) {
1026 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1027 }
1028
1029 /**
1030 * Generates the instruction to jump to the given label.
1031 *
1032 * @param label where to jump if the condition is <tt>true</tt>.
1033 */
1034 public void goTo(final Label label) {
1035 mv.visitJumpInsn(Opcodes.GOTO, label);
1036 }
1037
1038 /**
1039 * Generates a RET instruction.
1040 *
1041 * @param local a local variable identifier, as returned by
1042 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
1043 */
1044 public void ret(final int local) {
1045 mv.visitVarInsn(Opcodes.RET, local);
1046 }
1047
1048 /**
1049 * Generates the instructions for a switch statement.
1050 *
1051 * @param keys the switch case keys.
1052 * @param generator a generator to generate the code for the switch cases.
1053 */
1054 public void tableSwitch(
1055 final int[] keys,
1056 final TableSwitchGenerator generator)
1057 {
1058 float density;
1059 if (keys.length == 0) {
1060 density = 0;
1061 } else {
1062 density = (float) keys.length
1063 / (keys[keys.length - 1] - keys[0] + 1);
1064 }
1065 tableSwitch(keys, generator, density >= 0.5f);
1066 }
1067
1068 /**
1069 * Generates the instructions for a switch statement.
1070 *
1071 * @param keys the switch case keys.
1072 * @param generator a generator to generate the code for the switch cases.
1073 * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or
1074 * <tt>false</tt> to use a LOOKUPSWITCH instruction.
1075 */
1076 public void tableSwitch(
1077 final int[] keys,
1078 final TableSwitchGenerator generator,
1079 final boolean useTable)
1080 {
1081 for (int i = 1; i < keys.length; ++i) {
1082 if (keys[i] < keys[i - 1]) {
1083 throw new IllegalArgumentException("keys must be sorted ascending");
1084 }
1085 }
1086 Label def = newLabel();
1087 Label end = newLabel();
1088 if (keys.length > 0) {
1089 int len = keys.length;
1090 int min = keys[0];
1091 int max = keys[len - 1];
1092 int range = max - min + 1;
1093 if (useTable) {
1094 Label[] labels = new Label[range];
1095 Arrays.fill(labels, def);
1096 for (int i = 0; i < len; ++i) {
1097 labels[keys[i] - min] = newLabel();
1098 }
1099 mv.visitTableSwitchInsn(min, max, def, labels);
1100 for (int i = 0; i < range; ++i) {
1101 Label label = labels[i];
1102 if (label != def) {
1103 mark(label);
1104 generator.generateCase(i + min, end);
1105 }
1106 }
1107 } else {
1108 Label[] labels = new Label[len];
1109 for (int i = 0; i < len; ++i) {
1110 labels[i] = newLabel();
1111 }
1112 mv.visitLookupSwitchInsn(def, keys, labels);
1113 for (int i = 0; i < len; ++i) {
1114 mark(labels[i]);
1115 generator.generateCase(keys[i], end);
1116 }
1117 }
1118 }
1119 mark(def);
1120 generator.generateDefault();
1121 mark(end);
1122 }
1123
1124 /**
1125 * Generates the instruction to return the top stack value to the caller.
1126 */
1127 public void returnValue() {
1128 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1129 }
1130
1131 // ------------------------------------------------------------------------
1132 // Instructions to load and store fields
1133 // ------------------------------------------------------------------------
1134
1135 /**
1136 * Generates a get field or set field instruction.
1137 *
1138 * @param opcode the instruction's opcode.
1139 * @param ownerType the class in which the field is defined.
1140 * @param name the name of the field.
1141 * @param fieldType the type of the field.
1142 */
1143 private void fieldInsn(
1144 final int opcode,
1145 final Type ownerType,
1146 final String name,
1147 final Type fieldType)
1148 {
1149 mv.visitFieldInsn(opcode,
1150 ownerType.getInternalName(),
1151 name,
1152 fieldType.getDescriptor());
1153 }
1154
1155 /**
1156 * Generates the instruction to push the value of a static field on the
1157 * stack.
1158 *
1159 * @param owner the class in which the field is defined.
1160 * @param name the name of the field.
1161 * @param type the type of the field.
1162 */
1163 public void getStatic(final Type owner, final String name, final Type type)
1164 {
1165 fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1166 }
1167
1168 /**
1169 * Generates the instruction to store the top stack value in a static field.
1170 *
1171 * @param owner the class in which the field is defined.
1172 * @param name the name of the field.
1173 * @param type the type of the field.
1174 */
1175 public void putStatic(final Type owner, final String name, final Type type)
1176 {
1177 fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1178 }
1179
1180 /**
1181 * Generates the instruction to push the value of a non static field on the
1182 * stack.
1183 *
1184 * @param owner the class in which the field is defined.
1185 * @param name the name of the field.
1186 * @param type the type of the field.
1187 */
1188 public void getField(final Type owner, final String name, final Type type) {
1189 fieldInsn(Opcodes.GETFIELD, owner, name, type);
1190 }
1191
1192 /**
1193 * Generates the instruction to store the top stack value in a non static
1194 * field.
1195 *
1196 * @param owner the class in which the field is defined.
1197 * @param name the name of the field.
1198 * @param type the type of the field.
1199 */
1200 public void putField(final Type owner, final String name, final Type type) {
1201 fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1202 }
1203
1204 // ------------------------------------------------------------------------
1205 // Instructions to invoke methods
1206 // ------------------------------------------------------------------------
1207
1208 /**
1209 * Generates an invoke method instruction.
1210 *
1211 * @param opcode the instruction's opcode.
1212 * @param type the class in which the method is defined.
1213 * @param method the method to be invoked.
1214 */
1215 private void invokeInsn(
1216 final int opcode,
1217 final Type type,
1218 final Method method)
1219 {
1220 String owner = type.getSort() == Type.ARRAY
1221 ? type.getDescriptor()
1222 : type.getInternalName();
1223 mv.visitMethodInsn(opcode,
1224 owner,
1225 method.getName(),
1226 method.getDescriptor());
1227 }
1228
1229 /**
1230 * Generates the instruction to invoke a normal method.
1231 *
1232 * @param owner the class in which the method is defined.
1233 * @param method the method to be invoked.
1234 */
1235 public void invokeVirtual(final Type owner, final Method method) {
1236 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);
1237 }
1238
1239 /**
1240 * Generates the instruction to invoke a constructor.
1241 *
1242 * @param type the class in which the constructor is defined.
1243 * @param method the constructor to be invoked.
1244 */
1245 public void invokeConstructor(final Type type, final Method method) {
1246 invokeInsn(Opcodes.INVOKESPECIAL, type, method);
1247 }
1248
1249 /**
1250 * Generates the instruction to invoke a static method.
1251 *
1252 * @param owner the class in which the method is defined.
1253 * @param method the method to be invoked.
1254 */
1255 public void invokeStatic(final Type owner, final Method method) {
1256 invokeInsn(Opcodes.INVOKESTATIC, owner, method);
1257 }
1258
1259 /**
1260 * Generates the instruction to invoke an interface method.
1261 *
1262 * @param owner the class in which the method is defined.
1263 * @param method the method to be invoked.
1264 */
1265 public void invokeInterface(final Type owner, final Method method) {
1266 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);
1267 }
1268
1269 // ------------------------------------------------------------------------
1270 // Instructions to create objects and arrays
1271 // ------------------------------------------------------------------------
1272
1273 /**
1274 * Generates a type dependent instruction.
1275 *
1276 * @param opcode the instruction's opcode.
1277 * @param type the instruction's operand.
1278 */
1279 private void typeInsn(final int opcode, final Type type) {
1280 String desc;
1281 if (type.getSort() == Type.ARRAY) {
1282 desc = type.getDescriptor();
1283 } else {
1284 desc = type.getInternalName();
1285 }
1286 mv.visitTypeInsn(opcode, desc);
1287 }
1288
1289 /**
1290 * Generates the instruction to create a new object.
1291 *
1292 * @param type the class of the object to be created.
1293 */
1294 public void newInstance(final Type type) {
1295 typeInsn(Opcodes.NEW, type);
1296 }
1297
1298 /**
1299 * Generates the instruction to create a new array.
1300 *
1301 * @param type the type of the array elements.
1302 */
1303 public void newArray(final Type type) {
1304 int typ;
1305 switch (type.getSort()) {
1306 case Type.BOOLEAN:
1307 typ = Opcodes.T_BOOLEAN;
1308 break;
1309 case Type.CHAR:
1310 typ = Opcodes.T_CHAR;
1311 break;
1312 case Type.BYTE:
1313 typ = Opcodes.T_BYTE;
1314 break;
1315 case Type.SHORT:
1316 typ = Opcodes.T_SHORT;
1317 break;
1318 case Type.INT:
1319 typ = Opcodes.T_INT;
1320 break;
1321 case Type.FLOAT:
1322 typ = Opcodes.T_FLOAT;
1323 break;
1324 case Type.LONG:
1325 typ = Opcodes.T_LONG;
1326 break;
1327 case Type.DOUBLE:
1328 typ = Opcodes.T_DOUBLE;
1329 break;
1330 default:
1331 typeInsn(Opcodes.ANEWARRAY, type);
1332 return;
1333 }
1334 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1335 }
1336
1337 // ------------------------------------------------------------------------
1338 // Miscelaneous instructions
1339 // ------------------------------------------------------------------------
1340
1341 /**
1342 * Generates the instruction to compute the length of an array.
1343 */
1344 public void arrayLength() {
1345 mv.visitInsn(Opcodes.ARRAYLENGTH);
1346 }
1347
1348 /**
1349 * Generates the instruction to throw an exception.
1350 */
1351 public void throwException() {
1352 mv.visitInsn(Opcodes.ATHROW);
1353 }
1354
1355 /**
1356 * Generates the instructions to create and throw an exception. The
1357 * exception class must have a constructor with a single String argument.
1358 *
1359 * @param type the class of the exception to be thrown.
1360 * @param msg the detailed message of the exception.
1361 */
1362 public void throwException(final Type type, final String msg) {
1363 newInstance(type);
1364 dup();
1365 push(msg);
1366 invokeConstructor(type, Method.getMethod("void <init> (String)"));
1367 throwException();
1368 }
1369
1370 /**
1371 * Generates the instruction to check that the top stack value is of the
1372 * given type.
1373 *
1374 * @param type a class or interface type.
1375 */
1376 public void checkCast(final Type type) {
1377 if (!type.equals(OBJECT_TYPE)) {
1378 typeInsn(Opcodes.CHECKCAST, type);
1379 }
1380 }
1381
1382 /**
1383 * Generates the instruction to test if the top stack value is of the given
1384 * type.
1385 *
1386 * @param type a class or interface type.
1387 */
1388 public void instanceOf(final Type type) {
1389 typeInsn(Opcodes.INSTANCEOF, type);
1390 }
1391
1392 /**
1393 * Generates the instruction to get the monitor of the top stack value.
1394 */
1395 public void monitorEnter() {
1396 mv.visitInsn(Opcodes.MONITORENTER);
1397 }
1398
1399 /**
1400 * Generates the instruction to release the monitor of the top stack value.
1401 */
1402 public void monitorExit() {
1403 mv.visitInsn(Opcodes.MONITOREXIT);
1404 }
1405
1406 // ------------------------------------------------------------------------
1407 // Non instructions
1408 // ------------------------------------------------------------------------
1409
1410 /**
1411 * Marks the end of the visited method.
1412 */
1413 public void endMethod() {
1414 if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1415 mv.visitMaxs(0, 0);
1416 }
1417 mv.visitEnd();
1418 }
1419
1420 /**
1421 * Marks the start of an exception handler.
1422 *
1423 * @param start beginning of the exception handler's scope (inclusive).
1424 * @param end end of the exception handler's scope (exclusive).
1425 * @param exception internal name of the type of exceptions handled by the
1426 * handler.
1427 */
1428 public void catchException(
1429 final Label start,
1430 final Label end,
1431 final Type exception)
1432 {
1433 mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName());
1434 }
1435}