예제 #1
0
  private void atStringConcatExpr(Expr expr, int type1, int dim1, String cname1)
      throws CompileError {
    int type2 = exprType;
    int dim2 = arrayDim;
    boolean type2Is2 = is2word(type2, dim2);
    boolean type2IsString = (type2 == CLASS && jvmJavaLangString.equals(className));

    if (type2Is2) convToString(type2, dim2);

    if (is2word(type1, dim1)) {
      bytecode.addOpcode(DUP_X2);
      bytecode.addOpcode(POP);
    } else bytecode.addOpcode(SWAP);

    // even if type1 is String, the left operand might be null.
    convToString(type1, dim1);
    bytecode.addOpcode(SWAP);

    if (!type2Is2 && !type2IsString) convToString(type2, dim2);

    bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    exprType = CLASS;
    arrayDim = 0;
    className = jvmJavaLangString;
  }
예제 #2
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;");
 }
예제 #3
0
  private void atStringPlusEq(Expr expr, int type, int dim, String cname, ASTree right)
      throws CompileError {
    if (!jvmJavaLangString.equals(cname)) badAssign(expr);

    convToString(type, dim); // the value might be null.
    right.accept(this);
    convToString(exprType, arrayDim);
    bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    exprType = CLASS;
    arrayDim = 0;
    className = jvmJavaLangString;
  }
 /** 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;
 }
예제 #5
0
  /**
   * When creates the delegate initializer code when the delegate is injected into a method.
   *
   * <p>super initializer method is called first, and then _initMH is called
   *
   * @param file
   * @param intializerMethodInfo
   * @param delegateParameterPosition
   * @return
   */
  private Bytecode createDelegateInitializerCode(
      ClassFile file, MethodInformation intializerMethodInfo, int delegateParameterPosition) {
    Bytecode b = new Bytecode(file.getConstPool());
    // we need to push all the pareters on the stack to call the corresponding
    // superclass arguments
    b.addAload(0); // load this
    int localVariables = 1;
    int actualDelegateParamterPosition = 0;
    for (int i = 0; i < intializerMethodInfo.getMethod().getParameterTypes().length; ++i) {
      if (i == delegateParameterPosition) {
        // figure out the actual position of the delegate in the local
        // variables
        actualDelegateParamterPosition = localVariables;
      }
      Class<?> type = intializerMethodInfo.getMethod().getParameterTypes()[i];
      BytecodeUtils.addLoadInstruction(
          b, DescriptorUtils.classToStringRepresentation(type), localVariables);
      if (type == long.class || type == double.class) {
        localVariables = localVariables + 2;
      } else {
        localVariables++;
      }
    }
    b.addInvokespecial(
        file.getSuperclass(), intializerMethodInfo.getName(), intializerMethodInfo.getDescriptor());
    // if this method returns a value it is now sitting on top of the stack
    // we will leave it there are return it later

    // now we need to call _initMH
    b.addAload(0); // load this
    b.addAload(actualDelegateParamterPosition); // load the delegate
    b.addInvokevirtual(file.getName(), "_initMH", "(Ljava/lang/Object;)V");
    // return the object from the top of the stack that we got from calling
    // the superclass method earlier
    BytecodeUtils.addReturnInstruction(b, intializerMethodInfo.getReturnType());
    b.setMaxLocals(localVariables);
    return b;
  }
  /**
   * 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;
    }
  }