com.android.utils.AsmUtils Java Examples

The following examples show how to use com.android.utils.AsmUtils. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: IncrementalSupportVisitor.java    From AnoleFix with MIT License 5 votes vote down vote up
/**
 * Add all constructors from the passed ClassNode's methods. {@see ClassNode#methods}
 *
 * @param methods                 the constructors already encountered in the ClassNode hierarchy
 * @param classNode               the class to save all new methods from.
 * @param keepPrivateConstructors whether to keep the private constructors.
 */
private void addAllNewConstructors(Map<String, MethodNode> methods, ClassNode classNode,
                                   boolean keepPrivateConstructors) {
    //noinspection unchecked
    for (MethodNode method : (List<MethodNode>) classNode.methods) {
        if (!method.name.equals(AsmUtils.CONSTRUCTOR)) {
            continue;
        }

        if (!isAccessCompatibleWithInstantRun(method.access)) {
            continue;
        }

        if (!keepPrivateConstructors && (method.access & Opcodes.ACC_PRIVATE) != 0) {
            continue;
        }
        if (!classNode.name.equals(visitedClassName)
                && !classNode.name.equals(visitedSuperName)) {
            continue;
        }
        String key = classNode.name + "." + method.desc;
        if (methods.containsKey(key)) {
            continue;
        }
        methods.put(key, method);
    }
}
 
Example #2
Source File: IncrementalSupportVisitor.java    From AnoleFix with MIT License 4 votes vote down vote up
/**
 * Insert Constructor specific logic({@link ConstructorArgsRedirection} and
 * {@link ConstructorDelegationDetector}) for constructor redirecting or
 * normal method redirecting ({@link MethodRedirection}) for other methods.
 */
@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(AsmUtils.CLASS_INITIALIZER)) {
        return defaultVisitor;
    } else {
        ISMethodVisitor mv = new ISMethodVisitor(defaultVisitor, access, name, desc);
        if (name.equals(AsmUtils.CONSTRUCTOR)) {

            ConstructorDelegationDetector.Constructor constructor =
                    ConstructorDelegationDetector.deconstruct(visitedClassName, method);
            LabelNode start = new LabelNode();
            LabelNode after = 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));
            }
            method.instructions.insert(constructor.delegation, after);
            mv.addRedirection(
                    new ConstructorArgsRedirection(
                            start,
                            visitedClassName,
                            constructor.args.name + "." + constructor.args.desc,
                            after,
                            Type.getArgumentTypes(constructor.delegation.desc)));

            mv.addRedirection(new MethodRedirection(after, constructor.body.name + "."
                    + constructor.body.desc, Type.getReturnType(desc)));
        } else {
            mv.addRedirection(new MethodRedirection(
                    new LabelNode(mv.getStartLabel()),
                    name + "." + desc,
                    Type.getReturnType(desc)));
        }
        method.accept(mv);
        return null;
    }
}
 
Example #3
Source File: IncrementalSupportVisitor.java    From AnoleFix with MIT License 4 votes vote down vote up
/***
 * Inserts a trampoline to this class so that the updated methods can make calls to
 * constructors.
 * <p>
 * <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<String, MethodNode>();

    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(AsmUtils.CONSTRUCTOR,
            ConstructorArgsRedirection.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(0);
    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 = 0;
            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, AsmUtils.CONSTRUCTOR,
                    methodNode.desc, false);

            mv.visitInsn(Opcodes.RETURN);
        }

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

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