Example usage for org.objectweb.asm.tree MethodInsnNode getOpcode

List of usage examples for org.objectweb.asm.tree MethodInsnNode getOpcode

Introduction

In this page you can find the example usage for org.objectweb.asm.tree MethodInsnNode getOpcode.

Prototype

public int getOpcode() 

Source Link

Document

Returns the opcode of this instruction.

Usage

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

public boolean collectCodeBlocks() {
    final int numIns = mn.instructions.size();

    codeBlocks[0] = FrameInfo.FIRST;/*from ww  w. ja  va 2 s.c  o m*/
    for (int i = 0; i < numIns; i++) {
        final Frame f = frames[i];
        if (f != null) { // reachable ?
            AbstractInsnNode in = mn.instructions.get(i);
            if (in.getType() == AbstractInsnNode.METHOD_INSN
                    || in.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) {
                Boolean susp = true;
                if (in.getType() == AbstractInsnNode.METHOD_INSN) {
                    final MethodInsnNode min = (MethodInsnNode) in;
                    int opcode = min.getOpcode();

                    if (isReflectInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG,
                                "Reflective method call at instruction %d is assumed suspendable", i);
                    else if (isMethodHandleInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG,
                                "MethodHandle invocation at instruction %d is assumed suspendable", i);
                    else if (isInvocationHandlerInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG,
                                "InvocationHandler invocation at instruction %d is assumed suspendable", i);
                    else {
                        SuspendableType st = db.isMethodSuspendable(min.owner, min.name, min.desc, opcode);
                        if (st == SuspendableType.NON_SUSPENDABLE)
                            susp = false;
                        else if (st == null) {
                            db.log(LogLevel.WARNING,
                                    "Method not found in class - assuming suspendable: %s#%s%s (at%s#%s)",
                                    min.owner, min.name, min.desc, className, mn.name);
                            susp = true;
                        } else if (susp)
                            db.log(LogLevel.DEBUG, "Method call at instruction %d to %s#%s%s is suspendable", i,
                                    min.owner, min.name, min.desc);
                        if (st == SuspendableType.SUSPENDABLE_SUPER)
                            this.hasSuspendableSuperCalls = true;
                    }
                } else { // invoke dynamic
                    final InvokeDynamicInsnNode idin = (InvokeDynamicInsnNode) in;
                    if (idin.bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")) { // lambda
                        db.log(LogLevel.DEBUG, "Lambda at instruction %d", i);
                        susp = false;
                    } else
                        db.log(LogLevel.DEBUG,
                                "InvokeDynamic Method call at instruction %d to is assumed suspendable", i);
                }

                if (susp) {
                    FrameInfo fi = addCodeBlock(f, i);
                    splitTryCatch(fi);
                } else {
                    if (in.getType() == AbstractInsnNode.METHOD_INSN) {// not invokedynamic
                        final MethodInsnNode min = (MethodInsnNode) in;
                        db.log(LogLevel.DEBUG, "Method call at instruction %d to %s#%s%s is not suspendable", i,
                                min.owner, min.name, min.desc);
                        int blockingId = isBlockingCall(min);
                        if (blockingId >= 0 && !isAllowedToBlock(className, mn.name)) {
                            int mask = 1 << blockingId;
                            if (!db.isAllowBlocking()) {
                                throw new UnableToInstrumentException(
                                        "blocking call to " + min.owner + "#" + min.name + min.desc, className,
                                        mn.name, mn.desc);
                            } else if ((warnedAboutBlocking & mask) == 0) {
                                warnedAboutBlocking |= mask;
                                db.log(LogLevel.WARNING, "Method %s#%s%s contains potentially blocking call to "
                                        + min.owner + "#" + min.name + min.desc, className, mn.name, mn.desc);
                            }
                        }
                    }
                }
            }
        }
    }
    addCodeBlock(null, numIns);

    return numCodeBlocks > 1;
}

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

public void accept(MethodVisitor mv, boolean hasAnnotation) {
    db.log(LogLevel.INFO, "Instrumenting method %s#%s%s", className, mn.name, mn.desc);

    mv.visitAnnotation(ALREADY_INSTRUMENTED_DESC, true);
    final boolean handleProxyInvocations = HANDLE_PROXY_INVOCATIONS & hasSuspendableSuperCalls;
    mv.visitCode();//from   w ww .  j  a  v a2  s  .  co  m

    Label lMethodStart = new Label();
    Label lMethodStart2 = new Label();
    Label lMethodEnd = new Label();
    Label lCatchSEE = new Label();
    Label lCatchUTE = new Label();
    Label lCatchAll = new Label();
    Label[] lMethodCalls = new Label[numCodeBlocks - 1];

    for (int i = 1; i < numCodeBlocks; i++)
        lMethodCalls[i - 1] = new Label();

    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);

    //        if (verifyInstrumentation) {
    //            mv.visitInsn(Opcodes.ICONST_0);
    //            mv.visitVarInsn(Opcodes.ISTORE, lvarSuspendableCalled);
    //        }
    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, EXCEPTION_NAME);
    if (handleProxyInvocations)
        mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchUTE, UNDECLARED_THROWABLE_NAME);

    // Prepare visitTryCatchBlocks for InvocationTargetException.
    // With reflective invocations, the SuspendExecution exception will be wrapped in InvocationTargetException. We need to catch it and unwrap it.
    // Note that the InvocationTargetException will be regenrated on every park, adding further overhead on top of the reflective call.
    // This must be done here, before all other visitTryCatchBlock, because the exception's handler
    // will be matched according to the order of in which visitTryCatchBlock has been called. Earlier calls take precedence.
    Label[][] refInvokeTryCatch = new Label[numCodeBlocks - 1][];
    for (int i = 1; i < numCodeBlocks; i++) {
        FrameInfo fi = codeBlocks[i];
        AbstractInsnNode in = mn.instructions.get(fi.endInstruction);
        if (mn.instructions.get(fi.endInstruction) instanceof MethodInsnNode) {
            MethodInsnNode min = (MethodInsnNode) in;
            if (isReflectInvocation(min.owner, min.name)) {
                Label[] ls = new Label[3];
                for (int k = 0; k < 3; k++)
                    ls[k] = new Label();
                refInvokeTryCatch[i - 1] = ls;
                mv.visitTryCatchBlock(ls[0], ls[1], ls[2], "java/lang/reflect/InvocationTargetException");
            }
        }
    }

    for (Object o : mn.tryCatchBlocks) {
        TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        if (EXCEPTION_NAME.equals(tcb.type) && !hasAnnotation) // we allow catch of SuspendExecution in method annotated with @Suspendable.
            throw new UnableToInstrumentException("catch for SuspendExecution", className, mn.name, mn.desc);
        if (handleProxyInvocations && UNDECLARED_THROWABLE_NAME.equals(tcb.type)) // we allow catch of SuspendExecution in method annotated with @Suspendable.
            throw new UnableToInstrumentException("catch for UndeclaredThrowableException", className, mn.name,
                    mn.desc);
        //          if (INTERRUPTED_EXCEPTION_NAME.equals(tcb.type))
        //              throw new UnableToInstrumentException("catch for " + InterruptedException.class.getSimpleName(), className, mn.name, mn.desc);

        tcb.accept(mv);
    }

    if (mn.visibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.visibleParameterAnnotations, true);

    if (mn.invisibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.invisibleParameterAnnotations, false);

    if (mn.visibleAnnotations != null) {
        for (Object o : mn.visibleAnnotations) {
            AnnotationNode an = (AnnotationNode) o;
            an.accept(mv.visitAnnotation(an.desc, true));
        }
    }

    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchAll, null);

    mv.visitMethodInsn(Opcodes.INVOKESTATIC, STACK_NAME, "getStack", "()L" + STACK_NAME + ";");
    mv.visitInsn(Opcodes.DUP);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);

    // println(mv, "STACK: ", lvarStack);
    // dumpStack(mv);
    if (DUAL) {
        mv.visitJumpInsn(Opcodes.IFNULL, lMethodStart);
        mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    }

    emitStoreResumed(mv, true); // we'll assume we have been resumed

    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "nextMethodEntry", "()I");
    mv.visitTableSwitchInsn(1, numCodeBlocks - 1, lMethodStart2, lMethodCalls);

    mv.visitLabel(lMethodStart2);

    // the following code handles the case of an instrumented method called not as part of a suspendable code path
    // isFirstInStack will return false in that case.
    mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "isFirstInStackOrPushed", "()Z");
    mv.visitJumpInsn(Opcodes.IFNE, lMethodStart); // if true
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);

    mv.visitLabel(lMethodStart);

    emitStoreResumed(mv, false); // no, we have not been resumed

    dumpCodeBlock(mv, 0, 0);

    for (int i = 1; i < numCodeBlocks; i++) {
        FrameInfo fi = codeBlocks[i];

        MethodInsnNode min = (MethodInsnNode) (mn.instructions.get(fi.endInstruction));
        if (isYieldMethod(min.owner, min.name)) { // special case - call to yield
            if (min.getOpcode() != Opcodes.INVOKESTATIC)
                throw new UnableToInstrumentException("invalid call to suspending method.", className, mn.name,
                        mn.desc);

            final int numYieldArgs = TypeAnalyzer.getNumArguments(min.desc);
            final boolean yieldReturnsValue = (Type.getReturnType(min.desc) != Type.VOID_TYPE);

            emitStoreState(mv, i, fi, numYieldArgs); // we preserve the arguments for the call to yield on the operand stack
            emitStoreResumed(mv, false); // we have not been resumed
            // emitSuspendableCalled(mv);

            min.accept(mv); // we call the yield method
            if (yieldReturnsValue)
                mv.visitInsn(Opcodes.POP); // we ignore the returned value...
            mv.visitLabel(lMethodCalls[i - 1]); // we resume AFTER the call

            final Label afterPostRestore = new Label();
            mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
            mv.visitJumpInsn(Opcodes.IFEQ, afterPostRestore);
            emitPostRestore(mv);
            mv.visitLabel(afterPostRestore);

            emitRestoreState(mv, i, fi, numYieldArgs);
            if (yieldReturnsValue)
                mv.visitVarInsn(Opcodes.ILOAD, lvarResumed); // ... and replace the returned value with the value of resumed

            dumpCodeBlock(mv, i, 1); // skip the call
        } else {
            final Label lbl = new Label();
            if (DUAL) {
                mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
                mv.visitJumpInsn(Opcodes.IFNULL, lbl);
            }

            // normal case - call to a suspendable method - resume before the call
            emitStoreState(mv, i, fi, 0);
            emitStoreResumed(mv, false); // we have not been resumed
            // emitPreemptionPoint(mv, PREEMPTION_CALL);

            mv.visitLabel(lMethodCalls[i - 1]);
            emitRestoreState(mv, i, fi, 0);

            if (DUAL)
                mv.visitLabel(lbl);

            if (isReflectInvocation(min.owner, min.name)) {
                // We catch the InvocationTargetException and unwrap it if it wraps a SuspendExecution exception.
                Label[] ls = refInvokeTryCatch[i - 1];
                final Label startTry = ls[0];
                final Label endTry = ls[1];
                final Label startCatch = ls[2];
                final Label endCatch = new Label();
                final Label notSuspendExecution = new Label();

                // mv.visitTryCatchBlock(startTry, endTry, startCatch, "java/lang/reflect/InvocationTargetException");
                mv.visitLabel(startTry); // try {
                min.accept(mv); //   method.invoke()
                mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue); // save return value
                mv.visitLabel(endTry); // }
                mv.visitJumpInsn(Opcodes.GOTO, endCatch);
                mv.visitLabel(startCatch); // catch(InvocationTargetException ex) {
                mv.visitInsn(Opcodes.DUP);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause",
                        "()Ljava/lang/Throwable;");
                mv.visitTypeInsn(Opcodes.INSTANCEOF, EXCEPTION_NAME);
                mv.visitJumpInsn(Opcodes.IFEQ, notSuspendExecution);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause",
                        "()Ljava/lang/Throwable;");
                mv.visitLabel(notSuspendExecution);
                mv.visitInsn(Opcodes.ATHROW);
                mv.visitLabel(endCatch);

                mv.visitVarInsn(Opcodes.ALOAD, lvarInvocationReturnValue); // restore return value
                dumpCodeBlock(mv, i, 1); // skip the call
            } else {
                // emitSuspendableCalled(mv);
                dumpCodeBlock(mv, i, 0);
            }
        }
    }

    mv.visitLabel(lMethodEnd);

    if (handleProxyInvocations) {
        mv.visitLabel(lCatchUTE);
        mv.visitInsn(Opcodes.DUP);

        // println(mv, "CTCH: ");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;");
        // println(mv, "CAUSE: ");
        mv.visitTypeInsn(Opcodes.INSTANCEOF, EXCEPTION_NAME);
        mv.visitJumpInsn(Opcodes.IFEQ, lCatchAll);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;");
        mv.visitJumpInsn(Opcodes.GOTO, lCatchSEE);
    }

    mv.visitLabel(lCatchAll);
    emitPopMethod(mv);
    mv.visitLabel(lCatchSEE);

    // println(mv, "THROW: ");
    mv.visitInsn(Opcodes.ATHROW); // rethrow shared between catchAll and catchSSE

    if (mn.localVariables != null) {
        for (Object o : mn.localVariables)
            ((LocalVariableNode) o).accept(mv);
    }

    mv.visitMaxs(mn.maxStack + ADD_OPERANDS, mn.maxLocals + NUM_LOCALS + additionalLocals);
    mv.visitEnd();
}

From source file:com.android.tools.lint.checks.ApiDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//from   w ww.  j a  v a2s .  c om
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (mApiDatabase == null) {
        return;
    }

    if (AOSP_BUILD && classNode.name.startsWith("android/support/")) { //$NON-NLS-1$
        return;
    }

    // Requires util package (add prebuilts/tools/common/asm-tools/asm-debug-all-4.0.jar)
    //classNode.accept(new TraceClassVisitor(new PrintWriter(System.out)));

    int classMinSdk = getClassMinSdk(context, classNode);
    if (classMinSdk == -1) {
        classMinSdk = getMinSdk(context);
    }

    List methodList = classNode.methods;
    if (methodList.isEmpty()) {
        return;
    }

    boolean checkCalls = context.isEnabled(UNSUPPORTED) || context.isEnabled(INLINED);
    boolean checkMethods = context.isEnabled(OVERRIDE) && context.getMainProject().getBuildSdk() >= 1;
    String frameworkParent = null;
    if (checkMethods) {
        LintDriver driver = context.getDriver();
        String owner = classNode.superName;
        while (owner != null) {
            // For virtual dispatch, walk up the inheritance chain checking
            // each inherited method
            if ((owner.startsWith("android/") //$NON-NLS-1$
                    && !owner.startsWith("android/support/")) //$NON-NLS-1$
                    || owner.startsWith("java/") //$NON-NLS-1$
                    || owner.startsWith("javax/")) { //$NON-NLS-1$
                frameworkParent = owner;
                break;
            }
            owner = driver.getSuperClass(owner);
        }
        if (frameworkParent == null) {
            checkMethods = false;
        }
    }

    if (checkCalls) { // Check implements/extends
        if (classNode.superName != null) {
            String signature = classNode.superName;
            checkExtendsClass(context, classNode, classMinSdk, signature);
        }
        if (classNode.interfaces != null) {
            @SuppressWarnings("unchecked") // ASM API
            List<String> interfaceList = classNode.interfaces;
            for (String signature : interfaceList) {
                checkExtendsClass(context, classNode, classMinSdk, signature);
            }
        }
    }

    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        int minSdk = getLocalMinSdk(method.invisibleAnnotations);
        if (minSdk == -1) {
            minSdk = classMinSdk;
        }

        InsnList nodes = method.instructions;

        if (checkMethods && Character.isJavaIdentifierStart(method.name.charAt(0))) {
            int buildSdk = context.getMainProject().getBuildSdk();
            String name = method.name;
            assert frameworkParent != null;
            int api = mApiDatabase.getCallVersion(frameworkParent, name, method.desc);
            if (api > buildSdk && buildSdk != -1) {
                // TODO: Don't complain if it's annotated with @Override; that means
                // somehow the build target isn't correct.
                String fqcn;
                String owner = classNode.name;
                if (CONSTRUCTOR_NAME.equals(name)) {
                    fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                } else {
                    fqcn = ClassContext.getFqcn(owner) + '#' + name;
                }
                String message = String.format(
                        "This method is not overriding anything with the current build "
                                + "target, but will in API level %1$d (current target is %2$d): %3$s",
                        api, buildSdk, fqcn);

                Location location = context.getLocation(method, classNode);
                context.report(OVERRIDE, method, null, location, message, null);
            }
        }

        if (!checkCalls) {
            continue;
        }

        if (CHECK_DECLARATIONS) {
            // Check types in parameter list and types of local variables
            List localVariables = method.localVariables;
            if (localVariables != null) {
                for (Object v : localVariables) {
                    LocalVariableNode var = (LocalVariableNode) v;
                    String desc = var.desc;
                    if (desc.charAt(0) == 'L') {
                        // "Lpackage/Class;" => "package/Bar"
                        String className = desc.substring(1, desc.length() - 1);
                        int api = mApiDatabase.getClassVersion(className);
                        if (api > minSdk) {
                            String fqcn = ClassContext.getFqcn(className);
                            String message = String.format(
                                    "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk,
                                    fqcn);
                            report(context, message, var.start, method,
                                    className.substring(className.lastIndexOf('/') + 1), null,
                                    SearchHints.create(NEAREST).matchJavaSymbol());
                        }
                    }
                }
            }

            // Check return type
            // The parameter types are already handled as local variables so we can skip
            // right to the return type.
            // Check types in parameter list
            String signature = method.desc;
            if (signature != null) {
                int args = signature.indexOf(')');
                if (args != -1 && signature.charAt(args + 1) == 'L') {
                    String type = signature.substring(args + 2, signature.length() - 1);
                    int api = mApiDatabase.getClassVersion(type);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(type);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                        report(context, message, first, method, method.name, null,
                                SearchHints.create(BACKWARD).matchJavaSymbol());
                    }
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                String desc = node.desc;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                boolean checkingSuperClass = false;
                while (owner != null) {
                    int api = mApiDatabase.getCallVersion(owner, name, desc);
                    if (api > minSdk) {
                        if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                            // We're in a compiler-generated method to generate an
                            // array indexed by enum ordinal values to enum values. The enum
                            // itself must be requiring a higher API number than is
                            // currently used, but the call site for the switch statement
                            // will also be referencing it, so no need to report these
                            // calls.
                            break;
                        }

                        if (!checkingSuperClass && node.getOpcode() == Opcodes.INVOKEVIRTUAL
                                && methodDefinedLocally(classNode, name, desc)) {
                            break;
                        }

                        String fqcn;
                        if (CONSTRUCTOR_NAME.equals(name)) {
                            fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                        } else {
                            fqcn = ClassContext.getFqcn(owner) + '#' + name;
                        }
                        String message = String.format(
                                "Call requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);

                        if (name.equals(ORDINAL_METHOD) && instruction.getNext() != null
                                && instruction.getNext().getNext() != null
                                && instruction.getNext().getOpcode() == Opcodes.IALOAD
                                && instruction.getNext().getNext().getOpcode() == Opcodes.TABLESWITCH) {
                            message = String.format(
                                    "Enum for switch requires API level %1$d " + "(current min is %2$d): %3$s",
                                    api, minSdk, ClassContext.getFqcn(owner));
                        }

                        report(context, message, node, method, name, null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith("javax/")) { //$NON-NLS-1$
                        // The API map has already inlined all inherited methods
                        // so no need to keep checking up the chain
                        // -- unless it's the support library which is also in
                        // the android/ namespace:
                        if (owner.startsWith("android/support/")) { //$NON-NLS-1$
                            owner = context.getDriver().getSuperClass(owner);
                        } else {
                            owner = null;
                        }
                    } else if (owner.startsWith("java/")) { //$NON-NLS-1$
                        if (owner.equals(LocaleDetector.DATE_FORMAT_OWNER)) {
                            checkSimpleDateFormat(context, method, node, minSdk);
                        }
                        // Already inlined; see comment above
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC && api == -1) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }

                    checkingSuperClass = true;
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                int api = mApiDatabase.getFieldVersion(owner, name);
                if (api > minSdk) {
                    if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                        checkSwitchBlock(context, classNode, node, method, name, owner, api, minSdk);
                        continue;
                    }
                    String fqcn = ClassContext.getFqcn(owner) + '#' + name;
                    if (mPendingFields != null) {
                        mPendingFields.remove(fqcn);
                    }
                    String message = String.format("Field requires API level %1$d (current min is %2$d): %3$s",
                            api, minSdk, fqcn);
                    report(context, message, node, method, name, null,
                            SearchHints.create(FORWARD).matchJavaSymbol());
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();

                    int api = mApiDatabase.getClassVersion(className);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(className);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        report(context, message, node, method,
                                className.substring(className.lastIndexOf('/') + 1), null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.InvalidPackageDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//from   ww  w .ja v a  2s.co  m
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!context.isFromClassLibrary() || shouldSkip(context.file)) {
        return;
    }

    if (mApiDatabase == null) {
        return;
    }

    if (classNode.name.startsWith(JAVAX_PKG_PREFIX)) {
        mJavaxLibraryClasses.add(classNode.name);
    }

    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        InsnList nodes = method.instructions;

        // Check return type
        // The parameter types are already handled as local variables so we can skip
        // right to the return type.
        // Check types in parameter list
        String signature = method.desc;
        if (signature != null) {
            int args = signature.indexOf(')');
            if (args != -1 && signature.charAt(args + 1) == 'L') {
                String type = signature.substring(args + 2, signature.length() - 1);
                if (isInvalidPackage(type)) {
                    AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                    record(context, method, first, type);
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String owner = node.owner;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                while (owner != null) {
                    if (isInvalidPackage(owner)) {
                        record(context, method, instruction, owner);
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith(JAVA_PKG_PREFIX) || owner.startsWith(JAVAX_PKG_PREFIX)) {
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String owner = node.owner;
                if (isInvalidPackage(owner)) {
                    record(context, method, instruction, owner);
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();
                    if (isInvalidPackage(className)) {
                        record(context, method, instruction, className);
                    }
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.SecureRandomGeneratorDetector.java

License:Apache License

@Override
public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode call) {
    if (mIgnore) {
        return;//from  ww  w  . j  a v a2s .  c o  m
    }

    String owner = call.owner;
    String name = call.name;

    // Look for the workaround code: if we see a Class.forName on the harmony NativeCrypto,
    // we'll consider that a sign.

    if (name.equals(FOR_NAME)) {
        if (call.getOpcode() != Opcodes.INVOKESTATIC || !owner.equals(JAVA_LANG_CLASS)) {
            return;
        }
        AbstractInsnNode prev = LintUtils.getPrevInstruction(call);
        if (prev instanceof LdcInsnNode) {
            Object cst = ((LdcInsnNode) prev).cst;
            //noinspection SpellCheckingInspection
            if (cst instanceof String && "org.apache.harmony.xnet.provider.jsse.NativeCrypto".equals(cst)) {
                mIgnore = true;
            }
        }
        return;
    }

    // Look for calls that probably require a properly initialized random number generator.
    assert owner.equals(JAVAX_CRYPTO_KEY_GENERATOR) || owner.equals(JAVA_SECURITY_KEY_PAIR_GENERATOR)
            || owner.equals(JAVAX_CRYPTO_KEY_AGREEMENT) || owner.equals(OWNER_SECURE_RANDOM)
            || owner.equals(JAVAX_CRYPTO_CIPHER) || owner.equals(JAVAX_CRYPTO_SIGNATURE)
            || owner.equals(JAVAX_NET_SSL_SSLENGINE) : owner;
    boolean warn = false;

    if (owner.equals(JAVAX_CRYPTO_SIGNATURE)) {
        warn = name.equals(INIT_SIGN);
    } else if (owner.equals(JAVAX_CRYPTO_CIPHER)) {
        if (name.equals(INIT)) {
            int arity = getDescArity(call.desc);
            AbstractInsnNode node = call;
            for (int i = 0; i < arity; i++) {
                node = LintUtils.getPrevInstruction(node);
                if (node == null) {
                    break;
                }
            }
            if (node != null) {
                int opcode = node.getOpcode();
                if (opcode == Opcodes.ICONST_3 || // Cipher.WRAP_MODE
                        opcode == Opcodes.ICONST_1) { // Cipher.ENCRYPT_MODE
                    warn = true;
                }
            }
        }
    } else if (name.equals(GET_INSTANCE) || name.equals(CONSTRUCTOR_NAME) || name.equals(WRAP)
            || name.equals(UNWRAP)) { // For SSLEngine
        warn = true;
    }

    if (warn) {
        if (mLocation != null) {
            return;
        }
        if (context.getMainProject().getMinSdk() > 18) {
            // Fix no longer needed
            mIgnore = true;
            return;
        }

        if (context.getDriver().isSuppressed(ISSUE, classNode, method, call)) {
            mIgnore = true;
        } else {
            mLocation = context.getLocation(call);
        }
    }
}

From source file:com.android.tools.lint.checks.WrongCallDetector.java

License:Apache License

@Override
public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode call) {
    String name = call.name;//from   w w w .java2s.  c o  m
    // Call is only allowed if it is both only called on the super class (invoke special)
    // as well as within the same overriding method (e.g. you can't call super.onLayout
    // from the onMeasure method)
    if (call.getOpcode() != Opcodes.INVOKESPECIAL || !name.equals(method.name)) {
        String suggestion = Character.toLowerCase(name.charAt(2)) + name.substring(3);
        String message = String.format(
                "Suspicious method call; should probably call \"%1$s\" rather than \"%2$s\"", suggestion, name);
        context.report(ISSUE, method, call, context.getLocation(call), message, null);
    }
}

From source file:com.dragome.callbackevictor.serverside.bytecode.transformation.asm.ContinuationMethodAdapter.java

License:Apache License

public void visitCode() {
    mv.visitCode();// w w  w .j av  a  2 s  . c  om

    int fsize = labels.size();
    Label[] restoreLabels = new Label[fsize];
    for (int i = 0; i < restoreLabels.length; i++) {
        restoreLabels[i] = new Label();
    }

    // verify if restoring
    Label l0 = new Label();

    // PC: StackRecorder stackRecorder = StackRecorder.get();
    mv.visitMethodInsn(INVOKESTATIC, STACK_RECORDER, "get", "()L" + STACK_RECORDER + ";", false);
    mv.visitInsn(DUP);
    mv.visitVarInsn(ASTORE, stackRecorderVar);
    mv.visitLabel(startLabel);

    // PC: if (stackRecorder != null && !stackRecorder.isRestoring) {  
    mv.visitJumpInsn(IFNULL, l0);
    mv.visitVarInsn(ALOAD, stackRecorderVar);
    mv.visitFieldInsn(GETFIELD, STACK_RECORDER, "isRestoring", "Z");
    mv.visitJumpInsn(IFEQ, l0);

    mv.visitVarInsn(ALOAD, stackRecorderVar);
    // PC:    stackRecorder.popInt();
    mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Int", "()I", false);
    mv.visitTableSwitchInsn(0, fsize - 1, l0, restoreLabels);

    // switch cases
    for (int i = 0; i < fsize; i++) {
        Label frameLabel = labels.get(i);
        mv.visitLabel(restoreLabels[i]);

        MethodInsnNode mnode = nodes.get(i);
        Frame frame = analyzer.getFrames()[canalyzer.getIndex(mnode)];

        // for each local variable store the value in locals popping it from the stack!
        // locals
        int lsize = frame.getLocals();
        for (int j = lsize - 1; j >= 0; j--) {
            BasicValue value = (BasicValue) frame.getLocal(j);
            if (isNull(value)) {
                mv.visitInsn(ACONST_NULL);
                mv.visitVarInsn(ASTORE, j);
            } else if (value == BasicValue.UNINITIALIZED_VALUE) {
                // TODO ??
            } else if (value == BasicValue.RETURNADDRESS_VALUE) {
                // TODO ??
            } else {
                mv.visitVarInsn(ALOAD, stackRecorderVar);
                Type type = value.getType();
                if (value.isReference()) {
                    mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Object",
                            "()Ljava/lang/Object;", false);
                    Type t = value.getType();
                    String desc = t.getDescriptor();
                    if (desc.charAt(0) == '[') {
                        mv.visitTypeInsn(CHECKCAST, desc);
                    } else {
                        mv.visitTypeInsn(CHECKCAST, t.getInternalName());
                    }
                    mv.visitVarInsn(ASTORE, j);

                } else {
                    mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPopMethod(type),
                            "()" + type.getDescriptor(), false);
                    mv.visitVarInsn(type.getOpcode(ISTORE), j);
                }
            }
        }

        if (frame instanceof MonitoringFrame) {
            int[] monitoredLocals = ((MonitoringFrame) frame).getMonitored();
            // System.out.println(System.identityHashCode(frame)+" AMonitored locals "+monitoredLocals.length);
            for (int monitoredLocal : monitoredLocals) {
                // System.out.println(System.identityHashCode(frame)+" AMonitored local "+monitoredLocals[j]);
                mv.visitVarInsn(ALOAD, monitoredLocal);
                mv.visitInsn(MONITORENTER);
            }
        }

        // stack
        int argSize = Type.getArgumentTypes(mnode.desc).length;
        int ownerSize = mnode.getOpcode() == INVOKESTATIC ? 0 : 1; // TODO
        int initSize = mnode.name.equals("<init>") ? 2 : 0;
        int ssize = frame.getStackSize();
        for (int j = 0; j < ssize - argSize - ownerSize - initSize; j++) {
            BasicValue value = (BasicValue) frame.getStack(j);
            if (isNull(value)) {
                mv.visitInsn(ACONST_NULL);
            } else if (value == BasicValue.UNINITIALIZED_VALUE) {
                // TODO ??
            } else if (value == BasicValue.RETURNADDRESS_VALUE) {
                // TODO ??
            } else if (value.isReference()) {
                mv.visitVarInsn(ALOAD, stackRecorderVar);
                mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Object", "()Ljava/lang/Object;",
                        false);
                mv.visitTypeInsn(CHECKCAST, value.getType().getInternalName());
            } else {
                Type type = value.getType();
                mv.visitVarInsn(ALOAD, stackRecorderVar);
                mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPopMethod(type),
                        "()" + type.getDescriptor(), false);
            }
        }

        boolean hasMethodRef = false;
        if (mnode.getOpcode() != INVOKESTATIC) {
            // Load the object whose method we are calling  
            BasicValue value = ((BasicValue) frame.getStack(ssize - argSize - 1));
            if (isNull(value)) {
                // If user code causes NPE, then we keep this behavior: load null to get NPE at runtime 
                mv.visitInsn(ACONST_NULL);
            } else {
                hasMethodRef = true;

                mv.visitVarInsn(ALOAD, stackRecorderVar);
                mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Reference",
                        "()Ljava/lang/Object;", false);
                mv.visitTypeInsn(CHECKCAST, value.getType().getInternalName());

            }
        }

        // Create null types for the parameters of the method invocation
        // RS:
        if (hasMethodRef && canalyzer._continueReflection && mnode.name.contains("invoke")
                && mnode.owner.contains("java/lang/reflect/Method")) {
            ContinuationMethodAnalyzer.MyVariables vars = canalyzer._reflectMapping.get(mnode);
            mv.visitVarInsn(ALOAD, vars.objectVar());
            mv.visitVarInsn(ALOAD, vars.argsVar());
            //mv.visitVarInsn(ALOAD, 2);
            //mv.visitVarInsn(ALOAD, 4);
        }
        //RS:
        else {
            for (Type paramType : Type.getArgumentTypes(mnode.desc)) {
                pushDefault(paramType);
            }
        }

        // continue to the next method
        mv.visitJumpInsn(GOTO, frameLabel);
    }

    // PC: }
    // end of start block
    mv.visitLabel(l0);
}

From source file:com.navercorp.pinpoint.profiler.instrument.ASMMethodVariables.java

License:Apache License

AbstractInsnNode findInitConstructorInstruction() {
    int nested = 0;
    for (AbstractInsnNode insnNode = this.methodNode.instructions
            .getFirst(); insnNode != null; insnNode = insnNode.getNext()) {
        if (insnNode instanceof TypeInsnNode) {
            if (insnNode.getOpcode() == Opcodes.NEW) {
                // new object().
                nested++;//from  www  .ja v a 2s. com
            }
        } else if (insnNode instanceof MethodInsnNode) {
            final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
            if (methodInsnNode.getOpcode() == Opcodes.INVOKESPECIAL && methodInsnNode.name.equals("<init>")) {
                if (--nested < 0) {
                    // find this() or super().
                    return insnNode.getNext();
                }
            }
        }
    }

    return null;
}

From source file:com.offbynull.coroutines.instrumenter.asm.MethodInvokeUtils.java

License:Open Source License

/**
 * Get the number of arguments required for an invocation of some method. This includes the 'this' argument for non-static methods.
 * <p>/*from  w ww .ja  v  a  2  s  .  c  o m*/
 * NOTE THAT THIS IS NOT THE NUMBER OF ITEMS ON THE STACK. If the method takes in doubles or longs, each double or long encountered
 * would be 2 items on the stack. This method returns the number of arguments required for the method to be invoked, not the number of
 * items required to be on the stack for the method to be invoked.
 * @param invokeNode the invocation instruction (either normal invocation or invokedynamic)
 * @return number of arguments required by this method
 * @throws NullPointerException if any argument is {@code null}
 * @throws IllegalArgumentException if {@code invokeNode} is neither of type {@link MethodInsnNode} nor {@link InvokeDynamicInsnNode},
 * or if type of invocation ({@link MethodInsnNode}) cannot be determined
 */
public static int getArgumentCountRequiredForInvocation(AbstractInsnNode invokeNode) {
    Validate.notNull(invokeNode);

    if (invokeNode instanceof MethodInsnNode) {
        MethodInsnNode methodInsnNode = (MethodInsnNode) invokeNode;
        int extra;
        int paramCount;

        switch (methodInsnNode.getOpcode()) {
        case Opcodes.INVOKEVIRTUAL:
        case Opcodes.INVOKESPECIAL:
        case Opcodes.INVOKEINTERFACE:
            extra = 1;
            break;
        case Opcodes.INVOKESTATIC:
            extra = 0;
            break;
        default:
            throw new IllegalArgumentException(); // unknown invocation type? probably badly generated instruction node
        }
        Type methodType = Type.getType(methodInsnNode.desc);
        paramCount = methodType.getArgumentTypes().length;

        return paramCount + extra;
    } else if (invokeNode instanceof InvokeDynamicInsnNode) {
        InvokeDynamicInsnNode invokeDynamicInsnNode = (InvokeDynamicInsnNode) invokeNode;
        int paramCount;

        Type methodType = Type.getType(invokeDynamicInsnNode.desc);
        paramCount = methodType.getArgumentTypes().length;

        return paramCount;
    } else {
        throw new IllegalArgumentException();
    }
}

From source file:com.offbynull.coroutines.instrumenter.asm.SearchUtils.java

License:Open Source License

/**
 * Get the number of items that need to be on the stack for an invocation of some method.
 * @param invokeNode the invocation instruction (either normal invocation or invokedynamic)
 * @return number of items required on the stack for this method
 * @throws NullPointerException if any argument is {@code null}
 * @throws IllegalArgumentException if {@code invokeNode} is neither of type {@link MethodInsnNode} nor {@link InvokeDynamicInsnNode},
 * or if type of invocation ({@link MethodInsnNode}) cannot be determined
 *//*from  ww w . j  a  va 2  s . c  om*/
public static int getRequiredStackCountForInvocation(AbstractInsnNode invokeNode) {
    Validate.notNull(invokeNode);

    if (invokeNode instanceof MethodInsnNode) {
        MethodInsnNode methodInsnNode = (MethodInsnNode) invokeNode;
        int extra;
        int paramCount;

        switch (methodInsnNode.getOpcode()) {
        case Opcodes.INVOKEVIRTUAL:
        case Opcodes.INVOKESPECIAL:
        case Opcodes.INVOKEINTERFACE:
            extra = 1;
            break;
        case Opcodes.INVOKESTATIC:
            extra = 0;
            break;
        default:
            throw new IllegalArgumentException(); // unknown invocation type? probably badly generated instruction node
        }
        Type methodType = Type.getType(methodInsnNode.desc);
        paramCount = methodType.getArgumentTypes().length;

        return paramCount + extra;
    } else if (invokeNode instanceof InvokeDynamicInsnNode) {
        InvokeDynamicInsnNode invokeDynamicInsnNode = (InvokeDynamicInsnNode) invokeNode;
        int paramCount;

        Type methodType = Type.getType(invokeDynamicInsnNode.desc);
        paramCount = methodType.getArgumentTypes().length;

        return paramCount;
    } else {
        throw new IllegalArgumentException();
    }
}