예제 #1
0
 public void getDeclaredMethod(
     ClassFile file,
     Bytecode code,
     String declaringClass,
     String methodName,
     String[] parameterTypes) {
   // get the correct class type to use to resolve the method
   MethodInformation methodInfo =
       new StaticMethodInformation(
           "getTargetClass",
           parameterTypes,
           "Ljava/lang/Class;",
           TargetInstanceProxy.class.getName());
   invokeMethodHandler(file, code, methodInfo, false, DEFAULT_METHOD_RESOLVER);
   code.addCheckcast("java/lang/Class");
   // now we have the class on the stack
   code.addLdc(methodName);
   // now we need to load the parameter types into an array
   code.addIconst(parameterTypes.length);
   code.addAnewarray("java.lang.Class");
   for (int i = 0; i < parameterTypes.length; ++i) {
     code.add(Opcode.DUP); // duplicate the array reference
     code.addIconst(i);
     // now load the class object
     String type = parameterTypes[i];
     BytecodeUtils.pushClassType(code, type);
     // and store it in the array
     code.add(Opcode.AASTORE);
   }
   code.addInvokevirtual(
       "java.lang.Class",
       "getDeclaredMethod",
       "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
 }
    public static void rewriteFakeMethod(CodeIterator methodBody, String methodDescriptor) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so it does not need to be boxed
      if (ret.length() != 1) {
        return;
      }
      byte ar = (byte) Opcode.ARETURN;
      byte[] areturn = {ar};
      // void methods are special
      if (ret.equals("V")) {

        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);
            // replace a RETURN opcode with
            // ACONST_NULL
            // ARETURN
            // to return a null value
            if (opcode == Opcode.RETURN) {
              Bytecode code = new Bytecode(methodBody.get().getConstPool());
              code.add(Opcode.ACONST_NULL);
              code.add(Opcode.ARETURN);
              methodBody.insertAt(index, code.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      } else {
        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);

            switch (opcode) {
              case Opcode.IRETURN:
              case Opcode.LRETURN:
              case Opcode.DRETURN:
              case Opcode.FRETURN:
                // write a NOP over the old return instruction
                // insert the boxing code to get an object on the stack
                Bytecode b = new Bytecode(methodBody.get().getConstPool());
                Boxing.box(b, ret.charAt(0));
                b.addOpcode(Opcode.ARETURN);
                methodBody.insertAt(index, b.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      }
    }
예제 #3
0
 /**
  * calls _initMH on the method handler and then stores the result in the methodHandler field as
  * then new methodHandler
  */
 private Bytecode createMethodHandlerInitializerBody(ClassFile proxyClassType) {
   Bytecode b = new Bytecode(proxyClassType.getConstPool(), 1, 2);
   b.add(Opcode.ALOAD_0);
   StaticMethodInformation methodInfo =
       new StaticMethodInformation(
           "_initMH", new Class[] {Object.class}, void.class, proxyClassType.getName());
   invokeMethodHandler(proxyClassType, b, methodInfo, false, DEFAULT_METHOD_RESOLVER);
   b.addCheckcast("javassist/util/proxy/MethodHandler");
   b.addPutfield(
       proxyClassType.getName(),
       "methodHandler",
       DescriptorUtils.classToStringRepresentation(MethodHandler.class));
   b.add(Opcode.RETURN);
   log.trace("Created MH initializer body for decorator proxy:  " + getBeanType());
   return b;
 }
예제 #4
0
  private void atSwitchStmnt(Stmnt st) throws CompileError {
    compileExpr(st.head());

    ArrayList prevBreakList = breakList;
    breakList = new ArrayList();
    int opcodePc = bytecode.currentPc();
    bytecode.addOpcode(LOOKUPSWITCH);
    int npads = 3 - (opcodePc & 3);
    while (npads-- > 0) bytecode.add(0);

    Stmnt body = (Stmnt) st.tail();
    int npairs = 0;
    for (ASTList list = body; list != null; list = list.tail())
      if (((Stmnt) list.head()).getOperator() == CASE) ++npairs;

    // opcodePc2 is the position at which the default jump offset is.
    int opcodePc2 = bytecode.currentPc();
    bytecode.addGap(4);
    bytecode.add32bit(npairs);
    bytecode.addGap(npairs * 8);

    long[] pairs = new long[npairs];
    int ipairs = 0;
    int defaultPc = -1;
    for (ASTList list = body; list != null; list = list.tail()) {
      Stmnt label = (Stmnt) list.head();
      int op = label.getOperator();
      if (op == DEFAULT) defaultPc = bytecode.currentPc();
      else if (op != CASE) fatal();
      else {
        pairs[ipairs++] =
            ((long) computeLabel(label.head()) << 32)
                + ((long) (bytecode.currentPc() - opcodePc) & 0xffffffff);
      }

      hasReturned = false;
      ((Stmnt) label.tail()).accept(this);
    }

    Arrays.sort(pairs);
    int pc = opcodePc2 + 8;
    for (int i = 0; i < npairs; ++i) {
      bytecode.write32bit(pc, (int) (pairs[i] >>> 32));
      bytecode.write32bit(pc + 4, (int) pairs[i]);
      pc += 8;
    }

    if (defaultPc < 0 || breakList.size() > 0) hasReturned = false;

    int endPc = bytecode.currentPc();
    if (defaultPc < 0) defaultPc = endPc;

    bytecode.write32bit(opcodePc2, defaultPc - opcodePc);

    patchGoto(breakList, endPc);
    breakList = prevBreakList;
  }
예제 #5
0
  private void initExtraHarvest() {
    try {
      CtClass terraForming =
          HookManager.getInstance()
              .getClassPool()
              .get("com.wurmonline.server.behaviours.Terraforming");

      CtClass[] paramTypes = {
        HookManager.getInstance().getClassPool().get("com.wurmonline.server.creatures.Creature"),
        CtPrimitiveType.intType,
        CtPrimitiveType.intType,
        CtPrimitiveType.booleanType,
        CtPrimitiveType.intType,
        CtPrimitiveType.floatType,
        HookManager.getInstance().getClassPool().get("com.wurmonline.server.items.Item")
      };

      CtMethod method =
          terraForming.getMethod(
              "harvest", Descriptor.ofMethod(CtPrimitiveType.booleanType, paramTypes));
      MethodInfo methodInfo = method.getMethodInfo();
      CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
      CodeIterator codeIterator = codeAttribute.iterator();

      LocalVariableAttribute attr =
          (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
      int quantityIndex = -1;
      for (int i = 0; i < attr.tableLength(); i++) {
        if ("quantity".equals(attr.variableName(i))) {
          quantityIndex = attr.index(i);
        }
      }

      if (quantityIndex == -1) {
        throw new HookException("Quantity variable can not be resolved");
      }

      while (codeIterator.hasNext()) {
        int pos = codeIterator.next();
        int op = codeIterator.byteAt(pos);
        if (op == CodeIterator.ISTORE) {
          int fieldRefIdx = codeIterator.byteAt(pos + 1);
          if (quantityIndex == fieldRefIdx) {
            Bytecode bytecode = new Bytecode(codeIterator.get().getConstPool());
            bytecode.addIconst(extraHarvest);
            bytecode.add(Bytecode.IADD);
            codeIterator.insertAt(pos, bytecode.get());
            break;
          }
        }
      }
    } catch (NotFoundException | BadBytecode e) {
      throw new HookException(e);
    }
  }
    /**
     * Gets the correct return instruction for a proxy method
     *
     * @param pool
     * @param methodDescriptor
     */
    public static void addReturnProxyMethod(String methodDescriptor, Bytecode b) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so just do an ARETURN
      if (ret.length() != 1) {
        b.addCheckcast(DescriptorUtils.getReturnTypeInJvmFormat(methodDescriptor));
        b.add(Opcode.ARETURN);
        return;
      }
      // void methods are special
      if (ret.equals("V")) {
        b.add(Opcode.RETURN);
        return;
      } else {
        // unbox the primitive type

        char tp = ret.charAt(0);
        Boxing.unbox(b, tp);
        if (tp == 'F') {
          b.add(Opcode.FRETURN);
        } else if (tp == 'D') {
          b.add(Opcode.DRETURN);
        } else if (tp == 'J') {
          b.add(Opcode.LRETURN);
        } else {
          b.add(Opcode.IRETURN);
        }
        return;
      }
    }
 /**
  * Client proxies are equal to other client proxies for the same bean.
  *
  * <p>The corresponding java code: <code>
  * return other instanceof MyProxyClassType.class
  * </code>
  */
 @Override
 protected MethodInfo generateEqualsMethod(ClassFile proxyClassType) {
   MethodInfo method =
       new MethodInfo(proxyClassType.getConstPool(), "equals", "(Ljava/lang/Object;)Z");
   method.setAccessFlags(AccessFlag.PUBLIC);
   Bytecode b = new Bytecode(proxyClassType.getConstPool());
   b.addAload(1);
   b.addInstanceof(proxyClassType.getName());
   b.add(Opcode.IRETURN);
   b.setMaxLocals(2);
   b.setMaxStack(1);
   method.setCodeAttribute(b.toCodeAttribute());
   return method;
 }
 /** Client proxies use the following hashCode: <code>MyProxyName.class.hashCode()</code> */
 @Override
 protected MethodInfo generateHashCodeMethod(ClassFile proxyClassType) {
   MethodInfo method = new MethodInfo(proxyClassType.getConstPool(), "hashCode", "()I");
   method.setAccessFlags(AccessFlag.PUBLIC);
   Bytecode b = new Bytecode(proxyClassType.getConstPool());
   // MyProxyName.class.hashCode()
   int classLocation = proxyClassType.getConstPool().addClassInfo(proxyClassType.getName());
   b.addLdc(classLocation);
   // now we have the class object on top of the stack
   b.addInvokevirtual("java.lang.Object", "hashCode", "()I");
   // now we have the hashCode
   b.add(Opcode.IRETURN);
   b.setMaxLocals(1);
   b.setMaxStack(1);
   method.setCodeAttribute(b.toCodeAttribute());
   return method;
 }
  /**
   * add a bogus constructor call to a bytecode sequence so a constructor can pass bytecode
   * validation
   *
   * @param bytecode
   */
  public static boolean addBogusConstructorCall(ClassFile file, Bytecode code) {
    MethodInfo constructorToCall = null;
    for (Object meth : file.getMethods()) {
      MethodInfo m = (MethodInfo) meth;
      if (m.getName().equals("<init>")) {
        constructorToCall = m;
        break;
      }
    }
    if (constructorToCall == null) {
      return false;
    }
    // push this onto the stack
    code.add(Bytecode.ALOAD_0);

    String[] params =
        DescriptorUtils.descriptorStringToParameterArray(constructorToCall.getDescriptor());
    for (String p : params) {
      // int char short boolean byte
      if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
        // push integer 0
        code.add(Opcode.ICONST_0);
      }
      // long
      else if (p.equals("J")) {
        code.add(Opcode.LCONST_0);
      }
      // double
      else if (p.equals("D")) {
        code.add(Opcode.DCONST_0);
      }
      // float
      else if (p.equals("F")) {
        code.add(Opcode.FCONST_0);
      }
      // arrays and reference types
      else {
        code.add(Opcode.ACONST_NULL);
      }
    }
    // all our args should be pushed onto the stack, call the constructor
    code.addInvokespecial(file.getName(), "<init>", constructorToCall.getDescriptor());
    code.add(Opcode.RETURN);
    return true;
  }
  public static void pushParametersIntoArray(Bytecode bc, String methodDescriptor) {
    String[] params = DescriptorUtils.descriptorStringToParameterArray(methodDescriptor);
    // now we need an array:
    bc.addIconst(params.length);
    bc.addAnewarray("java.lang.Object");
    // now we have our array sitting on top of the stack
    // we need to stick our parameters into it. We do this is reverse
    // as we can't pull them from the bottom of the stack
    for (int i = params.length - 1; i >= 0; --i) {

      if (DescriptorUtils.isWide(params[i])) {
        // dup the array below the wide
        bc.add(Opcode.DUP_X2);
        // now do it again so we have two copies
        bc.add(Opcode.DUP_X2);
        // now pop it, the is the equivalent of a wide swap
        bc.add(Opcode.POP);
      } else {
        // duplicate the array to place 3
        bc.add(Opcode.DUP_X1);
        // now swap
        bc.add(Opcode.SWAP);
      }
      // now the parameter is above the array
      // box it if nessesary
      if (DescriptorUtils.isPrimitive(params[i])) {
        Boxing.box(bc, params[i].charAt(0));
      }
      // add the array index
      bc.addIconst(i);
      bc.add(Opcode.SWAP);
      bc.add(Opcode.AASTORE);
      // we still have the array on the top of the stack becuase we
      // duplicated it earlier
    }
  }
  /** Add a method to a class that simply delegates to the parent implementation of the method */
  public static void addDelegatingMethod(ClassFile file, MethodData mData)
      throws BadBytecode, DuplicateMemberException {
    MethodInfo m =
        new MethodInfo(file.getConstPool(), mData.getMethodName(), mData.getDescriptor());
    m.setAccessFlags(mData.getAccessFlags());
    Bytecode code = new Bytecode(file.getConstPool());

    String[] params = DescriptorUtils.descriptorStringToParameterArray(mData.getDescriptor());
    code.add(Opcode.ALOAD_0); // push this
    int count = 1; // zero is the this pointer
    int maxLocals = 1;
    for (String p : params) {
      // int char short boolean byte
      if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
        // push integer 0
        code.addIload(count);
        maxLocals++;
      }
      // long
      else if (p.equals("J")) {
        code.addLload(count);
        maxLocals += 2;
        count++;
      }
      // double
      else if (p.equals("D")) {
        code.addDload(count);
        maxLocals += 2;
        count++;
      }
      // float
      else if (p.equals("F")) {
        code.addFload(count);
        maxLocals++;
      }
      // arrays and reference types
      else {
        code.addAload(count);
        maxLocals++;
      }
      count++;
    }
    code.addInvokespecial(file.getSuperclass(), mData.getMethodName(), mData.getDescriptor());
    String p = DescriptorUtils.getReturnTypeInJvmFormat(mData.getDescriptor());
    // int char short boolean byte
    if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
      code.add(Opcode.IRETURN);
    }
    // long
    else if (p.equals("J")) {
      code.add(Opcode.LRETURN);
    }
    // double
    else if (p.equals("D")) {
      code.add(Opcode.DRETURN);
    }
    // float
    else if (p.equals("F")) {
      code.add(Opcode.FRETURN);
    }
    // void
    else if (p.equals("V")) {
      code.add(Opcode.RETURN);
    }
    // arrays and reference types
    else {
      code.add(Opcode.ARETURN);
    }
    CodeAttribute ca = code.toCodeAttribute();
    ca.computeMaxStack();
    ca.setMaxLocals(maxLocals);
    m.setCodeAttribute(ca);
    file.addMethod(m);
  }
 /**
  * inserts a 16 bit offset into the bytecode
  *
  * @param b
  * @param value
  */
 public static void add16bit(Bytecode b, int value) {
   value = value % 65536;
   b.add(value >> 8);
   b.add(value % 256);
 }
예제 #13
0
  private void atPlusPlus(int token, ASTree oprand, Expr expr, boolean doDup) throws CompileError {
    boolean isPost = oprand == null; // ++i or i++?
    if (isPost) oprand = expr.oprand2();

    if (oprand instanceof Variable) {
      Declarator d = ((Variable) oprand).getDeclarator();
      int t = exprType = d.getType();
      arrayDim = d.getArrayDim();
      int var = getLocalVar(d);
      if (arrayDim > 0) badType(expr);

      if (t == DOUBLE) {
        bytecode.addDload(var);
        if (doDup && isPost) bytecode.addOpcode(DUP2);

        bytecode.addDconst(1.0);
        bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
        if (doDup && !isPost) bytecode.addOpcode(DUP2);

        bytecode.addDstore(var);
      } else if (t == LONG) {
        bytecode.addLload(var);
        if (doDup && isPost) bytecode.addOpcode(DUP2);

        bytecode.addLconst((long) 1);
        bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
        if (doDup && !isPost) bytecode.addOpcode(DUP2);

        bytecode.addLstore(var);
      } else if (t == FLOAT) {
        bytecode.addFload(var);
        if (doDup && isPost) bytecode.addOpcode(DUP);

        bytecode.addFconst(1.0f);
        bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
        if (doDup && !isPost) bytecode.addOpcode(DUP);

        bytecode.addFstore(var);
      } else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
        if (doDup && isPost) bytecode.addIload(var);

        int delta = token == PLUSPLUS ? 1 : -1;
        if (var > 0xff) {
          bytecode.addOpcode(WIDE);
          bytecode.addOpcode(IINC);
          bytecode.addIndex(var);
          bytecode.addIndex(delta);
        } else {
          bytecode.addOpcode(IINC);
          bytecode.add(var);
          bytecode.add(delta);
        }

        if (doDup && !isPost) bytecode.addIload(var);
      } else badType(expr);
    } else {
      if (oprand instanceof Expr) {
        Expr e = (Expr) oprand;
        if (e.getOperator() == ARRAY) {
          atArrayPlusPlus(token, isPost, e, doDup);
          return;
        }
      }

      atFieldPlusPlus(token, isPost, oprand, expr, doDup);
    }
  }
  /**
   * Calls methodHandler.invoke with a null method parameter in order to get the underlying
   * instance. The invocation is then forwarded to this instance with generated bytecode.
   */
  protected Bytecode createForwardingMethodBody(ClassFile file, MethodInformation methodInfo)
      throws NotFoundException {
    Method method = methodInfo.getMethod();
    // we can only use bytecode based invocation for some methods
    // at the moment we restrict it solely to public methods with public
    // return and parameter types
    boolean bytecodeInvocationAllowed =
        Modifier.isPublic(method.getModifiers())
            && Modifier.isPublic(method.getReturnType().getModifiers());
    for (Class<?> paramType : method.getParameterTypes()) {
      if (!Modifier.isPublic(paramType.getModifiers())) {
        bytecodeInvocationAllowed = false;
        break;
      }
    }
    if (!bytecodeInvocationAllowed) {
      return createInterceptorBody(file, methodInfo);
    }
    Bytecode b = new Bytecode(file.getConstPool());
    int localCount = MethodUtils.calculateMaxLocals(method) + 1;

    // create a new interceptor invocation context whenever we invoke a method on a client proxy
    // we use a try-catch block in order to make sure that endInterceptorContext() is invoked
    // regardless whether
    // the method has succeeded or not
    int start = b.currentPc();
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext",
        "startInterceptorContext",
        "()V");

    b.add(Opcode.ALOAD_0);
    b.addGetfield(
        file.getName(),
        "methodHandler",
        DescriptorUtils.classToStringRepresentation(MethodHandler.class));
    // pass null arguments to methodHandler.invoke
    b.add(Opcode.ALOAD_0);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);

    // now we have all our arguments on the stack
    // lets invoke the method
    b.addInvokeinterface(
        MethodHandler.class.getName(),
        "invoke",
        "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
        5);

    b.addCheckcast(methodInfo.getDeclaringClass());

    // now we should have the target bean instance on top of the stack
    // we need to dup it so we still have it to compare to the return value
    b.add(Opcode.DUP);

    // lets create the method invocation
    String methodDescriptor = methodInfo.getDescriptor();
    BytecodeUtils.loadParameters(b, methodDescriptor);
    if (method.getDeclaringClass().isInterface()) {
      b.addInvokeinterface(
          methodInfo.getDeclaringClass(),
          methodInfo.getName(),
          methodDescriptor,
          method.getParameterTypes().length + 1);
    } else {
      b.addInvokevirtual(methodInfo.getDeclaringClass(), methodInfo.getName(), methodDescriptor);
    }

    // end the interceptor context, everything was fine
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");

    // jump over the catch block
    b.addOpcode(Opcode.GOTO);
    JumpMarker gotoEnd = JumpUtils.addJumpInstruction(b);

    // create catch block
    b.addExceptionHandler(start, b.currentPc(), b.currentPc(), 0);
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");
    b.add(Opcode.ATHROW);

    // update the correct address to jump over the catch block
    gotoEnd.mark();

    // if this method returns a primitive we just return
    if (method.getReturnType().isPrimitive()) {
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    } else {
      // otherwise we have to check that the proxy is not returning 'this;
      // now we need to check if the proxy has return 'this' and if so return
      // an
      // instance of the proxy.
      // currently we have result, beanInstance on the stack.
      b.add(Opcode.DUP_X1);
      // now we have result, beanInstance, result
      // we need to compare result and beanInstance

      // first we need to build up the inner conditional that just returns
      // the
      // result
      b.add(Opcode.IF_ACMPEQ);
      JumpMarker returnInstruction = JumpUtils.addJumpInstruction(b);
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
      returnInstruction.mark();

      // now add the case where the proxy returns 'this';
      b.add(Opcode.ALOAD_0);
      b.addCheckcast(methodInfo.getMethod().getReturnType().getName());
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    }
    if (b.getMaxLocals() < localCount) {
      b.setMaxLocals(localCount);
    }
    return b;
  }
  public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass) {
    Set<Integer> methodCallLocations = new HashSet<Integer>();
    Integer newCallLocation = null;
    Integer methodReflectionLocation = null;
    Integer fakeCallRequiredLocation = null;
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
      // we have a method call
      if (pool.getTag(i) == ConstPool.CONST_Methodref) {
        String className = pool.getMethodrefClassName(i);
        String methodName = pool.getMethodrefName(i);

        if (className.equals(Method.class.getName())) {
          if (methodName.equals("invoke")) {
            // store the location in the const pool of the method ref
            methodCallLocations.add(i);
            // we have found a method call

            // if we have not already stored a reference to our new
            // method in the const pool
            if (newCallLocation == null) {
              methodReflectionLocation =
                  pool.addClassInfo("org.fakereplace.reflection.MethodReflection");
              int nt = pool.addNameAndTypeInfo("fakeCallRequired", "(Ljava/lang/reflect/Method;)Z");
              fakeCallRequiredLocation = pool.addMethodrefInfo(methodReflectionLocation, nt);
              newCallLocation = pool.addNameAndTypeInfo(METHOD_NAME, REPLACED_METHOD_DESCRIPTOR);
            }
          }
        }
      }
    }

    // this means we found an instance of the call, now we have to iterate
    // through the methods and replace instances of the call
    if (newCallLocation != null) {
      List<MethodInfo> methods = file.getMethods();
      for (MethodInfo m : methods) {
        try {
          // ignore abstract methods
          if (m.getCodeAttribute() == null) {
            continue;
          }
          CodeIterator it = m.getCodeAttribute().iterator();
          while (it.hasNext()) {
            // loop through the bytecode
            int index = it.next();
            int op = it.byteAt(index);
            // if the bytecode is a method invocation
            if (op == CodeIterator.INVOKEVIRTUAL) {
              int val = it.s16bitAt(index + 1);
              // if the method call is one of the methods we are
              // replacing
              if (methodCallLocations.contains(val)) {
                Bytecode b = new Bytecode(file.getConstPool());
                // our stack looks like Method, instance,params
                // we need Method, instance, params , Method
                b.add(Opcode.DUP_X2);
                b.add(Opcode.POP);
                b.add(Opcode.DUP_X2);
                b.add(Opcode.POP);
                b.add(Opcode.DUP_X2);
                b.addInvokestatic(
                    methodReflectionLocation, "fakeCallRequired", "(Ljava/lang/reflect/Method;)Z");
                b.add(Opcode.IFEQ);
                JumpMarker performRealCall = JumpUtils.addJumpInstruction(b);
                // now perform the fake call
                b.addInvokestatic(methodReflectionLocation, "invoke", REPLACED_METHOD_DESCRIPTOR);
                b.add(Opcode.GOTO);
                JumpMarker finish = JumpUtils.addJumpInstruction(b);
                performRealCall.mark();
                b.addInvokevirtual(Method.class.getName(), METHOD_NAME, METHOD_DESCRIPTOR);
                finish.mark();
                it.writeByte(CodeIterator.NOP, index);
                it.writeByte(CodeIterator.NOP, index + 1);
                it.writeByte(CodeIterator.NOP, index + 2);
                it.insert(b.get());
              }
            }
          }
          m.getCodeAttribute().computeMaxStack();
        } catch (Exception e) {
          log.error("Bad byte code transforming " + file.getName());
          e.printStackTrace();
        }
      }
      return true;
    } else {
      return false;
    }
  }