Search in sources :

Example 1 with SynchronizedMethodNode

use of com.newrelic.weave.utils.SynchronizedMethodNode in project newrelic-java-agent by newrelic.

the class Reference method addMethodsAndFields.

/**
 * Fetch all methods and fields of a class node including those inherited from supertypes+interfaces. The results
 * will be stored in the passed in methods and fields lists.
 *
 * @param classCache Cache to use to fetch supertype resources
 * @param classNode The node to scan
 * @param methods classNode's methods will be appended to this list.
 * @param fields classNode's fields will be appended to this list.
 */
private static void addMethodsAndFields(ClassCache classCache, ClassNode classNode, List<MethodNode> methods, List<FieldNode> fields) throws IOException {
    ClassInformation classInfo = classCache.getClassInformation(classNode.name);
    for (MemberInformation methodInfo : classInfo.getAllMethods(classCache)) {
        MethodNode methodNode = new SynchronizedMethodNode();
        methodNode.name = methodInfo.name;
        methodNode.desc = methodInfo.desc;
        methodNode.access = methodInfo.access;
        methods.add(methodNode);
    }
    for (MemberInformation fieldInfo : classInfo.getAllFields(classCache)) {
        fields.add(new SynchronizedFieldNode(WeaveUtils.ASM_API_LEVEL, fieldInfo.access, fieldInfo.name, fieldInfo.desc, null, null));
    }
}
Also used : ClassInformation(com.newrelic.weave.utils.ClassInformation) MethodNode(org.objectweb.asm.tree.MethodNode) SynchronizedMethodNode(com.newrelic.weave.utils.SynchronizedMethodNode) SynchronizedMethodNode(com.newrelic.weave.utils.SynchronizedMethodNode) MemberInformation(com.newrelic.weave.utils.ClassInformation.MemberInformation) SynchronizedFieldNode(com.newrelic.weave.utils.SynchronizedFieldNode)

Example 2 with SynchronizedMethodNode

use of com.newrelic.weave.utils.SynchronizedMethodNode in project newrelic-java-agent by newrelic.

the class ErrorTrapWeaveMethodsProcessor method process.

/**
 * This method processor will wrap weave code with try/catch blocks. Weaver.callOriginal() will not be wrapped.
 * <p/>
 *
 * When weave code throws an unexpected exception (an exception thrown without an explicit throw call), the error
 * handler will be invoked and then the original return value will be returned. The error handler may throw an
 * exception to prevent the original return value from being returned.
 * <p/>
 *
 * Weave code which occurs before callOriginal is the preamble. Weave code which occurs after callOriginal is the
 * postamble.
 *
 * @return
 */
public MethodNode process() {
    if (errorTrapHandler == ErrorTrapHandler.NO_ERROR_TRAP_HANDLER) {
        return this.trappedMethod;
    }
    Type originalReturnType = Type.getReturnType(trappedMethod.desc);
    boolean isVoid = originalReturnType.equals(Type.VOID_TYPE);
    if ((null == startOfOriginalMethodLabelNode || null == endOfOriginalMethodLabelNode) && !isVoid) {
        // no support for error-trapping non-void methods which do not call Weaver.callOriginal()
        return trappedMethod;
    }
    List<TryCatchBlockNode> priorityTryCatch = new ArrayList<>();
    if (null != trappedMethod.tryCatchBlocks) {
        // weave try/catch blocks take priority over error-trap
        priorityTryCatch.addAll(trappedMethod.tryCatchBlocks);
    }
    // Used to write the bytecode for error trapping
    MethodNode generatorMethod = new SynchronizedMethodNode(WeaveUtils.ASM_API_LEVEL);
    GeneratorAdapter generator = new GeneratorAdapter(trappedMethod.access, new Method(trappedMethod.name, trappedMethod.desc), generatorMethod);
    // Any errors which are explicitly thrown will not go through the error trap.
    LocalVariableNode weaveExplicitThrow = null;
    if (isThrowCalled(trappedMethod)) {
        // create a variable to store the explicit throw
        weaveExplicitThrow = new LocalVariableNode("weaveExplicitThrow", Type.getDescriptor(Throwable.class), null, startOfTrapLabelNode, endOfTrapLabelNode, findIndexForNewLocal(trappedMethod));
        trappedMethod.maxLocals++;
        generator.push((String) null);
        generator.storeLocal(weaveExplicitThrow.index, Type.getType(Throwable.class));
        trappedMethod.visitLocalVariable(weaveExplicitThrow.name, weaveExplicitThrow.desc, weaveExplicitThrow.signature, weaveExplicitThrow.start.getLabel(), weaveExplicitThrow.end.getLabel(), weaveExplicitThrow.index);
        ErrorTrapWeaveMethodsProcessor.storeExceptionAtThrowSites(trappedMethod, weaveExplicitThrow.index);
        trappedMethod.instructions.insertBefore(startOfTrapLabelNode, generatorMethod.instructions);
    }
    if (null == startOfOriginalMethodLabelNode || null == endOfOriginalMethodLabelNode) {
        // a void method which does not call Weaver.callOriginal. Probably a constructor.
        // @formatter:off
        /*-
             * Throwable weaveExplicitThrow = null;
             * try{
             *     //weave code
             * }
             * catch(Throwable t){
             *     if(null != weaveExplicitThrow)
             *          throw t;
             *     errorHandle(t);
             *     return;
             * }
             */
        // @formatter:on
        generator.goTo(endOfTrapLabelNode.getLabel());
        Label handler = new Label();
        generator.visitLabel(handler);
        if (null != weaveExplicitThrow) {
            writeRethrowExplicitThrow(generator, weaveExplicitThrow);
        }
        this.writeHandler(generator, errorTrapHandler);
        trappedMethod.instructions.insertBefore(endOfTrapLabelNode, generatorMethod.instructions);
        trappedMethod.visitTryCatchBlock(startOfTrapLabelNode.getLabel(), handler, handler, Type.getInternalName(Throwable.class));
    } else {
        // @formatter:off
        /*-
            * Throwable weaveExplicitThrow = null;
            * boolean weaveThrowableWasThrown = false;
            * try{
            *     //weave preamble
            * }
            * catch(Throwable t){
            *     if(null != weaveExplicitThrow)
            *          throw t;
            *     errorHandle(t)
            *     weaveExceptionWasThrown = true;
            * }
            * Object weaveOriginalReturnVale = Weaver.callOriginal()
            * if(weaveExceptionWasThrown){
            *     return weaveOriginalReturnValue
            * }
            * try{
            *     //weave postamble
            * }
            * catch(Throwable t){
            *     if(null != weaveExplicitThrow)
            *          throw t;
            *     errorHandle(t)
            *     return weaveOriginalReturnValue
            * }
            */
        // @formatter:on
        LocalVariableNode weaveThrowableWasThrown;
        LocalVariableNode weaveOriginalReturnValue = null;
        LabelNode localsStart = WeaveUtils.makeLabelNode();
        trappedMethod.instructions.insert(localsStart);
        initializePreambleLocals(trappedMethod, startOfOriginalMethodLabelNode, localsStart);
        // Store the original return value in a new local variable
        if (!isVoid) {
            weaveOriginalReturnValue = new LocalVariableNode("weaveOriginalReturnValue", originalReturnType.getDescriptor(), null, startOfTrapLabelNode, endOfTrapLabelNode, findIndexForNewLocal(trappedMethod));
            trappedMethod.maxLocals++;
            trappedMethod.visitLocalVariable(weaveOriginalReturnValue.name, weaveOriginalReturnValue.desc, weaveOriginalReturnValue.signature, weaveOriginalReturnValue.start.getLabel(), weaveOriginalReturnValue.end.getLabel(), weaveOriginalReturnValue.index);
            storeOriginalReturnValue(generatorMethod, generator, trappedMethod, startOfOriginalMethodLabelNode, endOfOriginalMethodLabelNode, weaveOriginalReturnValue);
        }
        // add and initialize weaveThrowableWasThrown
        {
            // generator.visitLabel(localsStart.getLabel());
            weaveThrowableWasThrown = new LocalVariableNode("weaveThrowableWasThrown", Type.BOOLEAN_TYPE.getDescriptor(), null, startOfTrapLabelNode, endOfTrapLabelNode, findIndexForNewLocal(trappedMethod));
            trappedMethod.maxLocals++;
            trappedMethod.visitLocalVariable(weaveThrowableWasThrown.name, weaveThrowableWasThrown.desc, weaveThrowableWasThrown.signature, weaveThrowableWasThrown.start.getLabel(), weaveThrowableWasThrown.end.getLabel(), weaveThrowableWasThrown.index);
            writeStoreInitialValue(generator, weaveThrowableWasThrown);
            if (!isVoid) {
                writeStoreInitialValue(generator, weaveOriginalReturnValue);
            }
            trappedMethod.instructions.insertBefore(startOfTrapLabelNode, generatorMethod.instructions);
        }
        // handler for preabmle
        {
            generator.goTo(startOfOriginalMethodLabelNode.getLabel());
            Label preambleHandler = new Label();
            generator.visitLabel(preambleHandler);
            if (null != weaveExplicitThrow) {
                writeRethrowExplicitThrow(generator, weaveExplicitThrow);
            }
            writeHandler(generator, errorTrapHandler);
            generator.push(true);
            generator.storeLocal(weaveThrowableWasThrown.index, Type.BOOLEAN_TYPE);
            trappedMethod.instructions.insertBefore(startOfOriginalMethodLabelNode, generatorMethod.instructions);
            trappedMethod.visitTryCatchBlock(startOfTrapLabelNode.getLabel(), preambleHandler, preambleHandler, Type.getInternalName(Throwable.class));
        }
        // return weaveOriginalReturnValue if weaveThrowableWasThrown
        {
            LabelNode continueMethod = WeaveUtils.makeLabelNode();
            generator.push(false);
            generator.loadLocal(weaveThrowableWasThrown.index);
            generator.ifICmp(Opcodes.IFEQ, continueMethod.getLabel());
            if (isVoid) {
                generator.visitInsn(Opcodes.RETURN);
            } else {
                generator.loadLocal(weaveOriginalReturnValue.index);
                generator.returnValue();
            }
            generator.visitLabel(continueMethod.getLabel());
            trappedMethod.instructions.insertBefore(endOfOriginalMethodLabelNode, generatorMethod.instructions);
        }
        // handler for postamble
        {
            Label postambleHandler = new Label();
            generator.visitLabel(postambleHandler);
            if (null != weaveExplicitThrow) {
                writeRethrowExplicitThrow(generator, weaveExplicitThrow);
            }
            writeHandler(generator, errorTrapHandler);
            if (isVoid) {
                generator.visitInsn(Opcodes.RETURN);
            } else {
                generator.loadLocal(weaveOriginalReturnValue.index);
                generator.returnValue();
            }
            trappedMethod.instructions.insertBefore(endOfTrapLabelNode, generatorMethod.instructions);
            trappedMethod.visitTryCatchBlock(endOfOriginalMethodLabelNode.getLabel(), postambleHandler, postambleHandler, Type.getInternalName(Throwable.class));
        }
    }
    if (trappedMethod.tryCatchBlocks != null && priorityTryCatch.size() > 0) {
        sortTryCatchBlocks(trappedMethod, priorityTryCatch);
    }
    trappedMethod.instructions.resetLabels();
    return trappedMethod;
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) TryCatchBlockNode(org.objectweb.asm.tree.TryCatchBlockNode) SynchronizedMethodNode(com.newrelic.weave.utils.SynchronizedMethodNode) ArrayList(java.util.ArrayList) Label(org.objectweb.asm.Label) Method(org.objectweb.asm.commons.Method) LocalVariableNode(org.objectweb.asm.tree.LocalVariableNode) Type(org.objectweb.asm.Type) MethodNode(org.objectweb.asm.tree.MethodNode) SynchronizedMethodNode(com.newrelic.weave.utils.SynchronizedMethodNode) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Aggregations

SynchronizedMethodNode (com.newrelic.weave.utils.SynchronizedMethodNode)2 MethodNode (org.objectweb.asm.tree.MethodNode)2 ClassInformation (com.newrelic.weave.utils.ClassInformation)1 MemberInformation (com.newrelic.weave.utils.ClassInformation.MemberInformation)1 SynchronizedFieldNode (com.newrelic.weave.utils.SynchronizedFieldNode)1 ArrayList (java.util.ArrayList)1 Label (org.objectweb.asm.Label)1 Type (org.objectweb.asm.Type)1 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)1 Method (org.objectweb.asm.commons.Method)1 LabelNode (org.objectweb.asm.tree.LabelNode)1 LocalVariableNode (org.objectweb.asm.tree.LocalVariableNode)1 TryCatchBlockNode (org.objectweb.asm.tree.TryCatchBlockNode)1