Search in sources :

Example 11 with AnnotationNode

use of org.objectweb.asm.tree.AnnotationNode in project sling by apache.

the class GenerateAdapterMetadataMojo method parseAdaptableAnnotation.

@SuppressWarnings("unchecked")
private void parseAdaptableAnnotation(final AnnotationNode annotation, final ClassNode annotatedClass, final Map<String, Object> descriptor) throws JsonException {
    String adaptableClassName = null;
    List<AnnotationNode> adapters = null;
    final List<?> values = annotation.values;
    final Iterator<?> it = values.iterator();
    while (it.hasNext()) {
        Object name = it.next();
        Object value = it.next();
        if ("adaptableClass".equals(name)) {
            adaptableClassName = ((Type) value).getClassName();
        } else if ("adapters".equals(name)) {
            adapters = (List<AnnotationNode>) value;
        }
    }
    if (adaptableClassName == null || adapters == null) {
        throw new IllegalArgumentException("Adaptable annotation is malformed. Expecting a classname and a list of adapter annotation.");
    }
    Map<String, Object> adaptableDescription;
    if (descriptor.containsKey(adaptableClassName)) {
        adaptableDescription = (Map<String, Object>) descriptor.get(adaptableClassName);
    } else {
        adaptableDescription = new HashMap<>();
        descriptor.put(adaptableClassName, adaptableDescription);
    }
    for (final AnnotationNode adapter : adapters) {
        parseAdapterAnnotation(adapter, annotatedClass, adaptableDescription);
    }
}
Also used : AnnotationNode(org.objectweb.asm.tree.AnnotationNode) List(java.util.List)

Example 12 with AnnotationNode

use of org.objectweb.asm.tree.AnnotationNode in project sling by apache.

the class GenerateAdapterMetadataMojo method parseAdaptablesAnnotation.

private void parseAdaptablesAnnotation(final AnnotationNode annotation, final ClassNode classNode, final Map<String, Object> descriptor) throws JsonException {
    final Iterator<?> it = annotation.values.iterator();
    while (it.hasNext()) {
        Object name = it.next();
        Object value = it.next();
        if ("value".equals(name)) {
            @SuppressWarnings("unchecked") final List<AnnotationNode> annotations = (List<AnnotationNode>) value;
            for (final AnnotationNode innerAnnotation : annotations) {
                if (ADAPTABLE_DESC.equals(innerAnnotation.desc)) {
                    parseAdaptableAnnotation(innerAnnotation, classNode, descriptor);
                }
            }
        }
    }
}
Also used : AnnotationNode(org.objectweb.asm.tree.AnnotationNode) List(java.util.List)

Example 13 with AnnotationNode

use of org.objectweb.asm.tree.AnnotationNode in project quasar by puniverse.

the class InstrumentMethod method accept.

public void accept(MethodVisitor mv, boolean hasAnnotation) {
    db.log(LogLevel.INFO, "Instrumenting method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
    if (mn.name.charAt(0) == '<')
        throw new UnableToInstrumentException("special method", className, mn.name, mn.desc);
    collectCallsites();
    final boolean skipInstrumentation = canInstrumentationBeSkipped(suspCallsBcis);
    emitInstrumentedAnn(db, mv, mn, sourceName, className, skipInstrumentation, startSourceLine, endSourceLine, suspCallsSourceLines, suspCallsNames, null);
    if (skipInstrumentation) {
        db.log(LogLevel.INFO, "[OPTIMIZE] Skipping instrumentation for method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
        // Dump
        mn.accept(mv);
        return;
    }
    // Else instrument
    // Must be called first, sets flags & state used below
    collectCodeBlocks();
    // noinspection ConstantConditions
    final boolean handleProxyInvocations = HANDLE_PROXY_INVOCATIONS && callsSuspendableSupers;
    mv.visitCode();
    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];
    Label[][] refInvokeTryCatch;
    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, SUSPEND_EXECUTION_NAME);
    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, RUNTIME_SUSPEND_EXECUTION_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.
    refInvokeTryCatch = new Label[numCodeBlocks - 1][];
    for (int i = 1; i < numCodeBlocks; i++) {
        final FrameInfo fi = codeBlocks[i];
        final 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");
            }
        }
    }
    // Output try-catch blocks
    for (final Object o : mn.tryCatchBlocks) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        if (// we allow catch of SuspendExecution only in methods annotated with @Suspendable and in lambda-generated ones.
        SUSPEND_EXECUTION_NAME.equals(tcb.type) && !hasAnnotation && !mn.name.startsWith(Classes.LAMBDA_METHOD_PREFIX))
            throw new UnableToInstrumentException("catch for SuspendExecution", className, mn.name, mn.desc);
        if (// we allow catch of SuspendExecution in method annotated with @Suspendable.
        handleProxyInvocations && UNDECLARED_THROWABLE_NAME.equals(tcb.type))
            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);
    }
    // Output parameter annotations
    if (mn.visibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.visibleParameterAnnotations, true);
    if (mn.invisibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.invisibleParameterAnnotations, false);
    // Output method annotations
    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 + ";", false);
    mv.visitInsn(Opcodes.DUP);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
    // println(mv, "STACK: ", lvarStack);
    // dumpStack(mv);
    // DUAL
    mv.visitJumpInsn(Opcodes.IFNULL, lMethodStart);
    mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    // we'll assume we have been resumed
    emitStoreResumed(mv, true);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "nextMethodEntry", "()I", false);
    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", false);
    // if true
    mv.visitJumpInsn(Opcodes.IFNE, lMethodStart);
    // This will reset the fiber stack local if isFirstStack returns false.
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
    mv.visitLabel(lMethodStart);
    // no, we have not been resumed
    emitStoreResumed(mv, false);
    dumpCodeBlock(mv, 0, 0);
    // Blocks leading to suspendable calls
    for (int i = 1; i < numCodeBlocks; i++) {
        final FrameInfo fi = codeBlocks[i];
        // Emit instrumented call
        final AbstractInsnNode min = mn.instructions.get(fi.endInstruction);
        final String owner = getMethodOwner(min), name = getMethodName(min), desc = getMethodDesc(min);
        if (isYieldMethod(owner, 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(desc);
            final boolean yieldReturnsValue = (Type.getReturnType(desc) != Type.VOID_TYPE);
            // we preserve the arguments for the call to yield on the operand stack
            emitStoreState(mv, i, fi, numYieldArgs);
            // we have not been resumed
            emitStoreResumed(mv, false);
            // emitSuspendableCalled(mv);
            // we call the yield method
            min.accept(mv);
            if (yieldReturnsValue)
                // we ignore the returned value...
                mv.visitInsn(Opcodes.POP);
            // we resume AFTER the call
            mv.visitLabel(lMethodCalls[i - 1]);
            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)
                // ... and replace the returned value with the value of resumed
                mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
            // See #211: if Fiber.park() is the last call before catch, ASM generates
            // empty handlers (start_pc = end_pc) that won't pass ASM's nor JVM's bytecode checker because of
            // exception_table's spec here: https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.3
            mv.visitInsn(Opcodes.NOP);
            dumpCodeBlock(mv, i, 1);
        } else {
            final Label lbl = new Label();
            // 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);
            // we have not been resumed
            emitStoreResumed(mv, false);
            // emitPreemptionPoint(mv, PREEMPTION_CALL);
            mv.visitLabel(lMethodCalls[i - 1]);
            emitRestoreState(mv, i, fi, 0);
            // DUAL
            mv.visitLabel(lbl);
            if (isReflectInvocation(owner, 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");
                // try {
                mv.visitLabel(startTry);
                // method.invoke()
                min.accept(mv);
                // save return value
                mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);
                // }
                mv.visitLabel(endTry);
                mv.visitJumpInsn(Opcodes.GOTO, endCatch);
                // catch(InvocationTargetException ex) {
                mv.visitLabel(startCatch);
                mv.visitInsn(Opcodes.DUP);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
                mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
                mv.visitJumpInsn(Opcodes.IFEQ, notSuspendExecution);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
                mv.visitLabel(notSuspendExecution);
                mv.visitInsn(Opcodes.ATHROW);
                mv.visitLabel(endCatch);
                // restore return value
                mv.visitVarInsn(Opcodes.ALOAD, lvarInvocationReturnValue);
                dumpCodeBlock(mv, i, 1);
            } else {
                // emitSuspendableCalled(mv);
                dumpCodeBlock(mv, i, 0);
            }
        }
    }
    // Emit catchall's catch section
    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;", false);
        // println(mv, "CAUSE: ");
        mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
        mv.visitJumpInsn(Opcodes.IFEQ, lCatchAll);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
        mv.visitJumpInsn(Opcodes.GOTO, lCatchSEE);
    }
    mv.visitLabel(lCatchAll);
    emitPopMethod(mv);
    mv.visitLabel(lCatchSEE);
    // println(mv, "THROW: ");
    // rethrow shared between catchAll and catchSSE
    mv.visitInsn(Opcodes.ATHROW);
    if (mn.localVariables != null) {
        for (Object o : mn.localVariables) ((LocalVariableNode) o).accept(mv);
    }
    // Needed by ASM analysis
    mv.visitMaxs(mn.maxStack + ADD_OPERANDS, mn.maxLocals + NUM_LOCALS + additionalLocals);
    mv.visitEnd();
}
Also used : TryCatchBlockNode(org.objectweb.asm.tree.TryCatchBlockNode) Label(org.objectweb.asm.Label) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode)

Example 14 with AnnotationNode

use of org.objectweb.asm.tree.AnnotationNode in project MinecraftForge by MinecraftForge.

the class EventSubscriberTransformer method transform.

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
    if (basicClass == null)
        return null;
    ClassNode classNode = new ClassNode();
    new ClassReader(basicClass).accept(classNode, 0);
    boolean isSubscriber = false;
    for (MethodNode methodNode : classNode.methods) {
        List<AnnotationNode> anns = methodNode.visibleAnnotations;
        if (anns != null && Iterables.any(anns, SubscribeEventPredicate.INSTANCE)) {
            if (Modifier.isPrivate(methodNode.access)) {
                String msg = "Cannot apply @SubscribeEvent to private method %s/%s%s";
                throw new RuntimeException(String.format(msg, classNode.name, methodNode.name, methodNode.desc));
            }
            methodNode.access = toPublic(methodNode.access);
            isSubscriber = true;
        }
    }
    if (isSubscriber) {
        classNode.access = toPublic(classNode.access);
        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        classNode.accept(writer);
        return writer.toByteArray();
    }
    return basicClass;
}
Also used : ClassNode(org.objectweb.asm.tree.ClassNode) MethodNode(org.objectweb.asm.tree.MethodNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) ClassReader(org.objectweb.asm.ClassReader) ClassWriter(org.objectweb.asm.ClassWriter)

Example 15 with AnnotationNode

use of org.objectweb.asm.tree.AnnotationNode in project spring-loaded by spring-projects.

the class SpringLoadedTests method toStringField.

@SuppressWarnings("unchecked")
protected String toStringField(byte[] classdata, String fieldname) {
    StringBuilder sb = new StringBuilder();
    FieldNode fieldNode = getField(classdata, fieldname);
    if (fieldNode == null) {
        return null;
    }
    List<AnnotationNode> annos = fieldNode.visibleAnnotations;
    if (annos != null) {
        sb.append("vis(").append(toStringAnnotations(annos)).append(") ");
    }
    annos = fieldNode.invisibleAnnotations;
    if (annos != null) {
        sb.append("invis(").append(toStringAnnotations(annos)).append(") ");
    }
    // will need implementing at some point:
    //		List<Attribute> attrs = fieldNode.attrs;
    //		if (attrs = !null) {
    //			sb.append("attrs(").append(toStringAttributes(attrs)).append(") ");
    //		}
    sb.append("0x").append(Integer.toHexString(fieldNode.access)).append("(").append(ClassPrinter.toAccessForMember(fieldNode.access)).append(") ");
    sb.append(fieldNode.name).append(" ");
    sb.append(fieldNode.desc).append(" ");
    if (fieldNode.signature != null) {
        sb.append(fieldNode.signature).append(" ");
    }
    if (fieldNode.value != null) {
        sb.append(fieldNode.value).append(" ");
    }
    return sb.toString().trim();
}
Also used : FieldNode(org.objectweb.asm.tree.FieldNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode)

Aggregations

AnnotationNode (org.objectweb.asm.tree.AnnotationNode)16 ClassNode (org.objectweb.asm.tree.ClassNode)6 List (java.util.List)4 ClassReader (org.objectweb.asm.ClassReader)4 MethodNode (org.objectweb.asm.tree.MethodNode)4 FieldNode (org.objectweb.asm.tree.FieldNode)3 File (java.io.File)2 Type (org.objectweb.asm.Type)2 MethodInsnNode (org.objectweb.asm.tree.MethodInsnNode)2 ModContainer (cpw.mods.fml.common.ModContainer)1 ArtifactVersion (cpw.mods.fml.common.versioning.ArtifactVersion)1 DefaultArtifactVersion (cpw.mods.fml.common.versioning.DefaultArtifactVersion)1 VersionRange (cpw.mods.fml.common.versioning.VersionRange)1 FileInputStream (java.io.FileInputStream)1 FileOutputStream (java.io.FileOutputStream)1 FileWriter (java.io.FileWriter)1 IOException (java.io.IOException)1 Array (java.lang.reflect.Array)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1