Search in sources :

Example 1 with MethodInfo

use of javassist.bytecode.MethodInfo in project pinpoint by naver.

the class JavaAssistUtils method lookupLocalVariableAttribute.

/**
     * get LocalVariableAttribute
     *
     * @param method
     * @return null if the class is not compiled with debug option
     */
public static LocalVariableAttribute lookupLocalVariableAttribute(CtBehavior method) {
    if (method == null) {
        throw new NullPointerException("method must not be null");
    }
    MethodInfo methodInfo = method.getMethodInfo2();
    CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
    if (codeAttribute == null) {
        return null;
    }
    AttributeInfo localVariableTable = codeAttribute.getAttribute(LocalVariableAttribute.tag);
    LocalVariableAttribute local = (LocalVariableAttribute) localVariableTable;
    return local;
}
Also used : AttributeInfo(javassist.bytecode.AttributeInfo) CodeAttribute(javassist.bytecode.CodeAttribute) MethodInfo(javassist.bytecode.MethodInfo) LocalVariableAttribute(javassist.bytecode.LocalVariableAttribute)

Example 2 with MethodInfo

use of javassist.bytecode.MethodInfo in project hibernate-orm by hibernate.

the class BulkAccessorFactory method addGetter.

private void addGetter(ClassFile classfile, final Method[] getters) throws CannotCompileException {
    final ConstPool constPool = classfile.getConstPool();
    final int targetBeanConstPoolIndex = constPool.addClassInfo(this.targetBean.getName());
    final String desc = GET_SETTER_DESC;
    final MethodInfo getterMethodInfo = new MethodInfo(constPool, GENERATED_GETTER_NAME, desc);
    final Bytecode code = new Bytecode(constPool, 6, 4);
    /* | this | bean | args | raw bean | */
    if (getters.length >= 0) {
        // aload_1 // load bean
        code.addAload(1);
        // checkcast // cast bean
        code.addCheckcast(this.targetBean.getName());
        // astore_3 // store bean
        code.addAstore(3);
        for (int i = 0; i < getters.length; ++i) {
            if (getters[i] != null) {
                final Method getter = getters[i];
                // aload_2 // args
                code.addAload(2);
                // iconst_i // continue to aastore
                // growing stack is 1
                code.addIconst(i);
                final Class returnType = getter.getReturnType();
                int typeIndex = -1;
                if (returnType.isPrimitive()) {
                    typeIndex = FactoryHelper.typeIndex(returnType);
                    // new
                    code.addNew(FactoryHelper.wrapperTypes[typeIndex]);
                    // dup
                    code.addOpcode(Opcode.DUP);
                }
                // aload_3 // load the raw bean
                code.addAload(3);
                final String getterSignature = RuntimeSupport.makeDescriptor(getter);
                final String getterName = getter.getName();
                if (this.targetBean.isInterface()) {
                    // invokeinterface
                    code.addInvokeinterface(targetBeanConstPoolIndex, getterName, getterSignature, 1);
                } else {
                    // invokevirtual
                    code.addInvokevirtual(targetBeanConstPoolIndex, getterName, getterSignature);
                }
                if (typeIndex >= 0) {
                    // is a primitive type
                    // invokespecial
                    code.addInvokespecial(FactoryHelper.wrapperTypes[typeIndex], MethodInfo.nameInit, FactoryHelper.wrapperDesc[typeIndex]);
                }
                // aastore // args
                code.add(Opcode.AASTORE);
                code.growStack(-3);
            }
        }
    }
    // return
    code.addOpcode(Opcode.RETURN);
    getterMethodInfo.setCodeAttribute(code.toCodeAttribute());
    getterMethodInfo.setAccessFlags(AccessFlag.PUBLIC);
    classfile.addMethod(getterMethodInfo);
}
Also used : ConstPool(javassist.bytecode.ConstPool) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode) Method(java.lang.reflect.Method)

Example 3 with MethodInfo

use of javassist.bytecode.MethodInfo in project hibernate-orm by hibernate.

the class BulkAccessorFactory method addSetter.

private void addSetter(ClassFile classfile, final Method[] setters) throws CannotCompileException {
    final ConstPool constPool = classfile.getConstPool();
    final int targetTypeConstPoolIndex = constPool.addClassInfo(this.targetBean.getName());
    final String desc = GET_SETTER_DESC;
    final MethodInfo setterMethodInfo = new MethodInfo(constPool, GENERATED_SETTER_NAME, desc);
    final Bytecode code = new Bytecode(constPool, 4, 6);
    StackMapTable stackmap = null;
    /* | this | bean | args | i | raw bean | exception | */
    if (setters.length > 0) {
        // required to exception table
        int start;
        int end;
        // iconst_0 // i
        code.addIconst(0);
        // istore_3 // store i
        code.addIstore(3);
        // aload_1 // load the bean
        code.addAload(1);
        // checkcast // cast the bean into a raw bean
        code.addCheckcast(this.targetBean.getName());
        // astore 4 // store the raw bean
        code.addAstore(4);
        /* current stack len = 0 */
        // start region to handling exception (BulkAccessorException)
        start = code.currentPc();
        int lastIndex = 0;
        for (int i = 0; i < setters.length; ++i) {
            if (setters[i] != null) {
                final int diff = i - lastIndex;
                if (diff > 0) {
                    // iinc 3, 1
                    code.addOpcode(Opcode.IINC);
                    code.add(3);
                    code.add(diff);
                    lastIndex = i;
                }
            }
            /* current stack len = 0 */
            // aload 4 // load the raw bean
            code.addAload(4);
            // aload_2 // load the args
            code.addAload(2);
            // iconst_i
            code.addIconst(i);
            // aaload
            code.addOpcode(Opcode.AALOAD);
            // checkcast
            final Class[] setterParamTypes = setters[i].getParameterTypes();
            final Class setterParamType = setterParamTypes[0];
            if (setterParamType.isPrimitive()) {
                // checkcast (case of primitive type)
                // invokevirtual (case of primitive type)
                this.addUnwrapper(code, setterParamType);
            } else {
                // checkcast (case of reference type)
                code.addCheckcast(setterParamType.getName());
            }
            /* current stack len = 2 */
            final String rawSetterMethodDesc = RuntimeSupport.makeDescriptor(setters[i]);
            if (!this.targetBean.isInterface()) {
                // invokevirtual
                code.addInvokevirtual(targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc);
            } else {
                // invokeinterface
                final Class[] params = setters[i].getParameterTypes();
                int size;
                if (params[0].equals(Double.TYPE) || params[0].equals(Long.TYPE)) {
                    size = 3;
                } else {
                    size = 2;
                }
                code.addInvokeinterface(targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc, size);
            }
        }
        // end region to handling exception (BulkAccessorException)
        end = code.currentPc();
        // return
        code.addOpcode(Opcode.RETURN);
        /* current stack len = 0 */
        // register in exception table
        final int throwableTypeIndex = constPool.addClassInfo(THROWABLE_CLASS_NAME);
        final int handlerPc = code.currentPc();
        code.addExceptionHandler(start, end, handlerPc, throwableTypeIndex);
        // astore 5 // store exception
        code.addAstore(5);
        // new // BulkAccessorException
        code.addNew(BULKEXCEPTION_CLASS_NAME);
        // dup
        code.addOpcode(Opcode.DUP);
        // aload 5 // load exception
        code.addAload(5);
        // iload_3 // i
        code.addIload(3);
        // invokespecial // BulkAccessorException.<init>
        final String consDesc = "(Ljava/lang/Throwable;I)V";
        code.addInvokespecial(BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, consDesc);
        // athrow
        code.addOpcode(Opcode.ATHROW);
        final StackMapTable.Writer writer = new StackMapTable.Writer(32);
        final int[] localTags = { StackMapTable.OBJECT, StackMapTable.OBJECT, StackMapTable.OBJECT, StackMapTable.INTEGER };
        final int[] localData = { constPool.getThisClassInfo(), constPool.addClassInfo("java/lang/Object"), constPool.addClassInfo("[Ljava/lang/Object;"), 0 };
        final int[] stackTags = { StackMapTable.OBJECT };
        final int[] stackData = { throwableTypeIndex };
        writer.fullFrame(handlerPc, localTags, localData, stackTags, stackData);
        stackmap = writer.toStackMapTable(constPool);
    } else {
        // return
        code.addOpcode(Opcode.RETURN);
    }
    final CodeAttribute ca = code.toCodeAttribute();
    if (stackmap != null) {
        ca.setAttribute(stackmap);
    }
    setterMethodInfo.setCodeAttribute(ca);
    setterMethodInfo.setAccessFlags(AccessFlag.PUBLIC);
    classfile.addMethod(setterMethodInfo);
}
Also used : ConstPool(javassist.bytecode.ConstPool) CodeAttribute(javassist.bytecode.CodeAttribute) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode) StackMapTable(javassist.bytecode.StackMapTable)

Example 4 with MethodInfo

use of javassist.bytecode.MethodInfo in project hibernate-orm by hibernate.

the class PersistentAttributesEnhancer method enhanceAttributesAccess.

protected void enhanceAttributesAccess(CtClass managedCtClass, IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
    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("$$_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;
                }
                // only transform access to fields of the entity being enhanced
                if (!managedCtClass.getName().equals(constPool.getFieldrefClassName(itr.u16bitAt(index + 1)))) {
                    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.INVOKEVIRTUAL, index);
                    itr.write16bit(methodIndex, index + 1);
                } else {
                    final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter());
                    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 EnhancementException(msg, bb);
        }
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) CodeIterator(javassist.bytecode.CodeIterator) ClassPool(javassist.ClassPool) EnhancementException(org.hibernate.bytecode.enhance.spi.EnhancementException) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode)

Example 5 with MethodInfo

use of javassist.bytecode.MethodInfo in project hibernate-orm by hibernate.

the class PersistentAttributesEnhancer method extendedEnhancement.

// --- //
/**
 * 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 aCtClass Class to enhance (not an entity class).
 */
public void extendedEnhancement(CtClass aCtClass) {
    final ConstPool constPool = aCtClass.getClassFile().getConstPool();
    final ClassPool classPool = aCtClass.getClassPool();
    for (Object oMethod : aCtClass.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 = classPool.getCtClass(fieldClassName);
                if (!enhancementContext.isEntityClass(targetCtClass) && !enhancementContext.isCompositeClass(targetCtClass)) {
                    continue;
                }
                if (targetCtClass == aCtClass || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName)) || PersistentAttributesHelper.hasAnnotation(targetCtClass, fieldName, Id.class) || "this$0".equals(fieldName)) {
                    continue;
                }
                log.debugf("Extended enhancement: Transforming access to field [%s.%s] from method [%s#%s]", fieldClassName, fieldName, aCtClass.getName(), 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 extended enhancement in method [%s]", methodName);
            throw new EnhancementException(msg, bb);
        } catch (NotFoundException nfe) {
            final String msg = String.format("Unable to perform extended enhancement in method [%s]", methodName);
            throw new EnhancementException(msg, nfe);
        }
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) CtClass(javassist.CtClass) CodeIterator(javassist.bytecode.CodeIterator) ClassPool(javassist.ClassPool) EnhancementException(org.hibernate.bytecode.enhance.spi.EnhancementException) NotFoundException(javassist.NotFoundException) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode)

Aggregations

MethodInfo (javassist.bytecode.MethodInfo)54 Bytecode (javassist.bytecode.Bytecode)28 BadBytecode (javassist.bytecode.BadBytecode)19 CodeIterator (javassist.bytecode.CodeIterator)18 CodeAttribute (javassist.bytecode.CodeAttribute)17 ConstPool (javassist.bytecode.ConstPool)17 ClassFile (javassist.bytecode.ClassFile)12 LocalVariableAttribute (javassist.bytecode.LocalVariableAttribute)10 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)9 List (java.util.List)7 ClassPool (javassist.ClassPool)7 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6 DataOutputStream (java.io.DataOutputStream)6 IOException (java.io.IOException)6 CtMethod (javassist.CtMethod)6 HashMap (java.util.HashMap)5 HashSet (java.util.HashSet)5 Set (java.util.Set)5 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)5 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4