Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 868   Methods: 41
NCLOC: 648   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
BytecodeHelper.java 0% 0% 0% 0%
coverage
 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;
 51   
 import java.lang.reflect.Modifier;
 52   
 import java.math.BigDecimal;
 53   
 import java.math.BigInteger;
 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  0
     public CodeVisitor getCodeVisitor() {
 75  0
         return cv;
 76   
     }
 77   
 
 78  0
     public BytecodeHelper(CodeVisitor cv) {
 79  0
         this.cv = cv;
 80   
     }
 81   
 
 82   
     /**
 83   
      * Generates the bytecode to autobox the current value on the stack
 84   
      */
 85  0
     public void box(Class type) {
 86  0
         if (type.isPrimitive() && type != void.class) {
 87  0
             String returnString = "(" + getTypeDescription(type.getName()) + ")Ljava/lang/Object;";
 88  0
             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  0
     public void quickBoxIfNecessary(Class cls) {
 97  0
         String type = cls.getName();
 98  0
         String descr = getTypeDescription(type);
 99  0
         if (cls == boolean.class) {
 100  0
             boxBoolean();
 101   
         }
 102  0
         else if (cls.isPrimitive() && cls != void.class) {
 103   
             // use a special integer pool in the invokerhelper
 104  0
             if (cls == Integer.TYPE) {
 105  0
                 cv.visitMethodInsn(
 106   
                         INVOKESTATIC,
 107   
                         getClassInternalName(InvokerHelper.class.getName()),
 108   
                         "integerValue",
 109   
                         "(I)Ljava/lang/Integer;"
 110   
                 );
 111  0
                 return;
 112   
             }
 113   
 
 114  0
             String wrapperName = getObjectTypeForPrimitive(type);
 115  0
             String internName = getClassInternalName(wrapperName);
 116  0
             cv.visitTypeInsn(NEW, internName);
 117  0
             cv.visitInsn(DUP);
 118  0
             if (type.equals("double") || type.equals("long")) {
 119  0
                 cv.visitInsn(DUP2_X2);
 120  0
                 cv.visitInsn(POP2);
 121   
             } else {
 122  0
                 cv.visitInsn(DUP2_X1);
 123  0
                 cv.visitInsn(POP2);
 124   
             }
 125  0
             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  0
     public void quickUnboxIfNecessary(Class cls) {
 138  0
         String type = cls.getName();
 139   
 
 140  0
         if (cls.isPrimitive() && cls != void.class) { // todo care when BigDecimal or BigIneteger on stack
 141  0
             String wrapperName = getObjectTypeForPrimitive(type);
 142  0
             String internName = getClassInternalName(wrapperName);
 143  0
             if (cls == boolean.class) {
 144  0
                 cv.visitTypeInsn(CHECKCAST, internName);
 145  0
                 cv.visitMethodInsn(INVOKEVIRTUAL, internName, type + "Value", "()" + getTypeDescription(type));
 146   
             } else { // numbers
 147  0
                 cv.visitTypeInsn(CHECKCAST, "java/lang/Number");
 148  0
                 cv.visitMethodInsn(INVOKEVIRTUAL, /*internName*/"java/lang/Number", type + "Value", "()" + getTypeDescription(type));
 149   
             }
 150   
         }
 151   
 
 152   
     }
 153   
 
 154  0
     public void box(String type) {
 155  0
         if (isPrimitiveType(type) && !type.equals("void")) {
 156  0
             String returnString = "(" + getTypeDescription(type) + ")Ljava/lang/Object;";
 157  0
             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  0
     public void unbox(Class type) {
 166  0
         if (type.isPrimitive() && type != void.class) {
 167  0
             String returnString = "(Ljava/lang/Object;)" + getTypeDescription(type.getName());
 168  0
             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  0
     public void unbox(String type) {
 180  0
         if (isPrimitiveType(type) && !type.equals("void")) {
 181  0
             String returnString = "(Ljava/lang/Object;)" + getTypeDescription(type);
 182  0
             cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(InvokerHelper.class.getName()), type + "Unbox", returnString);
 183   
         }
 184   
     }
 185   
 
 186  0
     public static boolean isPrimitiveType(String type) {
 187  0
         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  0
     public static String getTypeDescription(String name) {
 205   
         // lets avoid class loading
 206   
         // return getType(name).getDescriptor();
 207  0
         if (name == null) {
 208  0
             return "Ljava/lang/Object;";
 209   
         }
 210  0
         if (name.equals("void")) {
 211  0
             return "V";
 212   
         }
 213   
 
 214  0
         if (name.startsWith("[")) { // todo need to take care of multi-dimentional array
 215  0
             return name.replace('.', '/');
 216   
         }
 217   
 
 218  0
         String prefix = "";
 219  0
         if (name.endsWith("[]")) {
 220  0
             prefix = "[";
 221  0
             name = name.substring(0, name.length() - 2);
 222   
         }
 223   
 
 224  0
         if (name.equals("int")) {
 225  0
             return prefix + "I";
 226   
         }
 227  0
         else if (name.equals("long")) {
 228  0
             return prefix + "J";
 229   
         }
 230  0
         else if (name.equals("short")) {
 231  0
             return prefix + "S";
 232   
         }
 233  0
         else if (name.equals("float")) {
 234  0
             return prefix + "F";
 235   
         }
 236  0
         else if (name.equals("double")) {
 237  0
             return prefix + "D";
 238   
         }
 239  0
         else if (name.equals("byte")) {
 240  0
             return prefix + "B";
 241   
         }
 242  0
         else if (name.equals("char")) {
 243  0
             return prefix + "C";
 244   
         }
 245  0
         else if (name.equals("boolean")) {
 246  0
             return prefix + "Z";
 247   
         }
 248  0
         return prefix + "L" + name.replace('.', '/') + ";";
 249   
     }
 250   
 
 251   
     /**
 252   
      * @return the ASM internal name of the type
 253   
      */
 254  0
     public static String getClassInternalName(String name) {
 255  0
         if (name == null) {
 256  0
             return "java/lang/Object";
 257   
         }
 258  0
         String answer = name.replace('.', '/');
 259  0
         if (answer.endsWith("[]")) {
 260  0
             return "[" + answer.substring(0, answer.length() - 2);
 261   
         }
 262  0
         return answer;
 263   
     }
 264   
 
 265   
     /**
 266   
      * @return the regular class name of the type
 267   
      */
 268  0
     public static String getClassRegularName(String name) {
 269  0
         if (name == null) {
 270  0
             return "java.lang.Object";
 271   
         }
 272  0
         if (name.startsWith("L")) {
 273  0
             name = name.substring(1);
 274  0
             if (name.endsWith(";"))
 275  0
                 name = name.substring(0, name.length() - 1);
 276   
         }
 277  0
         String answer = name.replace('/', '.');
 278  0
         return answer;
 279   
     }
 280   
 
 281   
     /**
 282   
      * @return the ASM method type descriptor
 283   
      */
 284  0
     public static String getMethodDescriptor(String returnTypeName, Parameter[] paramTypeNames) {
 285   
         // lets avoid class loading
 286  0
         StringBuffer buffer = new StringBuffer("(");
 287  0
         for (int i = 0; i < paramTypeNames.length; i++) {
 288  0
             buffer.append(getTypeDescription(paramTypeNames[i].getType()));
 289   
         }
 290  0
         buffer.append(")");
 291  0
         buffer.append(getTypeDescription(returnTypeName));
 292  0
         return buffer.toString();
 293   
     }
 294   
 
 295   
     /**
 296   
      * @return the ASM method type descriptor
 297   
      */
 298  0
     public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
 299   
         // lets avoid class loading
 300  0
         StringBuffer buffer = new StringBuffer("(");
 301  0
         for (int i = 0; i < paramTypes.length; i++) {
 302  0
             buffer.append(getTypeDescription(paramTypes[i]));
 303   
         }
 304  0
         buffer.append(")");
 305  0
         buffer.append(getTypeDescription(returnType));
 306  0
         return buffer.toString();
 307   
     }
 308   
 
 309  0
     public static String getMethodDescriptor(Method meth) {
 310  0
         return getMethodDescriptor(meth.getReturnType(), meth.getParameterTypes());
 311   
     }
 312   
 
 313  0
     public static String getTypeDescription(Class type) {
 314  0
         if (type.isArray()) {
 315  0
             return type.getName().replace('.', '/');
 316   
         }
 317   
         else {
 318  0
             return getTypeDescription(type.getName());
 319   
         }
 320   
     }
 321   
 
 322   
     /**
 323   
      * @return an array of ASM internal names of the type
 324   
      */
 325  0
     public static String[] getClassInternalNames(String[] names) {
 326  0
         int size = names.length;
 327  0
         String[] answer = new String[size];
 328  0
         for (int i = 0; i < size; i++) {
 329  0
             answer[i] = getClassInternalName(names[i]);
 330   
         }
 331  0
         return answer;
 332   
     }
 333   
 
 334  0
     protected void pushConstant(boolean value) {
 335  0
         if (value) {
 336  0
             cv.visitInsn(ICONST_1);
 337   
         }
 338   
         else {
 339  0
             cv.visitInsn(ICONST_0);
 340   
         }
 341   
     }
 342   
 
 343  0
     protected void pushConstant(int value) {
 344  0
         switch (value) {
 345   
             case 0 :
 346  0
                 cv.visitInsn(ICONST_0);
 347  0
                 break;
 348   
             case 1 :
 349  0
                 cv.visitInsn(ICONST_1);
 350  0
                 break;
 351   
             case 2 :
 352  0
                 cv.visitInsn(ICONST_2);
 353  0
                 break;
 354   
             case 3 :
 355  0
                 cv.visitInsn(ICONST_3);
 356  0
                 break;
 357   
             case 4 :
 358  0
                 cv.visitInsn(ICONST_4);
 359  0
                 break;
 360   
             case 5 :
 361  0
                 cv.visitInsn(ICONST_5);
 362  0
                 break;
 363   
             default :
 364  0
                 if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
 365  0
                     cv.visitIntInsn(BIPUSH, value);
 366   
                 }
 367  0
                 else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
 368  0
                     cv.visitIntInsn(SIPUSH, value);
 369   
                 }
 370   
                 else {
 371  0
                     cv.visitLdcInsn(new Integer(value));
 372   
                 }
 373   
         }
 374   
     }
 375   
 
 376  0
     public void doCast(String type) {
 377  0
         if (!type.equals("java.lang.Object")) {
 378  0
             if (isPrimitiveType(type) && !type.equals("void")) {
 379  0
                 unbox(type);
 380   
             }
 381   
             else {
 382  0
                 cv.visitTypeInsn(
 383   
                     CHECKCAST,
 384  0
                     type.endsWith("[]") ? getTypeDescription(type) : getClassInternalName(type));
 385   
             }
 386   
         }
 387   
     }
 388   
 
 389  0
     public void doCast(Class type) {
 390  0
         String name = type.getName();
 391  0
         if (type.isArray()) {
 392  0
             name = type.getComponentType().getName() + "[]";
 393   
         }
 394  0
         doCast(name);
 395   
     }
 396   
 
 397  0
     public void load(String type, int idx) {
 398  0
         if (type.equals("double")) {
 399  0
             cv.visitVarInsn(DLOAD, idx);
 400   
         }
 401  0
         else if (type.equals("float")) {
 402  0
             cv.visitVarInsn(FLOAD, idx);
 403   
         }
 404  0
         else if (type.equals("long")) {
 405  0
             cv.visitVarInsn(LLOAD, idx);
 406   
         }
 407  0
         else if (
 408  0
             type.equals("boolean")
 409   
                 || type.equals("char")
 410   
                 || type.equals("byte")
 411   
                 || type.equals("int")
 412   
                 || type.equals("short")) {
 413  0
             cv.visitVarInsn(ILOAD, idx);
 414   
         }
 415   
         else {
 416  0
             cv.visitVarInsn(ALOAD, idx);
 417   
         }
 418   
     }
 419   
 
 420  0
     public void load(Variable v) {
 421  0
         load(v.getTypeName(), v.getIndex());
 422   
     }
 423   
 
 424  0
     public void store(String type, int idx) {
 425  0
         if (type.equals("double")) {
 426  0
             cv.visitVarInsn(DSTORE, idx);
 427   
         }
 428  0
         else if (type.equals("float")) {
 429  0
             cv.visitVarInsn(FSTORE, idx);
 430   
         }
 431  0
         else if (type.equals("long")) {
 432  0
             cv.visitVarInsn(LSTORE, idx);
 433   
         }
 434  0
         else if (
 435  0
             type.equals("boolean")
 436   
                 || type.equals("char")
 437   
                 || type.equals("byte")
 438   
                 || type.equals("int")
 439   
                 || type.equals("short")) {
 440  0
             cv.visitVarInsn(ISTORE, idx);
 441   
         }
 442   
         else {
 443  0
             cv.visitVarInsn(ASTORE, idx);
 444   
         }
 445   
     }
 446   
 
 447  0
     public void store(Variable v, boolean markStart) {
 448  0
         String type = v.getTypeName();
 449  0
         int idx = v.getIndex();
 450   
 
 451  0
         if (type.equals("double")) {
 452  0
             cv.visitVarInsn(DSTORE, idx);
 453   
         }
 454  0
         else if (type.equals("float")) {
 455  0
             cv.visitVarInsn(FSTORE, idx);
 456   
         }
 457  0
         else if (type.equals("long")) {
 458  0
             cv.visitVarInsn(LSTORE, idx);
 459   
         }
 460  0
         else if (
 461  0
             type.equals("boolean")
 462   
                 || type.equals("char")
 463   
                 || type.equals("byte")
 464   
                 || type.equals("int")
 465   
                 || type.equals("short")) {
 466  0
             cv.visitVarInsn(ISTORE, idx);
 467   
         }
 468   
         else {
 469  0
             cv.visitVarInsn(ASTORE, idx);
 470   
         }
 471  0
         if (AsmClassGenerator2.CREATE_DEBUG_INFO && markStart) {
 472  0
             Label l = v.getStartLabel();
 473  0
             if (l != null) {
 474  0
                 cv.visitLabel(l);
 475   
             } else {
 476  0
                 System.out.println("start label == null! what to do about this?");
 477   
             }
 478   
         }
 479   
     }
 480   
 
 481  0
     public void store(Variable v) {
 482  0
         store(v, false);
 483   
     }
 484   
 
 485   
 
 486  0
     public static String getObjectTypeForPrimitive(String type) {
 487  0
         if (type.equals("boolean")) {
 488  0
             return Boolean.class.getName();
 489   
         }
 490  0
         else if (type.equals("byte")) {
 491  0
             return Byte.class.getName();
 492   
         }
 493  0
         else if (type.equals("char")) {
 494  0
             return Character.class.getName();
 495   
         }
 496  0
         else if (type.equals("short")) {
 497  0
             return Short.class.getName();
 498   
         }
 499  0
         else if (type.equals("int")) {
 500  0
             return Integer.class.getName();
 501   
         }
 502  0
         else if (type.equals("long")) {
 503  0
             return Long.class.getName();
 504   
         }
 505  0
         else if (type.equals("float")) {
 506  0
             return Float.class.getName();
 507   
         }
 508  0
         else if (type.equals("double")) {
 509  0
             return Double.class.getName();
 510   
         }
 511   
         else {
 512  0
             return type;
 513   
         }
 514   
     }
 515   
 
 516   
     /**
 517   
      *
 518   
      * @param type  "int[]" etc
 519   
      * @return "[I" format
 520   
      */
 521  0
     public static String getObjectArrayTypeForPrimitiveArray(String type) {
 522  0
         String prefix = "";
 523  0
         while (type.endsWith("[]")) {
 524  0
             prefix += "[";
 525  0
             type = type.substring(0, type.length() - 2);
 526   
         }
 527   
 
 528  0
         if (prefix.length() ==0)
 529  0
             return type;
 530   
 
 531  0
         String suffix = getObjectTypeForPrimitive(type);
 532  0
         return prefix + "L" + suffix + ";";
 533   
     }
 534   
 
 535   
 
 536   
     
 537   
     /**
 538   
      * load the constant on the operand stack. primitives auto-boxed.
 539   
      */
 540  0
     void loadConstant (Object value) {
 541  0
         if (value == null) {
 542  0
             cv.visitInsn(ACONST_NULL);
 543   
         }
 544  0
         else if (value instanceof String) {
 545  0
             cv.visitLdcInsn(value);
 546   
         }
 547  0
         else if (value instanceof Number) {
 548   
             /** todo it would be more efficient to generate class constants */
 549  0
             Number n = (Number) value;
 550  0
             String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
 551  0
             cv.visitTypeInsn(NEW, className);
 552  0
             cv.visitInsn(DUP);
 553  0
             String methodType;
 554  0
             if (n instanceof Double) {
 555  0
                 cv.visitLdcInsn(n);
 556  0
                 methodType = "(D)V";
 557   
             }
 558  0
             else if (n instanceof Float) {
 559  0
                 cv.visitLdcInsn(n);
 560  0
                 methodType = "(F)V";
 561   
             }
 562  0
             else if (n instanceof Long) {
 563  0
                 cv.visitLdcInsn(n);
 564  0
                 methodType = "(J)V";
 565   
             }
 566  0
             else if (n instanceof BigDecimal) {
 567  0
                 cv.visitLdcInsn(n.toString());
 568  0
                 methodType = "(Ljava/lang/String;)V";
 569   
             }
 570  0
             else if (n instanceof BigInteger) {
 571  0
                 cv.visitLdcInsn(n.toString());
 572  0
                 methodType = "(Ljava/lang/String;)V";
 573   
             }
 574  0
             else if (n instanceof Integer){
 575   
                 //cv.visitLdcInsn(n);
 576  0
                 pushConstant(n.intValue());
 577  0
                 methodType = "(I)V";
 578   
             }
 579   
             else
 580   
             {
 581  0
                 throw new ClassGeneratorException(
 582   
                         "Cannot generate bytecode for constant: " + value
 583   
                         + " of type: " + value.getClass().getName()
 584   
                         +".  Numeric constant type not supported.");
 585   
             }
 586  0
             cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
 587   
         }
 588  0
         else if (value instanceof Boolean) {
 589  0
             Boolean bool = (Boolean) value;
 590  0
             String text = (bool.booleanValue()) ? "TRUE" : "FALSE";
 591  0
             cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
 592   
         }
 593  0
         else if (value instanceof Class) {
 594  0
             Class vc = (Class) value;
 595  0
             if (vc.getName().equals("java.lang.Void")) {
 596   
                 // load nothing here for void
 597   
             } else {
 598  0
                 throw new ClassGeneratorException(
 599   
                 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
 600   
             }
 601   
         }
 602   
         else {
 603  0
             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  0
     public void loadVar(Variable variable, boolean holder) {
 615  0
         String type = variable.getTypeName();
 616  0
         int index = variable.getIndex();
 617  0
         if (holder) {
 618  0
             cv.visitVarInsn(ALOAD, index);
 619  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
 620   
         } else {
 621  0
             cv.visitVarInsn(ALOAD, index); // todo? shall xload based on the type?
 622   
         }
 623   
     }
 624   
     
 625  0
     public void storeVar(Variable variable, boolean holder) {
 626  0
         String  type   = variable.getTypeName();
 627  0
         int     index  = variable.getIndex();
 628   
         
 629  0
         if (holder) {
 630   
             //int tempIndex = visitASTOREInTemp("reference", type);
 631  0
             cv.visitVarInsn(ALOAD, index);
 632  0
             cv.visitInsn(SWAP);  // assuming the value on stack is single word
 633   
             //cv.visitVarInsn(ALOAD, tempIndex);
 634  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
 635   
         }
 636   
         else {
 637  0
             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  0
     public void putField(FieldNode fld) {
 654  0
         putField(fld, getClassInternalName(fld.getOwner()));
 655   
     }
 656   
 
 657  0
     public void putField(FieldNode fld, String ownerName) {
 658  0
         cv.visitFieldInsn(PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
 659   
     }
 660   
 
 661  0
     public void loadThis() {
 662  0
         cv.visitVarInsn(ALOAD, 0);
 663   
     }
 664   
 
 665  0
     public static Class boxOnPrimitive(Class cls) {
 666  0
         Class ans = cls;
 667  0
         if (ans == null)
 668  0
             return null;
 669   
 
 670  0
         if (cls.isPrimitive() && cls != void.class) {
 671  0
             if (cls == int.class) {
 672  0
                 ans = Integer.class;
 673   
             }
 674  0
             else if (cls == byte.class) {
 675  0
                 ans = Byte.class;
 676   
             }
 677  0
             else if (cls == char.class) {
 678  0
                 ans = Character.class;
 679   
             }
 680  0
             else if (cls == short.class) {
 681  0
                 ans = Short.class;
 682   
             }
 683  0
             else if (cls == boolean.class) {
 684  0
                 ans = Boolean.class;
 685   
             }
 686  0
             else if (cls == float.class) {
 687  0
                 ans = Float.class;
 688   
             }
 689  0
             else if (cls == long.class) {
 690  0
                 ans = Long.class;
 691   
             }
 692  0
             else if (cls == double.class) {
 693  0
                 ans = Double.class;
 694   
             }
 695   
         }
 696  0
         else if (cls.isArray()){
 697   
             // let's convert primitive array too
 698  0
             int dimension = 0;
 699  0
             Class elemType = null;
 700  0
             do {
 701  0
                 ++dimension;
 702  0
                 elemType = cls.getComponentType();
 703  0
             } while(elemType.isArray());
 704   
 
 705  0
             if (elemType.isPrimitive()) {
 706  0
                 Class boxElem = null;
 707  0
                 if (elemType == int.class) {
 708  0
                     boxElem = Integer.class;
 709   
                 }
 710  0
                 else if (elemType == byte.class) {
 711  0
                     boxElem = Byte.class;
 712   
                 }
 713  0
                 else if (elemType == char.class) {
 714  0
                     boxElem = Character.class;
 715   
                 }
 716  0
                 else if (elemType == short.class) {
 717  0
                     boxElem = Short.class;
 718   
                 }
 719  0
                 else if (elemType == boolean.class) {
 720  0
                     boxElem = Boolean.class;
 721   
                 }
 722  0
                 else if (elemType == float.class) {
 723  0
                     boxElem = Float.class;
 724   
                 }
 725  0
                 else if (elemType == long.class) {
 726  0
                     boxElem = Long.class;
 727   
                 }
 728  0
                 else if (elemType == double.class) {
 729  0
                     boxElem = Double.class;
 730   
                 }
 731   
                 // I need to construct a new array type for the box version
 732  0
                 String typeName = "";
 733  0
                 for (int i = 0; i < dimension; i++){
 734  0
                     typeName += "[";
 735   
                 }
 736  0
                 typeName += "L" + boxElem.getName() + ";";
 737  0
                 try {
 738  0
                     return Class.forName(typeName);
 739   
                 } catch (ClassNotFoundException e) {
 740  0
                     throw new RuntimeException(e); // should never have come here
 741   
                 }
 742   
             }
 743   
         }
 744  0
         return ans;
 745   
     }
 746   
 
 747   
     /**
 748   
      * create the bytecode to invoke a method
 749   
      * @param meth the method object to invoke
 750   
      */
 751  0
     public void invoke(Method meth) {
 752  0
         int op = Modifier.isStatic(meth.getModifiers()) ?
 753   
                     INVOKESTATIC :
 754  0
                     (meth.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL);
 755   
 
 756  0
         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  0
     public void boxBoolean() {
 768  0
         Label l0 = new Label();
 769  0
         cv.visitJumpInsn(IFEQ, l0);
 770  0
         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
 771  0
         Label l1 = new Label();
 772  0
         cv.visitJumpInsn(GOTO, l1);
 773  0
         cv.visitLabel(l0);
 774  0
         cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
 775  0
         cv.visitLabel(l1);
 776   
     }
 777   
 
 778  0
     public static String getMethodDescriptor(MetaMethod metamethod) {
 779  0
         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  0
     public void mark(String msg) {
 787  0
         cv.visitLdcInsn(msg);
 788  0
         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  0
     public static String formatNameForClassLoading(String name) {
 799  0
         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  0
             return name;
 810   
         }
 811   
 
 812  0
         if (name == null) {
 813  0
             return "java.lang.Object;";
 814   
         }
 815   
 
 816  0
         if (name.startsWith("[")) {
 817  0
             return name.replace('/', '.');
 818   
         }
 819   
         
 820  0
         if (name.startsWith("L")) {
 821  0
             name = name.substring(1);
 822  0
             if (name.endsWith(";")) {
 823  0
                 name = name.substring(0, name.length() - 1);
 824   
             }
 825  0
             return name.replace('/', '.');
 826   
         }
 827   
 
 828  0
         String prefix = "";
 829  0
         if (name.endsWith("[]")) { // todo need process multi
 830  0
             prefix = "[";
 831  0
             name = name.substring(0, name.length() - 2);
 832  0
             if (name.equals("int")) {
 833  0
                 return prefix + "I";
 834   
             }
 835  0
             else if (name.equals("long")) {
 836  0
                 return prefix + "J";
 837   
             }
 838  0
             else if (name.equals("short")) {
 839  0
                 return prefix + "S";
 840   
             }
 841  0
             else if (name.equals("float")) {
 842  0
                 return prefix + "F";
 843   
             }
 844  0
             else if (name.equals("double")) {
 845  0
                 return prefix + "D";
 846   
             }
 847  0
             else if (name.equals("byte")) {
 848  0
                 return prefix + "B";
 849   
             }
 850  0
             else if (name.equals("char")) {
 851  0
                 return prefix + "C";
 852   
             }
 853  0
             else if (name.equals("boolean")) {
 854  0
                 return prefix + "Z";
 855   
             }
 856   
             else {
 857  0
                 return prefix + "L" + name.replace('/', '.') + ";";
 858   
             }
 859   
         }
 860  0
         return name.replace('/', '.');
 861   
 
 862   
     }
 863   
 
 864  0
     public void dup() {
 865  0
         cv.visitInsn(DUP);
 866   
     }
 867   
 }
 868