User: juhalindfors
  Date: 02/02/28 11:58:14

  Added:       src/main/org/jboss/mx/capability
                        OptimizedMBeanDispatcher.java
  Log:
  byte code optimized dispatcher
  
  Revision  Changes    Path
  1.1                  
jmx/src/main/org/jboss/mx/capability/OptimizedMBeanDispatcher.java
  
  Index: OptimizedMBeanDispatcher.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.mx.capability;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.lang.reflect.InvocationTargetException;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  import java.io.File;
  import java.net.URL;
  import java.net.URLClassLoader;
  
  import javax.management.IntrospectionException;
  import javax.management.MBeanException;
  import javax.management.MBeanInfo;
  import javax.management.MBeanOperationInfo;
  import javax.management.MBeanParameterInfo;
  import javax.management.ReflectionException;
  
  import javax.management.loading.DefaultLoaderRepository;
  
  import org.apache.bcel.Constants;
  import org.apache.bcel.generic.ClassGen;
  import org.apache.bcel.generic.MethodGen;
  import org.apache.bcel.generic.ConstantPoolGen;
  import org.apache.bcel.generic.InstructionHandle;
  import org.apache.bcel.generic.InstructionList;
  import org.apache.bcel.generic.ObjectType;
  import org.apache.bcel.generic.ArrayType;
  import org.apache.bcel.generic.Type;
  
  import org.apache.bcel.generic.ACONST_NULL;
  import org.apache.bcel.generic.ALOAD;
  import org.apache.bcel.generic.AALOAD;
  import org.apache.bcel.generic.ASTORE;
  import org.apache.bcel.generic.ARETURN;
  import org.apache.bcel.generic.CHECKCAST;
  import org.apache.bcel.generic.DLOAD;
  import org.apache.bcel.generic.DSTORE;
  import org.apache.bcel.generic.FLOAD;
  import org.apache.bcel.generic.FSTORE;
  import org.apache.bcel.generic.ICONST;
  import org.apache.bcel.generic.IFEQ;
  import org.apache.bcel.generic.IFNULL;
  import org.apache.bcel.generic.IFNONNULL;
  import org.apache.bcel.generic.ILOAD;
  import org.apache.bcel.generic.IRETURN;
  import org.apache.bcel.generic.ISTORE;
  import org.apache.bcel.generic.INVOKESTATIC;
  import org.apache.bcel.generic.INVOKESPECIAL;
  import org.apache.bcel.generic.INVOKEVIRTUAL;
  import org.apache.bcel.generic.GETFIELD;
  import org.apache.bcel.generic.GETSTATIC;
  import org.apache.bcel.generic.LDC;
  import org.apache.bcel.generic.LLOAD;
  import org.apache.bcel.generic.LSTORE;
  import org.apache.bcel.generic.NEW;
  import org.apache.bcel.generic.POP;
  import org.apache.bcel.generic.PUSH;
  import org.apache.bcel.generic.RETURN;
  
  import org.apache.bcel.classfile.JavaClass;
  
  import org.jboss.mx.loading.LoaderRepository;
  
  import org.jboss.mx.metadata.AOResolver;
  
  
  /**
   * Byte code optimized dispatcher for Standard MBeans.
   *
   * @see org.jboss.mx.capability.ReflectedMBeanDispatcher
   *
   * @author  <a href="mailto:[EMAIL PROTECTED]";>Juha Lindfors</a>.
   * @version $Revision: 1.1 $
   *   
   */
  public class OptimizedMBeanDispatcher
  {
     // Constants -----------------------------------------------------
     final static Class SUPER_CLASS = ReflectedMBeanDispatcher.class;
     
     
     // Static --------------------------------------------------------
     public static ReflectedMBeanDispatcher create(MBeanInfo info, Object resource)
     {
        try
        {
           // FIXME: just a hack for now, we shouldnt use the file system,
           //        instead create a custom cl for the generated class and feed
           //        the byte stream directly
           //
           // ALSO NOTICE if youre editing the code that creates byte codes to 
           // 'build clobber' before you run test to delete the existing classes. 
           // Otherwise the system classloader will pick up the classes generated
           // from the previous run
           
           
           // construct class template
           String className     = resource.getClass().getName().replace('.', '_') + 
"_Dispatcher";
           String superClass    = SUPER_CLASS.getName();
           String fileName      = className + ".class";
           int modifiers        = Constants.ACC_PUBLIC;
           String[] interfaces  = new String[0];
           
           ClassGen clazz       = new ClassGen(className, superClass, fileName, 
modifiers, interfaces);
           ConstantPoolGen cp   = clazz.getConstantPool();
           
           clazz.addMethod(createConstructor(cp, className).getMethod());
           clazz.addMethod(createInvoke(cp, info, className, 
resource.getClass().getName()).getMethod());
           clazz.update();
           
           JavaClass c = clazz.getJavaClass();
           
           File file = new File("output\\classes\\" + fileName);
           c.dump(file);
           
           Class dispatcherClass = DefaultLoaderRepository.loadClass(className);
           Constructor constr = dispatcherClass.getConstructor(
                 new Class[] { MBeanInfo.class, AOResolver.class, Object.class }
           );
           
           Object o = constr.newInstance(new Object[] { info, new AOResolver(info), 
resource });
  
           return (ReflectedMBeanDispatcher)o;
        }
        catch (Exception e)
        {
           e.printStackTrace();
           throw new Error();
        }
     }
     
     /**
      * Returns the signature of a MBean operation using the grammar required by
      * the class file format, excluding the method name. <p>
      *
      * <h4>The Java Virtual Machine Specification: 4.3.3 Method Descriptors</h4>
      *
      * A method descriptor represents the parameters that the method takes and the 
value that it returns:   <br><i><pre>
      *
      * MethodDescriptor:
      *    ( ParameterDescriptor* ) ReturnDescriptor 
      * </pre></i>
      *
      * A parameter descriptor represents a parameter passed to a method:   
<br><i><pre>
      *
      * ParameterDescriptor:
      *    FieldType
      * </pre></i>
      *
      * A return descriptor represents the type of the value returned from a method. 
It is a series of characters generated by the grammar:  <br><i><pre>
      *
      * ReturnDescriptor:
      *    FieldType
      *    V
      * </pre></i>
      *
      * The character V indicates that the method returns no value (its return type is 
void).  <p>
      *
      * For example, the method descriptor for the method <br>
      *
      * <pre>  Object mymethod(int i, double d, Thread t)  </pre>
      *
      * is <br>
      *
      * <b><pre>  (IDLjava/lang/Thread;)Ljava/lang/Object;  </pre></b>
      *
      * Note that internal forms of the fully qualified names of Thread and Object are 
used in the method descriptor.
      */
     public static String getMethodDescriptor(MBeanParameterInfo[] signature, String 
returnType)
     {
        
        StringBuffer sign = new StringBuffer(256);
        sign.append("(");
        
        for (int i = 0; i < signature.length; ++i)
           sign.append(getDescriptorForType(signature[i].getName()));
  
        sign.append(")" + getDescriptorForType(returnType));
        
        return sign.toString();
     }
  
     /**
     * Returns a descriptor for a given Java type. See {@link 
java.lang.Class#getName() Class.getName()}
     * for details on the grammar for arrays and primitive types. Note that the 
internal form of the fully
     * qualified name for class Object is used, so for example, the returned 
descriptor for
     * <tt>java.lang.Object</tt> is
     *
     * <b><pre>Ljava/lang/Object;</pre></b>
     *
     * See JVM spec �4.2 and �4.3 for detailed description of the internal class name 
format and grammar notation.
     *
     * @param name  fully qualified name of the Java type
     * @return descriptor string using the JVM grammar
     */
     public static String getDescriptorForType(String name)
     {
        if (name.equals(Byte.TYPE.getName()))               return "B";
        else if (name.equals(Character.TYPE.getName()))     return "C";
        else if (name.equals(Double.TYPE.getName()))        return "D";
        else if (name.equals(Float.TYPE.getName()))         return "F";
        else if (name.equals(Integer.TYPE.getName()))       return "I";
        else if (name.equals(Long.TYPE.getName()))          return "J";
        else if (name.equals(Short.TYPE.getName()))         return "S";
        else if (name.equals(Boolean.TYPE.getName()))       return "Z";
        else if (name.equals(Void.TYPE.getName()))          return "V";
        else if (name.startsWith("["))                      return name.replace('.', 
'/');
        else                                                return "L" + 
name.replace('.', '/') + ";";
     }
  
     public static boolean isPrimitive(String name)
     {
        if (name.equals(Byte.TYPE.getName())      ||
            name.equals(Character.TYPE.getName()) ||
            name.equals(Double.TYPE.getName())    ||
            name.equals(Float.TYPE.getName())     ||
            name.equals(Integer.TYPE.getName())   ||
            name.equals(Long.TYPE.getName())      ||
            name.equals(Short.TYPE.getName())     ||
            name.equals(Boolean.TYPE.getName()))
                 
                 return true;
                 
        return false;
     }
     
     
     
     // Protected -----------------------------------------------------
     
     /**
      * creates constructor <tt>&lt;init&gt;(MBeanInfo info, AOResolver resolver, 
Object resource)</tt>
      * that calls <tt>super(info, resolver, resource)</tt> in its implementation
      *
      * @param   cp          constant pool
      * @param   className   name of the class being generated
      */
     protected static MethodGen createConstructor(ConstantPoolGen cp, String className)
     {                  
        InstructionList constrInstructions = new InstructionList();
        
        int constrRefIndex   = cp.addMethodref(
              SUPER_CLASS.getName(),
              "<init>", 
              "(" + getDescriptorForType(MBeanInfo.class.getName())
                  + getDescriptorForType(AOResolver.class.getName())
                  + getDescriptorForType(Object.class.getName())
                  + ")V"
        );
        
        constrInstructions.append(new ALOAD(0));                                   // 
Stack:  => ..., this
        constrInstructions.append(new ALOAD(1));                                   // 
Stack:  => ..., this, arg1 [MBeanInfo]
        constrInstructions.append(new ALOAD(2));                                   // 
Stack:  => ..., this, arg1 [MBeanInfo], arg2 [AOResolver]
        constrInstructions.append(new ALOAD(3));                                   // 
Stack:  => ..., this, arg1 [MBeanInfo], arg2 [AOResolver], arg3 [Object]
        constrInstructions.append(new INVOKESPECIAL(constrRefIndex));              // 
Stack:  => ...
        constrInstructions.append(new RETURN());                                   // 
Stack:  => <empty>
        
        MethodGen constrMethod = new MethodGen(
              Constants.ACC_PUBLIC,
              Type.VOID,
              new Type[] { 
                    new ObjectType(MBeanInfo.class.getName()),
                    new ObjectType(AOResolver.class.getName()),
                    new ObjectType(Object.class.getName())  },
              new String[] { "info", "resolver", "resource" },
              "<init>",
              className, constrInstructions, cp
        );
        constrMethod.setMaxStack(4);
  
        return constrMethod;
     }
  
     /**
      * Creates the implementation of the <tt>invoke(String actionName, Object[] args, 
String[] signature)</tt>
      * method. This implementation currently handles all non overloaded MBean 
operation invocations.
      * Overloaded operations still fall back to the default reflected invocations. <p>
      *
      * The Java equivalent of the implementation looks roughly as follows:<br><pre>
      *
      * public void invoke(String actionName, Object[] args, String[] signature)
      * {
      *    if (actionName != null)
      *    {
      *       try
      *       {
      *          if (actionName.equals(&lt;operName1&gt;))
      *             return ((&lt;resource 
type&gt;)super.getResourceObject()).&lt;operName1&gt;((&lt;arg1 type&gt;)arg1, 
(&lt;arg2 type&gt;)arg2, ...);
      *          else if (actionName.equals(&lt;operName2&gt;))
      *             return ((&lt;resource 
type&gt;)super.getResourceObject()).&lt;operName2&gt;((&lt;arg1 type&gt;)arg1, 
(&lt;arg2 type&gt;)arg2, ...);
      *
      *          ...
      *
      *          else
      *             super.invoke(actionName, args, signature);
      *      }
      *      catch (Throwable t)
      *      {
      *          super.invoke(actionName, args, signature);
      *      }
      *    }
      * }
      * </pre>
      *
      * @param   cp                   constant pool of the class being generated
      * @param   info                 metadata of the MBean
      * @param   className            name of the class being generated
      * @param   resourceClassName    name of the resource class being invoked
      */
     protected static MethodGen createInvoke(ConstantPoolGen cp, MBeanInfo info, 
String className, String resourceClassName)
     {
        InstructionList invokeInstructions = new InstructionList();
        MethodEntry[] operations           = getOperations(info);
        
        // load operation name strings and methods to constant pool
        for (int i = 0; i < operations.length; ++i) {
           operations[i].nameIndexInCP   = cp.addString(operations[i].getName());
           operations[i].methodIndexInCP = cp.addMethodref(
                    resourceClassName,
                    operations[i].getName(),
                    operations[i].methodDescriptor
           );
        }  
           
           
        int invokeIndex = cp.addMethodref(
              SUPER_CLASS.getName(),
              "invoke",
              "(L" + String.class.getName().replace('.', '/') + ";" 
                   + Object[].class.getName().replace('.', '/')  
                   + String[].class.getName().replace('.', '/') + ")L" 
                   + Object.class.getName().replace('.', '/') + ";"
        );
  
        int getResourceObjectIndex = cp.addMethodref(
              SUPER_CLASS.getName(),
              "getResourceObject",
              "()Ljava/lang/Object;"
        );
  
        int strEqualsIndex = cp.addMethodref(
              String.class.getName(),
              "equals",
              "(L" + Object.class.getName().replace('.', '/') + ";)" 
                   + "Z"
        );
  
        InstructionHandle beginTryBlock             = null;
        InstructionHandle endTryBlock               = null;
        
        IFNULL ifOperationEqualsNull                = new IFNULL(null);
        IFEQ operationElseIfBranch                  = null;
        
        if (operations.length > 0)
        {
           //
           //    if (actionName != null)
           //
           invokeInstructions.append(new ALOAD(1));                                   
// Stack:  => ..., arg1 [String]
           
           beginTryBlock = 
              invokeInstructions.append(ifOperationEqualsNull);                       
// Stack:  => ...
  
           for (int i = 0; i < operations.length; ++i)
           {
              //
              //  if (actionName.equals(operations[i].getName());
              //
              InstructionHandle jumpToNextElse = 
                    invokeInstructions.append(new ALOAD(1));                          
// Stack:  => ..., arg1 [String]
              invokeInstructions.append(new LDC(operations[i].nameIndexInCP));        
// Stack:  => ..., opName [String]          
              invokeInstructions.append(new INVOKEVIRTUAL(strEqualsIndex));           
// Stack:  => ..., 0 | 1 [boolean]
  
              // set the jump target for previous else if branch
              if (operationElseIfBranch != null)
                 operationElseIfBranch.setTarget(jumpToNextElse);
           
              operationElseIfBranch = new IFEQ(null);
              invokeInstructions.append(operationElseIfBranch);                       
// Stack:  => ...
  
              invokeInstructions.append(new ALOAD(0));                                
// Stack:  => ..., this
              invokeInstructions.append(new INVOKEVIRTUAL(getResourceObjectIndex));   
// Stack:  => ..., resource [Object]
           
              int x = cp.addClass(resourceClassName);
              invokeInstructions.append(new CHECKCAST(x));                            
// Stack:  => ..., resource [<resource object type>]
           
              // if invocation has args, we need to push them into stack
              if (operations[i].getSignature().length > 0)
              {
                 
                 for (int arrayIndex = 0; arrayIndex < 
operations[i].getSignature().length; ++arrayIndex)
                 {
                    invokeInstructions.append(new ALOAD(2));                          
// Stack:  => ..., resource [<type>], arg2 [Object[]]
                    invokeInstructions.append(new PUSH(cp, arrayIndex));              
// Stack:  => ..., resource [<type>], arg2 [Object[]], array index [int]
                    invokeInstructions.append(new AALOAD());                          
// Stack:  => ..., resource [<type>], array[index] [Object]
  
                    // Args come in as objects. If signature has a primitive type
                    // we need to convert the arg before we can invoke the operation
                    String type = operations[i].getSignature() [arrayIndex].getName();
                    
                    if (isPrimitive(type))
                       invokeInstructions.append(convertObjectToPrimitive(cp, type)); 
// Stack:  => ..., resource[<type>], value [<primitive>]
        
                    else
                    {
                       x = cp.addClass(type);
                       invokeInstructions.append(new CHECKCAST(x));                   
// Stack:  => ..., resource[<type>], value [<reference>]                    
                    }
                 }
              }
              
              //
              //    resource.<operation>(<arg 1, ... arg n>)
              //
              x = operations[i].methodIndexInCP;
              invokeInstructions.append(new INVOKEVIRTUAL(x));                        
// Stack:  => ..., returnvalue
              
              // Wrap primitive return values into their corresponding wrapper objects
              String type = operations[i].getReturnType();
              
              if (isPrimitive(type))
              {
                 invokeInstructions.append(convertPrimitiveToObject(cp, type));       
// Stack:  => ..., objectref [wrapper]    
                 invokeInstructions.append(new ARETURN());                            
// Stack:  => <empty>
              }
              else if (type.equals(Void.TYPE.getName())) 
              {
                 invokeInstructions.append(new ACONST_NULL());                        
// Stack:  => ..., null
                 invokeInstructions.append(new ARETURN());                            
// Stack:  => <empty>
              }
              else
              {
                 invokeInstructions.append(new ARETURN());                            
// Stack:  => <empty>
              }
           }
        }
        
        //
        //  super.invoke(actionName, args, signature)  if no match was found
        //
        InstructionHandle jumpToSuperInvoke = 
              invokeInstructions.append(new ALOAD(0));                                
// Stack:  => ..., this
        invokeInstructions.append(new ALOAD(1));                                      
// Stack:  => ..., this, arg1 [String]
        invokeInstructions.append(new ALOAD(2));                                      
// Stack:  => ..., this, arg1 [String], arg2 [Object[]]
        invokeInstructions.append(new ALOAD(3));                                      
// Stack:  => ..., this, arg1 [String], arg2 [Object[]], arg3 [String[]]
        invokeInstructions.append(new INVOKESPECIAL(invokeIndex));                    
// Stack:  => ..., reference [Object]
        invokeInstructions.append(new ARETURN());                                     
// Stack:  => <empty>
  
        // set the jump targets
        ifOperationEqualsNull.setTarget(jumpToSuperInvoke);
        
        if (operations.length > 0)
        {
           // set the last else branch to call super.invoke
           if (operationElseIfBranch != null)
              operationElseIfBranch.setTarget(jumpToSuperInvoke);
  
           // set the try catch block limits
           beginTryBlock = beginTryBlock.getNext();
           endTryBlock = jumpToSuperInvoke.getPrev();
        }
  
  
        // exception handler (it's a cheap shot -- if there is any exception, re-invoke
        // on super class and let it handle all exceptions)
        InstructionHandle exceptionHandlerCode = 
              invokeInstructions.append(new ALOAD(0));
        invokeInstructions.append(new ALOAD(1));
        invokeInstructions.append(new ALOAD(2));
        invokeInstructions.append(new ALOAD(3));
        invokeInstructions.append(new INVOKESPECIAL(invokeIndex));
        invokeInstructions.append(new ARETURN());
        
        MethodGen invokeMethod = new MethodGen(
              Constants.ACC_PUBLIC,
              Type.OBJECT,
              new Type[] { 
                    Type.STRING,
                    new ArrayType(Object.class.getName(), 1),
                    new ArrayType(String.class.getName(), 1)
              },
              new String[] { 
                    "operationName",
                    "args",
                    "signature"
              },
              "invoke",
              className, invokeInstructions, cp
        );
        invokeMethod.setMaxLocals(7);
        invokeMethod.setMaxStack(calculateMaxStackSize(info));
        
        invokeMethod.addException(ReflectionException.class.getName());
        invokeMethod.addException(MBeanException.class.getName());
        
        if (operations.length > 0) {
           invokeMethod.addExceptionHandler(beginTryBlock, endTryBlock, 
exceptionHandlerCode, new ObjectType("java.lang.Throwable"));
        }
        
        return invokeMethod;
     }
     
     private static int calculateMaxStackSize(MBeanInfo info)
     {
        MBeanOperationInfo[] operations = info.getOperations();
        int maxSize = 7;
        
        for (int i = 0; i < operations.length; ++i)
        {
           if (operations[i].getSignature().length > maxSize + 2)
              maxSize = operations[i].getSignature().length + 2;
        }
  
        return maxSize;
     }
     
     /**
      * Converts a reference to a primitve wrapper object into a primite value type.
      * This method assumes that the wrapper object reference is already loaded at the
      * top of the operand stack. The stack is modified so that the object reference
      * to a primitive wrapper is replaced by the corresponding value in the stack.
      *
      * @param   cp    constant pool
      * @param   type  class name of the primitive wrapper object to convert
      * @return  an instruction list that replaces an object reference of a primitive
      *          wrapper object to its corresponding value in the operand stack
      */
     protected static InstructionList convertObjectToPrimitive(ConstantPoolGen cp, 
String type)
     {
        InstructionList il = new InstructionList();
  
        int intValueIndex     = cp.addMethodref(Integer.class.getName(), "intValue", 
"()I");
        int byteValueIndex    = cp.addMethodref(Byte.class.getName(), "byteValue", 
"()B");
        int charValueIndex    = cp.addMethodref(Character.class.getName(), 
"charValue", "()C");
        int doubleValueIndex  = cp.addMethodref(Double.class.getName(), "doubleValue", 
"()D");
        int floatValueIndex   = cp.addMethodref(Float.class.getName(), "floatValue", 
"()F");
        int longValueIndex    = cp.addMethodref(Long.class.getName(), "longValue", 
"()J");
        int shortValueIndex   = cp.addMethodref(Short.class.getName(), "shortValue", 
"()S");
        int booleanValueIndex = cp.addMethodref(Boolean.class.getName(), 
"booleanValue", "()Z");
  
        //
        // Assumes the wrapper object reference is on top of the stack
        //
        
        if (type.equals(Integer.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Integer");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Integer]
           il.append(new INVOKEVIRTUAL(intValueIndex));                            // 
Stack:  => ..., value [int]                     
        }
        
        else if (type.equals(Byte.TYPE.getName()))
        {  
           int x = cp.addClass("java.lang.Byte");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Boolean]
           il.append(new INVOKEVIRTUAL(byteValueIndex));                           // 
Stack:  => ..., 0 | 1 [boolean]
        }
        
        else if (type.equals(Character.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Character");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Character]
           il.append(new INVOKEVIRTUAL(charValueIndex));                           // 
Stack:  => ..., value [char]
        }
        
        else if (type.equals(Double.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Double");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Double]
           il.append(new INVOKEVIRTUAL(doubleValueIndex));                         // 
Stack:  => ..., value [double]
        }
        
        else if (type.equals(Float.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Float");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Float]
           il.append(new INVOKEVIRTUAL(floatValueIndex));                          // 
Stack:  => ..., value [float]
        }
        
        else if (type.equals(Long.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Long");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Long]
           il.append(new INVOKEVIRTUAL(longValueIndex));                           // 
Stack:  => ..., value [long]
        }
        
        else if (type.equals(Short.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Short");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Short]
           il.append(new INVOKEVIRTUAL(shortValueIndex));                          // 
Stack:  => ..., value [short]
        }
        
        else if (type.equals(Boolean.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Boolean");
           il.append(new CHECKCAST(x));                                            // 
Stack:  => ..., type [Boolean]
           il.append(new INVOKEVIRTUAL(booleanValueIndex));                        // 
Stack:  => ..., value [boolean]
        }
        
        return il;
     }
                    
     
     /**
      * Converts a primitive into its corresponding object wrapper reference.
      * This method assumes the primitve is already pushed to the top of the operand
      * stack. The stack is modified so that the primitive value is replaced
      * by a reference to its corresponding wrapper object that has been
      * initialized to contain the same value.
      *
      * @param   cp    constant pool
      * @param   type  type string of the primitive, for example {@link 
java.lang.Integer#TYPE Integer.TYPE.getName()}
      * @return  an instruction list that replaces the primitive type at the top of
      *          the operand stack with its corresponding, initialized, wrapper object
      */
     protected static InstructionList convertPrimitiveToObject(ConstantPoolGen cp, 
String type)
     {
        InstructionList il = new InstructionList();
          
        if (type.equals(Boolean.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Boolean");
           int constrIndex = cp.addMethodref("java.lang.Boolean", "<init>", "(B)V");
           
           il.append(new ISTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new ILOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
        
        else if (type.equals(Short.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Short");
           int constrIndex = cp.addMethodref("java.lang.Short", "<init>", "(S)V");
           
           il.append(new ISTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new ILOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
        
        else if (type.equals(Long.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Long");
           int constrIndex = cp.addMethodref("java.lang.Long", "<init>", "(J)V");
           
           il.append(new LSTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(6));
           il.append(new ALOAD(6));
           il.append(new LLOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(6));
        }
        
        else if (type.equals(Integer.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Integer");
           int constrIndex = cp.addMethodref("java.lang.Integer", "<init>", "(I)V");
           
           il.append(new ISTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new ILOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
        
        else if (type.equals(Float.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Float");
           int constrIndex = cp.addMethodref("java.lang.Float", "<init>", "(F)V");
           
           il.append(new FSTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new FLOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
        
        else if (type.equals(Double.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Double");
           int constrIndex = cp.addMethodref("java.lang.Double", "<init>", "(D)V");
           
           il.append(new DSTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(6));
           il.append(new ALOAD(6));
           il.append(new DLOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(6));
        }
        
        else if (type.equals(Character.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Character");
           int constrIndex = cp.addMethodref("java.lang.Character", "<init>", "(C)V");
           
           il.append(new ISTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new ILOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
        
        else if (type.equals(Byte.TYPE.getName()))
        {
           int x = cp.addClass("java.lang.Byte");
           int constrIndex = cp.addMethodref("java.lang.Byte", "<init>", "(B)V");
           
           il.append(new ISTORE(4));
           il.append(new NEW(x));
           il.append(new ASTORE(5));
           il.append(new ALOAD(5));
           il.append(new ILOAD(4));
           il.append(new INVOKESPECIAL(constrIndex));
           il.append(new ALOAD(5));
        }
  
        return il;
     }
  
                    
     /**
      * Returns a subset of MBean's operations. Overloaded operations are not 
supported yet,
      * so they're left out of the list and their invocations are delegated to the 
reflection
      * based super class. <p>
      * 
      * Overloaded operations that differ in their arg list length may be able to gain 
in
      * performance if implemented directly with byte code. Overloaded operations with
      * equal arg list length may not show much difference compared to ternary search 
tree
      * based resolver.
      */
     protected static MethodEntry[] getOperations(MBeanInfo info)
     {
        HashMap operationMap            = new HashMap();
        ArrayList overloadList          = new ArrayList();
        MBeanOperationInfo[] operations = info.getOperations();
        
        for (int i = 0; i < operations.length; ++i)
        {
           String methodName = operations[i].getName();
           
           if (operationMap.containsKey(methodName))
              overloadList.add(methodName);       
           else
              operationMap.put(methodName, new MethodEntry(operations[i]));
        }   
        
        // method overloading not supported yet
        Iterator it = overloadList.iterator();
        while (it.hasNext())
           operationMap.remove(it.next());
           
        return (MethodEntry[])operationMap.values().toArray(new MethodEntry[0]);
     }
     
        
     // Inner classes -------------------------------------------------   
     private static class MethodEntry extends MBeanOperationInfo {
     
        String methodDescriptor = null;
        int nameIndexInCP       = -1;
        int methodIndexInCP     = -1;
        
        public MethodEntry(MBeanOperationInfo info)
        {
           super(info.getName(), info.getDescription(), info.getSignature(), 
info.getReturnType(), info.getImpact());
  
           this.methodDescriptor = getMethodDescriptor(info.getSignature(), 
info.getReturnType());
        }
     }
  
     
  }
        
  
  
  
  
  
  

_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to