Code Search for Developers
 
 
  

ClassFactory.java from DrJava at Krugle


Show ClassFactory.java syntax highlighted

/*
 * DynamicJava - Copyright (C) 1999-2001
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DYADE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dyade shall not be
 * used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from
 * Dyade.
 *
 */

package koala.dynamicjava.interpreter;

import java.io.*;
import java.lang.reflect.*;

import koala.dynamicjava.classfile.*;

/**
 * The instances of this class dynamically create java classes
 *
 * @author Stephane Hillion
 * @version 1.0 - 1999/05/08
 */

public class ClassFactory extends ClassFile {
  
  private final static String VOID_NAME =
    JVMUtilities.getName("void");
  private final static String BOOLEAN_NAME =
    JVMUtilities.getName("boolean");
  private final static String CHAR_NAME =
    JVMUtilities.getName("char");
  private final static String INT_NAME =
    JVMUtilities.getName("int");
  private final static String LONG_NAME =
    JVMUtilities.getName("long");
  private final static String FLOAT_NAME =
    JVMUtilities.getName("float");
  private final static String DOUBLE_NAME =
    JVMUtilities.getName("double");
  private final static String BYTE_NAME =
    JVMUtilities.getName("byte");
  private final static String SHORT_NAME =
    JVMUtilities.getName("short");
  private final static String OBJECT_NAME =
    JVMUtilities.getName("java.lang.Object");
  
  private final static String BOOLEAN_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Boolean");
  private final static String CHAR_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Character");
  private final static String INT_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Integer");
  private final static String LONG_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Long");
  private final static String FLOAT_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Float");
  private final static String DOUBLE_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Double");
  private final static String BYTE_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Byte");
  private final static String SHORT_WRAPPER_NAME =
    JVMUtilities.getName("java.lang.Short");
  private final static String NUMBER_NAME =
    JVMUtilities.getName("java.lang.Number");
  
  /**
   * The class "java.lang.Boolean" identifier
   */
  private final static ClassIdentifier BOOLEAN_IDENTIFIER = 
    new ClassIdentifier(BOOLEAN_WRAPPER_NAME);
  
  /**
   * The Boolean(boolean) constructor identifier
   */
  private final static MethodIdentifier BOOLEAN_CONSTRUCTOR = 
    new MethodIdentifier
    (BOOLEAN_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { BOOLEAN_NAME });
  
  /**
   * The class "java.lang.Character" identifier
   */
  private final static ClassIdentifier CHARACTER_IDENTIFIER = 
    new ClassIdentifier(CHAR_WRAPPER_NAME);
  
  /**
   * The Character(char) constructor identifier
   */
  private final static MethodIdentifier CHARACTER_CONSTRUCTOR = 
    new MethodIdentifier
    (CHAR_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { CHAR_NAME });
  
  /**
   * The class "java.lang.Integer" identifier
   */
  private final static ClassIdentifier INTEGER_IDENTIFIER = 
    new ClassIdentifier(INT_WRAPPER_NAME);
  
  /**
   * The Integer(int) constructor identifier
   */
  private final static MethodIdentifier INTEGER_CONSTRUCTOR = 
    new MethodIdentifier
    (INT_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { INT_NAME });
  
  /**
   * The class "java.lang.Long" identifier
   */
  private final static ClassIdentifier LONG_IDENTIFIER = 
    new ClassIdentifier(LONG_WRAPPER_NAME);
  
  /**
   * The Long(long) constructor identifier
   */
  private final static MethodIdentifier LONG_CONSTRUCTOR = 
    new MethodIdentifier
    (LONG_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { LONG_NAME });
  
  /**
   * The class "java.lang.Float" identifier
   */
  private final static ClassIdentifier FLOAT_IDENTIFIER = 
    new ClassIdentifier(FLOAT_WRAPPER_NAME);
  
  /**
   * The Float(float) constructor identifier
   */
  private final static MethodIdentifier FLOAT_CONSTRUCTOR = 
    new MethodIdentifier
    (FLOAT_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { FLOAT_NAME });
  
  /**
   * The class "java.lang.Double" identifier
   */
  private final static ClassIdentifier DOUBLE_IDENTIFIER = 
    new ClassIdentifier(DOUBLE_WRAPPER_NAME);
  
  /**
   * The Double(double) constructor identifier
   */
  private final static MethodIdentifier DOUBLE_CONSTRUCTOR = 
    new MethodIdentifier
    (DOUBLE_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { DOUBLE_NAME });
  
  /**
   * The class "java.lang.Byte" identifier
   */
  private final static ClassIdentifier BYTE_IDENTIFIER = 
    new ClassIdentifier(BYTE_WRAPPER_NAME);
  
  /**
   * The Byte(byte) constructor identifier
   */
  private final static MethodIdentifier BYTE_CONSTRUCTOR = 
    new MethodIdentifier
    (BYTE_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { BYTE_NAME });
  
  /**
   * The class "java.lang.Short" identifier
   */
  private final static ClassIdentifier SHORT_IDENTIFIER = 
    new ClassIdentifier(SHORT_WRAPPER_NAME);
  
  /**
   * The Short(short) constructor identifier
   */
  private final static MethodIdentifier SHORT_CONSTRUCTOR = 
    new MethodIdentifier
    (SHORT_WRAPPER_NAME, "<init>", VOID_NAME, new String[] { SHORT_NAME });
  
  /**
   * The class "java.lang.Object" identifier
   */
  private final static ClassIdentifier OBJECT_IDENTIFIER = 
    new ClassIdentifier(OBJECT_NAME);
  
  /**
   * The class "java.lang.Number" identifier
   */
  private final static ClassIdentifier NUMBER_IDENTIFIER = 
    new ClassIdentifier(NUMBER_NAME);
  
  /**
   * The identifier for Number.booleanValue()
   */
  private final static MethodIdentifier BOOLEAN_BOOLEAN_VALUE_METHOD =
    new MethodIdentifier(BOOLEAN_WRAPPER_NAME, "booleanValue",
                         BOOLEAN_NAME, new String[0]);
  
  /**
   * The identifier for Number.charValue()
   */
  private final static MethodIdentifier CHARACTER_CHAR_VALUE_METHOD =
    new MethodIdentifier(CHAR_WRAPPER_NAME, "charValue", CHAR_NAME, new String[0]);
  
  /**
   * The identifier for Number.intValue()
   */
  private final static MethodIdentifier NUMBER_INT_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "intValue", INT_NAME, new String[0]);
  
  /**
   * The identifier for Number.longValue()
   */
  private final static MethodIdentifier NUMBER_LONG_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "longValue", LONG_NAME, new String[0]);
  
  /**
   * The identifier for Number.floatValue()
   */
  private final static MethodIdentifier NUMBER_FLOAT_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "floatValue", FLOAT_NAME, new String[0]);
  
  /**
   * The identifier for Number.doubleValue()
   */
  private final static MethodIdentifier NUMBER_DOUBLE_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "doubleValue", DOUBLE_NAME, new String[0]);
  
  /**
   * The identifier for Number.byteValue()
   */
  private final static MethodIdentifier NUMBER_BYTE_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "byteValue", BYTE_NAME, new String[0]);
  
  /**
   * The identifier for Number.shortValue()
   */
  private final static MethodIdentifier NUMBER_SHORT_VALUE_METHOD =
    new MethodIdentifier(NUMBER_NAME, "shortValue", SHORT_NAME, new String[0]);
  
  /**
   * The name of the class to build
   */
  private String name;
  
  /**
   * The name of the superclass of the class to build
   */
  private String superName;
  
  /**
   * Whether the class to build is static
   */
  private boolean isStaticClass;
  
  /**
   * The identifier of the method called from the generated methods
   */
  private MethodIdentifier interpreterMethod;
  
  /**
   * The identifier of the method called from the generated constructors
   */
  private MethodIdentifier interpretArgumentsMethod;
  
  /**
   * The identifier for ThrownException.getException()
   */
  private MethodIdentifier thrownExceptionMethod;
  
  /**
   * The name of the thrown exception
   */
  private String thrownExceptionName;
  
  /**
   * The InnerClassAttribute
   */
  private InnerClassesAttribute innerClassesAttribute;
  
  /**
   * The classloader identifier
   */
  private String classLoaderId;
  
  /**
   * Creates a new class factory for an innerclass
   * @param af     the access flags
   * @param name   the name of the class to create
   * @param sname  the name of the superclass
   * @param interp the class of the interpreter used to evaluate the body of
   *               the methods.
   *               It must implement methods with the following signatures:<br>
   *               <code>public static Object[] interpretArguments
   *                     (String key, Object[] args)</code><br>
   *               <code>public static Object invokeMethod
   *                     (String key, Object obj, Object[] args)</code>
   * @param except the class of the exception used to manage exception throwing.
   *               It must implement a method with the following signature:<br>
   *               <code>public Throwable getException()</code>.
   * @param clid   the class loader identifier
   */
  public ClassFactory(int     af,
                      String  name,
                      String  sname,
                      Class<?>   interp,
                      Class<?>   except,
                      String  clid) {
    super(name, sname);
    this.name = name;
    superName = sname;
    classLoaderId = clid;
    
    isStaticClass = (af & Modifier.STATIC) != 0;
    int taf = af & ~Modifier.PRIVATE
      & ~Modifier.PROTECTED
      & ~Modifier.STATIC;
    setAccessFlags(taf | 0x20 /* SUPER */ | (isStaticClass ? Modifier.PUBLIC : 0));
    
    String interpClassName = interp.getName();
    
    interpreterMethod =
      new MethodIdentifier
      (JVMUtilities.getName(interpClassName),
       "invokeMethod",
       JVMUtilities.getReturnTypeName("java.lang.Object"),
       new String[] {
      JVMUtilities.getParameterTypeName("java.lang.String"),
        JVMUtilities.getParameterTypeName("java.lang.Object"),
        JVMUtilities.getParameterTypeName("java.lang.Object[]") });
      
      interpretArgumentsMethod =
        new MethodIdentifier
        (JVMUtilities.getName(interpClassName),
         "interpretArguments",
         JVMUtilities.getReturnTypeName("java.lang.Object[]"),
         new String[] {
        JVMUtilities.getParameterTypeName("java.lang.String"),
          JVMUtilities.getParameterTypeName("java.lang.Object[]") });
        
        thrownExceptionName = except.getName();
        thrownExceptionMethod =
          new MethodIdentifier
          (JVMUtilities.getName(thrownExceptionName),
           "getException",
           JVMUtilities.getReturnTypeName("java.lang.Exception"),
           new String[0]);
  }
  
  /**
   * Computes a method identifier. It starts with the name of
   * the class followed by a '#'.
   * @param cname  the name of the class
   * @param mname  the name of the method
   * @param pnames the names of the parameter classes
   * @param clid   the classloader identifier
   */
  public static String getMethodIdentifier(String       cname,
                                           String       mname,
                                           String[]     pnames,
                                           String       clid) {
    String result = cname + "#" + mname + "(";
    if (pnames.length > 0) {
      result += pnames[0];
    }
    for (int i = 1; i < pnames.length; i++) {
      result += "," + pnames[i];
    }
    return result + ")" + clid;
  }
  
  /**
   * Creates the class initializer.
   * @return the method identifier
   */
  public String createClassInitializer() {
    try {
      MethodInfo mi = createMethod("void", "<clinit>", new String[0]);
      String result = getMethodIdentifier(name,
                                          "<clinit>",
                                          new String[0],
                                          classLoaderId);
      
      mi.setAccessFlags(Modifier.STATIC);
      
      ConstantPool          cp        = getConstantPool();
      ByteArrayOutputStream bytes     = new ByteArrayOutputStream();
      DataOutputStream      data      = new DataOutputStream(bytes);
      MethodIdentifier      mid;
      
      // Params array creation /////////////////////////////////////////////
      
      /* Object[] t = new Object[<pt.length>]; */
      
      //   Put 0 on the stack
      bipush(0, data);
      
      // Create the array (anewarray <java/lang/Object>)
      data.writeByte(0xBD);
      short s = cp.put(OBJECT_IDENTIFIER);
      data.writeShort(s);
      
      // Store the result in the local variable 0
      astore(0, data);
      
      // Method invocation ////////////////////////////////////////////////
      
      // Interpreter.invokeMethod(class+name+signature, null, t);
      
      // ldc <class+name+sig>
      s = cp.put(new ConstantString(result));
      if (s > 256) {
        data.writeByte(0x13);
        data.writeShort(s);
      } else {
        data.writeByte(0x12);
        data.writeByte(s);
      }
      
      // aconst_null
      data.writeByte(0x01);
      
      // loads the table
      aload(0, data);
      
      // invokestatic Interpreter.invokeMethod
      data.writeByte(0xB8);
      data.writeShort(cp.put(interpreterMethod));
      
      // return
      data.writeByte(0xB1);
      
      CodeAttribute ca = mi.createCodeAttribute();
      ca.setCode(bytes.toByteArray(), (short)1, (short)6);
      
      return result;
    } catch (IOException e) {
      // Should never append
      e.printStackTrace();     
    }
    return null;
  }
  
  /**
   * Adds a constructor to the class. The body is automatically
   * generated.
   * @param af  the access flags
   * @param pt  the parameters types
   * @param ex  the exceptions thrown
   * @param sup the name of the super constructor
   * @param st  the initialization method parameter types
   * @return the constructor identifier
   */
  public String addConstructor(int af, String[] pt, String[] ex,
                               String sup, String[] st) {
    try {
      String result = getMethodIdentifier(name, "<init>", pt, classLoaderId);
      
      MethodInfo mi = createMethod("void", "<init>", pt);
      mi.setAccessFlags(af);
      
      ConstantPool          cp        = getConstantPool();
      ByteArrayOutputStream bytes     = new ByteArrayOutputStream();
      DataOutputStream      data      = new DataOutputStream(bytes);
      short                 maxStack  = (short)6;
      short                 maxLocals = (short)3;
      
      // Compute the max locals
      for (int i = 0; i < pt.length; i++) {
        String s = pt[i];
        if (s.equals("long") || s.equals("double")) {
          maxLocals += 2;
        } else {
          maxLocals += 1;
        }
      }
      short variablesStart = maxLocals;
      for (int i = 0; i < st.length; i++) {
        String s = st[i];
        if (s.equals("long") || s.equals("double")) {
          maxLocals += 2;
          maxStack  += 2;
        } else {
          maxLocals += 1;
          maxStack  += 1;
        }
      }     
      
      // Params array creation /////////////////////////////////////////////
      
      /* Object[] t = new Object[<pt.length>]; */
      
      //   Put <pt.length> on the stack
      bipush(pt.length, data);
      
      // Create the array (anewarray <java/lang/Object>)
      data.writeByte(0xBD);
      short s = cp.put(OBJECT_IDENTIFIER);
      data.writeShort(s);
      
      // Store the result in the local variable <variablesStart - 1>
      if (variablesStart < 5) {
        // astore_<variablesStart - 1>
        data.writeByte(0x4B + variablesStart-1);
      } else {
        // astore <variablesStart - 1>
        data.writeByte(0x3A);
        data.writeByte(variablesStart-1);
      }
      
      // Fill params array //////////////////////////////////////////////////
      
      /* t[0] = param1;
       t[1] = param2;
       ...             */
      
      int currentLocal = 1;
      for (int i = 0; i < pt.length; i++) {
        String a = pt[i];
        
        // Load the array reference
        aload(variablesStart - 1, data);
        
        // Load the array index
        bipush(i, data);
        
        // Load the argument
        if (a.equals("int")) {
          loadInt(currentLocal, data, cp);
          
        } else if (a.equals("long")) {
          loadLong(currentLocal, data, cp);
          currentLocal++;
          
        } else if (a.equals("float")) {
          loadFloat(currentLocal, data, cp);
          
        } else if (a.equals("double")) {
          loadDouble(currentLocal, data, cp);
          currentLocal++;
          
        } else if (a.equals("byte")) {
          loadByte(currentLocal, data, cp);
          
        } else if (a.equals("short")) {
          loadShort(currentLocal, data, cp);
          
        } else if (a.equals("boolean")) {
          loadBoolean(currentLocal, data, cp);
          
        } else if (a.equals("char")) {
          loadChar(currentLocal, data, cp);
          
        } else {
          aload(currentLocal, data);
        }
        
        // Put the argument in the array (aastore)
        data.writeByte(0x53);
        currentLocal++;
      }
      
      short tryStart = (short)data.size();
      
      // Method invocation ////////////////////////////////////////////////
      
      // Interpreter.interpretArguments(class+name+signature, t);
      
      // ldc <class+name+sig>
      s = cp.put(new ConstantString(result));
      if (s > 256) {
        data.writeByte(0x13);
        data.writeShort(s);
      } else {
        data.writeByte(0x12);
        data.writeByte(s);
      }
      
      // loads the table
      aload(variablesStart - 1, data);
      
      // invokestatic Interpreter.interpretArguments
      data.writeByte(0xB8);
      data.writeShort(cp.put(interpretArgumentsMethod));
      
      // Store the result in the local variable <variablesStart-2>
      astore(variablesStart - 2, data);
      
      // Result management ///////////////////////////////////////////////
      
      currentLocal = variablesStart;
      
      // Unwrap each element of the array and store it in a local variable
      for (int i = 0; i < st.length; i++) {
        String a = st[i];
        
        // Load the array reference
        aload(variablesStart - 2, data);
        
        // Load the array index
        bipush(i, data);
        
        // aaload
        data.writeByte(0x32);
        
        if (a.equals("int")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.intValue:()I
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_INT_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // istore_<currentLocal>
            data.writeByte(0x3B + currentLocal);
          } else {
            // istore <currentLocal>
            data.writeByte(0x36);
            data.writeByte(currentLocal);
          }
          
        } else if (a.equals("long")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.longValue:()J
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_LONG_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // lstore_<currentLocal>
            data.writeByte(0x3F + currentLocal);
          } else {
            // lstore <currentLocal>
            data.writeByte(0x37);
            data.writeByte(currentLocal);
          }
          currentLocal++;
          
        } else if (a.equals("float")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.floatValue:()F
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_FLOAT_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // fstore_<currentLocal>
            data.writeByte(0x43 + currentLocal);
          } else {
            // fstore <currentLocal>
            data.writeByte(0x38);
            data.writeByte(currentLocal);
          }
          
        } else if (a.equals("double")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.doubleValue:()D
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_DOUBLE_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // dstore_<currentLocal>
            data.writeByte(0x47 + currentLocal);
          } else {
            // dstore <currentLocal>
            data.writeByte(0x39);
            data.writeByte(currentLocal);
          }
          currentLocal++;
          
        } else if (a.equals("byte")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.byteValue:()B
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_BYTE_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // istore_<currentLocal>
            data.writeByte(0x3B + currentLocal);
          } else {
            // istore <currentLocal>
            data.writeByte(0x36);
            data.writeByte(currentLocal);
          }
          
        } else if (a.equals("short")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.shortValue:()S
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_SHORT_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // istore_<currentLocal>
            data.writeByte(0x3B + currentLocal);
          } else {
            // istore <currentLocal>
            data.writeByte(0x36);
            data.writeByte(currentLocal);
          }
          
        } else if (a.equals("boolean")) {
          // checkcast java.lang.Boolean
          data.writeByte(0xC0);
          data.writeShort(cp.put(BOOLEAN_IDENTIFIER));
          
          // invokevirtual java/lang/Boolean.booleanValue:()Z
          data.writeByte(0xB6);
          data.writeShort(cp.put(BOOLEAN_BOOLEAN_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // istore_<currentLocal>
            data.writeByte(0x3B + currentLocal);
          } else {
            // istore <currentLocal>
            data.writeByte(0x36);
            data.writeByte(currentLocal);
          }
          
        } else if (a.equals("char")) {
          // checkcast java.lang.Character
          data.writeByte(0xC0);
          data.writeShort(cp.put(CHARACTER_IDENTIFIER));
          
          // invokevirtual java/lang/Character.charValue:()Z
          data.writeByte(0xB6);
          data.writeShort(cp.put(CHARACTER_CHAR_VALUE_METHOD));
          
          if (currentLocal < 4) {
            // istore_<currentLocal>
            data.writeByte(0x3B + currentLocal);
          } else {
            // istore <currentLocal>
            data.writeByte(0x36);
            data.writeByte(currentLocal);
          }
          
        } else {
          astore(currentLocal, data);
        }
        
        currentLocal++;
      }
      
      // Constructor invocation //////////////////////////////////////////////
      
      // aload_0
      data.writeByte(0x2A);
      
      currentLocal = variablesStart;
      
      // Push each stored variable on the stack
      for (int i = 0; i < st.length; i++) {
        String a = st[i];
        
        if (a.equals("int")) {
          iload(currentLocal, data);
        } else if (a.equals("long")) {
          if (currentLocal < 4) {
            // lload_<currentLocal>
            data.writeByte(0x1E + currentLocal);
          } else {
            // lload <currentLocal>
            data.writeByte(0x16);
            data.writeByte(currentLocal);
          }      
          currentLocal++;
          
        } else if (a.equals("float")) {
          if (currentLocal < 4) {
            // fload_<currentLocal>
            data.writeByte(0x22 + currentLocal);
          } else {
            // fload <currentLocal>
            data.writeByte(0x17);
            data.writeByte(currentLocal);
          }      
          
        } else if (a.equals("double")) {
          if (currentLocal < 4) {
            // dload_<currentLocal>
            data.writeByte(0x26 + currentLocal);
          } else {
            // dload <currentLocal>
            data.writeByte(0x18);
            data.writeByte(currentLocal);
          }
          currentLocal++;
          
        } else if (a.equals("byte")) {
          iload(currentLocal, data);
          
        } else if (a.equals("short")) {
          iload(currentLocal, data);
          
        } else if (a.equals("boolean")) {
          iload(currentLocal, data);
          
        } else if (a.equals("char")) {
          iload(currentLocal, data);
          
        } else {
          aload(currentLocal, data);
          
          // checkcast <rt>
          data.writeByte(0xC0);
          data.writeShort
            (cp.put(new ClassIdentifier(JVMUtilities.getName(st[i]))));
        }
        
        currentLocal++;
      }
      
      data.writeByte(0xB7);
      
      for (int i = 0; i < st.length; i++) {
        st[i] = JVMUtilities.getParameterTypeName(st[i]);
      }
      
      // invokespecial sup
      MethodIdentifier mid = new MethodIdentifier
        (JVMUtilities.getName(sup),
         "<init>",
         JVMUtilities.getName("void"),
         st);
      
      data.writeShort(cp.put(mid));
      
      // Interpreter.invokeMethod(class+name+signature, this, t); ////////////
      
      // ldc <class+name+sig>
      s = cp.put(new ConstantString(result));
      if (s > 256) {
        data.writeByte(0x13);
        data.writeShort(s);
      } else {
        data.writeByte(0x12);
        data.writeByte(s);
      }
      
      // aload_0
      data.writeByte(0x2A);
      
      // loads the table
      aload(variablesStart - 1, data);
      
      // invokestatic Interpreter.invokeMethod
      data.writeByte(0xB8);
      data.writeShort(cp.put(interpreterMethod));
      
      // return
      data.writeByte(0xB1);
      
      // Exceptions ////////////////////////////////////////////////////////
      
      short tryEnd = (short)data.size();
      
      // Create the handler bytecode
      if (ex.length > 0) {
        maxLocals += 2;
        
        // catch (ThrownException e)
        astore(maxLocals - 2, data);
        aload(maxLocals - 2, data);
        
        // Exception ex = e.getException();
        
        // invokevirtual e.getException()
        data.writeByte(0xB6);
        data.writeShort(cp.put(thrownExceptionMethod));
        
        astore(maxLocals - 1, data);
        
        // if (ex instanceof <ex[i]>) throw (<ex[i]>)ex;
        for (int i = 0; i < ex.length; i++) {
          // instanceof <ex[i]>
          aload(maxLocals - 1, data);
          data.writeByte(0xC1);
          s = cp.put(new ClassIdentifier(JVMUtilities.getName(ex[i])));
          data.writeShort(s);
          
          // ifeq ...
          data.writeByte(0x99);
          if (maxLocals < 5) {
            // ... 8
            data.writeShort(0x08);
          } else {
            // ... 9
            data.writeShort(0x09);
          }
          
          aload(maxLocals - 1, data);
          
          // checkcast <ex[i]>
          data.writeByte(0xC0);
          data.writeShort(s);
          
          // athrow
          data.writeByte(0xBF);
        }
        
        aload(maxLocals - 2, data);
        
        // athrow
        data.writeByte(0xBF);
      }
      
      CodeAttribute ca = mi.createCodeAttribute();
      ca.setCode(bytes.toByteArray(), maxLocals, maxStack);
      
      // Fill the exception table
      if (ex.length > 0) {
        ca.addExceptionTableEntry
          (tryStart, tryEnd, tryEnd, thrownExceptionName);
      }
      
      // Adds the exceptions to the exceptions attribute
      if (ex.length > 0) {
        ExceptionsAttribute ea = mi.createExceptionsAttribute();
        for (int i = 0; i < ex.length; i++) {
          ea.addException(ex[i]);
        }
      }
      
      return result;
    } catch (IOException e) {
      // Should never append
      e.printStackTrace();     
    }
    return null;
  }
  
  /**
   * Adds a field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addField(int af, String ft, String nm) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
  }
  
  /**
   * Adds a constant int field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantIntField(int af, String ft, String nm, Integer v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(v);
  }
  
  /**
   * Adds a constant long field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantLongField(int af, String ft, String nm, Long v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(v);
  }
  
  /**
   * Adds a constant float field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantFloatField(int af, String ft, String nm, Float v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(v);
  }
  
  /**
   * Adds a constant double field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantDoubleField(int af, String ft, String nm, Double v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(v);
  }
  
  /**
   * Adds a constant boolean field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantBooleanField(int af, String ft, String nm, Boolean v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(new Integer(v.booleanValue() ? 1 : 0));
  }
  
  /**
   * Adds a constant string field to the class.
   * @param af the access flags
   * @param ft the field type
   * @param nm the field name
   */
  public void addConstantStringField(int af, String ft, String nm, String v) {
    FieldInfo fi = createField(ft, nm);
    fi.setAccessFlags(af);
    fi.setConstantValueAttribute(v);
  }
  
  /**
   * Adds an InnerClasses entry
   */
  public InnerClassesEntry addInnerClassesEntry() {
    if (innerClassesAttribute == null) {
      innerClassesAttribute = new InnerClassesAttribute(getConstantPool());
      setInnerClassesAttribute(innerClassesAttribute);
    }
    return innerClassesAttribute.addInnerClassesEntry();
  }
  
  /**
   * Adds a method that calls the supermethod of the given method
   * @param af the access flags
   * @param rt the return type
   * @param nm the name of the method
   * @param pt the parameters types
   * @param ex the exceptions thrown
   */
  public void addSuperMethodAccessor(int af,
                                     String rt,
                                     String nm,
                                     String[] pt,
                                     String[] ex) {
    try {
      MethodInfo mi = createMethod(rt, "super$" + nm, pt);
      mi.setAccessFlags(Modifier.PUBLIC);
      
      ConstantPool          cp        = getConstantPool();
      ByteArrayOutputStream bytes     = new ByteArrayOutputStream();
      DataOutputStream      data      = new DataOutputStream(bytes);
      short                 maxStack;
      boolean               isStatic = Modifier.isStatic(af);
      short                 maxLocals = (short)(isStatic ? 1 : 2);
      MethodIdentifier      mid;
      
      // Compute the max locals
      for (int i = 0; i < pt.length; i++) {
        String s = pt[i];
        if (s.equals("long") || s.equals("double")) {
          maxLocals += 2;
        } else {
          maxLocals += 1;
        }
      }
      maxStack = maxLocals;
      
      int currentLocal = 0;
      if (!isStatic) {
        // aload_0
        data.writeByte(0x2A);
        currentLocal = 1;
      }
      
      // Push each local variable on the stack
      for (int i = 0; i < pt.length; i++) {
        String a = pt[i];
        
        if (a.equals("int")) {
          iload(currentLocal, data);
        } else if (a.equals("long")) {
          if (currentLocal < 4) {
            // lload_<currentLocal>
            data.writeByte(0x1E + currentLocal);
          } else {
            // lload <currentLocal>
            data.writeByte(0x16);
            data.writeByte(currentLocal);
          }      
          currentLocal++;
          
        } else if (a.equals("float")) {
          if (currentLocal < 4) {
            // fload_<currentLocal>
            data.writeByte(0x22 + currentLocal);
          } else {
            // fload <currentLocal>
            data.writeByte(0x17);
            data.writeByte(currentLocal);
          }      
          
        } else if (a.equals("double")) {
          if (currentLocal < 4) {
            // dload_<currentLocal>
            data.writeByte(0x26 + currentLocal);
          } else {
            // dload <currentLocal>
            data.writeByte(0x18);
            data.writeByte(currentLocal);
          }
          currentLocal++;
          
        } else if (a.equals("byte")) {
          iload(currentLocal, data);
          
        } else if (a.equals("short")) {
          iload(currentLocal, data);
          
        } else if (a.equals("boolean")) {
          iload(currentLocal, data);
          
        } else if (a.equals("char")) {
          iload(currentLocal, data);
          
        } else {
          aload(currentLocal, data);
          
          // checkcast <pt[i]>
          data.writeByte(0xC0);
          data.writeShort
            (cp.put(new ClassIdentifier(JVMUtilities.getName(pt[i]))));
        }
        
        currentLocal++;
      }
      
      String[] st = new String[pt.length];
      for (int i = 0; i < pt.length; i++) {
        st[i] = JVMUtilities.getParameterTypeName(pt[i]);
      }
      
      mid = new MethodIdentifier
        (JVMUtilities.getName(superName),
         nm,
         JVMUtilities.getReturnTypeName(rt),
         st);
      
      if (isStatic) {
        // invokestatic method
        data.writeByte(0xB8);
      } else {
        // invokespecial method
        data.writeByte(0xB7);
      }
      data.writeShort(cp.put(mid));
      
      // Return ////////////////////////////////////////////////////////////
      
      if (rt.equals("void")) {
        // return
        data.writeByte(0xB1);
      } else if (rt.equals("int")) {
        // ireturn
        data.writeByte(0xAC);
        
      } else if (rt.equals("long")) {
        // lreturn
        data.writeByte(0xAD);
        
      } else if (rt.equals("float")) {
        // freturn
        data.writeByte(0xAE);
        
      } else if (rt.equals("double")) {
        // dreturn
        data.writeByte(0xAF);
        
      } else if (rt.equals("byte")) {
        // ireturn
        data.writeByte(0xAC);
        
      } else if (rt.equals("short")) {
        // ireturn
        data.writeByte(0xAC);
        
      } else if (rt.equals("boolean")) {
        // ireturn
        data.writeByte(0xAC);
        
      } else if (rt.equals("char")) {
        // ireturn
        data.writeByte(0xAC);
        
      } else {
        // areturn
        data.writeByte(0xB0);
      }
      
      CodeAttribute ca = mi.createCodeAttribute();
      ca.setCode(bytes.toByteArray(), maxLocals, maxStack);
      
      // Adds the exceptions to the exceptions attribute
      if (ex.length > 0) {
        ExceptionsAttribute ea = mi.createExceptionsAttribute();
        for (int i = 0; i < ex.length; i++) {
          ea.addException(ex[i]);
        }
      }
      
    } catch (IOException e) {
      // Should never append
      e.printStackTrace();      
    }
  }     
  
  /**
   * Adds a method to the class. The body is automatically
   * generated.
   * @param af the access flags
   * @param rt the return type
   * @param nm the name of the method
   * @param pt the parameters types
   * @param ex the exceptions thrown
   * @return the method identifier
   */
  public String addMethod(int af, String rt, String nm, String[] pt, String[] ex) {
    try {
      MethodInfo mi = createMethod(rt, nm, pt);
      String result = getMethodIdentifier(name, nm, pt, classLoaderId);
      
      mi.setAccessFlags(af);
      
      if (!mi.isAbstract()) {
        ConstantPool          cp        = getConstantPool();
        ByteArrayOutputStream bytes     = new ByteArrayOutputStream();
        DataOutputStream      data      = new DataOutputStream(bytes);
        short                 maxStack  = (short)6;
        short                 maxLocals = (short)((mi.isStatic()) ? 1 : 2);
        MethodIdentifier      mid;
        
        // Compute the max locals
        for (int i = 0; i < pt.length; i++) {
          String s = pt[i];
          if (s.equals("long") || s.equals("double")) {
            maxLocals += 2;
          } else {
            maxLocals += 1;
          }
        }
        
        // Params array creation /////////////////////////////////////////////
        
        /* Object[] t = new Object[<pt.length>]; */
        
        //   Put <pt.length> on the stack
        bipush(pt.length, data);
        
        // Create the array (anewarray <java/lang/Object>)
        data.writeByte(0xBD);
        short s = cp.put(OBJECT_IDENTIFIER);
        data.writeShort(s);
        
        // Store the result in the local variable #maxLocals - 1
        astore(maxLocals - 1, data);
        
        // Fill params array //////////////////////////////////////////////////
        
        /* t[0] = param1;
         t[1] = param2;
         ...             */
        
        int currentLocal = (mi.isStatic()) ? 0 : 1;
        for (int i = 0; i < pt.length; i++) {
          String a = pt[i];
          
          // Load the array reference
          aload(maxLocals - 1, data);
          
          // Push the array index
          bipush(i, data);
          
          // Load the argument
          if (a.equals("int")) {
            loadInt(currentLocal, data, cp);
            
          } else if (a.equals("long")) {
            loadLong(currentLocal, data, cp);
            currentLocal++;
            
          } else if (a.equals("float")) {
            loadFloat(currentLocal, data, cp);
            
          } else if (a.equals("double")) {
            loadDouble(currentLocal, data, cp);
            currentLocal++;
            
          } else if (a.equals("byte")) {
            loadByte(currentLocal, data, cp);
            
          } else if (a.equals("short")) {
            loadShort(currentLocal, data, cp);
            
          } else if (a.equals("boolean")) {
            loadBoolean(currentLocal, data, cp);
            
          } else if (a.equals("char")) {
            loadChar(currentLocal, data, cp);
            
          } else {
            aload(currentLocal, data);
          }
          
          // Put the argument in the array (aastore)
          data.writeByte(0x53);
          currentLocal++;
        }
        
        short tryStart = (short)data.size();
        
        // Method invocation ////////////////////////////////////////////////
        
        // Interpreter.invokeMethod(class+name+signature, this, t);
        
        // ldc <class+name+sig>
        s = cp.put(new ConstantString(result));
        if (s > 256) {
          data.writeByte(0x13);
          data.writeShort(s);
        } else {
          data.writeByte(0x12);
          data.writeByte(s);
        }
        
        if (mi.isStatic()) {
          // aconst_null
          data.writeByte(0x01);
        } else {
          // aload_0
          data.writeByte(0x2A);
        }
        
        // loads the table
        aload(maxLocals - 1, data);
        
        // invokestatic Interpreter.invokeMethod
        data.writeByte(0xB8);
        data.writeShort(cp.put(interpreterMethod));
        
        // Return ////////////////////////////////////////////////////////////
        
        if (rt.equals("void")) {
          // return
          data.writeByte(0xB1);
        } else if (rt.equals("int")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.intValue:()I
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_INT_VALUE_METHOD));
          
          // ireturn
          data.writeByte(0xAC);
          
        } else if (rt.equals("long")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.longValue:()J
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_LONG_VALUE_METHOD));
          
          // lreturn
          data.writeByte(0xAD);
          
        } else if (rt.equals("float")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.floatValue:()F
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_FLOAT_VALUE_METHOD));
          
          // freturn
          data.writeByte(0xAE);
          
        } else if (rt.equals("double")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.doubleValue:()D
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_DOUBLE_VALUE_METHOD));
          
          // dreturn
          data.writeByte(0xAF);
          
        } else if (rt.equals("byte")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.byteValue:()B
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_BYTE_VALUE_METHOD));
          
          // ireturn
          data.writeByte(0xAC);
          
        } else if (rt.equals("short")) {
          // checkcast java.lang.Number
          data.writeByte(0xC0);
          data.writeShort(cp.put(NUMBER_IDENTIFIER));
          
          // invokevirtual java/lang/Number.shortValue:()S
          data.writeByte(0xB6);
          data.writeShort(cp.put(NUMBER_SHORT_VALUE_METHOD));
          
          // ireturn
          data.writeByte(0xAC);
          
        } else if (rt.equals("boolean")) {
          // checkcast java.lang.Boolean
          data.writeByte(0xC0);
          data.writeShort(cp.put(BOOLEAN_IDENTIFIER));
          
          // invokevirtual java/lang/Boolean.booleanValue:()Z
          data.writeByte(0xB6);
          data.writeShort(cp.put(BOOLEAN_BOOLEAN_VALUE_METHOD));
          
          // ireturn
          data.writeByte(0xAC);
          
        } else if (rt.equals("char")) {
          // checkcast java.lang.Character
          data.writeByte(0xC0);
          data.writeShort(cp.put(CHARACTER_IDENTIFIER));
          
          // invokevirtual java/lang/Character.charValue:()C
          data.writeByte(0xB6);
          data.writeShort(cp.put(CHARACTER_CHAR_VALUE_METHOD));
          
          // ireturn
          data.writeByte(0xAC);
          
        } else {
          // checkcast <rt>
          data.writeByte(0xC0);
          data.writeShort
            (cp.put(new ClassIdentifier(JVMUtilities.getName(rt))));
          
          // areturn
          data.writeByte(0xB0);
        }
        
        // Exceptions ////////////////////////////////////////////////////////
        
        short tryEnd = (short)data.size();
        
        // Create the handler bytecode
        if (ex.length > 0) {
          maxLocals += 2;
          
          // catch (ThrownException e)
          astore(maxLocals - 2, data);
          aload(maxLocals - 2, data);
          
          // Exception ex = e.getException();
          
          // invokevirtual e.getException()
          data.writeByte(0xB6);
          data.writeShort(cp.put(thrownExceptionMethod));
          
          astore(maxLocals - 1, data);
          
          // if (ex instanceof <ex[i]>) throw (<ex[i]>)ex;
          for (int i = 0; i < ex.length; i++) {
            // instanceof <ex[i]>
            aload(maxLocals - 1, data);
            data.writeByte(0xC1);
            s = cp.put(new ClassIdentifier(JVMUtilities.getName(ex[i])));
            data.writeShort(s);
            
            // ifeq ...
            data.writeByte(0x99);
            if (maxLocals < 5) {
              // ... 8
              data.writeShort(0x08);
            } else {
              // ... 9
              data.writeShort(0x09);
            }
            
            aload(maxLocals - 1, data);
            
            // checkcast <ex[i]>
            data.writeByte(0xC0);
            data.writeShort(s);
            
            // athrow
            data.writeByte(0xBF);
          }
          
          aload(maxLocals - 2, data);
          
          // athrow
          data.writeByte(0xBF);
        }
        
        CodeAttribute ca = mi.createCodeAttribute();
        ca.setCode(bytes.toByteArray(), maxLocals, maxStack);
        
        // Fill the exception table
        if (ex.length > 0) {
          ca.addExceptionTableEntry
            (tryStart, tryEnd, tryEnd, thrownExceptionName);
        }
      } // end if (!mi.isAbstract())
      
      // Adds the exceptions to the exceptions attribute
      if (ex.length > 0) {
        ExceptionsAttribute ea = mi.createExceptionsAttribute();
        for (int i = 0; i < ex.length; i++) {
          ea.addException(ex[i]);
        }
      }
      
      return result;
    } catch (IOException e) {
      // Should never append
      e.printStackTrace();      
    }
    return null;
  }
  
  /**
   * Returns the generated class
   */
  public byte[] getByteCode() {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
      write(out);
      
      /*
       File f = new File(name+"xxx.class");
       FileOutputStream fos = new FileOutputStream(f);
       fos.write(out.toByteArray());
       fos.close();
       */
      
    } catch (IOException e) {
      // Should never append
      e.printStackTrace();
    }
    return out.toByteArray();
  }
  
  /**
   * This method generates the code that loads a local variable on the stack
   * @param local  the local variable to load
   * @param data   the stream where the code is written     
   */
  private void iload(int local, DataOutputStream data) throws IOException {
    if (local < 4) {
      // iload_<local>
      data.writeByte(0x1A + local);
    } else {
      // iload <local>
      data.writeByte(0x15);
      data.writeByte(local);
    }
  }
  
  /**
   * This method generates the code that loads a local variable on the stack
   * @param local  the local variable to load
   * @param data   the stream where the code is written     
   */
  private void aload(int local, DataOutputStream data) throws IOException {
    if (local < 4) {
      // aload_<local>
      data.writeByte(0x2A + local);
    } else {
      // aload <local>
      data.writeByte(0x19);
      data.writeByte(local);
    }
  }
  
  /**
   * This method generates the code that stores a local variable from the stack
   * @param local  the local variable to store
   * @param data   the stream where the code is written     
   */
  private void astore(int local, DataOutputStream data) throws IOException {
    if (local < 4) {
      // aload_<local>
      data.writeByte(0x4B + local);
    } else {
      // aload <local>
      data.writeByte(0x3A);
      data.writeByte(local);
    }
  }
  
  /**
   * This method generates the code that push a byte constant on the stack
   * @param cst  the local variable to store
   * @param data the stream where the code is written     
   */
  private void bipush(int cst, DataOutputStream data) throws IOException {
    if (cst < 6) {
      // iconst_<i>
      data.writeByte(0x03 + cst);
    } else {
      // bipush <i>
      data.writeByte(0x10);
      data.writeByte(cst);
    }
  }
  
  /**
   * This method generates the code that puts an int argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadInt(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Integer (new <java/lang/Integer>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(INTEGER_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);
    
    // Load the argument
    if (currentLocal < 4) {
      // iload_<i>
      data.writeByte(0x1A + currentLocal);
    } else {
      // iload <i>
      data.writeByte(0x15);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Integer.<init>:(I)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(INTEGER_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a long argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadLong(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Long (new <java/lang/Long>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(LONG_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // lload_<i>
      data.writeByte(0x1E + currentLocal);
    } else {
      // lload <i>
      data.writeByte(0x16);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Long.<init>:(J)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(LONG_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a float argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadFloat(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Float (new <java/lang/Float>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(FLOAT_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // fload_<i>
      data.writeByte(0x22 + currentLocal);
    } else {
      // fload <i>
      data.writeByte(0x17);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Float.<init>:(F)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(FLOAT_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a double argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadDouble(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Double (new <java/lang/Double>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(DOUBLE_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // fload_<i>
      data.writeByte(0x26 + currentLocal);
    } else {
      // fload <i>
      data.writeByte(0x18);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Double.<init>:(D)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(DOUBLE_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a byte argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadByte(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Byte (new <java/lang/Byte>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(BYTE_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // iload_<i>
      data.writeByte(0x1A + currentLocal);
    } else {
      // iload <i>
      data.writeByte(0x15);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Byte.<init>:(B)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(BYTE_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a short argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadShort(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Short (new <java/lang/Short>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(SHORT_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // iload_<i>
      data.writeByte(0x1A + currentLocal);
    } else {
      // iload <i>
      data.writeByte(0x15);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Short.<init>:(S)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(SHORT_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a boolean argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadBoolean(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Boolean (new <java/lang/Boolean>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(BOOLEAN_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);    
    
    // Load the argument
    if (currentLocal < 4) {
      // iload_<i>
      data.writeByte(0x1A + currentLocal);
    } else {
      // iload <i>
      data.writeByte(0x15);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Boolean.<init>:(B)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(BOOLEAN_CONSTRUCTOR));
  }
  
  /**
   * This method generates the code that puts a char argument in the
   * table passed to 'Interpreter.invokeMethod'
   * @param currentLocal the current parameter
   * @param data         the stream where the code is written
   * @param cp           the constant pool
   */
  private void loadChar(int currentLocal, DataOutputStream data, ConstantPool cp)
    throws IOException {
    // Create a new Character (new <java/lang/Character>)
    data.writeByte(0xBB);
    data.writeShort(cp.put(CHARACTER_IDENTIFIER));
    
    // duplicate the top operand (dup)
    data.writeByte(0x59);      
    
    // Load the argument
    if (currentLocal < 4) {
      // iload_<i>
      data.writeByte(0x1A + currentLocal);
    } else {
      // iload <i>
      data.writeByte(0x15);
      data.writeByte(currentLocal);
    }
    
    // Calls <init> (invokespecial <java/lang/Character.<init>:(C)V>)
    data.writeByte(0xB7);
    data.writeShort(cp.put(CHARACTER_CONSTRUCTOR));
  }
}




See more files for this project here

DrJava

DrJava is a lightweight programming environment for Java designed to foster test-driven software development. It includes an intelligent program editor, an interactions pane for evaluating program text, a source level debugger, and a unit testing tool.

Project homepage: http://sourceforge.net/projects/drjava
Programming language(s): Java
License: other

  context/
    AbstractVariable.java
    Context.java
    GlobalContext.java
    MethodContext.java
    MethodModificationError.java
    NoSuchFunctionException.java
    NoSuchKeyException.java
    SimpleContext.java
    StaticContext.java
    VariableContext.java
    VariableContextTest.java
    package.html
  error/
    BreakException.java
    CatchedExceptionError.java
    ContinueException.java
    ExecutionError.java
    PossibleExecutionError.java
    ReturnException.java
    ThrownException.java
    WrongVersionException.java
    package.html
  modifier/
    ArrayModifier.java
    FinalVariableModifier.java
    InvalidModifier.java
    LeftHandSideModifier.java
    ObjectFieldModifier.java
    StaticFieldModifier.java
    SuperFieldModifier.java
    VariableModifier.java
    package.html
  resources/
    messages.properties
  AbstractTypeChecker.java
  ClassFactory.java
  ClassInfoCompiler.java
  ClassLoaderContainer.java
  ClassPool.java
  DynamicjavaTest.java
  EvaluationVisitor.java
  EvaluationVisitorTest.java
  ForEachNamingTest.java
  ForEachTypingTest.java
  Interpreter.java
  InterpreterException.java
  InterpreterUtilities.java
  Main.java
  NameVisitor.java
  NodeProperties.java
  TreeClassFinder.java
  TreeClassLoader.java
  TreeCompiler.java
  TreeInterpreter.java
  Type.ast
  TypeChecker14.java
  TypeChecker15.java
  TypeCheckerTest.java
  TypeVariable.java
  UninitializedObject.java
  package.html