Example usage for org.objectweb.asm Opcodes ACC_PUBLIC

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

Introduction

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

Prototype

int ACC_PUBLIC

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

Click Source Link

Usage

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

License:Apache License

@Nullable
public static File instrumentClass(int targetApiLevel, @NonNull File inputRootDirectory,
        @NonNull File inputFile, @NonNull File outputDirectory, @NonNull VisitorBuilder visitorBuilder,
        @NonNull ILogger logger) throws IOException {

    byte[] classBytes;
    String path = FileUtils.relativePath(inputFile, inputRootDirectory);

    // if the class is not eligible for IR, return the non instrumented version or null if
    // the override class is requested.
    if (!isClassEligibleForInstantRun(inputFile)) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            File outputFile = new File(outputDirectory, path);
            Files.createParentDirs(outputFile);
            Files.copy(inputFile, outputFile);
            return outputFile;
        } else {//from w  w  w  .  ja  va  2  s  . com
            return null;
        }
    }
    classBytes = Files.toByteArray(inputFile);
    ClassReader classReader = new ClassReader(classBytes);
    // override the getCommonSuperClass to use the thread context class loader instead of
    // the system classloader. This is useful as ASM needs to load classes from the project
    // which the system classloader does not have visibility upon.
    // TODO: investigate if there is not a simpler way than overriding.
    ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES) {
        @Override
        protected String getCommonSuperClass(final String type1, final String type2) {
            Class<?> c, d;
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            try {
                c = Class.forName(type1.replace('/', '.'), false, classLoader);
                d = Class.forName(type2.replace('/', '.'), false, classLoader);
            } catch (ClassNotFoundException e) {
                // This may happen if we're processing class files which reference APIs not
                // available on the target device. In this case return a dummy value, since this
                // is ignored during dx compilation.
                return "instant/run/NoCommonSuperClass";
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (c.isAssignableFrom(d)) {
                return type1;
            }
            if (d.isAssignableFrom(c)) {
                return type2;
            }
            if (c.isInterface() || d.isInterface()) {
                return "java/lang/Object";
            } else {
                do {
                    c = c.getSuperclass();
                } while (!c.isAssignableFrom(d));
                return c.getName().replace('.', '/');
            }
        }
    };

    ClassNode classNode = AsmUtils.readClass(classReader);

    // when dealing with interface, we just copy the inputFile over without any changes unless
    // this is a package private interface.
    AccessRight accessRight = AccessRight.fromNodeAccess(classNode.access);
    File outputFile = new File(outputDirectory, path);
    if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            // don't change the name of interfaces.
            Files.createParentDirs(outputFile);
            if (accessRight == AccessRight.PACKAGE_PRIVATE) {
                classNode.access = classNode.access | Opcodes.ACC_PUBLIC;
                classNode.accept(classWriter);
                Files.write(classWriter.toByteArray(), outputFile);
            } else {
                // just copy the input file over, no change.
                Files.write(classBytes, outputFile);
            }
            return outputFile;
        } else {
            return null;
        }
    }

    AsmUtils.DirectoryBasedClassReader directoryClassReader = new AsmUtils.DirectoryBasedClassReader(
            getBinaryFolder(inputFile, classNode));

    // if we are targeting a more recent version than the current device, disable instant run
    // for that class.
    List<ClassNode> parentsNodes = isClassTargetingNewerPlatform(targetApiLevel, TARGET_API_TYPE,
            directoryClassReader, classNode, logger) ? ImmutableList.of()
                    : AsmUtils.parseParents(logger, directoryClassReader, classNode, targetApiLevel);
    // if we could not determine the parent hierarchy, disable instant run.
    if (parentsNodes.isEmpty() || isPackageInstantRunDisabled(inputFile)) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            Files.createParentDirs(outputFile);
            Files.write(classBytes, outputFile);
            return outputFile;
        } else {
            return null;
        }
    }

    outputFile = new File(outputDirectory, visitorBuilder.getMangledRelativeClassFilePath(path));
    Files.createParentDirs(outputFile);
    IncrementalVisitor visitor = visitorBuilder.build(classNode, parentsNodes, classWriter, logger);

    if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
        /*
         * Classes that do not have a serial version unique identifier, will be updated to
         * contain one. This is accomplished by using the {@link SerialVersionUIDAdder} class
         * visitor that is added when this visitor is created (see the constructor). This way,
         * the serialVersionUID is the same for instrumented and non-instrumented classes. All
         * classes will have a serialVersionUID, so if some of the classes that is extended
         * starts implementing {@link java.io.Serializable}, serialization and deserialization
         * will continue to work correctly.
         */
        classNode.accept(new SerialVersionUIDAdder(visitor));
    } else {
        classNode.accept(visitor);
    }

    Files.write(classWriter.toByteArray(), outputFile);
    return outputFile;
}

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

License:Apache License

@NonNull
private static InstantRunVerifierStatus verifyFields(@NonNull ClassNode originalClass,
        @NonNull ClassNode updatedClass) {

    //noinspection unchecked
    Diff diff = diffList(originalClass.fields, updatedClass.fields, new Comparator<FieldNode>() {

        @Override/*from  w ww . j a v a 2 s.  com*/
        public boolean areEqual(@Nullable FieldNode first, @Nullable FieldNode second) {
            if ((first == null) && (second == null)) {
                return true;
            }
            if (first == null || second == null) {
                return true;
            }
            return first.name.equals(second.name) && first.desc.equals(second.desc)
                    && first.access == second.access && Objects.equal(first.value, second.value);
        }
    });

    if (diff != Diff.NONE) {
        // Detect R$something classes, and report changes in them separately.
        String name = originalClass.name;
        int index = name.lastIndexOf('/');
        if (index != -1 && name.startsWith("R$", index + 1) && (originalClass.access & Opcodes.ACC_PUBLIC) != 0
                && (originalClass.access & Opcodes.ACC_FINAL) != 0 && originalClass.outerClass == null
                && originalClass.interfaces.isEmpty() && originalClass.superName.equals("java/lang/Object")
                && name.length() > 3 && Character.isLowerCase(name.charAt(2))) {
            return R_CLASS_CHANGE;
        }
    }

    switch (diff) {
    case NONE:
        return COMPATIBLE;
    case ADDITION:
        return FIELD_ADDED;
    case REMOVAL:
        return FIELD_REMOVED;
    case CHANGE:
        return FIELD_TYPE_CHANGE;
    default:
        throw new RuntimeException("Unhandled action : " + diff);
    }
}

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 :// w  w  w . ja  v a  2 s  .  c om
 *      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  . j  a v a2s. c  om*/
@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 a2  s .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 ww w .ja  va  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.//from  w ww .ja va  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./* ww  w  .  java  2  s  .  c  om*/
 *
 * <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

/***
 * Inserts a trampoline to this class so that the updated methods can make calls to super
 * class methods./*from   w  ww.  jav a2s.  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

/**
 * Adds serialVersionUID for the classes that does not define one. Reason for this is that if a
 * class does not define a serialVersionUID value, and is used for serialization, instrumented
 * and non-instrumented class will have different serialVersionUID values, and that will break
 * serialization.//ww  w .  j av  a 2  s .co  m
 */
private void addSerialUidIfMissing() {
    // noinspection unchecked
    for (FieldNode f : (List<FieldNode>) classNode.fields) {
        if (f.name.equals("serialVersionUID")) {
            // We should not generate serial uuid, field already exists. Although it might
            // not be static, final, and long, adding would break the instrumented class.
            return;
        }
    }
    try {
        String className = Type.getObjectType(classNode.name).getClassName();
        Class<?> clazz = Class.forName(className, false, Thread.currentThread().getContextClassLoader());

        ObjectStreamClass objectStreamClass = ObjectStreamClass.lookupAny(clazz);
        long serialUuid = objectStreamClass.getSerialVersionUID();

        // adds the field
        super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "serialVersionUID",
                Type.LONG_TYPE.getDescriptor(), null, serialUuid);

    } catch (ClassNotFoundException ex) {
        LOG.verbose("Unable to add auto-generated serialVersionUID for %1$s : %2$s", classNode.name,
                ex.getMessage());
    } catch (LinkageError | AssertionError e) {
        // http://b.android.com/220635 - static initializer might be invoked
        LOG.warning("Unable to generate serialVersionUID for %s. In case you make this class"
                + " serializable and use it to persist data in InstantRun mode, please"
                + " add a serialVersionUID field.", classNode.name);
    }
}