KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > core > CodeEmitter


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.sf.cglib.core;
17
18 import java.io.*;
19 import java.util.*;
20 import org.objectweb.asm.*;
21
22 /**
23  * @author Juozas Baliuka, Chris Nokleberg
24  */

25 public class CodeEmitter extends LocalVariablesSorter {
26     private static final Signature BOOLEAN_VALUE =
27       TypeUtils.parseSignature("boolean booleanValue()");
28     private static final Signature CHAR_VALUE =
29       TypeUtils.parseSignature("char charValue()");
30     private static final Signature LONG_VALUE =
31       TypeUtils.parseSignature("long longValue()");
32     private static final Signature DOUBLE_VALUE =
33       TypeUtils.parseSignature("double doubleValue()");
34     private static final Signature FLOAT_VALUE =
35       TypeUtils.parseSignature("float floatValue()");
36     private static final Signature INT_VALUE =
37       TypeUtils.parseSignature("int intValue()");
38     private static final Signature CSTRUCT_NULL =
39       TypeUtils.parseConstructor("");
40     private static final Signature CSTRUCT_STRING =
41       TypeUtils.parseConstructor("String");
42
43     public static final int ADD = Constants.IADD;
44     public static final int MUL = Constants.IMUL;
45     public static final int XOR = Constants.IXOR;
46     public static final int USHR = Constants.IUSHR;
47     public static final int SUB = Constants.ISUB;
48     public static final int DIV = Constants.IDIV;
49     public static final int NEG = Constants.INEG;
50     public static final int REM = Constants.IREM;
51     public static final int AND = Constants.IAND;
52     public static final int OR = Constants.IOR;
53
54     public static final int GT = Constants.IFGT;
55     public static final int LT = Constants.IFLT;
56     public static final int GE = Constants.IFGE;
57     public static final int LE = Constants.IFLE;
58     public static final int NE = Constants.IFNE;
59     public static final int EQ = Constants.IFEQ;
60
61     private ClassEmitter ce;
62     private State state;
63
64     private static class State
65     extends MethodInfo
66     {
67         ClassInfo classInfo;
68         int access;
69         Signature sig;
70         Type[] argumentTypes;
71         int localOffset;
72         Type[] exceptionTypes;
73
74         State(ClassInfo classInfo, int access, Signature sig, Type[] exceptionTypes) {
75             this.classInfo = classInfo;
76             this.access = access;
77             this.sig = sig;
78             this.exceptionTypes = exceptionTypes;
79             localOffset = TypeUtils.isStatic(access) ? 0 : 1;
80             argumentTypes = sig.getArgumentTypes();
81         }
82
83         public ClassInfo getClassInfo() {
84             return classInfo;
85         }
86
87         public int getModifiers() {
88             return access;
89         }
90
91         public Signature getSignature() {
92             return sig;
93         }
94
95         public Type[] getExceptionTypes() {
96             return exceptionTypes;
97         }
98
99         public Attribute getAttribute() {
100             // TODO
101
return null;
102         }
103     }
104
105     CodeEmitter(ClassEmitter ce, MethodVisitor mv, int access, Signature sig, Type[] exceptionTypes) {
106         super(access, sig.getDescriptor(), mv);
107         this.ce = ce;
108         state = new State(ce.getClassInfo(), access, sig, exceptionTypes);
109     }
110
111     public CodeEmitter(CodeEmitter wrap) {
112         super(wrap);
113         this.ce = wrap.ce;
114         this.state = wrap.state;
115     }
116
117     public boolean isStaticHook() {
118         return false;
119     }
120
121     public Signature getSignature() {
122         return state.sig;
123     }
124
125     public Type getReturnType() {
126         return state.sig.getReturnType();
127     }
128
129     public MethodInfo getMethodInfo() {
130         return state;
131     }
132
133     public ClassEmitter getClassEmitter() {
134         return ce;
135     }
136
137     public void end_method() {
138         visitMaxs(0, 0);
139     }
140
141     public Block begin_block() {
142         return new Block(this);
143     }
144
145     public void catch_exception(Block block, Type exception) {
146         if (block.getEnd() == null) {
147             throw new IllegalStateException JavaDoc("end of block is unset");
148         }
149         mv.visitTryCatchBlock(block.getStart(),
150                               block.getEnd(),
151                               mark(),
152                               exception.getInternalName());
153     }
154
155     public void goTo(Label label) { mv.visitJumpInsn(Constants.GOTO, label); }
156     public void ifnull(Label label) { mv.visitJumpInsn(Constants.IFNULL, label); }
157     public void ifnonnull(Label label) { mv.visitJumpInsn(Constants.IFNONNULL, label); }
158
159     public void if_jump(int mode, Label label) {
160         mv.visitJumpInsn(mode, label);
161     }
162
163     public void if_icmp(int mode, Label label) {
164         if_cmp(Type.INT_TYPE, mode, label);
165     }
166
167     public void if_cmp(Type type, int mode, Label label) {
168         int intOp = -1;
169         int jumpmode = mode;
170         switch (mode) {
171         case GE: jumpmode = LT; break;
172         case LE: jumpmode = GT; break;
173         }
174         switch (type.getSort()) {
175         case Type.LONG:
176             mv.visitInsn(Constants.LCMP);
177             break;
178         case Type.DOUBLE:
179             mv.visitInsn(Constants.DCMPG);
180             break;
181         case Type.FLOAT:
182             mv.visitInsn(Constants.FCMPG);
183             break;
184         case Type.ARRAY:
185         case Type.OBJECT:
186             switch (mode) {
187             case EQ:
188                 mv.visitJumpInsn(Constants.IF_ACMPEQ, label);
189                 return;
190             case NE:
191                 mv.visitJumpInsn(Constants.IF_ACMPNE, label);
192                 return;
193             }
194             throw new IllegalArgumentException JavaDoc("Bad comparison for type " + type);
195         default:
196             switch (mode) {
197             case EQ: intOp = Constants.IF_ICMPEQ; break;
198             case NE: intOp = Constants.IF_ICMPNE; break;
199             case GE: swap(); /* fall through */
200             case LT: intOp = Constants.IF_ICMPLT; break;
201             case LE: swap(); /* fall through */
202             case GT: intOp = Constants.IF_ICMPGT; break;
203             }
204             mv.visitJumpInsn(intOp, label);
205             return;
206         }
207         if_jump(jumpmode, label);
208     }
209
210     public void pop() { mv.visitInsn(Constants.POP); }
211     public void pop2() { mv.visitInsn(Constants.POP2); }
212     public void dup() { mv.visitInsn(Constants.DUP); }
213     public void dup2() { mv.visitInsn(Constants.DUP2); }
214     public void dup_x1() { mv.visitInsn(Constants.DUP_X1); }
215     public void dup_x2() { mv.visitInsn(Constants.DUP_X2); }
216     public void dup2_x1() { mv.visitInsn(Constants.DUP2_X1); }
217     public void dup2_x2() { mv.visitInsn(Constants.DUP2_X2); }
218     public void swap() { mv.visitInsn(Constants.SWAP); }
219     public void aconst_null() { mv.visitInsn(Constants.ACONST_NULL); }
220
221     public void swap(Type prev, Type type) {
222         if (type.getSize() == 1) {
223             if (prev.getSize() == 1) {
224                 swap(); // same as dup_x1(), pop();
225
} else {
226                 dup_x2();
227                 pop();
228             }
229         } else {
230             if (prev.getSize() == 1) {
231                 dup2_x1();
232                 pop2();
233             } else {
234                 dup2_x2();
235                 pop2();
236             }
237         }
238     }
239
240     public void monitorenter() { mv.visitInsn(Constants.MONITORENTER); }
241     public void monitorexit() { mv.visitInsn(Constants.MONITOREXIT); }
242
243     public void math(int op, Type type) { mv.visitInsn(type.getOpcode(op)); }
244
245     public void array_load(Type type) { mv.visitInsn(type.getOpcode(Constants.IALOAD)); }
246     public void array_store(Type type) { mv.visitInsn(type.getOpcode(Constants.IASTORE)); }
247
248     /**
249      * Casts from one primitive numeric type to another
250      */

251     public void cast_numeric(Type from, Type to) {
252         if (from != to) {
253             if (from == Type.DOUBLE_TYPE) {
254                 if (to == Type.FLOAT_TYPE) {
255                     mv.visitInsn(Constants.D2F);
256                 } else if (to == Type.LONG_TYPE) {
257                     mv.visitInsn(Constants.D2L);
258                 } else {
259                     mv.visitInsn(Constants.D2I);
260                     cast_numeric(Type.INT_TYPE, to);
261                 }
262             } else if (from == Type.FLOAT_TYPE) {
263                 if (to == Type.DOUBLE_TYPE) {
264                     mv.visitInsn(Constants.F2D);
265                 } else if (to == Type.LONG_TYPE) {
266                     mv.visitInsn(Constants.F2L);
267                 } else {
268                     mv.visitInsn(Constants.F2I);
269                     cast_numeric(Type.INT_TYPE, to);
270                 }
271             } else if (from == Type.LONG_TYPE) {
272                 if (to == Type.DOUBLE_TYPE) {
273                     mv.visitInsn(Constants.L2D);
274                 } else if (to == Type.FLOAT_TYPE) {
275                     mv.visitInsn(Constants.L2F);
276                 } else {
277                     mv.visitInsn(Constants.L2I);
278                     cast_numeric(Type.INT_TYPE, to);
279                 }
280             } else {
281                 if (to == Type.BYTE_TYPE) {
282                     mv.visitInsn(Constants.I2B);
283                 } else if (to == Type.CHAR_TYPE) {
284                     mv.visitInsn(Constants.I2C);
285                 } else if (to == Type.DOUBLE_TYPE) {
286                     mv.visitInsn(Constants.I2D);
287                 } else if (to == Type.FLOAT_TYPE) {
288                     mv.visitInsn(Constants.I2F);
289                 } else if (to == Type.LONG_TYPE) {
290                     mv.visitInsn(Constants.I2L);
291                 } else if (to == Type.SHORT_TYPE) {
292                     mv.visitInsn(Constants.I2S);
293                 }
294             }
295         }
296     }
297
298     public void push(int i) {
299         if (i < -1) {
300             mv.visitLdcInsn(new Integer JavaDoc(i));
301         } else if (i <= 5) {
302             mv.visitInsn(TypeUtils.ICONST(i));
303         } else if (i <= Byte.MAX_VALUE) {
304             mv.visitIntInsn(Constants.BIPUSH, i);
305         } else if (i <= Short.MAX_VALUE) {
306             mv.visitIntInsn(Constants.SIPUSH, i);
307         } else {
308             mv.visitLdcInsn(new Integer JavaDoc(i));
309         }
310     }
311     
312     public void push(long value) {
313         if (value == 0L || value == 1L) {
314             mv.visitInsn(TypeUtils.LCONST(value));
315         } else {
316             mv.visitLdcInsn(new Long JavaDoc(value));
317         }
318     }
319     
320     public void push(float value) {
321         if (value == 0f || value == 1f || value == 2f) {
322             mv.visitInsn(TypeUtils.FCONST(value));
323         } else {
324             mv.visitLdcInsn(new Float JavaDoc(value));
325         }
326     }
327     public void push(double value) {
328         if (value == 0d || value == 1d) {
329             mv.visitInsn(TypeUtils.DCONST(value));
330         } else {
331             mv.visitLdcInsn(new Double JavaDoc(value));
332         }
333     }
334     
335     public void push(String JavaDoc value) {
336         mv.visitLdcInsn(value);
337     }
338
339     public void newarray() {
340         newarray(Constants.TYPE_OBJECT);
341     }
342
343     public void newarray(Type type) {
344         if (TypeUtils.isPrimitive(type)) {
345             mv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type));
346         } else {
347             emit_type(Constants.ANEWARRAY, type);
348         }
349     }
350     
351     public void arraylength() {
352         mv.visitInsn(Constants.ARRAYLENGTH);
353     }
354     
355     public void load_this() {
356         if (TypeUtils.isStatic(state.access)) {
357             throw new IllegalStateException JavaDoc("no 'this' pointer within static method");
358         }
359         mv.visitVarInsn(Constants.ALOAD, 0);
360     }
361     
362     /**
363      * Pushes all of the arguments of the current method onto the stack.
364      */

365     public void load_args() {
366         load_args(0, state.argumentTypes.length);
367     }
368
369     /**
370      * Pushes the specified argument of the current method onto the stack.
371      * @param index the zero-based index into the argument list
372      */

373     public void load_arg(int index) {
374         load_local(state.argumentTypes[index],
375                    state.localOffset + skipArgs(index));
376     }
377
378     // zero-based (see load_this)
379
public void load_args(int fromArg, int count) {
380         int pos = state.localOffset + skipArgs(fromArg);
381         for (int i = 0; i < count; i++) {
382             Type t = state.argumentTypes[fromArg + i];
383             load_local(t, pos);
384             pos += t.getSize();
385         }
386     }
387     
388     private int skipArgs(int numArgs) {
389         int amount = 0;
390         for (int i = 0; i < numArgs; i++) {
391             amount += state.argumentTypes[i].getSize();
392         }
393         return amount;
394     }
395
396     private void load_local(Type t, int pos) {
397         // TODO: make t == null ok?
398
mv.visitVarInsn(t.getOpcode(Constants.ILOAD), pos);
399     }
400
401     private void store_local(Type t, int pos) {
402         // TODO: make t == null ok?
403
mv.visitVarInsn(t.getOpcode(Constants.ISTORE), pos);
404     }
405     
406     public void iinc(Local local, int amount) {
407         mv.visitIincInsn(local.getIndex(), amount);
408     }
409     
410     public void store_local(Local local) {
411         store_local(local.getType(), local.getIndex());
412     }
413     
414     public void load_local(Local local) {
415         load_local(local.getType(), local.getIndex());
416     }
417
418     public void return_value() {
419         mv.visitInsn(state.sig.getReturnType().getOpcode(Constants.IRETURN));
420     }
421
422     public void getfield(String JavaDoc name) {
423         ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
424         int opcode = TypeUtils.isStatic(info.access) ? Constants.GETSTATIC : Constants.GETFIELD;
425         emit_field(opcode, ce.getClassType(), name, info.type);
426     }
427     
428     public void putfield(String JavaDoc name) {
429         ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
430         int opcode = TypeUtils.isStatic(info.access) ? Constants.PUTSTATIC : Constants.PUTFIELD;
431         emit_field(opcode, ce.getClassType(), name, info.type);
432     }
433
434     public void super_getfield(String JavaDoc name, Type type) {
435         emit_field(Constants.GETFIELD, ce.getSuperType(), name, type);
436     }
437     
438     public void super_putfield(String JavaDoc name, Type type) {
439         emit_field(Constants.PUTFIELD, ce.getSuperType(), name, type);
440     }
441
442     public void super_getstatic(String JavaDoc name, Type type) {
443         emit_field(Constants.GETSTATIC, ce.getSuperType(), name, type);
444     }
445     
446     public void super_putstatic(String JavaDoc name, Type type) {
447         emit_field(Constants.PUTSTATIC, ce.getSuperType(), name, type);
448     }
449
450     public void getfield(Type owner, String JavaDoc name, Type type) {
451         emit_field(Constants.GETFIELD, owner, name, type);
452     }
453     
454     public void putfield(Type owner, String JavaDoc name, Type type) {
455         emit_field(Constants.PUTFIELD, owner, name, type);
456     }
457
458     public void getstatic(Type owner, String JavaDoc name, Type type) {
459         emit_field(Constants.GETSTATIC, owner, name, type);
460     }
461     
462     public void putstatic(Type owner, String JavaDoc name, Type type) {
463         emit_field(Constants.PUTSTATIC, owner, name, type);
464     }
465
466     // package-protected for EmitUtils, try to fix
467
void emit_field(int opcode, Type ctype, String JavaDoc name, Type ftype) {
468         mv.visitFieldInsn(opcode,
469                           ctype.getInternalName(),
470                           name,
471                           ftype.getDescriptor());
472     }
473
474     public void super_invoke() {
475         super_invoke(state.sig);
476     }
477
478     public void super_invoke(Signature sig) {
479         emit_invoke(Constants.INVOKESPECIAL, ce.getSuperType(), sig);
480     }
481
482     public void invoke_constructor(Type type) {
483         invoke_constructor(type, CSTRUCT_NULL);
484     }
485
486     public void super_invoke_constructor() {
487         invoke_constructor(ce.getSuperType());
488     }
489     
490     public void invoke_constructor_this() {
491         invoke_constructor(ce.getClassType());
492     }
493
494     private void emit_invoke(int opcode, Type type, Signature sig) {
495         if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) &&
496             ((opcode == Constants.INVOKEVIRTUAL) ||
497              (opcode == Constants.INVOKESTATIC))) {
498             // TODO: error
499
}
500         mv.visitMethodInsn(opcode,
501                            type.getInternalName(),
502                            sig.getName(),
503                            sig.getDescriptor());
504     }
505     
506     public void invoke_interface(Type owner, Signature sig) {
507         emit_invoke(Constants.INVOKEINTERFACE, owner, sig);
508     }
509
510     public void invoke_virtual(Type owner, Signature sig) {
511         emit_invoke(Constants.INVOKEVIRTUAL, owner, sig);
512     }
513
514     public void invoke_static(Type owner, Signature sig) {
515         emit_invoke(Constants.INVOKESTATIC, owner, sig);
516     }
517
518     public void invoke_virtual_this(Signature sig) {
519         invoke_virtual(ce.getClassType(), sig);
520     }
521
522     public void invoke_static_this(Signature sig) {
523         invoke_static(ce.getClassType(), sig);
524     }
525
526     public void invoke_constructor(Type type, Signature sig) {
527         emit_invoke(Constants.INVOKESPECIAL, type, sig);
528     }
529
530     public void invoke_constructor_this(Signature sig) {
531         invoke_constructor(ce.getClassType(), sig);
532     }
533
534     public void super_invoke_constructor(Signature sig) {
535         invoke_constructor(ce.getSuperType(), sig);
536     }
537     
538     public void new_instance_this() {
539         new_instance(ce.getClassType());
540     }
541
542     public void new_instance(Type type) {
543         emit_type(Constants.NEW, type);
544     }
545
546     private void emit_type(int opcode, Type type) {
547         String JavaDoc desc;
548         if (TypeUtils.isArray(type)) {
549             desc = type.getDescriptor();
550         } else {
551             desc = type.getInternalName();
552         }
553         mv.visitTypeInsn(opcode, desc);
554     }
555
556     public void aaload(int index) {
557         push(index);
558         aaload();
559     }
560
561     public void aaload() { mv.visitInsn(Constants.AALOAD); }
562     public void aastore() { mv.visitInsn(Constants.AASTORE); }
563     public void athrow() { mv.visitInsn(Constants.ATHROW); }
564
565     public Label make_label() {
566         return new Label();
567     }
568     
569     public Local make_local() {
570         return make_local(Constants.TYPE_OBJECT);
571     }
572     
573     public Local make_local(Type type) {
574         return new Local(newLocal(type.getSize()), type);
575     }
576
577     public void checkcast_this() {
578         checkcast(ce.getClassType());
579     }
580     
581     public void checkcast(Type type) {
582         if (!type.equals(Constants.TYPE_OBJECT)) {
583             emit_type(Constants.CHECKCAST, type);
584         }
585     }
586
587     public void instance_of(Type type) {
588         emit_type(Constants.INSTANCEOF, type);
589     }
590     
591     public void instance_of_this() {
592         instance_of(ce.getClassType());
593     }
594
595     public void process_switch(int[] keys, ProcessSwitchCallback callback) {
596         float density;
597         if (keys.length == 0) {
598             density = 0;
599         } else {
600             density = (float)keys.length / (keys[keys.length - 1] - keys[0] + 1);
601         }
602         process_switch(keys, callback, density >= 0.5f);
603     }
604
605     public void process_switch(int[] keys, ProcessSwitchCallback callback, boolean useTable) {
606         if (!isSorted(keys))
607             throw new IllegalArgumentException JavaDoc("keys to switch must be sorted ascending");
608         Label def = make_label();
609         Label end = make_label();
610
611         try {
612             if (keys.length > 0) {
613                 int len = keys.length;
614                 int min = keys[0];
615                 int max = keys[len - 1];
616                 int range = max - min + 1;
617
618                 if (useTable) {
619                     Label[] labels = new Label[range];
620                     Arrays.fill(labels, def);
621                     for (int i = 0; i < len; i++) {
622                         labels[keys[i] - min] = make_label();
623                     }
624                     mv.visitTableSwitchInsn(min, max, def, labels);
625                     for (int i = 0; i < range; i++) {
626                         Label label = labels[i];
627                         if (label != def) {
628                             mark(label);
629                             callback.processCase(i + min, end);
630                         }
631                     }
632                 } else {
633                     Label[] labels = new Label[len];
634                     for (int i = 0; i < len; i++) {
635                         labels[i] = make_label();
636                     }
637                     mv.visitLookupSwitchInsn(def, keys, labels);
638                     for (int i = 0; i < len; i++) {
639                         mark(labels[i]);
640                         callback.processCase(keys[i], end);
641                     }
642                 }
643             }
644
645             mark(def);
646             callback.processDefault();
647             mark(end);
648
649         } catch (RuntimeException JavaDoc e) {
650             throw e;
651         } catch (Error JavaDoc e) {
652             throw e;
653         } catch (Exception JavaDoc e) {
654             throw new CodeGenerationException(e);
655         }
656     }
657
658     private static boolean isSorted(int[] keys) {
659         for (int i = 1; i < keys.length; i++) {
660             if (keys[i] < keys[i - 1])
661                 return false;
662         }
663         return true;
664     }
665
666     public void mark(Label label) {
667         mv.visitLabel(label);
668     }
669
670     Label mark() {
671         Label label = make_label();
672         mv.visitLabel(label);
673         return label;
674     }
675
676     public void push(boolean value) {
677         push(value ? 1 : 0);
678     }
679
680     /**
681      * Toggles the integer on the top of the stack from 1 to 0 or vice versa
682      */

683     public void not() {
684         push(1);
685         math(XOR, Type.INT_TYPE);
686     }
687
688     public void throw_exception(Type type, String JavaDoc msg) {
689         new_instance(type);
690         dup();
691         push(msg);
692         invoke_constructor(type, CSTRUCT_STRING);
693         athrow();
694     }
695
696     /**
697      * If the argument is a primitive class, replaces the primitive value
698      * on the top of the stack with the wrapped (Object) equivalent. For
699      * example, char -> Character.
700      * If the class is Void, a null is pushed onto the stack instead.
701      * @param type the class indicating the current type of the top stack value
702      */

703     public void box(Type type) {
704         if (TypeUtils.isPrimitive(type)) {
705             if (type == Type.VOID_TYPE) {
706                 aconst_null();
707             } else {
708                 Type boxed = TypeUtils.getBoxedType(type);
709                 new_instance(boxed);
710                 if (type.getSize() == 2) {
711                     // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
712
dup_x2();
713                     dup_x2();
714                     pop();
715                 } else {
716                     // p -> po -> opo -> oop -> o
717
dup_x1();
718                     swap();
719                 }
720                 invoke_constructor(boxed, new Signature(Constants.CONSTRUCTOR_NAME, Type.VOID_TYPE, new Type[]{ type }));
721             }
722         }
723     }
724     
725     /**
726      * If the argument is a primitive class, replaces the object
727      * on the top of the stack with the unwrapped (primitive)
728      * equivalent. For example, Character -> char.
729      * @param type the class indicating the desired type of the top stack value
730      * @return true if the value was unboxed
731      */

732     public void unbox(Type type) {
733         Type t = Constants.TYPE_NUMBER;
734         Signature sig = null;
735         switch (type.getSort()) {
736         case Type.VOID:
737             return;
738         case Type.CHAR:
739             t = Constants.TYPE_CHARACTER;
740             sig = CHAR_VALUE;
741             break;
742         case Type.BOOLEAN:
743             t = Constants.TYPE_BOOLEAN;
744             sig = BOOLEAN_VALUE;
745             break;
746         case Type.DOUBLE:
747             sig = DOUBLE_VALUE;
748             break;
749         case Type.FLOAT:
750             sig = FLOAT_VALUE;
751             break;
752         case Type.LONG:
753             sig = LONG_VALUE;
754             break;
755         case Type.INT:
756         case Type.SHORT:
757         case Type.BYTE:
758             sig = INT_VALUE;
759         }
760
761         if (sig == null) {
762             checkcast(type);
763         } else {
764             checkcast(t);
765             invoke_virtual(t, sig);
766         }
767     }
768
769     /**
770      * Allocates and fills an Object[] array with the arguments to the
771      * current method. Primitive values are inserted as their boxed
772      * (Object) equivalents.
773      */

774     public void create_arg_array() {
775         /* generates:
776            Object[] args = new Object[]{ arg1, new Integer(arg2) };
777          */

778
779         push(state.argumentTypes.length);
780         newarray();
781         for (int i = 0; i < state.argumentTypes.length; i++) {
782             dup();
783             push(i);
784             load_arg(i);
785             box(state.argumentTypes[i]);
786             aastore();
787         }
788     }
789
790
791     /**
792      * Pushes a zero onto the stack if the argument is a primitive class, or a null otherwise.
793      */

794     public void zero_or_null(Type type) {
795         if (TypeUtils.isPrimitive(type)) {
796             switch (type.getSort()) {
797             case Type.DOUBLE:
798                 push(0d);
799                 break;
800             case Type.LONG:
801                 push(0L);
802                 break;
803             case Type.FLOAT:
804                 push(0f);
805                 break;
806             case Type.VOID:
807                 aconst_null();
808             default:
809                 push(0);
810             }
811         } else {
812             aconst_null();
813         }
814     }
815
816     /**
817      * Unboxes the object on the top of the stack. If the object is null, the
818      * unboxed primitive value becomes zero.
819      */

820     public void unbox_or_zero(Type type) {
821         if (TypeUtils.isPrimitive(type)) {
822             if (type != Type.VOID_TYPE) {
823                 Label nonNull = make_label();
824                 Label end = make_label();
825                 dup();
826                 ifnonnull(nonNull);
827                 pop();
828                 zero_or_null(type);
829                 goTo(end);
830                 mark(nonNull);
831                 unbox(type);
832                 mark(end);
833             }
834         } else {
835             checkcast(type);
836         }
837     }
838
839     public void visitMaxs(int maxStack, int maxLocals) {
840         if (!TypeUtils.isAbstract(state.access)) {
841             mv.visitMaxs(0, 0);
842         }
843     }
844
845     public void invoke(MethodInfo method, Type virtualType) {
846         ClassInfo classInfo = method.getClassInfo();
847         Type type = classInfo.getType();
848         Signature sig = method.getSignature();
849         if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
850             invoke_constructor(type, sig);
851         } else if (TypeUtils.isInterface(classInfo.getModifiers())) {
852             invoke_interface(type, sig);
853         } else if (TypeUtils.isStatic(method.getModifiers())) {
854             invoke_static(type, sig);
855         } else {
856             invoke_virtual(virtualType, sig);
857         }
858     }
859
860     public void invoke(MethodInfo method) {
861         invoke(method, method.getClassInfo().getType());
862     }
863 }
864
Popular Tags