Example usage for org.objectweb.asm Opcodes ACC_STATIC

List of usage examples for org.objectweb.asm Opcodes ACC_STATIC

Introduction

In this page you can find the example usage for org.objectweb.asm Opcodes ACC_STATIC.

Prototype

int ACC_STATIC

To view the source code for org.objectweb.asm Opcodes ACC_STATIC.

Click Source Link

Usage

From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Add all unseen methods from the passed ClassNode's methods.
 *
 * @see ClassNode#methods//from w w w .  ja va 2 s  .c o  m
 * @param instrumentedClass class that is being visited
 * @param superClass the class to save all new methods from
 * @param methods the methods already encountered in the ClassNode hierarchy
 */
private static void addAllNewMethods(ClassNode instrumentedClass, ClassNode superClass,
        Map<String, MethodReference> methods) {
    //noinspection unchecked
    for (MethodNode method : (List<MethodNode>) superClass.methods) {
        if (method.name.equals(ByteCodeUtils.CONSTRUCTOR) || method.name.equals("<clinit>")) {
            continue;
        }
        String name = method.name + "." + method.desc;
        if (isAccessCompatibleWithInstantRun(method.access) && !methods.containsKey(name)
                && (method.access & Opcodes.ACC_STATIC) == 0
                && isCallableFromSubclass(method, superClass, instrumentedClass)) {
            methods.put(name, new MethodReference(method, superClass));
        }
    }
}

From source file:com.android.build.gradle.internal.transforms.InstantRunTransform.java

License:Apache License

/**
 * Use asm to generate a concrete subclass of the AppPathLoaderImpl class.
 * It only implements one method :/*from  w w  w . j a v a2  s. c o m*/
 *      String[] getPatchedClasses();
 *
 * The method is supposed to return the list of classes that were patched in this iteration.
 * This will be used by the InstantRun runtime to load all patched classes and register them
 * as overrides on the original classes.2 class files.
 *
 * @param patchFileContents list of patched class names.
 * @param outputDir output directory where to generate the .class file in.
 */
private static void writePatchFileContents(@NonNull ImmutableList<String> patchFileContents,
        @NonNull File outputDir, long buildId) {

    ClassWriter cw = new ClassWriter(0);
    MethodVisitor mv;

    cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, IncrementalVisitor.APP_PATCHES_LOADER_IMPL,
            null, IncrementalVisitor.ABSTRACT_PATCHES_LOADER_IMPL, null);

    // Add the build ID to force the patch file to be repackaged.
    cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "BUILD_ID", "J", null, buildId);

    {
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, IncrementalVisitor.ABSTRACT_PATCHES_LOADER_IMPL, "<init>",
                "()V", false);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getPatchedClasses", "()[Ljava/lang/String;", null, null);
        mv.visitCode();
        mv.visitIntInsn(Opcodes.BIPUSH, patchFileContents.size());
        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
        for (int index = 0; index < patchFileContents.size(); index++) {
            mv.visitInsn(Opcodes.DUP);
            mv.visitIntInsn(Opcodes.BIPUSH, index);
            mv.visitLdcInsn(patchFileContents.get(index));
            mv.visitInsn(Opcodes.AASTORE);
        }
        mv.visitInsn(Opcodes.ARETURN);
        mv.visitMaxs(4, 1);
        mv.visitEnd();
    }
    cw.visitEnd();

    byte[] classBytes = cw.toByteArray();
    File outputFile = new File(outputDir, IncrementalVisitor.APP_PATCHES_LOADER_IMPL + ".class");
    try {
        Files.createParentDirs(outputFile);
        Files.write(classBytes, outputFile);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

From source file:com.android.build.gradle.internal2.incremental.ConstructorBuilder.java

License:Apache License

/**
 * Splits the constructor in two methods, the "set up" and the "body" parts (see above).
 *///from w w w .java  2 s. c  o  m
@NonNull
private static Constructor split(@NonNull String owner, @NonNull MethodNode method,
        @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine,
        @NonNull List<LocalVariable> variables, int localsAtLoadThis) {
    String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]);

    // Do not add the local array yet, as we treat it as a new variable.
    String newDesc = method.desc.replace(")V", ")Ljava/lang/Object;");
    newDesc = newDesc.replace("(", "([L" + owner + ";");

    Type[] argumentTypes = Type.getArgumentTypes(newDesc);

    // Store the non hotswappable part of the constructor
    List<AbstractInsnNode> fixed = Lists.newLinkedList();
    AbstractInsnNode insn = method.instructions.getFirst();
    while (insn != loadThis) {
        fixed.add(insn);
        insn = insn.getNext();
    }
    fixed.add(loadThis);

    MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null,
            exceptions);
    GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc);
    int newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;"));

    mv.loadLocal(newArgument);
    ByteCodeUtils.restoreVariables(mv, variables.subList(0, localsAtLoadThis));

    // Now insert the original method
    insn = loadThis.getNext();
    while (insn != delegation) {
        insn.accept(mv);
        insn = insn.getNext();
    }
    LabelNode labelBefore = new LabelNode();
    labelBefore.accept(mv);

    // Create the args array with the local variables and the values to send to the delegated constructor
    Type[] returnTypes = Type.getArgumentTypes(delegation.desc);
    // The extra elements for the local variables and the qualified name of the constructor.
    mv.push(returnTypes.length + 2);
    mv.newArray(Type.getType(Object.class));
    int args = mv.newLocal(Type.getType("[Ljava/lang/Object;"));
    mv.storeLocal(args);
    for (int i = returnTypes.length - 1; i >= 0; i--) {
        Type type = returnTypes[i];
        mv.loadLocal(args);
        mv.swap(type, Type.getType(Object.class));
        mv.push(i + 2);
        mv.swap(type, Type.INT_TYPE);
        mv.box(type);
        mv.arrayStore(Type.getType(Object.class));
    }

    // Store the qualified name of the constructor in the second element of the array.
    mv.loadLocal(args);
    mv.push(1);
    mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called.
    mv.arrayStore(Type.getType(Object.class));

    // Create the locals array and place it in the first element of the return array
    mv.loadLocal(args);
    mv.push(0);
    mv.push(argumentTypes.length + 1);
    mv.newArray(Type.getType(Object.class));
    ByteCodeUtils.loadVariableArray(mv, ByteCodeUtils.toLocalVariables(Arrays.asList(argumentTypes)), 0);

    mv.dup();
    mv.push(argumentTypes.length);
    ByteCodeUtils.newVariableArray(mv, variables);
    mv.arrayStore(Type.getType(Object.class));

    mv.arrayStore(Type.getType(Object.class));

    mv.loadLocal(args);
    mv.returnValue();

    // Move the first variable up to be an argument
    initArgs.desc = initArgs.desc.replace(")", "[Ljava/lang/Object;)");

    newDesc = method.desc.replace("(", "(L" + owner + ";");
    MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null,
            exceptions);
    mv = new GeneratorAdapter(body, body.access, body.name, body.desc);
    newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;"));

    LabelNode labelAfter = new LabelNode();
    labelAfter.accept(body);
    Set<LabelNode> bodyLabels = new HashSet<LabelNode>();

    mv.loadLocal(newArgument);
    ByteCodeUtils.restoreVariables(mv, variables);

    insn = delegation.getNext();
    while (insn != null) {
        if (insn instanceof LabelNode) {
            bodyLabels.add((LabelNode) insn);
        }
        insn.accept(mv);
        insn = insn.getNext();
    }

    // manually transfer the exception table from the existing constructor to the new
    // "init$body" method. The labels were transferred just above so we can reuse them.

    //noinspection unchecked
    for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) {
        tryCatch.accept(mv);
    }

    //noinspection unchecked
    for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) {
        boolean startsInBody = bodyLabels.contains(variable.start);
        boolean endsInBody = bodyLabels.contains(variable.end);
        if (!startsInBody && !endsInBody) {
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                variable.accept(initArgs);
            }
        } else if (startsInBody && endsInBody) {
            variable.accept(body);
        } else if (!startsInBody && endsInBody) {
            // The variable spans from the args to the end of the method, create two:
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                        variable.start, labelBefore, variable.index);
                var0.accept(initArgs);
            }
            LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                    labelAfter, variable.end, variable.index);
            var1.accept(body);
        } else {
            throw new IllegalStateException("Local variable starts after it ends.");
        }
    }
    // Move the first variable up to be an argument
    body.desc = body.desc.replace(")", "[Ljava/lang/Object;)");

    return new Constructor(owner, method, fixed, loadThis, loadThisLine, initArgs, delegation, body, variables,
            localsAtLoadThis);
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java

License:Apache License

/**
 * Turns this class into an override class that can be loaded by our custom class loader:
 *<ul>//from  w w  w  .  j  av a2s .  co m
 *   <li>Make the class name be OriginalName$override</li>
 *   <li>Ensure the class derives from java.lang.Object, no other inheritance</li>
 *   <li>Ensure the class has a public parameterless constructor that is a noop.</li>
 *</ul>
 */
@Override
public void visit(int version, int access, String name, String signature, String superName,
        String[] interfaces) {
    // TODO: modified by achellies, ?,??,?ClassClass,Opcodes.INVOKESPECIAL?super
    super.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name + OVERRIDE_SUFFIX, signature, superName, // TODO modified by achellies, "java/lang/Object" -> superName
            new String[] { CHANGE_TYPE.getInternalName() });

    if (DEBUG) {
        System.out.println(">>>>>>>> Processing " + name + "<<<<<<<<<<<<<");
    }

    visitedClassName = name;
    visitedSuperName = superName;
    instanceToStaticDescPrefix = "(L" + visitedClassName + ";";

    // Create empty constructor
    MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC, ByteCodeUtils.CONSTRUCTOR, "()V", null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, ByteCodeUtils.CONSTRUCTOR, "()V", // TODO modified by achellies, "java/lang/Object" -> superName
            false);
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();

    super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "$obsolete", "Z", null,
            null);
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java

License:Apache License

/**
 * Generates new delegates for all 'patchable' methods in the visited class. Delegates
 * are static methods that do the same thing the visited code does, but from outside the class.
 * For instance methods, the instance is passed as the first argument. Note that:
 * <ul>/*from   www. ja  v a  2 s  . c  om*/
 *   <li>We ignore the class constructor as we don't support it right now</li>
 *   <li>We skip abstract methods.</li>
 *   <li>For constructors split the method body into super arguments and the rest of
 *   the method body, see {@link ConstructorBuilder}</li>
 * </ul>
 */
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

    if (instantRunDisabled || !isAccessCompatibleWithInstantRun(access)) {
        // Nothing to generate.
        return null;
    }
    if (name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
        // we skip the class init as it can reset static fields which we don't support right now
        return null;
    }

    boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
    String newDesc = computeOverrideMethodDesc(desc, isStatic);

    if (DEBUG) {
        System.out.println(">>> Visiting method " + visitedClassName + ":" + name + ":" + desc);
        if (exceptions != null) {
            for (String exception : exceptions) {
                System.out.println("> Exception thrown : " + exception);
            }
        }
    }
    if (DEBUG) {
        System.out.println("New Desc is " + newDesc + ":" + isStatic);
    }

    // Do not carry on any access flags from the original method. For example synchronized
    // on the original method would translate into a static synchronized method here.
    access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
    MethodNode method = getMethodByNameInClass(name, desc, classNode);
    if (name.equals(ByteCodeUtils.CONSTRUCTOR)) {
        Constructor constructor = ConstructorBuilder.build(visitedClassName, method);

        MethodVisitor original = super.visitMethod(access, constructor.args.name, constructor.args.desc,
                constructor.args.signature, exceptions);
        ISVisitor mv = new ISVisitor(original, access, constructor.args.name, constructor.args.desc, isStatic,
                true /* isConstructor */);
        constructor.args.accept(mv);

        original = super.visitMethod(access, constructor.body.name, constructor.body.desc,
                constructor.body.signature, exceptions);
        mv = new ISVisitor(original, access, constructor.body.name, newDesc, isStatic,
                true /* isConstructor */);
        constructor.body.accept(mv);

        // Remember our created methods so we can generated the access$dispatch for them.
        addedMethods.add(constructor.args);
        addedMethods.add(constructor.body);
        return null;
    } else {
        String newName = isStatic ? computeOverrideMethodName(name, desc) : name;
        MethodVisitor original = super.visitMethod(access, newName, newDesc, signature, exceptions);
        return new ISVisitor(original, access, newName, newDesc, isStatic, false /* isConstructor */);
    }
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java

License:Apache License

/**
 * To each class, add the dispatch method called by the original code that acts as a trampoline to
 * invoke the changed methods./*w ww  .j  a  v  a  2 s.  c o  m*/
 * <p>
 * Pseudo code:
 * <code>
 *   Object access$dispatch(String name, object[] args) {
 *      if (name.equals(
 *          "firstMethod.(L$type;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) {
 *        return firstMethod(($type)arg[0], (String)arg[1], arg[2]);
 *      }
 *      if (name.equals("secondMethod.(L$type;Ljava/lang/String;I;)V")) {
 *        secondMethod(($type)arg[0], (String)arg[1], (int)arg[2]);
 *        return;
 *      }
 *      ...
 *      StringBuilder $local1 = new StringBuilder();
 *      $local1.append("Method not found ");
 *      $local1.append(name);
 *      $local1.append(" in " + visitedClassName +
 *          "$dispatch implementation, restart the application");
 *      throw new $package/InstantReloadException($local1.toString());
 *   }
 * </code>
 */
private void addDispatchMethod() {
    int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS;
    Method m = new Method("access$dispatch", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
    MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null);

    final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);

    if (TRACING_ENABLED) {
        mv.push("Redirecting ");
        mv.loadArg(0);
        trace(mv, 2);
    }

    List<MethodNode> allMethods = new ArrayList<>();

    // if we are disabled, do not generate any dispatch, the method will throw an exception
    // if invoked which should never happen.
    if (!instantRunDisabled) {
        //noinspection unchecked
        allMethods.addAll(classNode.methods);
        allMethods.addAll(addedMethods);
    }

    final Map<String, MethodNode> methods = new HashMap<>();
    for (MethodNode methodNode : allMethods) {
        if (methodNode.name.equals(ByteCodeUtils.CLASS_INITIALIZER)
                || methodNode.name.equals(ByteCodeUtils.CONSTRUCTOR)) {
            continue;
        }
        if (!isAccessCompatibleWithInstantRun(methodNode.access)) {
            continue;
        }
        methods.put(methodNode.name + "." + methodNode.desc, methodNode);
    }

    new StringSwitch() {
        @Override
        void visitString() {
            mv.visitVarInsn(Opcodes.ALOAD, 1);
        }

        @Override
        void visitCase(String methodName) {
            MethodNode methodNode = methods.get(methodName);
            String name = methodNode.name;
            boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0;
            String newDesc = computeOverrideMethodDesc(methodNode.desc, isStatic);

            if (TRACING_ENABLED) {
                trace(mv, "M: " + name + " P:" + newDesc);
            }
            Type[] args = Type.getArgumentTypes(newDesc);
            int argc = 0;
            for (Type t : args) {
                mv.visitVarInsn(Opcodes.ALOAD, 2);
                mv.push(argc);
                mv.visitInsn(Opcodes.AALOAD);
                ByteCodeUtils.unbox(mv, t);
                argc++;
            }
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, visitedClassName + "$override",
                    isStatic ? computeOverrideMethodName(name, methodNode.desc) : name, newDesc, false);
            Type ret = Type.getReturnType(methodNode.desc);
            if (ret.getSort() == Type.VOID) {
                mv.visitInsn(Opcodes.ACONST_NULL);
            } else {
                mv.box(ret);
            }
            mv.visitInsn(Opcodes.ARETURN);
        }

        @Override
        void visitDefault() {
            writeMissingMessageWithHash(mv, visitedClassName);
        }
    }.visit(mv, methods.keySet());

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

    super.visitEnd();
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Ensures that the class contains a $change field used for referencing the IncrementalChange
 * dispatcher./*from ww w  .  j a  v  a 2  s .  c  o  m*/
 *
 * <p>Also updates package_private visibility to public so we can call into this class from
 * outside the package.
 *
 * <p>All classes will have a serialVersionUID added (if one does not already exist), as
 * otherwise, serialVersionUID would be different for instrumented and non-instrumented classes.
 * We do this for all classes. Due to incremental changes, there could be a class that starts
 * implementing {@link java.io.Serializable}, thus making all of its subclasses serializable as
 * well. Those subclasses might be used for persistence, and we need to make sure their
 * serialVersionUID are stable across instant run and non-instant run builds.
 */
@Override
public void visit(int version, int access, String name, String signature, String superName,
        String[] interfaces) {
    visitedClassName = name;
    visitedSuperName = superName;

    // TODO: disabled by achellies
    //        addSerialUidIfMissing();
    super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_SYNTHETIC
            | Opcodes.ACC_TRANSIENT, "$change", getRuntimeTypeName(CHANGE_TYPE), null, null);
    access = transformClassAccessForInstantRun(access);
    super.visit(version, access, name, signature, superName, interfaces);
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Insert Constructor specific logic({@link ConstructorRedirection} and
 * {@link ConstructorBuilder}) for constructor redirecting or
 * normal method redirecting ({@link MethodRedirection}) for other methods.
 *///from   w w w .ja va 2  s  . c  o m
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

    access = transformAccessForInstantRun(access);

    MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions);
    MethodNode method = getMethodByNameInClass(name, desc, classNode);
    // does the method use blacklisted APIs.
    boolean hasIncompatibleChange = InstantRunMethodVerifier
            .verifyMethod(method) != InstantRunVerifierStatus.COMPATIBLE;

    if (hasIncompatibleChange || disableRedirectionForClass || !isAccessCompatibleWithInstantRun(access)
            || name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
        return defaultVisitor;
    } else {
        ArrayList<Type> args = new ArrayList<Type>(Arrays.asList(Type.getArgumentTypes(desc)));
        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
        if (!isStatic) {
            args.add(0, Type.getType(Object.class));
        }

        ISMethodVisitor mv = new ISMethodVisitor(defaultVisitor, access, name, desc);
        if (name.equals(ByteCodeUtils.CONSTRUCTOR)) {
            Constructor constructor = ConstructorBuilder.build(visitedClassName, method);
            LabelNode start = new LabelNode();
            method.instructions.insert(constructor.loadThis, start);
            if (constructor.lineForLoad != -1) {
                // Record the line number from the start of LOAD_0 for uninitialized 'this'.
                // This allows a breakpoint to be set at the line with this(...) or super(...)
                // call in the constructor.
                method.instructions.insert(constructor.loadThis,
                        new LineNumberNode(constructor.lineForLoad, start));
            }
            mv.addRedirection(new ConstructorRedirection(start, constructor, args));
        } else {
            mv.addRedirection(new MethodRedirection(new LabelNode(mv.getStartLabel()), name + "." + desc, args,
                    Type.getReturnType(desc)));
        }
        method.accept(mv);
        return null;
    }
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java

License:Apache License

/***
 * Inserts a trampoline to this class so that the updated methods can make calls to super
 * class methods.//from   ww  w  .  j a v  a2 s  .  c om
 * <p>
 * Pseudo code for this trampoline:
 * <code>
 *   Object access$super($classType instance, String name, object[] args) {
 *      switch(name) {
 *          case "firstMethod.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;":
 *            return super~instance.firstMethod((String)arg[0], arg[1]);
 *          case "secondMethod.(Ljava/lang/String;I)V":
 *            return super~instance.firstMethod((String)arg[0], arg[1]);
 *
 *          default:
 *            StringBuilder $local1 = new StringBuilder();
 *            $local1.append("Method not found ");
 *            $local1.append(name);
 *            $local1.append(" in " $classType $super implementation");
 *            throw new $package/InstantReloadException($local1.toString());
 *      }
 * </code>
 */
private void createAccessSuper() {
    int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_VARARGS;
    Method m = new Method("access$super",
            "(L" + visitedClassName + ";Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
    MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null);

    final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);

    // Gather all methods from itself and its superclasses to generate a giant access$super
    // implementation.
    // This will work fine as long as we don't support adding methods to a class.
    final Map<String, MethodReference> uniqueMethods = new HashMap<>();
    if (parentNodes.isEmpty()) {
        // if we cannot determine the parents for this class, let's blindly add all the
        // method of the current class as a gateway to a possible parent version.
        addAllNewMethods(classNode, classNode, uniqueMethods);
    } else {
        // otherwise, use the parent list.
        for (ClassNode parentNode : parentNodes) {
            addAllNewMethods(classNode, parentNode, uniqueMethods);
        }
    }

    new StringSwitch() {
        @Override
        void visitString() {
            mv.visitVarInsn(Opcodes.ALOAD, 1);
        }

        @Override
        void visitCase(String methodName) {
            MethodReference methodRef = uniqueMethods.get(methodName);

            mv.visitVarInsn(Opcodes.ALOAD, 0);

            Type[] args = Type.getArgumentTypes(methodRef.method.desc);
            int argc = 0;
            for (Type t : args) {
                mv.visitVarInsn(Opcodes.ALOAD, 2);
                mv.push(argc);
                mv.visitInsn(Opcodes.AALOAD);
                ByteCodeUtils.unbox(mv, t);
                argc++;
            }

            if (TRACING_ENABLED) {
                trace(mv, "super selected ", methodRef.owner.name, methodRef.method.name,
                        methodRef.method.desc);
            }
            String parentName = findParentClassForMethod(methodRef);
            LOG.verbose("Generating access$super for " + methodRef.method.name + " recv " + parentName);

            // Call super on the other object, yup this works cos we are on the right place to
            // call from.
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, parentName, methodRef.method.name, methodRef.method.desc,
                    false);

            Type ret = Type.getReturnType(methodRef.method.desc);
            if (ret.getSort() == Type.VOID) {
                mv.visitInsn(Opcodes.ACONST_NULL);
            } else {
                mv.box(ret);
            }
            mv.visitInsn(Opcodes.ARETURN);
        }

        @Override
        void visitDefault() {
            writeMissingMessageWithHash(mv, visitedClassName);
        }
    }.visit(mv, uniqueMethods.keySet());

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

From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Add all unseen methods from the passed ClassNode's methods.
 *
 * @see ClassNode#methods/* w  w w .j  ava  2s .  co m*/
 * @param instrumentedClass class that is being visited
 * @param superClass the class to save all new methods from
 * @param methods the methods already encountered in the ClassNode hierarchy
 */
private static void addAllNewMethods(ClassNode instrumentedClass, ClassNode superClass,
        Map<String, MethodReference> methods) {
    //noinspection unchecked
    for (MethodNode method : (List<MethodNode>) superClass.methods) {
        if (method.name.equals(ByteCodeUtils.CONSTRUCTOR)
                || method.name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
            continue;
        }
        String name = method.name + "." + method.desc;
        if (isAccessCompatibleWithInstantRun(method.access) && !methods.containsKey(name)
                && (method.access & Opcodes.ACC_STATIC) == 0
                && isCallableFromSubclass(method, superClass, instrumentedClass)) {
            methods.put(name, new MethodReference(method, superClass));
        }
    }
}