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.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  w ww . j ava  2  s  .co m
 *   <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 mv = createMethodAdapter(access, constructor.args.name, constructor.args.desc,
                constructor.args.desc, constructor.args.signature, exceptions, isStatic,
                true /* isConstructor */);
        constructor.args.accept(mv);

        mv = createMethodAdapter(access, constructor.body.name, constructor.body.desc, newDesc,
                constructor.body.signature, exceptions, 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;
        return createMethodAdapter(access, newName, newDesc, newDesc, signature, exceptions, isStatic,
                false /* isConstructor */);
    }
}

From source file:com.android.build.gradle.internal.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  w  w.j  av a2  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("<clinit>") || methodNode.name.equals("<init>")) {
            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.internal.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Ensures that the class contains a $change field used for referencing the IncrementalChange
 * dispatcher./*  w  w  w .  j a  v a 2s.c o m*/
 *
 * <p>Also updates package_private visibility to public so we can call into this class from
 * outside the package.
 */
@Override
public void visit(int version, int access, String name, String signature, String superName,
        String[] interfaces) {
    visitedClassName = name;
    visitedSuperName = superName;

    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.internal.incremental.IncrementalSupportVisitor.java

License:Apache License

@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
    int newAccess = access & (~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
    super.visitInnerClass(name, outerName, innerName, newAccess);
}

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

License:Apache License

/**
 * If a class is package private, make it public so instrumented code living in a different
 * class loader can instantiate them.//from w w w . j  a v  a 2  s . c  o  m
 *
 * <p>We also set the {@code ACC_SUPER} flag on every class, since otherwise the
 * {@code invokespecial} bytecodes in access$super get compiled to invoke-direct, which fails
 * at runtime (on KitKat). See the VM spec (4.1) for the whole story of {@code ACC_SUPER}. It
 * is only missing in classes generated by third-party tools, e.g. AspectJ.
 *
 * @param access the original class/method/field access.
 * @return the new access or the same one depending on the original access rights.
 */
private static int transformClassAccessForInstantRun(int access) {
    AccessRight accessRight = AccessRight.fromNodeAccess(access);
    int fixedVisibility = accessRight == AccessRight.PACKAGE_PRIVATE ? access | Opcodes.ACC_PUBLIC : access;

    // TODO: only do this on KitKat?
    return fixedVisibility | Opcodes.ACC_SUPER;
}

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

License:Apache License

/**
 * If a method/field is not private, make it public. This is to workaround the fact
 * <ul>Our restart.dex files are loaded with a different class loader than the main dex file
 * class loader on restart. so we need methods/fields to be public</ul>
 * <ul>Our reload.dex are loaded from a different class loader as well but methods/fields
 * are accessed through reflection, yet you need class visibility.</ul>
 *
 * remember that in Java, protected methods or fields can be acessed by classes in the same
 * package :/*from   ww w  . j a  v  a  2 s .  c o m*/
 * {@see https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html}
 *
 * @param access the original class/method/field access.
 * @return the new access or the same one depending on the original access rights.
 */
private static int transformAccessForInstantRun(int access) {
    AccessRight accessRight = AccessRight.fromNodeAccess(access);
    if (accessRight != AccessRight.PRIVATE) {
        access &= ~Opcodes.ACC_PROTECTED;
        access &= ~Opcodes.ACC_PRIVATE;
        return access | Opcodes.ACC_PUBLIC;
    }
    return access;
}

From source file:com.android.build.gradle.internal.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.j  a va2  s .c  o  m*/
 * <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);
            logger.verbose("Generating access$super for %1$s recev %2$s", methodRef.method.name, 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.internal.incremental.IncrementalSupportVisitor.java

License:Apache License

/***
 * Inserts a trampoline to this class so that the updated methods can make calls to
 * constructors.// w  ww.  j  a v a2  s  . c  om
 *
 * <p>
 * Pseudo code for this trampoline:
 * <code>
 *   ClassName(Object[] args, Marker unused) {
 *      String name = (String) args[0];
 *      if (name.equals(
 *          "java/lang/ClassName.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) {
 *        this((String)arg[1], arg[2]);
 *        return
 *      }
 *      if (name.equals("SuperClassName.(Ljava/lang/String;I)V")) {
 *        super((String)arg[1], (int)arg[2]);
 *        return;
 *      }
 *      ...
 *      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 createDispatchingThis() {
    // Gather all methods from itself and its superclasses to generate a giant constructor
    // implementation.
    // This will work fine as long as we don't support adding constructors to classes.
    final Map<String, MethodNode> uniqueMethods = new HashMap<>();

    addAllNewConstructors(uniqueMethods, classNode, true /*keepPrivateConstructors*/);
    for (ClassNode parentNode : parentNodes) {
        addAllNewConstructors(uniqueMethods, parentNode, false /*keepPrivateConstructors*/);
    }

    int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;

    Method m = new Method(ByteCodeUtils.CONSTRUCTOR, ConstructorRedirection.DISPATCHING_THIS_SIGNATURE);
    MethodVisitor visitor = super.visitMethod(0, m.getName(), m.getDescriptor(), null, null);
    final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);

    mv.visitCode();
    // Mark this code as redirection code
    Label label = new Label();
    mv.visitLineNumber(0, label);

    // Get and store the constructor canonical name.
    mv.visitVarInsn(Opcodes.ALOAD, 1);
    mv.push(1);
    mv.visitInsn(Opcodes.AALOAD);
    mv.unbox(Type.getType("Ljava/lang/String;"));
    final int constructorCanonicalName = mv.newLocal(Type.getType("Ljava/lang/String;"));
    mv.storeLocal(constructorCanonicalName);

    new StringSwitch() {

        @Override
        void visitString() {
            mv.loadLocal(constructorCanonicalName);
        }

        @Override
        void visitCase(String canonicalName) {
            MethodNode methodNode = uniqueMethods.get(canonicalName);
            String owner = canonicalName.split("\\.")[0];

            // Parse method arguments and
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            Type[] args = Type.getArgumentTypes(methodNode.desc);
            int argc = 1;
            for (Type t : args) {
                mv.visitVarInsn(Opcodes.ALOAD, 1);
                mv.push(argc + 1);
                mv.visitInsn(Opcodes.AALOAD);
                ByteCodeUtils.unbox(mv, t);
                argc++;
            }

            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, ByteCodeUtils.CONSTRUCTOR, methodNode.desc, false);

            mv.visitInsn(Opcodes.RETURN);
        }

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

    mv.visitMaxs(1, 3);
    mv.visitEnd();
}

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

License:Apache License

private static boolean isParentClassVisible(@NonNull ClassNode parent, @NonNull ClassNode child) {

    return ((parent.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0 || Objects
            .equal(ByteCodeUtils.getPackageName(parent.name), ByteCodeUtils.getPackageName(child.name)));
}

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

License:Apache License

@SuppressWarnings("SimplifiableIfStatement")
private static boolean isCallableFromSubclass(@NonNull MethodNode method, @NonNull ClassNode superClass,
        @NonNull ClassNode subclass) {//w w w.  j a  v  a2 s. c  o  m
    if ((method.access & Opcodes.ACC_PRIVATE) != 0) {
        return false;
    } else if ((method.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0) {
        return true;
    } else {
        // "package private" access modifier.
        return Objects.equal(ByteCodeUtils.getPackageName(superClass.name),
                ByteCodeUtils.getPackageName(subclass.name));
    }
}