Ejemplo n.º 1
0
  @Override
  protected void onApply(CtBehavior behavior, Bytecode bytecode) throws BadBytecode {

    bytecode = BytecodeTools.prepareMethodForBytecode(behavior, bytecode);

    // loop through the opcodes and change any GT/GE opcodes to ICMPGT/ICMPGE
    CodeIterator iterator = behavior.getMethodInfo().getCodeAttribute().iterator();
    while (iterator.hasNext()) {
      int index = iterator.next();
      int opcode = iterator.byteAt(index);
      switch (opcode) {
        case Opcode.IFGT:

          // overwrite the opcode
          iterator.writeByte(Opcode.IF_ICMPGT, index);

          // insert the method call
          iterator.insertAt(index, bytecode.get());
          behavior.getMethodInfo().getCodeAttribute().computeMaxStack();

          break;

        case Opcode.IFGE:

          // overwrite the opcode
          iterator.writeByte(Opcode.IF_ICMPGE, index);

          // insert the method call
          iterator.insertAt(index, bytecode.get());
          behavior.getMethodInfo().getCodeAttribute().computeMaxStack();

          break;
      }
    }
  }
  protected void enhanceAttributesAccess(
      CtClass managedCtClass,
      IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          final PersistentAttributeAccessMethods attributeMethods =
              attributeDescriptorMap.get(fieldName);

          // its not a field we have enhanced for interception, so skip it
          if (attributeMethods == null) {
            continue;
          }
          // System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName,
          // methodName );
          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getReader());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          } else {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      }
    }
  }
Ejemplo n.º 3
0
  private static void shiftIndex8(CodeIterator ci, int index, int opcode, int lessThan, int delta)
      throws BadBytecode {
    int var = ci.byteAt(index + 1);
    if (var < lessThan) return;

    var += delta;
    if (var < 0x100) ci.writeByte(var, index + 1);
    else {
      int pos = ci.insertExGap(2);
      ci.writeByte(WIDE, pos - 2);
      ci.writeByte(opcode, pos - 1);
      ci.write16bit(var, pos);
    }
  }
Ejemplo n.º 4
0
 /*  94:    */
 /*  95:    */ protected int match(
     int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp)
     /*  96:    */ throws BadBytecode
       /*  97:    */ {
   /*  98:110 */ if (this.newIndex == 0)
   /*  99:    */ {
     /* 100:111 */ int nt = cp.addNameAndTypeInfo(cp.addUtf8Info(this.newMethodname), typedesc);
     /* 101:    */
     /* 102:113 */ int ci = cp.addClassInfo(this.newClassname);
     /* 103:114 */ if (c == 185)
     /* 104:    */ {
       /* 105:115 */ this.newIndex = cp.addInterfaceMethodrefInfo(ci, nt);
       /* 106:    */ }
     /* 107:    */ else
     /* 108:    */ {
       /* 109:117 */ if ((this.newMethodIsPrivate) && (c == 182)) {
         /* 110:118 */ iterator.writeByte(183, pos);
         /* 111:    */ }
       /* 112:120 */ this.newIndex = cp.addMethodrefInfo(ci, nt);
       /* 113:    */ }
     /* 114:123 */ this.constPool = cp;
     /* 115:    */ }
   /* 116:126 */ iterator.write16bit(this.newIndex, pos + 1);
   /* 117:127 */ return pos;
   /* 118:    */ }
Ejemplo n.º 5
0
  /**
   * @param lessThan If the index of the local variable is less than this value, it does not change.
   *     Otherwise, the index is increased.
   * @param delta the indexes of the local variables are increased by this value.
   */
  private static void shiftIndex(CodeIterator ci, int lessThan, int delta) throws BadBytecode {
    int index = ci.next();
    int opcode = ci.byteAt(index);
    if (opcode < ILOAD) return;
    else if (opcode < IASTORE) {
      if (opcode < ILOAD_0) {
        // iload, lload, fload, dload, aload
        shiftIndex8(ci, index, opcode, lessThan, delta);
      } else if (opcode < IALOAD) {
        // iload_0, ..., aload_3
        shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD);
      } else if (opcode < ISTORE) return;
      else if (opcode < ISTORE_0) {
        // istore, lstore, ...
        shiftIndex8(ci, index, opcode, lessThan, delta);
      } else {
        // istore_0, ..., astore_3
        shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE);
      }
    } else if (opcode == IINC) {
      int var = ci.byteAt(index + 1);
      if (var < lessThan) return;

      var += delta;
      if (var < 0x100) ci.writeByte(var, index + 1);
      else {
        int plus = (byte) ci.byteAt(index + 2);
        int pos = ci.insertExGap(3);
        ci.writeByte(WIDE, pos - 3);
        ci.writeByte(IINC, pos - 2);
        ci.write16bit(var, pos - 1);
        ci.write16bit(plus, pos + 1);
      }
    } else if (opcode == RET) shiftIndex8(ci, index, opcode, lessThan, delta);
    else if (opcode == WIDE) {
      int var = ci.u16bitAt(index + 2);
      if (var < lessThan) return;

      var += delta;
      ci.write16bit(var, index + 2);
    }
  }
  protected void enhanceAttributesAccess(Map<String, CtField> fieldsMap, CtClass managedCtClass)
      throws Exception {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();
    final ClassPool classPool = managedCtClass.getClassPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement, and abstract methods (methods without any code)
      if (methodName.startsWith(DROOLS_PREFIX) || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }

          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          CtField ctField = fieldsMap.get(fieldName);
          if (ctField == null) {
            continue;
          }

          // if we are in constructors, only need to intercept assignment statement for Reactive
          // Collection/List/... (regardless they may be final)
          if (methodInfo.isConstructor() && !(isCtFieldACollection(ctField))) {
            continue;
          }

          if (op == Opcode.PUTFIELD) {
            // addMethod is a safe add, if constant already present it return the existing value
            // without adding.
            final int methodIndex = addMethod(constPool, writeMethods.get(fieldName));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new Exception(msg, bb);
      }
    }
  }
Ejemplo n.º 7
0
  private static void shiftIndex0(
      CodeIterator ci, int index, int opcode, int lessThan, int delta, int opcode_i_0, int opcode_i)
      throws BadBytecode {
    int var = (opcode - opcode_i_0) % 4;
    if (var < lessThan) return;

    var += delta;
    if (var < 4) ci.writeByte(opcode + delta, index);
    else {
      opcode = (opcode - opcode_i_0) / 4 + opcode_i;
      if (var < 0x100) {
        int pos = ci.insertExGap(1);
        ci.writeByte(opcode, pos - 1);
        ci.writeByte(var, pos);
      } else {
        int pos = ci.insertExGap(3);
        ci.writeByte(WIDE, pos - 1);
        ci.writeByte(opcode, pos);
        ci.write16bit(var, pos + 1);
      }
    }
  }
  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;
    }
  }
  /**
   * Replace access to fields of entities (for example, entity.field) with a call to the enhanced
   * getter / setter (in this example, entity.$$_hibernate_read_field()). It's assumed that the
   * target entity is enhanced as well.
   *
   * @param managedCtClass Class to enhance
   */
  public void enhanceFieldAccess(CtClass managedCtClass) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          int index = itr.next();
          int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          String fieldClassName =
              constPool.getClassInfo(constPool.getFieldrefClass(itr.u16bitAt(index + 1)));
          CtClass targetCtClass = this.classPool.getCtClass(fieldClassName);

          if (!enhancementContext.isEntityClass(targetCtClass)
              && !enhancementContext.isCompositeClass(targetCtClass)) {
            continue;
          }
          if (targetCtClass == managedCtClass
              || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName))
              || "this$0".equals(fieldName)) {
            continue;
          }

          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            int fieldReaderMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName,
                    "()" + constPool.getFieldrefType(itr.u16bitAt(index + 1)));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldReaderMethodIndex, index + 1);
          } else {
            int fieldWriterMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName,
                    "(" + constPool.getFieldrefType(itr.u16bitAt(index + 1)) + ")V");
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldWriterMethodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      } catch (NotFoundException nfe) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, nfe);
      }
    }
  }