Example #1
0
 Method generate(String currentClass, ConstantPoolGen cpg) {
   InstructionList il = new InstructionList();
   int instanceOffset = 0;
   short flags = Constants.ACC_PUBLIC;
   if (invokeKind != INVOKESTATIC) {
     instanceOffset = 1;
     il.append(InstructionFactory.createThis());
   } else {
     flags |= Constants.ACC_STATIC;
   }
   int pos = 0;
   for (int i = 0; i < args.length; i++) {
     il.append(InstructionFactory.createLoad(args[i], pos + instanceOffset));
     pos += args[i].getSize();
   }
   il.append(
       new InstructionFactory(cpg)
           .createInvoke(targetClass, methodName, returnType, args, invokeKind));
   il.append(InstructionFactory.createReturn(returnType));
   MethodGen newMethod =
       new MethodGen(
           flags, returnType, args, /*argNames*/ null, accessorName, currentClass, il, cpg);
   newMethod.setMaxLocals();
   newMethod.setMaxStack();
   return newMethod.getMethod();
 }
Example #2
0
  private void createMethod(Element method) throws IllegalXMLVMException {
    il = new InstructionList();
    instructionHandlerManager = new InstructionHandlerManager(il);
    String methodName = method.getAttributeValue("name");

    Element signature = method.getChild("signature", nsXMLVM);
    Type retType = collectReturnType(signature);
    Type[] argTypes = collectArgumentTypes(signature);
    short accessFlags = getAccessFlags(method);

    if (methodName.equals(
        ".cctor")) // Same concept, different names in .net/JVM.  Note we are doing init of statics
                   // for a class
    {
      System.out.println("Changed name to clinit");
      methodName = "<clinit>";
      accessFlags = 0x8; // static
    }

    MethodGen m =
        new MethodGen(
            accessFlags, retType, argTypes, null, methodName, fullQualifiedClassName, il, _cp);
    Element code = method.getChild("code", nsXMLVM);
    createCode(code);
    instructionHandlerManager.checkConsistency();
    m.setMaxLocals();
    m.setMaxStack();
    _cg.addMethod(m.getMethod());
    il.dispose();
  }
Example #3
0
  public static void main(String[] argv) throws Exception {
    JavaClass clazz = null;

    if ((clazz = Repository.lookupClass(argv[0])) == null) {
      clazz = new ClassParser(argv[0]).parse(); // May throw IOException
    }

    ClassGen cg = new ClassGen(clazz);

    Method[] methods = clazz.getMethods();

    for (int i = 0; i < methods.length; i++) {
      MethodGen mg = new MethodGen(methods[i], cg.getClassName(), cg.getConstantPool());
      cg.replaceMethod(methods[i], mg.getMethod());
    }

    Field[] fields = clazz.getFields();

    for (int i = 0; i < fields.length; i++) {
      FieldGen fg = new FieldGen(fields[i], cg.getConstantPool());
      cg.replaceField(fields[i], fg.getField());
    }

    cg.getJavaClass().dump(clazz.getClassName() + ".clazz");
  }
Example #4
0
 byte[] nullAdaptClass(final InputStream is, final String name) throws Exception {
   JavaClass jc = new ClassParser(is, name + ".class").parse();
   ClassGen cg = new ClassGen(jc);
   String cName = cg.getClassName();
   ConstantPoolGen cp = cg.getConstantPool();
   Method[] ms = cg.getMethods();
   for (int j = 0; j < ms.length; ++j) {
     MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp);
     boolean lv = ms[j].getLocalVariableTable() == null;
     boolean ln = ms[j].getLineNumberTable() == null;
     if (lv) {
       mg.removeLocalVariables();
     }
     if (ln) {
       mg.removeLineNumbers();
     }
     mg.stripAttributes(skipDebug);
     InstructionList il = mg.getInstructionList();
     if (il != null) {
       InstructionHandle ih = il.getStart();
       while (ih != null) {
         ih = ih.getNext();
       }
       if (compute) {
         mg.setMaxStack();
         mg.setMaxLocals();
       }
     }
     cg.replaceMethod(ms[j], mg.getMethod());
   }
   return cg.getJavaClass().getBytes();
 }
  /** Checks the specific method for consistency. */
  public static void checkMgen(MethodGen mgen) {

    if (skip_checks) return;

    try {
      mgen.toString();
      mgen.getLineNumberTable(mgen.getConstantPool());

      InstructionList ilist = mgen.getInstructionList();
      if (ilist == null || ilist.getStart() == null) return;
      CodeExceptionGen[] exceptionHandlers = mgen.getExceptionHandlers();
      for (CodeExceptionGen gen : exceptionHandlers) {
        assert ilist.contains(gen.getStartPC())
            : "exception handler "
                + gen
                + " has been forgotten in "
                + mgen.getClassName()
                + "."
                + mgen.getName();
      }
      MethodGen nmg = new MethodGen(mgen.getMethod(), mgen.getClassName(), mgen.getConstantPool());
      nmg.getLineNumberTable(mgen.getConstantPool());
    } catch (Throwable t) {
      System.out.printf("failure in method %s.%s\n", mgen.getClassName(), mgen.getName());
      t.printStackTrace();
      throw new Error(t);
    }
  }
  /**
   * Adds a prefix to the original method. To make it callable only from within the framework
   * itself.
   *
   * @param mg the MethodGen
   * @param method the current method
   * @param methodSequence the methods sequence number
   * @param uuid the definition UUID
   * @return the modified method
   */
  private Method addPrefixToMethod(
      final MethodGen mg, final Method method, final int methodSequence, final String uuid) {

    // change the method access flags (should always be set to protected)
    int accessFlags = mg.getAccessFlags();
    if ((accessFlags & Constants.ACC_PROTECTED) == 0) {
      // set the protected flag
      accessFlags |= Constants.ACC_PROTECTED;
    }
    if ((accessFlags & Constants.ACC_PRIVATE) != 0) {
      // clear the private flag
      accessFlags &= ~Constants.ACC_PRIVATE;
    }
    if ((accessFlags & Constants.ACC_PUBLIC) != 0) {
      // clear the public flag
      accessFlags &= ~Constants.ACC_PUBLIC;
    }

    mg.setName(getPrefixedMethodName(method, methodSequence, mg.getClassName()));

    mg.setAccessFlags(accessFlags);

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

    return mg.getMethod();
  }
Example #7
0
  private Method generateSuperAccessor(
      ConstantPoolGen cpg,
      String className,
      SuperMethodDescriptor superMethod,
      InstructionFactory factory) {
    int endPos = superMethod.signature.indexOf(')');
    String segment = superMethod.signature.substring(1, endPos);
    String[] typeNames = (segment.length() > 0) ? segment.split(",") : new String[0];
    Type[] argTypes = new Type[typeNames.length];
    for (int i = 0; i < argTypes.length; i++) argTypes[i] = Type.getType(typeNames[i]);

    int index = superMethod.signature.lastIndexOf(')') + 1;
    Type returnType = Type.getType(superMethod.signature.substring(index));

    Type baseType = new ObjectType(className);
    Type[] wrapperTypes = new Type[argTypes.length + 1];
    System.arraycopy(argTypes, 0, wrapperTypes, 1, argTypes.length);
    wrapperTypes[0] = baseType;
    String[] argNames = new String[wrapperTypes.length];
    for (int i = 0; i < argNames.length; i++) {
      argNames[i] = "arg" + i;
    }
    InstructionList il = new InstructionList();
    MethodGen mg =
        new MethodGen(
            (Constants.ACC_PUBLIC | Constants.ACC_STATIC),
            returnType,
            wrapperTypes,
            argNames,
            OT_PREFIX + superMethod.methodName + "$super",
            className,
            il,
            cpg);
    il.append(InstructionFactory.createLoad(baseType, 0)); // first argument is base instance
    for (int i = 0; i < argTypes.length; i++)
      il.append(InstructionFactory.createLoad(argTypes[i], i + 1));

    // if super method is also callin bound directly invoke the orig-version
    // (to avoid that BaseMethodTransformation.checkReplaceWickedSuper() has to rewrite this code
    // again):
    String methodName =
        (CallinBindingManager.isBoundBaseMethod(
                superMethod.superClass, superMethod.methodName, superMethod.signature))
            ? genOrigMethName(superMethod.methodName)
            : superMethod.methodName;

    il.append(
        factory.createInvoke(
            superMethod.superClass, methodName, returnType, argTypes, INVOKESPECIAL));
    il.append(InstructionFactory.createReturn(returnType));
    mg.setMaxStack();
    mg.setMaxLocals();
    return mg.getMethod();
  }
  @Override
  public MethodGen analyseInternal(final MethodGen methodGen) {
    assert methodGen != null : "Parameter 'methodGen' of method 'analyseInternal' must not be null";

    if (!methodGen.getMethod().isAbstract() && null != methodGen.getInstructionList()) {
      final List<InstructionHandle> instnsHandleList =
          Arrays.asList(methodGen.getInstructionList().getInstructionHandles());
      instnsHandleList.forEach(t -> analyseAsVisiting(t, methodGen));
      return methodGen;
    }
    return null;
  }
Example #9
0
  private void createMethod_0() {
    InstructionList il = new InstructionList();
    MethodGen method =
        new MethodGen(
            ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] {}, "<init>", objectType, il, _cp);

    InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0));
    il.append(
        _factory.createInvoke(
            "java.lang.Object", "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
    InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID));
    method.setMaxStack();
    method.setMaxLocals();
    _cg.addMethod(method.getMethod());
    il.dispose();
  }
Example #10
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();
  }
  /**
   * Adds a join point member field.
   *
   * @param cp the ConstantPoolGen
   * @param cg the ClassGen
   * @param mg the MethodGen
   * @param methodSequence the methods sequence number
   */
  private void addJoinPointField(
      final ConstantPoolGen cp, final ClassGen cg, final MethodGen mg, final int methodSequence) {

    final String joinPoint = getJoinPointName(mg.getMethod(), methodSequence);

    if (cg.containsField(joinPoint) != null) {
      return;
    }

    final FieldGen field =
        new FieldGen(
            Constants.ACC_PRIVATE | Constants.ACC_FINAL,
            new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS),
            joinPoint,
            cp);
    cg.addField(field.getField());
  }
  public void createFixture(JavaClassGenerator classGen) {
    MethodGen methodGen =
        new MethodGen(
            Constants.ACC_PUBLIC | Constants.ACC_STATIC, // public and static
            org.apache.bcel.generic.Type.VOID, // return type
            new org.apache.bcel.generic.Type[] // parameters
            {this.getDefiningClass().toBCEL()},
            null, // parameters names: we do not care
            "fixture" + fixtureNum, // method's name
            classGen.getClassName(), // defining class
            classGen.generateJavaBytecode(getCode()), // bytecode of the method
            classGen.getConstantPool()); // constant pool

    // we must always call these methods before the getMethod()
    // method below. They set the number of local variables and stack
    // elements used by the code of the method
    methodGen.setMaxStack();
    methodGen.setMaxLocals();

    // we add a method to the class that we are generating
    classGen.addMethod(methodGen.getMethod());
  }
Example #13
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();
  }
Example #14
0
 byte[] counterAdaptClass(final InputStream is, final String name) throws Exception {
   JavaClass jc = new ClassParser(is, name + ".class").parse();
   ClassGen cg = new ClassGen(jc);
   String cName = cg.getClassName();
   ConstantPoolGen cp = cg.getConstantPool();
   if (!cg.isInterface()) {
     FieldGen fg = new FieldGen(ACC_PUBLIC, Type.getType("I"), "_counter", cp);
     cg.addField(fg.getField());
   }
   Method[] ms = cg.getMethods();
   for (int j = 0; j < ms.length; ++j) {
     MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp);
     if (!mg.getName().equals("<init>") && !mg.isStatic() && !mg.isAbstract() && !mg.isNative()) {
       if (mg.getInstructionList() != null) {
         InstructionList il = new InstructionList();
         il.append(new ALOAD(0));
         il.append(new ALOAD(0));
         il.append(new GETFIELD(cp.addFieldref(name, "_counter", "I")));
         il.append(new ICONST(1));
         il.append(new IADD());
         il.append(new PUTFIELD(cp.addFieldref(name, "_counter", "I")));
         mg.getInstructionList().insert(il);
         mg.setMaxStack(Math.max(mg.getMaxStack(), 2));
         boolean lv = ms[j].getLocalVariableTable() == null;
         boolean ln = ms[j].getLineNumberTable() == null;
         if (lv) {
           mg.removeLocalVariables();
         }
         if (ln) {
           mg.removeLineNumbers();
         }
         cg.replaceMethod(ms[j], mg.getMethod());
       }
     }
   }
   return cg.getJavaClass().getBytes();
 }
 static void nullBCELAdapt(final byte[] b) throws IOException {
   JavaClass jc = new ClassParser(new ByteArrayInputStream(b), "class-name").parse();
   ClassGen cg = new ClassGen(jc);
   ConstantPoolGen cp = cg.getConstantPool();
   Method[] ms = cg.getMethods();
   for (int k = 0; k < ms.length; ++k) {
     MethodGen mg = new MethodGen(ms[k], cg.getClassName(), cp);
     boolean lv = ms[k].getLocalVariableTable() == null;
     boolean ln = ms[k].getLineNumberTable() == null;
     if (lv) {
       mg.removeLocalVariables();
     }
     if (ln) {
       mg.removeLineNumbers();
     }
     mg.stripAttributes(skipDebug);
     InstructionList il = mg.getInstructionList();
     if (il != null) {
       InstructionHandle ih = il.getStart();
       while (ih != null) {
         ih = ih.getNext();
       }
       if (compute) {
         mg.setMaxStack();
         mg.setMaxLocals();
       }
       if (computeFrames) {
         ModifiedPass3bVerifier verif;
         verif = new ModifiedPass3bVerifier(jc, k);
         verif.do_verify();
       }
     }
     cg.replaceMethod(ms[k], mg.getMethod());
   }
   cg.getJavaClass().getBytes();
 }
Example #16
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();
  }
Example #17
0
  /**
   * Processes each method in cg replacing any specified calls with static user calls.
   *
   * @param fullClassName must be packageName.className
   */
  private boolean map_calls(ClassGen cg, String fullClassName, ClassLoader loader) {

    boolean transformed = false;

    try {
      pgen = cg.getConstantPool();

      // Loop through each method in the class
      Method[] methods = cg.getMethods();
      for (int i = 0; i < methods.length; i++) {
        MethodGen mg = new MethodGen(methods[i], cg.getClassName(), pgen);

        // Get the instruction list and skip methods with no instructions
        InstructionList il = mg.getInstructionList();
        if (il == null) continue;

        if (debug) out.format("Original code: %s%n", mg.getMethod().getCode());

        instrument_method(methods[i], mg);

        // Remove the Local variable type table attribute (if any).
        // Evidently, some changes we make require this to be updated, but
        // without BCEL support, that would be hard to do.  Just delete it
        // for now (since it is optional, and we are unlikely to be used by
        // a debugger)
        for (Attribute a : mg.getCodeAttributes()) {
          if (is_local_variable_type_table(a)) {
            mg.removeCodeAttribute(a);
          }
        }

        // Update the instruction list
        mg.setInstructionList(il);
        mg.update();

        // Update the max stack and Max Locals
        mg.setMaxLocals();
        mg.setMaxStack();
        mg.update();

        // Update the method in the class
        cg.replaceMethod(methods[i], mg.getMethod());
        if (debug) out.format("Modified code: %s%n", mg.getMethod().getCode());

        // verify the new method
        // StackVer stackver = new StackVer();
        // VerificationResult vr = stackver.do_stack_ver (mg);
        // log ("vr for method %s = %s%n", mg.getName(), vr);
        // if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
        //  System.out.printf ("Warning BCEL Verify failed for method %s: %s",
        //                     mg.getName(), vr);
        //  System.out.printf ("Code: %n%s%n", mg.getMethod().getCode());
        // System.exit(1);
        // }
      }

      cg.update();
    } catch (Exception e) {
      out.format("Unexpected exception encountered: " + e);
      e.printStackTrace();
    }

    return transformed;
  }
  /**
   * 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();
  }