Search in sources :

Example 1 with StackMapTable

use of javassist.bytecode.StackMapTable 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)

Aggregations

Bytecode (javassist.bytecode.Bytecode)1 CodeAttribute (javassist.bytecode.CodeAttribute)1 ConstPool (javassist.bytecode.ConstPool)1 MethodInfo (javassist.bytecode.MethodInfo)1 StackMapTable (javassist.bytecode.StackMapTable)1