View Javadoc

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