Example usage for org.objectweb.asm MethodVisitor visitMaxs

List of usage examples for org.objectweb.asm MethodVisitor visitMaxs

Introduction

In this page you can find the example usage for org.objectweb.asm MethodVisitor visitMaxs.

Prototype

public void visitMaxs(final int maxStack, final int maxLocals) 

Source Link

Document

Visits the maximum stack size and the maximum number of local variables of the method.

Usage

From source file:boilerplate.processor.adapters.ToStringAdapter.java

License:Open Source License

private void addMethod() {
    List<String> fieldNames = new ArrayList<String>(typeInfo.fields.size());
    Map<String, FieldInfo> fields = new HashMap<String, FieldInfo>(typeInfo.fields.size());
    boolean hasAnnotatedFields = typeInfo.hasAnnotatedFields();
    for (FieldInfo info : typeInfo.fields) {
        if (!(hasAnnotatedFields ^ info.mark == Mark.INCLUDE)) {
            fieldNames.add(info.name);// ww w.  ja va2  s  . c o  m
            fields.put(info.name, info);
        }
    }
    Collections.sort(fieldNames);

    MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
    mv.visitCode();
    mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
    mv.visitInsn(DUP);
    mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
    mv.visitVarInsn(ASTORE, 1);
    for (String name : fieldNames) {
        FieldInfo info = fields.get(name);
        addField(mv, info);
    }
    mv.visitVarInsn(ALOAD, 1);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
    mv.visitInsn(ARETURN);
    mv.visitMaxs(4, 2);
    mv.visitEnd();
}

From source file:br.usp.each.saeg.badua.core.internal.instr.ClassInstrumenter.java

License:Open Source License

@Override
public void visitEnd() {
    // not instrument interfaces or
    // classes with probe count equals to zero
    if (interfaceType || classProbeCount == 0) {
        super.visitEnd();
        return;/* w w  w  .j  a  v  a  2s. co  m*/
    }

    final FieldVisitor fv = cv.visitField(InstrSupport.DATAFIELD_ACC, InstrSupport.DATAFIELD_NAME,
            InstrSupport.DATAFIELD_DESC, null, null);
    fv.visitEnd();

    final MethodVisitor mv = cv.visitMethod(InstrSupport.DATAMETHOD_ACC, InstrSupport.DATAMETHOD_NAME,
            InstrSupport.DATAMETHOD_DESC, null, null);
    mv.visitCode();

    // Load the value of the static data field:
    mv.visitFieldInsn(Opcodes.GETSTATIC, className, InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
    mv.visitInsn(Opcodes.DUP);

    // Stack[1]: [J
    // Stack[0]: [J

    // Skip initialization when we already have a data array:
    final Label alreadyInitialized = new Label();
    mv.visitJumpInsn(Opcodes.IFNONNULL, alreadyInitialized);

    // Stack[0]: [J

    mv.visitInsn(Opcodes.POP);
    mv.visitLdcInsn(classId);
    InstrSupport.push(mv, classProbeCount);
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, InstrSupport.RUNTIME_OWNER, InstrSupport.RUNTIME_NAME,
            InstrSupport.RUNTIME_DESC, false);

    // Stack[0]: [J

    mv.visitInsn(Opcodes.DUP);

    // Stack[1]: [J
    // Stack[0]: [J

    mv.visitFieldInsn(Opcodes.PUTSTATIC, className, InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);

    // Stack[0]: [J

    if (withFrames) {
        mv.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 1, new Object[] { InstrSupport.DATAFIELD_DESC });
    }
    mv.visitLabel(alreadyInitialized);
    mv.visitInsn(Opcodes.ARETURN);

    mv.visitMaxs(3, 0);
    mv.visitEnd();

    super.visitEnd();
}

From source file:br.usp.each.saeg.badua.test.validation.MaxTest.java

License:Open Source License

@Override
@Before//www .j av  a 2  s .c  o m
public void setUp() throws Exception {
    super.setUp();

    final int classVersion = Opcodes.V1_6;
    final int classAccessor = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER;
    final String className = "Max";
    final String superName = "java/lang/Object";

    final int methodAccessor = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
    final String methodName = "max";
    final String methodDesc = "([II)I";

    final ClassWriter cw = new ClassWriter(0);
    final MethodVisitor mw;

    cw.visit(classVersion, classAccessor, className, null, superName, null);
    mw = cw.visitMethod(methodAccessor, methodName, methodDesc, null, null);
    mw.visitCode();
    // block 0 (definitions {0, 1, 2, 3})
    mw.visitInsn(Opcodes.ICONST_0);
    mw.visitVarInsn(Opcodes.ISTORE, 2);
    mw.visitVarInsn(Opcodes.ALOAD, 0);
    mw.visitVarInsn(Opcodes.ILOAD, 2);
    mw.visitIincInsn(2, 1);
    mw.visitInsn(Opcodes.IALOAD);
    mw.visitVarInsn(Opcodes.ISTORE, 3);
    // block 1 (p-uses {1, 2})
    final Label backLoop = new Label();
    mw.visitLabel(backLoop);
    mw.visitVarInsn(Opcodes.ILOAD, 2);
    mw.visitVarInsn(Opcodes.ILOAD, 1);
    final Label breakLoop = new Label();
    mw.visitJumpInsn(Opcodes.IF_ICMPGE, breakLoop);
    // block 3 (p-uses {0, 2, 3})
    mw.visitVarInsn(Opcodes.ALOAD, 0);
    mw.visitVarInsn(Opcodes.ILOAD, 2);
    mw.visitInsn(Opcodes.IALOAD);
    mw.visitVarInsn(Opcodes.ILOAD, 3);
    final Label jump = new Label();
    mw.visitJumpInsn(Opcodes.IF_ICMPLE, jump);
    // block 5 (definitions {3}, uses {0, 2})
    mw.visitVarInsn(Opcodes.ALOAD, 0);
    mw.visitVarInsn(Opcodes.ILOAD, 2);
    mw.visitInsn(Opcodes.IALOAD);
    mw.visitVarInsn(Opcodes.ISTORE, 3);
    // block 4 (definitions {2}, uses {2})
    mw.visitLabel(jump);
    mw.visitIincInsn(2, 1);
    mw.visitJumpInsn(Opcodes.GOTO, backLoop);
    // block 2 ( uses {3})
    mw.visitLabel(breakLoop);
    mw.visitVarInsn(Opcodes.ILOAD, 3);
    mw.visitInsn(Opcodes.IRETURN);
    mw.visitMaxs(2, 4);
    mw.visitEnd();
    cw.visitEnd();

    final byte[] bytes = cw.toByteArray();
    klass = addClass(className, bytes);
    method = klass.getMethod(methodName, int[].class, int.class);
    classId = CRC64.checksum(bytes);

    RT.init(new RuntimeData());
}

From source file:bytecode.ClassExporter.java

License:Apache License

/**
 * Exports the given class node to a file. The location of this file is
 * determined by the output classpath. This will cause a
 * <code>RuntimeException</code> if the class is not deeply loaded.
 *
 * @param  c     Class node to be exported.
 *///from w  ww . j  ava  2  s  .  co  m
public static void export(ClassNode c) {
    // Form array of interface names.
    String[] interfaces = new String[c.getInterfaces().size()];
    int index = 0;

    for (ClassNode iface : c.getInterfaces()) {
        interfaces[index++] = iface.getName();
    }

    // Export Class Header
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

    cw.visit(Opcodes.V1_6, Modifier.getBitField(c.getModifiers()), c.getName(), null, // NOTE: Generic signature (for debugging/reflection).
            (c.getSuperClass() == null) ? null : c.getSuperClass().getName(), interfaces);

    // TODO: Inner / Outer Classes

    // Debug Information
    if (c.getSourceFile() != null) {
        cw.visitSource(c.getSourceFile(), null);
    }

    // Export Fields
    for (Field f : c.getFields()) {
        cw.visitField(Modifier.getBitField(f.getModifiers()), f.getName(), f.getType().getDescriptor(), null,
                f.getDefaultValue());
    }

    // Export Methods
    MethodVisitor mv;

    for (Method m : c.getMethods()) {
        if (!m.getModifiers().contains(Modifier.INHERITED)) {
            mv = cw.visitMethod(Modifier.getBitField(m.getModifiers()), m.getName(), m.getDescriptor(), null, // NOTE: Generic signature (for debugging/reflection).
                    null // TODO: Exceptions
            );

            // Export code unless NATIVE or ABSTRACT.
            if (!m.getModifiers().contains(Modifier.NATIVE) && !m.getModifiers().contains(Modifier.ABSTRACT)) {
                mv.visitCode();
                m.getImplementation().accept(new BlockExporter(mv));

                // Arguments are just dummys, the ClassWriter recalculates.
                mv.visitMaxs(0, 0);
            }

            mv.visitEnd();
        }
    }

    cw.visitEnd();

    File f = new File(outputDirectory, c.getName() + ".class");
    try {
        f.getParentFile().mkdirs();
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(cw.toByteArray());
    } catch (IOException e) {
        throw new RuntimeException("Could not create class file: " + f);
    }
}

From source file:cc.adf.metrics.agent.visitor.ApplicationModuleImplModifier.java

public static void addDetailNameMethod(ClassWriter cw) {
    MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "getDetailName", "()Ljava/lang/String;", null, null);
    mv.visitCode();//from   w  ww .j a va2s.c  o m
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKEVIRTUAL, "oracle/jbo/server/ApplicationModuleImpl", "isRoot", "()Z", false);
    Label l0 = new Label();
    mv.visitJumpInsn(IFEQ, l0);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, "oracle/jbo/server/ApplicationModuleImpl", "getName",
            "()Ljava/lang/String;", false);
    mv.visitInsn(ARETURN);
    mv.visitLabel(l0);
    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
    mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
    mv.visitInsn(DUP);
    mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, "oracle/jbo/server/ApplicationModuleImpl", "getRootApplicationModule",
            "()Loracle/jbo/server/ApplicationModuleImpl;", false);
    mv.visitMethodInsn(INVOKEVIRTUAL, "oracle/jbo/server/ApplicationModuleImpl", "getName",
            "()Ljava/lang/String;", false);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
            "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
    mv.visitLdcInsn("::");
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
            "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, "oracle/jbo/server/ApplicationModuleImpl", "getName",
            "()Ljava/lang/String;", false);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
            "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
    mv.visitInsn(ARETURN);
    mv.visitMaxs(2, 1);
    mv.visitEnd();
}

From source file:ch.eiafr.cojac.Agent.java

License:Apache License

/**
* This method works only with the FloatReplacerClasses class
* It instruments it to create a static initializer block to set
* all the static variables used by the agent and injected in the 
* instrumented application.//from  w  ww  . j  a  v a2s .c  o  m
* Warning: this is not the only place to set these variables, see class
* "CojacReferences" !
* This is used when there is more than one classloader in the application
*/
private byte[] setGlobalFields(byte[] byteCode, ClassLoader loader) {
    ClassReader cr = new ClassReader(byteCode);
    ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
    ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) {
        @Override
        public void visit(int version, int access, String name, String signature, String superName,
                String[] interfaces) {
            super.visit(version, access, name, signature, superName, interfaces);
            MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
            mv.visitLdcInsn(references.getDoubleWrapper());
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setNgWrapper", "(Ljava/lang/String;)V", false);
            mv.visitLdcInsn(references.getNgWrapper());
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setDoubleWrapper", "(Ljava/lang/String;)V", false);
            mv.visitLdcInsn(references.getFloatWrapper());
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setFloatWrapper", "(Ljava/lang/String;)V", false);
            mv.visitLdcInsn(references.getBigDecimalPrecision());
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setBigDecimalPrecision", "(I)V", false);
            mv.visitLdcInsn(references.getStabilityThreshold());
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setStabilityThreshold", "(D)V", false);
            mv.visitLdcInsn(references.getCheckUnstableComparisons() ? 1 : 0);
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, name, "setCheckUnstableComparisons", "(Z)V", false);
            mv.visitInsn(Opcodes.RETURN);
            mv.visitMaxs(0, 0);
        }
    };
    cr.accept(cv, ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
}

From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java

License:Apache License

public void nativeCall(MethodVisitor mv, int access, String owner, String name, String desc) {
    boolean isStatic = (access & ACC_STATIC) > 0;
    String newDesc = replaceFloatMethodDescription(desc);
    MethodVisitor newMv = ccv.addProxyMethod(access & ~ACC_NATIVE, name, newDesc, null, null);
    int varIndex = 0;
    int opcode = INVOKESTATIC;
    if (!isStatic) {
        newMv.visitVarInsn(ALOAD, 0);/*from w w  w.  j av  a  2 s.  c  o m*/
        varIndex = 1;
        opcode = INVOKEVIRTUAL;
    }
    ConversionContext cc = new ConversionContext(opcode, owner, name, desc);
    Type args[] = Type.getArgumentTypes(newDesc);
    for (Type type : args) {
        newMv.visitVarInsn(getLoadOpcode(type), varIndex);
        varIndex += type.getSize();
    }
    convertArgumentsToReal(mv, cc);
    // stack >> [target] allParamsArr [target] allParamsArr
    maybeConvertTarget(mv, cc.opcode, cc.owner);
    // stack >> [target] allParamsArr [newTarget] allParamsArr
    explodeOnStack(mv, cc, true);
    // stack >> [target] allParamsArr [newTarget] nprm0 nprm1 nprm2...
    newMv.visitMethodInsn(opcode, owner, name, desc, false);
    // stack >> [target] allParamsArr [possibleResult]
    checkArraysAfterCall(newMv, cc.convertedArrays, desc);
    // stack >> [target] [possibleResult]
    convertReturnType(newMv, desc);
    // stack >> [target] [newPossibleResult]
    newMv.visitInsn(afterFloatReplacement(Type.getReturnType(desc)).getOpcode(IRETURN));
    // stack >> [target]       // left on the stack... not a problem!
    newMv.visitMaxs(0, 0);
}

From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java

License:Apache License

private void createConvertMethod(String convertDesc, ConversionContext cc) {
    if (ccv.isProxyMethod(COJAC_TYPE_CONVERT_NAME, convertDesc))
        return; // the method already exists
    MethodVisitor newMv = ccv.addProxyMethod(ACC_STATIC, COJAC_TYPE_CONVERT_NAME, convertDesc, null, null);
    int varIndex = 0;
    newMv.visitLdcInsn(cc.outArgs.length + 1); // additional cell for the AllAsObjects array
    newMv.visitTypeInsn(ANEWARRAY, OBJ_TYPE.getInternalName());
    // stack >> prmsArr
    newMv.visitInsn(DUP);/*from www.  j a v a  2  s. c  om*/
    newMv.visitLdcInsn(cc.outArgs.length);
    newMv.visitInsn(DUP);
    newMv.visitTypeInsn(ANEWARRAY, OBJ_TYPE.getInternalName());
    // stack >> prmsArr prmsArr n asObjArr
    newMv.visitInsn(AASTORE);
    // stack >> prmsArr

    for (int i = 0; i < cc.outArgs.length; i++) {
        Type ia = cc.inArgs[i];
        newMv.visitInsn(DUP);
        newMv.visitInsn(DUP);
        newMv.visitLdcInsn(cc.outArgs.length);
        // stack >> prmsArr prmsArr prmsArr n
        newMv.visitInsn(AALOAD);
        newMv.visitTypeInsn(CHECKCAST, "[" + OBJ_TYPE.getDescriptor());
        // stack >> prmsArr prmsArr asObjArr
        newMv.visitLdcInsn(i);
        // stack >> prmsArr prmsArr asObjArr i
        newMv.visitVarInsn(getLoadOpcode(ia), varIndex);
        convertPrimitiveToObject(newMv, cc.inArgs[i]);
        // stack >> prmsArr prmsArr asObjArr i pi
        newMv.visitInsn(AASTORE);
        // stack >> prmsArr prmsArr
        newMv.visitLdcInsn(i);
        // stack >> prmsArr prmsArr i
        newMv.visitVarInsn(getLoadOpcode(ia), varIndex);
        varIndex += cc.inArgs[i].getSize();
        // stack >> prmsArr prmsArr i pi
        boolean keepBothVersions = (ia.getSort() == Type.ARRAY);
        if (keepBothVersions) { // keep the old reference (the Cojac one)
            newMv.visitLdcInsn(2);
            newMv.visitTypeInsn(ANEWARRAY, OBJ_TYPE.getInternalName());
            // stack >> prmsArr prmsArr i pi piArr
            newMv.visitInsn(DUP_X1);
            // stack >> prmsArr prmsArr i piArr pi piArr
            newMv.visitInsn(SWAP);
            // stack >> prmsArr prmsArr i piArr piArr pi
            newMv.visitInsn(DUP_X1);
            newMv.visitLdcInsn(0);
            newMv.visitInsn(SWAP);
            // stack >> prmsArr prmsArr i piArr pi piArr pi 0
            newMv.visitInsn(AASTORE);
            // stack >> prmsArr prmsArr i piArr
        }
        // stack >> prmsArr prmsArr i pi
        if (cc.needsConversion(i)) {
            convertCojacToRealType(cc.asOriginalJavaType(i), newMv);
        } else if (cc.shouldObjParamBeConverted && (ia.equals(OBJ_TYPE) || ia.equals(OBJ_ARRAY_TYPE))) {
            convertObjectToReal(newMv, ia);
        }
        /* This is where we could decide to convert back to JavaWrapper
         * when the argument is declared as Object
         * We don't do that to keep "enriched numbers" in collections
         * but sometimes we would like to convert, eg printf, format...
         */
        convertPrimitiveToObject(newMv, cc.outArgs[i]);
        // stack >> prmsArr prmsArr i pi
        if (keepBothVersions) { // keep the new reference (the java one)
            newMv.visitInsn(SWAP);
            newMv.visitInsn(DUP_X1);
            newMv.visitInsn(SWAP);
            newMv.visitLdcInsn(1);
            newMv.visitInsn(SWAP);
            newMv.visitInsn(AASTORE);
        }
        // stack >> prmsArr prmsArr i pi
        newMv.visitInsn(AASTORE);
        // stack >> prmsArr
    }
    newMv.visitInsn(ARETURN);
    newMv.visitMaxs(0, 0);
}

From source file:cn.annoreg.asm.DelegateGenerator.java

License:Open Source License

public static MethodVisitor generateStaticMethod(ClassVisitor parentClass, MethodVisitor parent,
        String className, String methodName, String desc, final Side side) {

    //This method is a little bit complicated.
    //We need to generate a delegate class implementing NetworkCallDelegate and a redirect
    //the code that originally generated here in parent, into the delegate class,
    //by returning a MethodVisitor under the ClassVisitor of the delegate class.
    //Besides, we should generate a call to NetworkCallManager into parent.

    //Above is the original method. Now it has a little bit change. To allow private call in
    //here, we need to generate the delegate method in this class instead of in a delegate class.
    //We make the delegate method public so that the delegate class can call it.

    //delegateName is a string used by both sides to identify a network-call delegate.
    final String delegateName = className + ":" + methodName + ":" + desc;
    final Type[] args = Type.getArgumentTypes(desc);
    final Type ret = Type.getReturnType(desc);

    //Check types
    for (Type t : args) {
        //TODO support these types
        if (!t.getDescriptor().startsWith("L") && !t.getDescriptor().startsWith("[")) {
            throw new RuntimeException("Unsupported argument type in network call. in method " + methodName
                    + ", " + t.getDescriptor());
        }//from   www. j av  a2  s.  c  o  m
    }
    if (!ret.equals(Type.VOID_TYPE)) {
        throw new RuntimeException(
                "Unsupported return value type in network call. " + "Only void is supported.");
    }

    //Generate call to NetworkCallManager in parent.
    parent.visitCode();
    //First parameter
    parent.visitLdcInsn(delegateName);
    //Second parameter: object array
    pushIntegerConst(parent, args.length); //array size
    parent.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class));
    for (int i = 0; i < args.length; ++i) {
        parent.visitInsn(Opcodes.DUP);
        pushIntegerConst(parent, i);
        parent.visitVarInsn(Opcodes.ALOAD, i);
        parent.visitInsn(Opcodes.AASTORE);
    }
    //Call cn.annoreg.mc.network.NetworkCallManager.onNetworkCall
    parent.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(NetworkCallManager.class),
            "onNetworkCall",
            Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(Object[].class)));
    parent.visitInsn(Opcodes.RETURN);
    parent.visitMaxs(5, args.length);
    parent.visitEnd();

    //Create delegate object.
    final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    final String delegateId = Integer.toString(delegateNextID++);
    final Type delegateClassType = Type.getType("cn/annoreg/asm/NetworkCallDelegate_" + delegateId);
    cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, delegateClassType.getInternalName(), null,
            Type.getInternalName(Object.class),
            new String[] { Type.getInternalName(NetworkCallDelegate.class) });
    //package cn.annoreg.asm;
    //class NetworkCallDelegate_? implements NetworkCallDelegate {
    {
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    //public NetworkCallDelegate_?() {}

    final String delegateFunctionName = methodName + "_delegate_" + delegateId;
    {
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "invoke",
                Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object[].class)), null, null);
        mv.visitCode();
        for (int i = 0; i < args.length; ++i) {
            mv.visitVarInsn(Opcodes.ALOAD, 1); //0 is this
            pushIntegerConst(mv, i);
            mv.visitInsn(Opcodes.AALOAD);
            mv.visitTypeInsn(Opcodes.CHECKCAST, args[i].getInternalName());
        }
        mv.visitMethodInsn(Opcodes.INVOKESTATIC,
                //delegateClassType.getInternalName(), //changed to original class
                className.replace('.', '/'), delegateFunctionName, desc);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(args.length + 2, 2);
        mv.visitEnd();
    }
    //@Override public void invoke(Object[] args) {
    //    xxxx.xxxx_delegated_xxx((Type0) args[0], (Type1) args[1], ...);
    //}

    //The returned MethodVisitor will visit the original version of the method,
    //including its annotation, where we can get StorageOptions.
    return new MethodVisitor(Opcodes.ASM4, parentClass.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
            delegateFunctionName, desc, null, null)) {

        //Remember storage options for each argument
        StorageOption.Option[] options = new StorageOption.Option[args.length];
        int targetIndex = -1;
        StorageOption.Target.RangeOption range = StorageOption.Target.RangeOption.SINGLE;
        double sendRange = -1;

        {
            for (int i = 0; i < options.length; ++i) {
                options[i] = StorageOption.Option.NULL; //set default value
            }
        }

        @Override
        public AnnotationVisitor visitParameterAnnotation(final int parameter, String desc, boolean visible) {
            Type type = Type.getType(desc);
            if (type.equals(Type.getType(StorageOption.Data.class))) {
                options[parameter] = StorageOption.Option.DATA;
            } else if (type.equals(Type.getType(StorageOption.Instance.class))) {
                //INSTANCE as defualt
                options[parameter] = StorageOption.Option.INSTANCE;

                //Change to NULLABLE_INSTANCE if nullable set to true
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visit(String name, Object value) {
                        if (name.equals("nullable")) {
                            if ((Boolean) value == true) {
                                options[parameter] = StorageOption.Option.NULLABLE_INSTANCE;
                            }
                        }
                        super.visit(name, value);
                    }
                };
            } else if (type.equals(Type.getType(StorageOption.Update.class))) {
                options[parameter] = StorageOption.Option.UPDATE;
            } else if (type.equals(Type.getType(StorageOption.Null.class))) {
                options[parameter] = StorageOption.Option.NULL;
            } else if (type.equals(Type.getType(StorageOption.Target.class))) {
                if (!args[parameter].equals(Type.getType(EntityPlayer.class))) {
                    throw new RuntimeException("Target annotation can only be used on EntityPlayer.");
                }
                if (targetIndex != -1) {
                    throw new RuntimeException("You can not specify multiple targets.");
                }
                options[parameter] = StorageOption.Option.INSTANCE;
                targetIndex = parameter;
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visitEnum(String name, String desc, String value) {
                        super.visitEnum(name, desc, value);
                        range = StorageOption.Target.RangeOption.valueOf(value);
                    }
                };
            } else if (type.equals(Type.getType(StorageOption.RangedTarget.class))) {
                if (targetIndex != -1) {
                    throw new RuntimeException("You can not specify multiple targets.");
                }
                range = null;
                targetIndex = parameter;
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visit(String name, Object value) {
                        super.visit(name, value);
                        sendRange = (double) value;
                    }
                };
            }
            return super.visitParameterAnnotation(parameter, desc, visible);
        }

        @Override
        public void visitEnd() {
            super.visitEnd();
            //This is the last method in the delegate class.
            //Finish the class and do the registration.
            cw.visitEnd();
            try {
                Class<?> clazz = classLoader.defineClass(delegateClassType.getClassName(), cw.toByteArray());
                NetworkCallDelegate delegateObj = (NetworkCallDelegate) clazz.newInstance();
                if (side == Side.CLIENT) {
                    NetworkCallManager.registerClientDelegateClass(delegateName, delegateObj, options,
                            targetIndex, range, sendRange);
                } else {
                    NetworkCallManager.registerServerDelegateClass(delegateName, delegateObj, options);
                }
            } catch (Throwable e) {
                throw new RuntimeException("Can not create delegate for network call.", e);
            }
        }
    };
    //public static void delegated(Type0 arg0, Type1, arg1, ...) {
    //    //Code generated by caller.
    //}
    //}
}

From source file:cn.annoreg.asm.DelegateGenerator.java

License:Open Source License

public static MethodVisitor generateNonStaticMethod(ClassVisitor parentClass, MethodVisitor parent,
        String className, String methodName, String desc, final Side side) {

    //convert desc to a non-static method form
    String nonstaticDesc;/*from ww  w  .  j  a  va  2  s  . c  om*/
    {
        Type staticType = Type.getMethodType(desc);
        Type retType = staticType.getReturnType();
        Type[] argsType = staticType.getArgumentTypes();
        Type[] argsTypeWithThis = new Type[argsType.length + 1];
        argsTypeWithThis[0] = Type.getType('L' + className.replace('.', '/') + ';');
        System.arraycopy(argsType, 0, argsTypeWithThis, 1, argsType.length);
        nonstaticDesc = Type.getMethodDescriptor(retType, argsTypeWithThis);
    }

    //delegateName is a string used by both sides to identify a network-call delegate.
    final String delegateName = className + ":" + methodName + ":" + desc;
    final Type[] args = Type.getArgumentTypes(nonstaticDesc);
    final Type ret = Type.getReturnType(nonstaticDesc);

    //Check types
    for (Type t : args) {
        //TODO support these types
        if (!t.getDescriptor().startsWith("L") && !t.getDescriptor().startsWith("[")) {
            throw new RuntimeException("Unsupported argument type in network call. ");
        }
    }
    if (!ret.equals(Type.VOID_TYPE)) {
        throw new RuntimeException(
                "Unsupported return value type in network call. " + "Only void is supported.");
    }

    //Generate call to NetworkCallManager in parent.
    parent.visitCode();
    //First parameter
    parent.visitLdcInsn(delegateName);
    //Second parameter: object array
    pushIntegerConst(parent, args.length); //this (0) has been included
    parent.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
    for (int i = 0; i < args.length; ++i) {
        parent.visitInsn(Opcodes.DUP);
        pushIntegerConst(parent, i);
        parent.visitVarInsn(Opcodes.ALOAD, i);
        parent.visitInsn(Opcodes.AASTORE);
    }
    //Call cn.annoreg.mc.network.NetworkCallManager.onNetworkCall
    parent.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(NetworkCallManager.class),
            "onNetworkCall", "(Ljava/lang/String;[Ljava/lang/Object;)V");
    parent.visitInsn(Opcodes.RETURN);
    parent.visitMaxs(5, args.length);
    parent.visitEnd();

    //Create delegate object.
    final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    final String delegateId = Integer.toString(delegateNextID++);
    final Type delegateClassType = Type.getType("cn/annoreg/asm/NetworkCallDelegate_" + delegateId);
    cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, delegateClassType.getInternalName(), null,
            Type.getInternalName(Object.class),
            new String[] { Type.getInternalName(NetworkCallDelegate.class) });
    //package cn.annoreg.asm;
    //class NetworkCallDelegate_? implements NetworkCallDelegate {
    {
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    //public NetworkCallDelegate_?() {}

    final String delegateMethodName = methodName + "_delegate_" + delegateId;
    {
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "invoke",
                Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object[].class)), null, null);
        mv.visitCode();

        //check if this is null
        mv.visitVarInsn(Opcodes.ALOAD, 1); //0 is this
        pushIntegerConst(mv, 0);
        mv.visitInsn(Opcodes.AALOAD);
        Label lblEnd = new Label();
        mv.visitJumpInsn(Opcodes.IFNULL, lblEnd);

        for (int i = 0; i < args.length; ++i) {
            mv.visitVarInsn(Opcodes.ALOAD, 1); //0 is this
            pushIntegerConst(mv, i);
            mv.visitInsn(Opcodes.AALOAD);
            mv.visitTypeInsn(Opcodes.CHECKCAST, args[i].getInternalName());
        }
        mv.visitMethodInsn(Opcodes.INVOKESTATIC,
                //delegateClassType.getInternalName(), 
                className.replace('.', '/'), delegateMethodName, nonstaticDesc);

        mv.visitLabel(lblEnd);

        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(args.length + 2, 2);
        mv.visitEnd();
    }
    //@Override public void invoke(Object[] args) {
    //    delegated((Type0) args[0], (Type1) args[1], ...);
    //}

    //The returned MethodVisitor will visit the original version of the method,
    //including its annotation, where we can get StorageOptions.
    return new MethodVisitor(Opcodes.ASM4, parentClass.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
            delegateMethodName, nonstaticDesc, null, null)) {

        //Remember storage options for each argument
        StorageOption.Option[] options = new StorageOption.Option[args.length];
        int targetIndex = -1;
        double sendRange = -1;
        StorageOption.Target.RangeOption range = StorageOption.Target.RangeOption.SINGLE;

        {
            for (int i = 0; i < options.length; ++i) {
                options[i] = StorageOption.Option.NULL; //set default value
            }
            options[0] = StorageOption.Option.INSTANCE;
        }

        @Override
        public AnnotationVisitor visitParameterAnnotation(int parameter_in_func, String desc, boolean visible) {
            final int parameter = parameter_in_func + 1; //skip this
            Type type = Type.getType(desc);
            if (type.equals(Type.getType(StorageOption.Data.class))) {
                options[parameter] = StorageOption.Option.DATA;
            } else if (type.equals(Type.getType(StorageOption.Instance.class))) {
                //INSTANCE as defualt
                options[parameter] = StorageOption.Option.INSTANCE;

                //Change to NULLABLE_INSTANCE if nullable set to true
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visit(String name, Object value) {
                        if (name.equals("nullable")) {
                            if ((Boolean) value == true) {
                                options[parameter] = StorageOption.Option.NULLABLE_INSTANCE;
                            }
                        }
                        super.visit(name, value);
                    }
                };
            } else if (type.equals(Type.getType(StorageOption.Update.class))) {
                options[parameter] = StorageOption.Option.UPDATE;
            } else if (type.equals(Type.getType(StorageOption.Null.class))) {
                options[parameter] = StorageOption.Option.NULL;
            } else if (type.equals(Type.getType(StorageOption.Target.class))) {
                if (!args[parameter].equals(Type.getType(EntityPlayer.class))) {
                    throw new RuntimeException("Target annotation can only be used on EntityPlayer.");
                }
                if (targetIndex != -1) {
                    throw new RuntimeException("You can not specify multiple targets.");
                }
                options[parameter] = StorageOption.Option.INSTANCE;
                targetIndex = parameter;
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visitEnum(String name, String desc, String value) {
                        super.visitEnum(name, desc, value);
                        range = StorageOption.Target.RangeOption.valueOf(value);
                    }
                };
            } else if (type.equals(Type.getType(StorageOption.RangedTarget.class))) {
                if (targetIndex != -1) {
                    throw new RuntimeException("You can not specify multiple targets.");
                }
                targetIndex = parameter;
                range = null;
                return new AnnotationVisitor(this.api,
                        super.visitParameterAnnotation(parameter, desc, visible)) {
                    @Override
                    public void visit(String name, Object value) {
                        super.visit(name, value);
                        sendRange = (double) value;
                    }
                };
            }
            return super.visitParameterAnnotation(parameter, desc, visible);
        }

        //TODO this option (from annotation)

        @Override
        public void visitEnd() {
            super.visitEnd();
            //This is the last method in the delegate class.
            //Finish the class and do the registration.
            cw.visitEnd();
            try {
                Class<?> clazz = classLoader.defineClass(delegateClassType.getClassName(), cw.toByteArray());
                NetworkCallDelegate delegateObj = (NetworkCallDelegate) clazz.newInstance();
                if (side == Side.CLIENT) {
                    NetworkCallManager.registerClientDelegateClass(delegateName, delegateObj, options,
                            targetIndex, range, sendRange);
                } else {
                    NetworkCallManager.registerServerDelegateClass(delegateName, delegateObj, options);
                }
            } catch (Throwable e) {
                throw new RuntimeException("Can not create delegate for network call.", e);
            }
        }
    };
    //public static void delegated(Type0 arg0, Type1, arg1, ...) {
    //    //Code generated by caller.
    //}
    //}
}