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 }