View Javadoc

1   /*
2    $Id: BytecodeHelper.java 4287 2006-12-01 13:00:13Z blackdrag $
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 java.math.BigDecimal;
49  import java.math.BigInteger;
50  
51  import org.codehaus.groovy.ast.ClassHelper;
52  import org.codehaus.groovy.ast.ClassNode;
53  import org.codehaus.groovy.ast.FieldNode;
54  import org.codehaus.groovy.ast.Parameter;
55  import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
56  import org.objectweb.asm.MethodVisitor;
57  import org.objectweb.asm.Opcodes;
58  import org.objectweb.asm.Label;
59  
60  /***
61   * A helper class for bytecode generation with AsmClassGenerator.
62   * 
63   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
64   * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
65   * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
66   * @version $Revision: 4287 $
67   */
68  public class BytecodeHelper implements Opcodes {
69  
70      private MethodVisitor cv;
71  
72      public MethodVisitor getMethodVisitor() {
73          return cv;
74      }
75  
76      public BytecodeHelper(MethodVisitor cv) {
77          this.cv = cv;
78      }
79      
80      /***
81       * box the primitive value on the stack
82       * @param type
83       */
84      public void quickBoxIfNecessary(ClassNode type) {
85          String descr = getTypeDescription(type);
86          if (type == ClassHelper.boolean_TYPE) {
87              boxBoolean();
88          }
89          else if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) {
90              ClassNode wrapper = ClassHelper.getWrapper(type);
91              String internName = getClassInternalName(wrapper);
92              cv.visitTypeInsn(NEW, internName);
93              cv.visitInsn(DUP);
94              if (type==ClassHelper.double_TYPE || type==ClassHelper.long_TYPE) {
95                  cv.visitInsn(DUP2_X2);
96                  cv.visitInsn(POP2);
97              } else {
98                  cv.visitInsn(DUP2_X1);
99                  cv.visitInsn(POP2);
100             }
101             cv.visitMethodInsn(INVOKESPECIAL, internName, "<init>", "(" + descr + ")V");
102         }
103     }
104     
105     public void quickUnboxIfNecessary(ClassNode type){
106         if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) { // todo care when BigDecimal or BigIneteger on stack
107             ClassNode wrapper = ClassHelper.getWrapper(type);
108             String internName = getClassInternalName(wrapper);
109             if (type == ClassHelper.boolean_TYPE) {
110                 cv.visitTypeInsn(CHECKCAST, internName);
111                 cv.visitMethodInsn(INVOKEVIRTUAL, internName, type.getName() + "Value", "()" + getTypeDescription(type));
112             } else { // numbers
113                 cv.visitTypeInsn(CHECKCAST, "java/lang/Number");
114                 cv.visitMethodInsn(INVOKEVIRTUAL, /*internName*/"java/lang/Number", type.getName() + "Value", "()" + getTypeDescription(type));
115             }
116         }
117     }
118     
119     /***
120      * Generates the bytecode to autobox the current value on the stack
121      */
122     public void box(Class type) {
123         if (type.isPrimitive() && type != void.class) {
124             String returnString = "(" + getTypeDescription(type) + ")Ljava/lang/Object;";
125             cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(DefaultTypeTransformation.class.getName()), "box", returnString);
126         }
127     }
128 
129     public void box(ClassNode type) {
130         if (type.isPrimaryClassNode()) return;
131         box(type.getTypeClass());
132     }
133 
134     /***
135      * Generates the bytecode to unbox the current value on the stack
136      */
137     public void unbox(Class type) {
138         if (type.isPrimitive() && type != Void.TYPE) {
139             String returnString = "(Ljava/lang/Object;)" + getTypeDescription(type);
140             cv.visitMethodInsn(
141                 INVOKESTATIC,
142                 getClassInternalName(DefaultTypeTransformation.class.getName()),
143                 type.getName() + "Unbox",
144                 returnString);
145         }
146     }
147     
148     public void unbox(ClassNode type) {
149         if (type.isPrimaryClassNode()) return;
150         unbox(type.getTypeClass());
151     }
152 
153     public static String getClassInternalName(ClassNode t){
154     	if (t.isPrimaryClassNode()){
155     		return getClassInternalName(t.getName());
156     	}
157         return getClassInternalName(t.getTypeClass());
158     }
159     
160     public static String getClassInternalName(Class t) {
161         return org.objectweb.asm.Type.getInternalName(t);
162     }
163     
164     /***
165      * @return the ASM internal name of the type
166      */
167     public static String getClassInternalName(String name) {
168         return name.replace('.', '/');
169     }
170     
171     /***
172      * @return the ASM method type descriptor
173      */
174     public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
175         StringBuffer buffer = new StringBuffer("(");
176         for (int i = 0; i < parameters.length; i++) {
177             buffer.append(getTypeDescription(parameters[i].getType()));
178         }
179         buffer.append(")");
180         buffer.append(getTypeDescription(returnType));
181         return buffer.toString();
182     }
183 
184     /***
185      * @return the ASM method type descriptor
186      */
187     public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
188         // lets avoid class loading
189         StringBuffer buffer = new StringBuffer("(");
190         for (int i = 0; i < paramTypes.length; i++) {
191             buffer.append(getTypeDescription(paramTypes[i]));
192         }
193         buffer.append(")");
194         buffer.append(getTypeDescription(returnType));
195         return buffer.toString();
196     }
197 
198     public static String getTypeDescription(Class c) {
199         return org.objectweb.asm.Type.getDescriptor(c);
200     }
201     
202     /***
203      * array types are special:
204      * eg.: String[]: classname: [Ljava.lang.String;
205      *      Object:   classname: java.lang.Object
206      *      int[] :   classname: [I
207      * unlike getTypeDescription '.' is not replaces by '/'. 
208      * it seems that makes problems for
209      * the class loading if '.' is replaced by '/'
210      * @return the ASM type description for class loading
211      */
212     public static String getClassLoadingTypeDescription(ClassNode c) {
213         StringBuffer buf = new StringBuffer();
214         boolean array = false;
215         while (true) {
216             if (c.isArray()) {
217                 buf.append('[');
218                 c = c.getComponentType();
219                 array = true;
220             } else {
221                 if (ClassHelper.isPrimitiveType(c)) {
222                     buf.append(getTypeDescription(c));
223                 } else {
224                     if (array) buf.append('L');
225                     buf.append(c.getName());
226                     if(array) buf.append(';');
227                 }
228                 return buf.toString();
229             }
230         }
231     }
232     
233     /***
234      * array types are special:
235      * eg.: String[]: classname: [Ljava/lang/String;
236      *      int[]: [I
237      * @return the ASM type description
238      */
239     public static String getTypeDescription(ClassNode c) {
240         StringBuffer buf = new StringBuffer();
241         ClassNode d = c;
242         while (true) {
243             if (ClassHelper.isPrimitiveType(d)) {
244                 char car;
245                 if (d == ClassHelper.int_TYPE) {
246                     car = 'I';
247                 } else if (d == ClassHelper.VOID_TYPE) {
248                     car = 'V';
249                 } else if (d == ClassHelper.boolean_TYPE) {
250                     car = 'Z';
251                 } else if (d == ClassHelper.byte_TYPE) {
252                     car = 'B';
253                 } else if (d == ClassHelper.char_TYPE) {
254                     car = 'C';
255                 } else if (d == ClassHelper.short_TYPE) {
256                     car = 'S';
257                 } else if (d == ClassHelper.double_TYPE) {
258                     car = 'D';
259                 } else if (d == ClassHelper.float_TYPE) {
260                     car = 'F';
261                 } else /* long */{
262                     car = 'J';
263                 }
264                 buf.append(car);
265                 return buf.toString();
266             } else if (d.isArray()) {
267                 buf.append('[');
268                 d = d.getComponentType();
269             } else {
270                 buf.append('L');
271                 String name = d.getName();
272                 int len = name.length();
273                 for (int i = 0; i < len; ++i) {
274                     char car = name.charAt(i);
275                     buf.append(car == '.' ? '/' : car);
276                 }
277                 buf.append(';');
278                 return buf.toString();
279             }
280         }
281     }
282 
283     /***
284      * @return an array of ASM internal names of the type
285      */
286     public static String[] getClassInternalNames(ClassNode[] names) {
287         int size = names.length;
288         String[] answer = new String[size];
289         for (int i = 0; i < size; i++) {
290             answer[i] = getClassInternalName(names[i]);
291         }
292         return answer;
293     }
294 
295     protected void pushConstant(boolean value) {
296         if (value) {
297             cv.visitInsn(ICONST_1);
298         }
299         else {
300             cv.visitInsn(ICONST_0);
301         }
302     }
303 
304     protected void pushConstant(int value) {
305         switch (value) {
306             case 0 :
307                 cv.visitInsn(ICONST_0);
308                 break;
309             case 1 :
310                 cv.visitInsn(ICONST_1);
311                 break;
312             case 2 :
313                 cv.visitInsn(ICONST_2);
314                 break;
315             case 3 :
316                 cv.visitInsn(ICONST_3);
317                 break;
318             case 4 :
319                 cv.visitInsn(ICONST_4);
320                 break;
321             case 5 :
322                 cv.visitInsn(ICONST_5);
323                 break;
324             default :
325                 if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
326                     cv.visitIntInsn(BIPUSH, value);
327                 }
328                 else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
329                     cv.visitIntInsn(SIPUSH, value);
330                 }
331                 else {
332                     cv.visitLdcInsn(new Integer(value));
333                 }
334         }
335     }
336 
337     public void doCast(Class type) {
338         if (type!=Object.class) {
339             if (type.isPrimitive() && type!=Void.TYPE) {
340                 unbox(type);
341             }
342             else {
343                 cv.visitTypeInsn(
344                     CHECKCAST,
345                     type.isArray() ? getTypeDescription(type) : getClassInternalName(type.getName()));
346             }
347         }
348     }
349     
350     public void doCast(ClassNode type) {
351         if (type==ClassHelper.OBJECT_TYPE) return;
352         if (ClassHelper.isPrimitiveType(type) && type!=ClassHelper.VOID_TYPE) {
353             unbox(type);
354         }
355         else {
356             cv.visitTypeInsn(
357                     CHECKCAST,
358                     type.isArray() ? getTypeDescription(type) : getClassInternalName(type));
359         }
360     }
361 
362     public void load(ClassNode type, int idx) {
363         if (type==ClassHelper.double_TYPE) {
364             cv.visitVarInsn(DLOAD, idx);
365         }
366         else if (type==ClassHelper.float_TYPE) {
367             cv.visitVarInsn(FLOAD, idx);
368         }
369         else if (type==ClassHelper.long_TYPE) {
370             cv.visitVarInsn(LLOAD, idx);
371         }
372         else if (
373             type==ClassHelper.boolean_TYPE
374                 || type==ClassHelper.char_TYPE
375                 || type==ClassHelper.byte_TYPE
376                 || type==ClassHelper.int_TYPE
377                 || type==ClassHelper.short_TYPE)
378         {    
379             cv.visitVarInsn(ILOAD, idx);
380         }
381         else {
382             cv.visitVarInsn(ALOAD, idx);
383         }
384     }
385 
386     public void load(Variable v) {
387     	load(v.getType(), v.getIndex());
388     }
389 
390     public void store(Variable v, boolean markStart) {
391         ClassNode type = v.getType();
392         unbox(type);
393         int idx = v.getIndex();
394 
395         if (type==ClassHelper.double_TYPE) {
396             cv.visitVarInsn(DSTORE, idx);
397         }
398         else if (type==ClassHelper.float_TYPE) {
399             cv.visitVarInsn(FSTORE, idx);
400         }
401         else if (type==ClassHelper.long_TYPE) {
402             cv.visitVarInsn(LSTORE, idx);
403         }
404         else if (
405                 type==ClassHelper.boolean_TYPE
406                 || type==ClassHelper.char_TYPE
407                 || type==ClassHelper.byte_TYPE
408                 || type==ClassHelper.int_TYPE
409                 || type==ClassHelper.short_TYPE) {
410             cv.visitVarInsn(ISTORE, idx);
411         }
412         else {
413             cv.visitVarInsn(ASTORE, idx);
414         }
415     }
416 
417     public void store(Variable v) {
418         store(v, false);
419     }
420 
421     /***
422      * load the constant on the operand stack. primitives auto-boxed.
423      */
424     void loadConstant (Object value) {
425         if (value == null) {
426             cv.visitInsn(ACONST_NULL);
427         }
428         else if (value instanceof String) {
429             cv.visitLdcInsn(value);
430         }
431         else if (value instanceof Character) {
432             String className = "java/lang/Character";
433             cv.visitTypeInsn(NEW, className);
434             cv.visitInsn(DUP);
435             cv.visitLdcInsn(value);
436             String methodType = "(C)V";
437             cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
438         }
439         else if (value instanceof Number) {
440             /*** todo it would be more efficient to generate class constants */
441             Number n = (Number) value;
442             String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
443             cv.visitTypeInsn(NEW, className);
444             cv.visitInsn(DUP);
445             String methodType;
446             if (n instanceof Integer) {
447             	//pushConstant(n.intValue());
448             	cv.visitLdcInsn(n);
449             	methodType = "(I)V";
450         	}
451             else if (n instanceof Double) {
452             	cv.visitLdcInsn(n);
453             	methodType = "(D)V";
454             }
455             else if (n instanceof Float) {
456             	cv.visitLdcInsn(n);
457             	methodType = "(F)V";
458             }
459             else if (n instanceof Long) {
460             	cv.visitLdcInsn(n);
461             	methodType = "(J)V";
462             }
463             else if (n instanceof BigDecimal) {
464             	cv.visitLdcInsn(n.toString());
465             	methodType = "(Ljava/lang/String;)V";
466             }
467             else if (n instanceof BigInteger) {
468             	cv.visitLdcInsn(n.toString());
469             	methodType = "(Ljava/lang/String;)V";
470             }
471             else if (n instanceof Short) {
472             	cv.visitLdcInsn(n);
473             	methodType = "(S)V";
474             }
475             else if (n instanceof Byte) {
476             	cv.visitLdcInsn(n);
477             	methodType = "(B)V";
478             }
479             else {
480         	throw new ClassGeneratorException(
481                                "Cannot generate bytecode for constant: " + value
482                              + " of type: " + value.getClass().getName()
483                              + ".  Numeric constant type not supported.");
484             }
485             cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
486         }
487         else if (value instanceof Boolean) {
488             Boolean bool = (Boolean) value;
489             String text = (bool.booleanValue()) ? "TRUE" : "FALSE";
490             cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
491         }
492         else if (value instanceof Class) {
493             Class vc = (Class) value;
494             if (vc.getName().equals("java.lang.Void")) {
495                 // load nothing here for void
496             } else {
497                 throw new ClassGeneratorException(
498                 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
499             }
500         }
501         else {
502             throw new ClassGeneratorException(
503                 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
504         }
505     }
506 
507 
508     /***
509      * load the value of the variable on the operand stack. unbox it if it's a reference
510      * @param variable
511      */
512     public void loadVar(Variable variable) {
513 		int index = variable.getIndex();
514 		if (variable.isHolder()) {
515 			cv.visitVarInsn(ALOAD, index);
516 			cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
517 		} else {
518             load(variable);
519             if (variable!=Variable.THIS_VARIABLE && variable!=Variable.SUPER_VARIABLE) {
520                 box(variable.getType());
521             }
522 		}
523 	}
524     
525     public void storeVar(Variable variable) {
526         String  type   = variable.getTypeName();
527         int     index  = variable.getIndex();
528         
529     	if (variable.isHolder()) {
530             cv.visitVarInsn(ALOAD, index);
531             cv.visitInsn(SWAP);  
532             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
533         }
534         else {
535             store(variable,false);
536         }
537     }
538 
539     public void putField(FieldNode fld) {
540     	putField(fld, getClassInternalName(fld.getOwner()));
541     }
542 
543     public void putField(FieldNode fld, String ownerName) {
544     	cv.visitFieldInsn(PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
545     }
546     
547     public void swapObjectWith(ClassNode type) {
548         if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
549             cv.visitInsn(DUP_X2);
550             cv.visitInsn(POP);
551         } else {
552             cv.visitInsn(SWAP);
553         }
554     }
555     
556     public void swapWithObject(ClassNode type) {
557         if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
558             cv.visitInsn(DUP2_X1);
559             cv.visitInsn(POP2);
560         } else {
561             cv.visitInsn(SWAP);
562         }
563     }
564 
565     public static ClassNode boxOnPrimitive(ClassNode type) {
566         if (!type.isArray()) return ClassHelper.getWrapper(type);
567         return boxOnPrimitive(type.getComponentType()).makeArray();
568     }
569 
570     /***
571      * convert boolean to Boolean
572      */
573     public void boxBoolean() {
574         Label l0 = new Label();
575         cv.visitJumpInsn(IFEQ, l0);
576         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
577         Label l1 = new Label();
578         cv.visitJumpInsn(GOTO, l1);
579         cv.visitLabel(l0);
580         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
581         cv.visitLabel(l1);
582     }
583 
584     /***
585      * negate a boolean on stack. true->false, false->true
586      */
587     public void negateBoolean(){
588         // code to negate the primitive boolean
589         Label endLabel = new Label();
590         Label falseLabel = new Label();
591         cv.visitJumpInsn(IFNE,falseLabel);
592         cv.visitInsn(ICONST_1);
593         cv.visitJumpInsn(GOTO,endLabel);
594         cv.visitLabel(falseLabel);
595         cv.visitInsn(ICONST_0);
596         cv.visitLabel(endLabel);
597     }
598 
599     /***
600      * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
601      * @param msg
602      */
603     public void mark(String msg) {
604         cv.visitLdcInsn(msg);
605         cv.visitInsn(POP);
606     }
607     
608     /***
609      * returns a name that Class.forName() can take. Notablely for arrays:
610      * [I, [Ljava.lang.String; etc
611      * Regular object type:  java.lang.String
612      * @param name
613      */
614     public static String formatNameForClassLoading(String name) {
615         if (name.equals("int")
616         		|| name.equals("long")
617 				|| name.equals("short")
618 				|| name.equals("float")
619 				|| name.equals("double")
620 				|| name.equals("byte")
621 				|| name.equals("char")
622 				|| name.equals("boolean")
623 				|| name.equals("void")
624         	) {
625             return name;
626         }
627 
628         if (name == null) {
629             return "java.lang.Object;";
630         }
631 
632         if (name.startsWith("[")) {
633             return name.replace('/', '.');
634         }
635         
636         if (name.startsWith("L")) {
637         	name = name.substring(1);
638         	if (name.endsWith(";")) {
639         		name = name.substring(0, name.length() - 1);
640         	}
641         	return name.replace('/', '.');
642         }
643 
644         String prefix = "";
645         if (name.endsWith("[]")) { // todo need process multi
646             prefix = "[";
647             name = name.substring(0, name.length() - 2);
648             if (name.equals("int")) {
649                 return prefix + "I";
650             }
651             else if (name.equals("long")) {
652                 return prefix + "J";
653             }
654             else if (name.equals("short")) {
655                 return prefix + "S";
656             }
657             else if (name.equals("float")) {
658                 return prefix + "F";
659             }
660             else if (name.equals("double")) {
661                 return prefix + "D";
662             }
663             else if (name.equals("byte")) {
664                 return prefix + "B";
665             }
666             else if (name.equals("char")) {
667                 return prefix + "C";
668             }
669             else if (name.equals("boolean")) {
670                 return prefix + "Z";
671             }
672             else {
673             	return prefix + "L" + name.replace('/', '.') + ";";
674             }
675         }
676         return name.replace('/', '.');
677 
678     }
679 
680     public void dup() {
681         cv.visitInsn(DUP);
682     }
683 
684     public void doReturn(ClassNode returnType) {
685         if (returnType==ClassHelper.double_TYPE) {
686             cv.visitInsn(DRETURN);
687         } else if (returnType==ClassHelper.float_TYPE) {
688             cv.visitInsn(FRETURN);
689         } else if (returnType==ClassHelper.long_TYPE) {
690             cv.visitInsn(LRETURN);
691         } else if (
692                    returnType==ClassHelper.boolean_TYPE
693                 || returnType==ClassHelper.char_TYPE
694                 || returnType==ClassHelper.byte_TYPE
695                 || returnType==ClassHelper.int_TYPE
696                 || returnType==ClassHelper.short_TYPE) 
697         { 
698             //byte,short,boolean,int are all IRETURN
699             cv.visitInsn(IRETURN);
700         } else if (returnType==ClassHelper.VOID_TYPE){
701             cv.visitInsn(RETURN);
702         } else {
703             cv.visitInsn(ARETURN);
704         }
705         
706     }
707     
708 }