KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > classgen > BytecodeHelper


1 /*
2  $Id: BytecodeHelper.java,v 1.14 2004/07/10 03:31:39 bran Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46 package org.codehaus.groovy.classgen;
47
48 import groovy.lang.MetaMethod;
49
50 import java.lang.reflect.Method JavaDoc;
51 import java.lang.reflect.Modifier JavaDoc;
52 import java.math.BigDecimal JavaDoc;
53 import java.math.BigInteger JavaDoc;
54
55 import org.codehaus.groovy.ast.FieldNode;
56 import org.codehaus.groovy.ast.Parameter;
57 import org.codehaus.groovy.runtime.InvokerHelper;
58 import org.objectweb.asm.CodeVisitor;
59 import org.objectweb.asm.Constants;
60 import org.objectweb.asm.Label;
61
62
63 /**
64  * A helper class for bytecode generation with AsmClassGenerator2.
65  *
66  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
67  * @author <a HREF="mailto:b55r@sina.com">Bing Ran</a>
68  * @version $Revision: 1.14 $
69  */

70 public class BytecodeHelper implements Constants {
71
72     private CodeVisitor cv;
73
74     public CodeVisitor getCodeVisitor() {
75         return cv;
76     }
77
78     public BytecodeHelper(CodeVisitor cv) {
79         this.cv = cv;
80     }
81
82     /**
83      * Generates the bytecode to autobox the current value on the stack
84      */

85     public void box(Class JavaDoc type) {
86         if (type.isPrimitive() && type != void.class) {
87             String JavaDoc returnString = "(" + getTypeDescription(type.getName()) + ")Ljava/lang/Object;";
88             cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(InvokerHelper.class.getName()), "box", returnString);
89         }
90     }
91
92     /**
93      * box the primitive value on the stack
94      * @param cls
95      */

96     public void quickBoxIfNecessary(Class JavaDoc cls) {
97         String JavaDoc type = cls.getName();
98         String JavaDoc descr = getTypeDescription(type);
99         if (cls == boolean.class) {
100             boxBoolean();
101         }
102         else if (cls.isPrimitive() && cls != void.class) {
103             // use a special integer pool in the invokerhelper
104
if (cls == Integer.TYPE) {
105                 cv.visitMethodInsn(
106                         INVOKESTATIC,
107                         getClassInternalName(InvokerHelper.class.getName()),
108                         "integerValue",
109                         "(I)Ljava/lang/Integer;"
110                 );
111                 return;
112             }
113
114             String JavaDoc wrapperName = getObjectTypeForPrimitive(type);
115             String JavaDoc internName = getClassInternalName(wrapperName);
116             cv.visitTypeInsn(NEW, internName);
117             cv.visitInsn(DUP);
118             if (type.equals("double") || type.equals("long")) {
119                 cv.visitInsn(DUP2_X2);
120                 cv.visitInsn(POP2);
121             } else {
122                 cv.visitInsn(DUP2_X1);
123                 cv.visitInsn(POP2);
124             }
125             cv.visitMethodInsn(INVOKESPECIAL, internName, "<init>", "(" + descr + ")V");
126
127 // Operand opr = new Operand(ITEM_Object, wrapperName, "", "");
128
// _safePop();
129
// push(opr);
130
}
131     }
132
133     /**
134      * unbox the ref on the stack
135      * @param cls
136      */

137     public void quickUnboxIfNecessary(Class JavaDoc cls) {
138         String JavaDoc type = cls.getName();
139
140         if (cls.isPrimitive() && cls != void.class) { // todo care when BigDecimal or BigIneteger on stack
141
String JavaDoc wrapperName = getObjectTypeForPrimitive(type);
142             String JavaDoc internName = getClassInternalName(wrapperName);
143             if (cls == boolean.class) {
144                 cv.visitTypeInsn(CHECKCAST, internName);
145                 cv.visitMethodInsn(INVOKEVIRTUAL, internName, type + "Value", "()" + getTypeDescription(type));
146             } else { // numbers
147
cv.visitTypeInsn(CHECKCAST, "java/lang/Number");
148                 cv.visitMethodInsn(INVOKEVIRTUAL, /*internName*/"java/lang/Number", type + "Value", "()" + getTypeDescription(type));
149             }
150         }
151
152     }
153
154     public void box(String JavaDoc type) {
155         if (isPrimitiveType(type) && !type.equals("void")) {
156             String JavaDoc returnString = "(" + getTypeDescription(type) + ")Ljava/lang/Object;";
157             cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(InvokerHelper.class.getName()), "box", returnString);
158             // todo optimize this
159
}
160     }
161
162     /**
163      * Generates the bytecode to unbox the current value on the stack
164      */

165     public void unbox(Class JavaDoc type) {
166         if (type.isPrimitive() && type != void.class) {
167             String JavaDoc returnString = "(Ljava/lang/Object;)" + getTypeDescription(type.getName());
168             cv.visitMethodInsn(
169                 INVOKESTATIC,
170                 getClassInternalName(InvokerHelper.class.getName()),
171                 type.getName() + "Unbox",
172                 returnString);
173         }
174     }
175
176     /**
177      * Generates the bytecode to unbox the current value on the stack
178      */

179     public void unbox(String JavaDoc type) {
180         if (isPrimitiveType(type) && !type.equals("void")) {
181             String JavaDoc returnString = "(Ljava/lang/Object;)" + getTypeDescription(type);
182             cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(InvokerHelper.class.getName()), type + "Unbox", returnString);
183         }
184     }
185
186     public static boolean isPrimitiveType(String JavaDoc type) {
187         return type != null
188             && (type.equals("boolean")
189                 || type.equals("byte")
190                 || type.equals("char")
191                 || type.equals("short")
192                 || type.equals("int")
193                 || type.equals("long")
194                 || type.equals("float")
195                 || type.equals("double"));
196     }
197
198     /**
199      * array types are special:
200      * eg.: String[]: classname: [Ljava/lang/String;
201      * int[]: [I
202      * @return the ASM type description
203      */

204     public static String JavaDoc getTypeDescription(String JavaDoc name) {
205         // lets avoid class loading
206
// return getType(name).getDescriptor();
207
if (name == null) {
208             return "Ljava/lang/Object;";
209         }
210         if (name.equals("void")) {
211             return "V";
212         }
213
214         if (name.startsWith("[")) { // todo need to take care of multi-dimentional array
215
return name.replace('.', '/');
216         }
217
218         String JavaDoc prefix = "";
219         if (name.endsWith("[]")) {
220             prefix = "[";
221             name = name.substring(0, name.length() - 2);
222         }
223
224         if (name.equals("int")) {
225             return prefix + "I";
226         }
227         else if (name.equals("long")) {
228             return prefix + "J";
229         }
230         else if (name.equals("short")) {
231             return prefix + "S";
232         }
233         else if (name.equals("float")) {
234             return prefix + "F";
235         }
236         else if (name.equals("double")) {
237             return prefix + "D";
238         }
239         else if (name.equals("byte")) {
240             return prefix + "B";
241         }
242         else if (name.equals("char")) {
243             return prefix + "C";
244         }
245         else if (name.equals("boolean")) {
246             return prefix + "Z";
247         }
248         return prefix + "L" + name.replace('.', '/') + ";";
249     }
250
251     /**
252      * @return the ASM internal name of the type
253      */

254     public static String JavaDoc getClassInternalName(String JavaDoc name) {
255         if (name == null) {
256             return "java/lang/Object";
257         }
258         String JavaDoc answer = name.replace('.', '/');
259         if (answer.endsWith("[]")) {
260             return "[" + answer.substring(0, answer.length() - 2);
261         }
262         return answer;
263     }
264
265     /**
266      * @return the regular class name of the type
267      */

268     public static String JavaDoc getClassRegularName(String JavaDoc name) {
269         if (name == null) {
270             return "java.lang.Object";
271         }
272         if (name.startsWith("L")) {
273             name = name.substring(1);
274             if (name.endsWith(";"))
275                 name = name.substring(0, name.length() - 1);
276         }
277         String JavaDoc answer = name.replace('/', '.');
278         return answer;
279     }
280
281     /**
282      * @return the ASM method type descriptor
283      */

284     public static String JavaDoc getMethodDescriptor(String JavaDoc returnTypeName, Parameter[] paramTypeNames) {
285         // lets avoid class loading
286
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("(");
287         for (int i = 0; i < paramTypeNames.length; i++) {
288             buffer.append(getTypeDescription(paramTypeNames[i].getType()));
289         }
290         buffer.append(")");
291         buffer.append(getTypeDescription(returnTypeName));
292         return buffer.toString();
293     }
294
295     /**
296      * @return the ASM method type descriptor
297      */

298     public static String JavaDoc getMethodDescriptor(Class JavaDoc returnType, Class JavaDoc[] paramTypes) {
299         // lets avoid class loading
300
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("(");
301         for (int i = 0; i < paramTypes.length; i++) {
302             buffer.append(getTypeDescription(paramTypes[i]));
303         }
304         buffer.append(")");
305         buffer.append(getTypeDescription(returnType));
306         return buffer.toString();
307     }
308
309     public static String JavaDoc getMethodDescriptor(Method meth) {
310         return getMethodDescriptor(meth.getReturnType(), meth.getParameterTypes());
311     }
312
313     public static String JavaDoc getTypeDescription(Class JavaDoc type) {
314         if (type.isArray()) {
315             return type.getName().replace('.', '/');
316         }
317         else {
318             return getTypeDescription(type.getName());
319         }
320     }
321
322     /**
323      * @return an array of ASM internal names of the type
324      */

325     public static String JavaDoc[] getClassInternalNames(String JavaDoc[] names) {
326         int size = names.length;
327         String JavaDoc[] answer = new String JavaDoc[size];
328         for (int i = 0; i < size; i++) {
329             answer[i] = getClassInternalName(names[i]);
330         }
331         return answer;
332     }
333
334     protected void pushConstant(boolean value) {
335         if (value) {
336             cv.visitInsn(ICONST_1);
337         }
338         else {
339             cv.visitInsn(ICONST_0);
340         }
341     }
342
343     protected void pushConstant(int value) {
344         switch (value) {
345             case 0 :
346                 cv.visitInsn(ICONST_0);
347                 break;
348             case 1 :
349                 cv.visitInsn(ICONST_1);
350                 break;
351             case 2 :
352                 cv.visitInsn(ICONST_2);
353                 break;
354             case 3 :
355                 cv.visitInsn(ICONST_3);
356                 break;
357             case 4 :
358                 cv.visitInsn(ICONST_4);
359                 break;
360             case 5 :
361                 cv.visitInsn(ICONST_5);
362                 break;
363             default :
364                 if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
365                     cv.visitIntInsn(BIPUSH, value);
366                 }
367                 else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
368                     cv.visitIntInsn(SIPUSH, value);
369                 }
370                 else {
371                     cv.visitLdcInsn(new Integer JavaDoc(value));
372                 }
373         }
374     }
375
376     public void doCast(String JavaDoc type) {
377         if (!type.equals("java.lang.Object")) {
378             if (isPrimitiveType(type) && !type.equals("void")) {
379                 unbox(type);
380             }
381             else {
382                 cv.visitTypeInsn(
383                     CHECKCAST,
384                     type.endsWith("[]") ? getTypeDescription(type) : getClassInternalName(type));
385             }
386         }
387     }
388
389     public void doCast(Class JavaDoc type) {
390         String JavaDoc name = type.getName();
391         if (type.isArray()) {
392             name = type.getComponentType().getName() + "[]";
393         }
394         doCast(name);
395     }
396
397     public void load(String JavaDoc type, int idx) {
398         if (type.equals("double")) {
399             cv.visitVarInsn(DLOAD, idx);
400         }
401         else if (type.equals("float")) {
402             cv.visitVarInsn(FLOAD, idx);
403         }
404         else if (type.equals("long")) {
405             cv.visitVarInsn(LLOAD, idx);
406         }
407         else if (
408             type.equals("boolean")
409                 || type.equals("char")
410                 || type.equals("byte")
411                 || type.equals("int")
412                 || type.equals("short")) {
413             cv.visitVarInsn(ILOAD, idx);
414         }
415         else {
416             cv.visitVarInsn(ALOAD, idx);
417         }
418     }
419
420     public void load(Variable v) {
421         load(v.getTypeName(), v.getIndex());
422     }
423
424     public void store(String JavaDoc type, int idx) {
425         if (type.equals("double")) {
426             cv.visitVarInsn(DSTORE, idx);
427         }
428         else if (type.equals("float")) {
429             cv.visitVarInsn(FSTORE, idx);
430         }
431         else if (type.equals("long")) {
432             cv.visitVarInsn(LSTORE, idx);
433         }
434         else if (
435             type.equals("boolean")
436                 || type.equals("char")
437                 || type.equals("byte")
438                 || type.equals("int")
439                 || type.equals("short")) {
440             cv.visitVarInsn(ISTORE, idx);
441         }
442         else {
443             cv.visitVarInsn(ASTORE, idx);
444         }
445     }
446
447     public void store(Variable v, boolean markStart) {
448         String JavaDoc type = v.getTypeName();
449         int idx = v.getIndex();
450
451         if (type.equals("double")) {
452             cv.visitVarInsn(DSTORE, idx);
453         }
454         else if (type.equals("float")) {
455             cv.visitVarInsn(FSTORE, idx);
456         }
457         else if (type.equals("long")) {
458             cv.visitVarInsn(LSTORE, idx);
459         }
460         else if (
461             type.equals("boolean")
462                 || type.equals("char")
463                 || type.equals("byte")
464                 || type.equals("int")
465                 || type.equals("short")) {
466             cv.visitVarInsn(ISTORE, idx);
467         }
468         else {
469             cv.visitVarInsn(ASTORE, idx);
470         }
471         if (AsmClassGenerator2.CREATE_DEBUG_INFO && markStart) {
472             Label l = v.getStartLabel();
473             if (l != null) {
474                 cv.visitLabel(l);
475             } else {
476                 System.out.println("start label == null! what to do about this?");
477             }
478         }
479     }
480
481     public void store(Variable v) {
482         store(v, false);
483     }
484
485
486     public static String JavaDoc getObjectTypeForPrimitive(String JavaDoc type) {
487         if (type.equals("boolean")) {
488             return Boolean JavaDoc.class.getName();
489         }
490         else if (type.equals("byte")) {
491             return Byte JavaDoc.class.getName();
492         }
493         else if (type.equals("char")) {
494             return Character JavaDoc.class.getName();
495         }
496         else if (type.equals("short")) {
497             return Short JavaDoc.class.getName();
498         }
499         else if (type.equals("int")) {
500             return Integer JavaDoc.class.getName();
501         }
502         else if (type.equals("long")) {
503             return Long JavaDoc.class.getName();
504         }
505         else if (type.equals("float")) {
506             return Float JavaDoc.class.getName();
507         }
508         else if (type.equals("double")) {
509             return Double JavaDoc.class.getName();
510         }
511         else {
512             return type;
513         }
514     }
515
516     /**
517      *
518      * @param type "int[]" etc
519      * @return "[I" format
520      */

521     public static String JavaDoc getObjectArrayTypeForPrimitiveArray(String JavaDoc type) {
522         String JavaDoc prefix = "";
523         while (type.endsWith("[]")) {
524             prefix += "[";
525             type = type.substring(0, type.length() - 2);
526         }
527
528         if (prefix.length() ==0)
529             return type;
530
531         String JavaDoc suffix = getObjectTypeForPrimitive(type);
532         return prefix + "L" + suffix + ";";
533     }
534
535
536     
537     /**
538      * load the constant on the operand stack. primitives auto-boxed.
539      */

540     void loadConstant (Object JavaDoc value) {
541         if (value == null) {
542             cv.visitInsn(ACONST_NULL);
543         }
544         else if (value instanceof String JavaDoc) {
545             cv.visitLdcInsn(value);
546         }
547         else if (value instanceof Number JavaDoc) {
548             /** todo it would be more efficient to generate class constants */
549             Number JavaDoc n = (Number JavaDoc) value;
550             String JavaDoc className = BytecodeHelper.getClassInternalName(value.getClass().getName());
551             cv.visitTypeInsn(NEW, className);
552             cv.visitInsn(DUP);
553             String JavaDoc methodType;
554             if (n instanceof Double JavaDoc) {
555                 cv.visitLdcInsn(n);
556                 methodType = "(D)V";
557             }
558             else if (n instanceof Float JavaDoc) {
559                 cv.visitLdcInsn(n);
560                 methodType = "(F)V";
561             }
562             else if (n instanceof Long JavaDoc) {
563                 cv.visitLdcInsn(n);
564                 methodType = "(J)V";
565             }
566             else if (n instanceof BigDecimal JavaDoc) {
567                 cv.visitLdcInsn(n.toString());
568                 methodType = "(Ljava/lang/String;)V";
569             }
570             else if (n instanceof BigInteger JavaDoc) {
571                 cv.visitLdcInsn(n.toString());
572                 methodType = "(Ljava/lang/String;)V";
573             }
574             else if (n instanceof Integer JavaDoc){
575                 //cv.visitLdcInsn(n);
576
pushConstant(n.intValue());
577                 methodType = "(I)V";
578             }
579             else
580             {
581                 throw new ClassGeneratorException(
582                         "Cannot generate bytecode for constant: " + value
583                         + " of type: " + value.getClass().getName()
584                         +". Numeric constant type not supported.");
585             }
586             cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
587         }
588         else if (value instanceof Boolean JavaDoc) {
589             Boolean JavaDoc bool = (Boolean JavaDoc) value;
590             String JavaDoc text = (bool.booleanValue()) ? "TRUE" : "FALSE";
591             cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
592         }
593         else if (value instanceof Class JavaDoc) {
594             Class JavaDoc vc = (Class JavaDoc) value;
595             if (vc.getName().equals("java.lang.Void")) {
596                 // load nothing here for void
597
} else {
598                 throw new ClassGeneratorException(
599                 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
600             }
601         }
602         else {
603             throw new ClassGeneratorException(
604                 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
605         }
606     }
607
608
609     /**
610      * load the value of the variable on the operand stack. unbox it if it's a reference
611      * @param variable
612      * @param holder
613      */

614     public void loadVar(Variable variable, boolean holder) {
615         String JavaDoc type = variable.getTypeName();
616         int index = variable.getIndex();
617         if (holder) {
618             cv.visitVarInsn(ALOAD, index);
619             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
620         } else {
621             cv.visitVarInsn(ALOAD, index); // todo? shall xload based on the type?
622
}
623     }
624     
625     public void storeVar(Variable variable, boolean holder) {
626         String JavaDoc type = variable.getTypeName();
627         int index = variable.getIndex();
628         
629         if (holder) {
630             //int tempIndex = visitASTOREInTemp("reference", type);
631
cv.visitVarInsn(ALOAD, index);
632             cv.visitInsn(SWAP); // assuming the value on stack is single word
633
//cv.visitVarInsn(ALOAD, tempIndex);
634
cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
635         }
636         else {
637             store(variable.deriveBoxedVersion()); // todo br seems right hand values on the stack are always object refs, primitives boxed
638
// if (!varStored) {
639
// //visitVariableStartLabel(variable);
640
// varStored = true;
641
// }
642
}
643     }
644     
645 // private int visitASTOREInTemp(String name, String type) {
646
// Variable var = defineVariable(createVariableName(name), type, false);
647
// int varIdx = var.getIndex();
648
// cv.visitVarInsn(ASTORE, varIdx);
649
// if (CREATE_DEBUG_INFO) cv.visitLabel(var.getStartLabel());
650
// return varIdx;
651
// }
652

653     public void putField(FieldNode fld) {
654         putField(fld, getClassInternalName(fld.getOwner()));
655     }
656
657     public void putField(FieldNode fld, String JavaDoc ownerName) {
658         cv.visitFieldInsn(PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
659     }
660
661     public void loadThis() {
662         cv.visitVarInsn(ALOAD, 0);
663     }
664
665     public static Class JavaDoc boxOnPrimitive(Class JavaDoc cls) {
666         Class JavaDoc ans = cls;
667         if (ans == null)
668             return null;
669
670         if (cls.isPrimitive() && cls != void.class) {
671             if (cls == int.class) {
672                 ans = Integer JavaDoc.class;
673             }
674             else if (cls == byte.class) {
675                 ans = Byte JavaDoc.class;
676             }
677             else if (cls == char.class) {
678                 ans = Character JavaDoc.class;
679             }
680             else if (cls == short.class) {
681                 ans = Short JavaDoc.class;
682             }
683             else if (cls == boolean.class) {
684                 ans = Boolean JavaDoc.class;
685             }
686             else if (cls == float.class) {
687                 ans = Float JavaDoc.class;
688             }
689             else if (cls == long.class) {
690                 ans = Long JavaDoc.class;
691             }
692             else if (cls == double.class) {
693                 ans = Double JavaDoc.class;
694             }
695         }
696         else if (cls.isArray()){
697             // let's convert primitive array too
698
int dimension = 0;
699             Class JavaDoc elemType = null;
700             do {
701                 ++dimension;
702                 elemType = cls.getComponentType();
703             } while(elemType.isArray());
704
705             if (elemType.isPrimitive()) {
706                 Class JavaDoc boxElem = null;
707                 if (elemType == int.class) {
708                     boxElem = Integer JavaDoc.class;
709                 }
710                 else if (elemType == byte.class) {
711                     boxElem = Byte JavaDoc.class;
712                 }
713                 else if (elemType == char.class) {
714                     boxElem = Character JavaDoc.class;
715                 }
716                 else if (elemType == short.class) {
717                     boxElem = Short JavaDoc.class;
718                 }
719                 else if (elemType == boolean.class) {
720                     boxElem = Boolean JavaDoc.class;
721                 }
722                 else if (elemType == float.class) {
723                     boxElem = Float JavaDoc.class;
724                 }
725                 else if (elemType == long.class) {
726                     boxElem = Long JavaDoc.class;
727                 }
728                 else if (elemType == double.class) {
729                     boxElem = Double JavaDoc.class;
730                 }
731                 // I need to construct a new array type for the box version
732
String JavaDoc typeName = "";
733                 for (int i = 0; i < dimension; i++){
734                     typeName += "[";
735                 }
736                 typeName += "L" + boxElem.getName() + ";";
737                 try {
738                     return Class.forName(typeName);
739                 } catch (ClassNotFoundException JavaDoc e) {
740                     throw new RuntimeException JavaDoc(e); // should never have come here
741
}
742             }
743         }
744         return ans;
745     }
746
747     /**
748      * create the bytecode to invoke a method
749      * @param meth the method object to invoke
750      */

751     public void invoke(Method meth) {
752         int op = Modifier.isStatic(meth.getModifiers()) ?
753                     INVOKESTATIC :
754                     (meth.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL);
755
756         cv.visitMethodInsn(
757                 op,
758                 getClassInternalName(meth.getDeclaringClass().getName()),
759                 meth.getName(),
760                 getMethodDescriptor(meth)
761                 );
762     }
763
764     /**
765      * convert boolean to Boolean
766      */

767     public void boxBoolean() {
768         Label l0 = new Label();
769         cv.visitJumpInsn(IFEQ, l0);
770         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
771         Label l1 = new Label();
772         cv.visitJumpInsn(GOTO, l1);
773         cv.visitLabel(l0);
774         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
775         cv.visitLabel(l1);
776     }
777
778     public static String JavaDoc getMethodDescriptor(MetaMethod metamethod) {
779         return getMethodDescriptor(metamethod.getReturnType(), metamethod.getParameterTypes());
780     }
781
782     /**
783      * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
784      * @param msg
785      */

786     public void mark(String JavaDoc msg) {
787         cv.visitLdcInsn(msg);
788         cv.visitInsn(POP);
789     }
790     
791     /**
792      * returns a name that Class.forName() can take. Notablely for arrays:
793      * [I, [Ljava.lang.String; etc
794      * Regular object type: java.lang.String
795      * @param name
796      * @return
797      */

798     public static String JavaDoc formatNameForClassLoading(String JavaDoc name) {
799         if (name.equals("int")
800                 || name.equals("long")
801                 || name.equals("short")
802                 || name.equals("float")
803                 || name.equals("double")
804                 || name.equals("byte")
805                 || name.equals("char")
806                 || name.equals("boolean")
807                 || name.equals("void")
808             ) {
809             return name;
810         }
811
812         if (name == null) {
813             return "java.lang.Object;";
814         }
815
816         if (name.startsWith("[")) {
817             return name.replace('/', '.');
818         }
819         
820         if (name.startsWith("L")) {
821             name = name.substring(1);
822             if (name.endsWith(";")) {
823                 name = name.substring(0, name.length() - 1);
824             }
825             return name.replace('/', '.');
826         }
827
828         String JavaDoc prefix = "";
829         if (name.endsWith("[]")) { // todo need process multi
830
prefix = "[";
831             name = name.substring(0, name.length() - 2);
832             if (name.equals("int")) {
833                 return prefix + "I";
834             }
835             else if (name.equals("long")) {
836                 return prefix + "J";
837             }
838             else if (name.equals("short")) {
839                 return prefix + "S";
840             }
841             else if (name.equals("float")) {
842                 return prefix + "F";
843             }
844             else if (name.equals("double")) {
845                 return prefix + "D";
846             }
847             else if (name.equals("byte")) {
848                 return prefix + "B";
849             }
850             else if (name.equals("char")) {
851                 return prefix + "C";
852             }
853             else if (name.equals("boolean")) {
854                 return prefix + "Z";
855             }
856             else {
857                 return prefix + "L" + name.replace('/', '.') + ";";
858             }
859         }
860         return name.replace('/', '.');
861
862     }
863
864     public void dup() {
865         cv.visitInsn(DUP);
866     }
867 }
868
Popular Tags