/**
   * Transforms the init method to create the newly added join point member field.
   *
   * @param cp the ConstantPoolGen
   * @param cg the ClassGen
   * @param init the constructor for the class
   * @param method the current method
   * @param factory the objectfactory
   * @param methodSequence the methods sequence number
   * @return the modified constructor
   */
  private MethodGen createJoinPointField(
      final ConstantPoolGen cp,
      final ClassGen cg,
      final Method init,
      final Method method,
      final InstructionFactory factory,
      final int methodSequence) {

    final MethodGen mg = new MethodGen(init, cg.getClassName(), cp);
    final InstructionList il = mg.getInstructionList();
    final InstructionHandle[] ihs = il.getInstructionHandles();

    // grab the handle to the the return instruction of the constructor
    InstructionHandle ih = ihs[0];
    for (int i = 0; i < ihs.length; i++) {
      Instruction instruction = ihs[i].getInstruction();
      if (instruction instanceof ReturnInstruction) {
        ih = ihs[i]; // set the instruction handle to the return instruction
        break;
      }
    }

    final String joinPoint = getJoinPointName(method, methodSequence);

    final InstructionHandle ihPost;
    ihPost = il.insert(ih, factory.createLoad(Type.OBJECT, 0));
    il.insert(ih, factory.createNew(TransformationUtil.THREAD_LOCAL_CLASS));

    il.insert(ih, InstructionConstants.DUP);

    il.insert(
        ih,
        factory.createInvoke(
            TransformationUtil.THREAD_LOCAL_CLASS,
            "<init>",
            Type.VOID,
            new Type[] {},
            Constants.INVOKESPECIAL));

    il.insert(
        ih,
        factory.createFieldAccess(
            cg.getClassName(),
            joinPoint,
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            Constants.PUTFIELD));
    il.redirectBranches(ih, ihPost);

    mg.setMaxStack();
    mg.setMaxLocals();

    return mg;
  }
Beispiel #2
0
  /**
   * Generates a setter method for the field described by 'fd' in the class 'class_name'.
   *
   * @param cpg the ConstantPoolGen of the class
   * @param class_name the name of the class
   * @param fd the FieldDescriptor describing the affected field
   * @param factory an InstructionFactory for this class
   * @return the generated getter method
   */
  private Method generateSetter(
      ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory) {
    String fieldName = fd.getFieldName();
    Type fieldType = Type.getType(fd.getFieldSignature());
    Type baseType = new ObjectType(class_name);

    Type[] argumentTypes;
    String[] argumentNames;
    if (fd.isStaticField()) {
      argumentTypes = new Type[] {fieldType};
      argumentNames = new String[] {"new_value"};
    } else {
      argumentTypes = new Type[] {baseType, fieldType};
      argumentNames = new String[] {"base_obj", "new_value"};
    }

    InstructionList il = new InstructionList();
    MethodGen mg =
        new MethodGen(
            (Constants.ACC_PUBLIC | Constants.ACC_STATIC),
            Type.VOID,
            argumentTypes,
            argumentNames,
            OT_PREFIX + "set$" + fieldName,
            class_name,
            il,
            cpg);

    int argumentPosition; // position for the argument holding the new field value.
    if (!fd.isStaticField()) {
      il.append(
          InstructionFactory.createLoad(
              baseType, 0)); // first argument is at slot 0 in static methods
      argumentPosition = 1;
    } else {
      argumentPosition = 0;
    }
    il.append(InstructionFactory.createLoad(fieldType, argumentPosition));
    short fieldKind = fd.isStaticField() ? Constants.PUTSTATIC : Constants.PUTFIELD;
    il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind));
    il.append(InstructionFactory.createReturn(Type.VOID));

    mg.removeNOPs();
    mg.setMaxStack();
    mg.setMaxLocals();
    return mg.getMethod();
  }
Beispiel #3
0
  /**
   * Generates a getter method for the field described by 'fd' in the class 'class_name'.
   *
   * @param cpg the ConstantPoolGen of the class
   * @param class_name the name of the class
   * @param fd the FieldDescriptor describing the affected field
   * @param factory an InstructionFactory for this class
   * @return the generated getter method
   */
  private Method generateGetter(
      ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory) {
    String fieldName = fd.getFieldName();
    Type fieldType = Type.getType(fd.getFieldSignature());
    Type baseType = new ObjectType(class_name);

    InstructionList il = new InstructionList();
    String[] argumentNames;
    Type[] argumentTypes;
    if (fd.isStaticField()) {
      argumentNames = new String[0];
      argumentTypes = new Type[0];
    } else {
      argumentNames = new String[] {"base_obj"};
      argumentTypes = new Type[] {baseType};
    }
    MethodGen mg =
        new MethodGen(
            (Constants.ACC_PUBLIC | Constants.ACC_STATIC),
            fieldType,
            argumentTypes,
            argumentNames,
            OT_PREFIX + "get$" + fieldName,
            class_name,
            il,
            cpg);
    if (!fd.isStaticField())
      il.append(
          InstructionFactory.createLoad(
              baseType, 0)); // first argument is at slot 0 in static methods
    short fieldKind = fd.isStaticField() ? Constants.GETSTATIC : Constants.GETFIELD;
    il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind));
    il.append(InstructionFactory.createReturn(fieldType));

    mg.removeNOPs();
    mg.setMaxStack();
    mg.setMaxLocals();
    return mg.getMethod();
  }
Beispiel #4
0
  private static void addTimer(ClassGen cgen, Method method) {

    // set up the construction tools
    InstructionFactory ifact = new InstructionFactory(cgen);
    InstructionList ilist = new InstructionList();
    ConstantPoolGen pgen = cgen.getConstantPool();
    String cname = cgen.getClassName();
    MethodGen wrapgen = new MethodGen(method, cname, pgen);
    wrapgen.setInstructionList(ilist);

    // rename a copy of the original method
    MethodGen methgen = new MethodGen(method, cname, pgen);
    cgen.removeMethod(method);
    String iname = methgen.getName() + "_timing";
    methgen.setName(iname);
    cgen.addMethod(methgen.getMethod());
    Type result = methgen.getReturnType();

    // compute the size of the calling parameters
    Type[] parameters = methgen.getArgumentTypes();
    int stackIndex = methgen.isStatic() ? 0 : 1;
    for (int i = 0; i < parameters.length; i++) {
      stackIndex += parameters[i].getSize();
    }

    // save time prior to invocation
    ilist.append(
        ifact.createInvoke(
            "java.lang.System",
            "currentTimeMillis",
            Type.LONG,
            Type.NO_ARGS,
            Constants.INVOKESTATIC));
    ilist.append(InstructionFactory.createStore(Type.LONG, stackIndex));

    // call the wrapped method
    int offset = 0;
    short invoke = Constants.INVOKESTATIC;
    if (!methgen.isStatic()) {
      ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));
      offset = 1;
      invoke = Constants.INVOKEVIRTUAL;
    }
    for (int i = 0; i < parameters.length; i++) {
      Type type = parameters[i];
      ilist.append(InstructionFactory.createLoad(type, offset));
      offset += type.getSize();
    }
    ilist.append(ifact.createInvoke(cname, iname, result, parameters, invoke));

    // store result for return later
    if (result != Type.VOID) {
      ilist.append(InstructionFactory.createStore(result, stackIndex + 2));
    }

    // print time required for method call
    ilist.append(
        ifact.createFieldAccess(
            "java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
    ilist.append(InstructionConstants.DUP);
    ilist.append(InstructionConstants.DUP);
    String text = "Call to method " + methgen.getName() + " took ";
    ilist.append(new PUSH(pgen, text));
    ilist.append(
        ifact.createInvoke(
            "java.io.PrintStream",
            "print",
            Type.VOID,
            new Type[] {Type.STRING},
            Constants.INVOKEVIRTUAL));
    ilist.append(
        ifact.createInvoke(
            "java.lang.System",
            "currentTimeMillis",
            Type.LONG,
            Type.NO_ARGS,
            Constants.INVOKESTATIC));
    ilist.append(InstructionFactory.createLoad(Type.LONG, stackIndex));
    ilist.append(InstructionConstants.LSUB);
    ilist.append(
        ifact.createInvoke(
            "java.io.PrintStream",
            "print",
            Type.VOID,
            new Type[] {Type.LONG},
            Constants.INVOKEVIRTUAL));
    ilist.append(new PUSH(pgen, " ms."));
    ilist.append(
        ifact.createInvoke(
            "java.io.PrintStream",
            "println",
            Type.VOID,
            new Type[] {Type.STRING},
            Constants.INVOKEVIRTUAL));

    // return result from wrapped method call
    if (result != Type.VOID) {
      ilist.append(InstructionFactory.createLoad(result, stackIndex + 2));
    }
    ilist.append(InstructionFactory.createReturn(result));

    // finalize the constructed method
    wrapgen.stripAttributes(true);
    wrapgen.setMaxStack();
    wrapgen.setMaxLocals();
    cgen.addMethod(wrapgen.getMethod());
    ilist.dispose();
  }
Beispiel #5
0
 public Instruction createInstructionGetstatic(Element inst) throws IllegalXMLVMException {
   String classType = inst.getAttributeValue("class-type");
   String field = inst.getAttributeValue("field");
   Type type = parseTypeString(inst.getAttributeValue("type"));
   return _factory.createFieldAccess(classType, field, type, Constants.GETSTATIC);
 }
  /**
   * Creates a proxy method for the original method specified. This method has the same signature as
   * the original method and catches the invocation for further processing by the framework before
   * redirecting to the original method.
   *
   * @todo pass the 'class' as a Class instance not a String to the join point. Add the class field
   *     to the class using BCEL (see AdviseStaticMethodTransformer.java)
   * @param cp the ConstantPoolGen
   * @param cg the ClassGen
   * @param originalMethod the current method
   * @param factory the objectfactory
   * @param methodId the id of the current method in the lookup tabl
   * @param methodSequence the methods sequence number
   * @param accessFlags the access flags of the original method
   * @param uuid the uuid for the weave model defining the pointcut
   * @param controllerClassName the class name of the controller class to use
   * @return the proxy method
   */
  private Method createProxyMethod(
      final ConstantPoolGen cp,
      final ClassGen cg,
      final MethodGen originalMethod,
      final InstructionFactory factory,
      final int methodId,
      final int methodSequence,
      final int accessFlags,
      final String uuid,
      final String controllerClassName) {

    InstructionList il = new InstructionList();

    String joinPoint = getJoinPointName(originalMethod.getMethod(), methodSequence);

    final MethodGen method =
        new MethodGen(
            accessFlags,
            Type.getReturnType(originalMethod.getSignature()),
            Type.getArgumentTypes(originalMethod.getSignature()),
            originalMethod.getArgumentNames(),
            originalMethod.getName(),
            cg.getClassName(),
            il,
            cp);

    String[] exceptions = originalMethod.getExceptions();
    for (int i = 0; i < exceptions.length; i++) {
      method.addException(exceptions[i]);
    }

    int indexParam = 1;
    int indexStack = 0;
    int indexJoinPoint = Type.getArgumentTypes(originalMethod.getSignature()).length * 2 + 1;

    // if (threadLocal == null) {
    //    threadLocal = new SerializableThreadLocal();
    // }
    il.append(factory.createLoad(Type.OBJECT, 0));
    il.append(
        factory.createFieldAccess(
            cg.getClassName(),
            joinPoint,
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            Constants.GETFIELD));

    BranchInstruction ifNotNull = factory.createBranchInstruction(Constants.IFNONNULL, null);
    il.append(ifNotNull);
    il.append(factory.createLoad(Type.OBJECT, 0));
    il.append(factory.createNew(TransformationUtil.THREAD_LOCAL_CLASS));

    il.append(InstructionConstants.DUP);
    il.append(
        factory.createInvoke(
            TransformationUtil.THREAD_LOCAL_CLASS,
            "<init>",
            Type.VOID,
            Type.NO_ARGS,
            Constants.INVOKESPECIAL));
    il.append(
        factory.createFieldAccess(
            cg.getClassName(),
            joinPoint.toString(),
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            Constants.PUTFIELD));

    // Object joinPoint = ___jp.get();
    BranchInstruction biIfNotNull = null;
    InstructionHandle ihIfNotNull = null;

    ifNotNull.setTarget(il.append(factory.createLoad(Type.OBJECT, 0)));

    il.append(
        factory.createFieldAccess(
            cg.getClassName(),
            joinPoint.toString(),
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            Constants.GETFIELD));
    il.append(
        factory.createInvoke(
            TransformationUtil.THREAD_LOCAL_CLASS,
            "get",
            Type.OBJECT,
            Type.NO_ARGS,
            Constants.INVOKEVIRTUAL));

    il.append(factory.createStore(Type.OBJECT, indexJoinPoint));
    il.append(factory.createLoad(Type.OBJECT, indexJoinPoint));

    // if (joinPoint == null) {
    biIfNotNull = factory.createBranchInstruction(Constants.IFNONNULL, null);
    il.append(biIfNotNull);

    // joinPoint = new WeakReference(new MemberMethodJoinPoint(uuid, this, "foo.bar.Baz", 10));
    //        il.append(factory.createNew(TransformationUtil.WEAK_REFERENCE_CLASS));
    //        il.append(InstructionConstants.DUP);

    il.append(factory.createNew(TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS));
    il.append(InstructionConstants.DUP);

    il.append(new PUSH(cp, uuid));
    il.append(factory.createLoad(Type.OBJECT, 0));
    il.append(new PUSH(cp, cg.getClassName()));
    il.append(new PUSH(cp, methodId));
    il.append(new PUSH(cp, controllerClassName));

    il.append(
        factory.createInvoke(
            TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS,
            "<init>",
            Type.VOID,
            new Type[] {Type.STRING, Type.OBJECT, Type.STRING, Type.INT, Type.STRING},
            Constants.INVOKESPECIAL));
    il.append(factory.createStore(Type.OBJECT, indexJoinPoint));

    // threadLocal.set(joinPoint);
    il.append(factory.createLoad(Type.OBJECT, 0));
    il.append(
        factory.createFieldAccess(
            cg.getClassName(),
            joinPoint.toString(),
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            Constants.GETFIELD));
    il.append(factory.createLoad(Type.OBJECT, indexJoinPoint));
    il.append(
        factory.createInvoke(
            TransformationUtil.THREAD_LOCAL_CLASS,
            "set",
            Type.VOID,
            new Type[] {Type.OBJECT},
            Constants.INVOKEVIRTUAL));

    ihIfNotNull = il.append(factory.createLoad(Type.OBJECT, indexJoinPoint));
    indexJoinPoint += 2;

    il.append(factory.createCheckCast(TransformationUtil.MEMBER_METHOD_JOIN_POINT_TYPE));
    il.append(factory.createStore(Type.OBJECT, indexJoinPoint));

    biIfNotNull.setTarget(ihIfNotNull);

    // if we have parameters, wrap them up
    if (Type.getArgumentTypes(originalMethod.getSignature()).length != 0) {

      // create and allocate the parameters array
      il.append(new PUSH(cp, Type.getArgumentTypes(originalMethod.getSignature()).length));
      il.append(factory.createNewArray(Type.OBJECT, (short) 1));

      il.append(InstructionConstants.DUP);
      il.append(new PUSH(cp, indexStack));
      indexStack++;

      // add all the parameters, wrap the primitive types in their object counterparts
      for (int count = 0;
          count < Type.getArgumentTypes(originalMethod.getSignature()).length;
          count++) {

        String wrapperClass = null;
        BasicType type = null;
        boolean hasLongOrDouble = false;

        if (Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof ObjectType
            || Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof ArrayType) {
          // we have an object or an array
          il.append(factory.createLoad(Type.OBJECT, indexParam));
          il.append(InstructionConstants.AASTORE);
          indexParam++;
        } else if (Type.getArgumentTypes(originalMethod.getSignature())[count]
            instanceof ArrayType) {
          // we have an array
          il.append(factory.createLoad(Type.OBJECT, indexParam));
          il.append(InstructionConstants.AASTORE);
          indexParam++;
        } else if (Type.getArgumentTypes(originalMethod.getSignature())[count]
            instanceof BasicType) {
          hasLongOrDouble = false;
          // we have a primitive type
          if ((Type.getArgumentTypes(originalMethod.getSignature())[count]).equals(Type.LONG)) {
            wrapperClass = "java.lang.Long";
            type = Type.LONG;
            hasLongOrDouble = true;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.INT)) {
            wrapperClass = "java.lang.Integer";
            type = Type.INT;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.SHORT)) {
            wrapperClass = "java.lang.Short";
            type = Type.SHORT;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.DOUBLE)) {
            wrapperClass = "java.lang.Double";
            type = Type.DOUBLE;
            hasLongOrDouble = true;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.FLOAT)) {
            wrapperClass = "java.lang.Float";
            type = Type.FLOAT;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.CHAR)) {
            wrapperClass = "java.lang.Character";
            type = Type.CHAR;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.BYTE)) {
            wrapperClass = "java.lang.Byte";
            type = Type.BYTE;
          } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count])
              .equals(Type.BOOLEAN)) {
            wrapperClass = "java.lang.Boolean";
            type = Type.BOOLEAN;
          } else {
            throw new RuntimeException(
                "unknown parameter type: "
                    + Type.getArgumentTypes(originalMethod.getSignature())[count]);
          }
          il.append(factory.createNew(wrapperClass));
          il.append(InstructionConstants.DUP);
          il.append(factory.createLoad(type, indexParam));
          il.append(
              factory.createInvoke(
                  wrapperClass, "<init>", Type.VOID, new Type[] {type}, Constants.INVOKESPECIAL));
          il.append(InstructionConstants.AASTORE);
          indexParam++;
        } // end handle basic or object type

        if (count != Type.getArgumentTypes(originalMethod.getSignature()).length - 1) {
          // if we don't have the last parameter, create the parameter on the stack
          il.append(InstructionConstants.DUP);
          il.append(new PUSH(cp, indexStack));
          indexStack++;

          // long or double needs two registers to fit
          if (hasLongOrDouble) indexParam++;
        }
      }

      // create the object array
      il.append(factory.createStore(Type.OBJECT, indexParam));

      // if threadsafe grab the newly retrieved local join point field from the stack
      il.append(factory.createLoad(Type.OBJECT, indexJoinPoint));

      // invoke joinPoint.setParameter(..)
      il.append(factory.createLoad(Type.OBJECT, indexParam));
      il.append(
          factory.createInvoke(
              TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS,
              "setParameters",
              Type.VOID,
              new Type[] {new ArrayType(Type.OBJECT, 1)},
              Constants.INVOKEVIRTUAL));
      indexParam++;
    } // end - if parameters.length != 0

    // if threadsafe grab the newly retrieved local join point field from the stack
    il.append(factory.createLoad(Type.OBJECT, indexJoinPoint));
    il.append(
        factory.createInvoke(
            TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS,
            "proceed",
            Type.OBJECT,
            Type.NO_ARGS,
            Constants.INVOKEVIRTUAL));

    if (!Type.getReturnType(originalMethod.getSignature()).equals(Type.VOID)) {
      // create the result from the invocation
      il.append(factory.createStore(Type.OBJECT, indexParam));
      il.append(factory.createLoad(Type.OBJECT, indexParam));

      // cast the result and return it, if the return type is a
      // primitive type, retrieve it from the wrapped object first
      // unless the return object is null (AW-100)
      if (Type.getReturnType(originalMethod.getSignature()) instanceof BasicType) {
        if (Type.getReturnType(originalMethod.getSignature()).equals(Type.VOID)) {; // skip
        } else {
          BranchInstruction ifNullBranch =
              factory.createBranchInstruction(Constants.IFNONNULL, null);
          InstructionHandle elseBranch = null;
          il.append(ifNullBranch);
          if (Type.getReturnType(originalMethod.getSignature()).equals(Type.LONG)) {
            il.append(new PUSH(cp, 0L));
            il.append(factory.createReturn(Type.LONG));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Long")));
            il.append(
                factory.createInvoke(
                    "java.lang.Long",
                    "longValue",
                    Type.LONG,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.INT)) {
            il.append(new PUSH(cp, 0));
            il.append(factory.createReturn(Type.INT));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Integer")));
            il.append(
                factory.createInvoke(
                    "java.lang.Integer",
                    "intValue",
                    Type.INT,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.SHORT)) {
            il.append(new PUSH(cp, (short) 0));
            il.append(factory.createReturn(Type.SHORT));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Short")));
            il.append(
                factory.createInvoke(
                    "java.lang.Short",
                    "shortValue",
                    Type.SHORT,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.DOUBLE)) {
            il.append(new PUSH(cp, 0.0d));
            il.append(factory.createReturn(Type.DOUBLE));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Double")));
            il.append(
                factory.createInvoke(
                    "java.lang.Double",
                    "doubleValue",
                    Type.DOUBLE,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.FLOAT)) {
            il.append(new PUSH(cp, 0.0f));
            il.append(factory.createReturn(Type.FLOAT));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Float")));
            il.append(
                factory.createInvoke(
                    "java.lang.Float",
                    "floatValue",
                    Type.FLOAT,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.CHAR)) {
            il.append(new PUSH(cp, '\u0000'));
            il.append(factory.createReturn(Type.CHAR));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Character")));
            il.append(
                factory.createInvoke(
                    "java.lang.Character",
                    "charValue",
                    Type.CHAR,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.BYTE)) {
            il.append(new PUSH(cp, (byte) 0));
            il.append(factory.createReturn(Type.BYTE));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Byte")));
            il.append(
                factory.createInvoke(
                    "java.lang.Byte",
                    "byteValue",
                    Type.BYTE,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.BOOLEAN)) {
            il.append(new PUSH(cp, false));
            il.append(factory.createReturn(Type.BOOLEAN));
            elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam));
            il.append(factory.createCheckCast(new ObjectType("java.lang.Boolean")));
            il.append(
                factory.createInvoke(
                    "java.lang.Boolean",
                    "booleanValue",
                    Type.BOOLEAN,
                    Type.NO_ARGS,
                    Constants.INVOKEVIRTUAL));
          } else {
            throw new Error(
                "unknown return type: " + Type.getReturnType(originalMethod.getSignature()));
          }
          ifNullBranch.setTarget(elseBranch);
        }
      } else {
        // cast the result to the right type
        il.append(
            factory.createCast(Type.OBJECT, Type.getReturnType(originalMethod.getSignature())));
      }
    }
    il.append(factory.createReturn(Type.getReturnType(originalMethod.getSignature())));

    method.setMaxStack();
    method.setMaxLocals();
    return method.getMethod();
  }