Search in sources :

Example 1 with SynchronizedClassNode

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

the class PreparedExtension method generateExtensionClass.

/**
 * Generate the {@link ClassNode} for the extension class.
 *
 * @return the {@link ClassNode} for the extension class
 */
public ClassNode generateExtensionClass() {
    // create the extension node
    ClassNode extension;
    {
        extension = new SynchronizedClassNode();
        Map<String, String> oldToNew = new HashMap<>(1);
        // first set the class name to the generated name
        oldToNew.put(extensionTemplate.name, extensionClassName);
        // supertype is just a marker. Remove for generated class
        oldToNew.put(extensionTemplate.superName, "java/lang/Object");
        ClassVisitor visitor = ReferenceUtils.getRenamingVisitor(oldToNew, extension);
        // update and methods or fields that collide with the @NewField names
        for (String newFieldName : match.getNewFields()) {
            visitor = updateCollidingFieldNames(visitor, newFieldName);
        }
        // copy extensionNode (with renames) into extension
        extensionTemplate.accept(visitor);
    }
    extension.visit(WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION, ACC_PUBLIC + ACC_SUPER, extensionClassName, null, "java/lang/Object", extensionTemplate.interfaces.toArray(new String[extensionTemplate.interfaces.size()]));
    FieldVisitor fv;
    ClassNode weaveClass = match.getWeave();
    // add new fields
    for (String newFieldName : match.getNewFields()) {
        FieldNode newField = WeaveUtils.findRequiredMatch(weaveClass.fields, newFieldName);
        // make the fields public since they'll be accessed from a different object
        // clear private, protected and final flags
        int access = newField.access;
        access |= Opcodes.ACC_PUBLIC;
        access &= ~(Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_FINAL);
        fv = extension.visitField(access, newField.name, newField.desc, newField.signature, newField.value);
        fv.visitEnd();
    }
    if (match.getExtensionClassInit() != null) {
        // static init
        MethodNode clinitMethodNode = WeaveUtils.getMethodNode(extension, "<clinit>", "()V");
        if (null == clinitMethodNode) {
            // no clinit, let's make an empty one
            extension.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
            clinitMethodNode = WeaveUtils.getMethodNode(extension, "<clinit>", "()V");
            clinitMethodNode.visitCode();
            clinitMethodNode.visitInsn(RETURN);
            // these get recomputed later
            clinitMethodNode.visitMaxs(0, 0);
            clinitMethodNode.visitEnd();
        }
        // initialize new fields from weaver class initializer
        Set<MethodNode> toInline = new HashSet<>();
        MethodNode classInit = rewriteNewFieldCalls(match.getExtensionClassInit());
        for (Method newMethod : match.getNewMethods()) {
            MethodNode newMethodNode = WeaveUtils.findMatch(match.getWeave().methods, newMethod);
            if (newMethodNode != null) {
                toInline.add(newMethodNode);
            }
        }
        classInit = MethodProcessors.inlineMethods(weaveClass.name, toInline, extensionClassName, classInit);
        AbstractInsnNode retInsn = clinitMethodNode.instructions.getLast();
        while (retInsn != null && retInsn.getOpcode() != Opcodes.RETURN) {
            retInsn = retInsn.getPrevious();
        }
        if (null != retInsn) {
            clinitMethodNode.instructions.remove(retInsn);
        }
        clinitMethodNode.instructions.add(classInit.instructions);
        clinitMethodNode.instructions.resetLabels();
    }
    extension.visitEnd();
    extension.visitMethod(ACC_PUBLIC, RESET_CHECK_NAME, RESET_CHECK_DESC, null, null);
    MethodNode resetMethod = WeaveUtils.getMethodNode(extension, RESET_CHECK_NAME, RESET_CHECK_DESC);
    final Label FALSE = new Label();
    for (String newFieldName : match.getNewFields()) {
        FieldNode newFieldNode = WeaveUtils.findMatch(match.getWeave().fields, newFieldName);
        if ((newFieldNode.access & Opcodes.ACC_STATIC) == 0) {
            writeFieldResetCheck(resetMethod, newFieldNode, FALSE);
        }
    }
    resetMethod.visitInsn(Opcodes.ICONST_1);
    resetMethod.visitInsn(IRETURN);
    resetMethod.visitLabel(FALSE);
    resetMethod.visitInsn(Opcodes.ICONST_0);
    resetMethod.visitInsn(IRETURN);
    resetMethod.visitMaxs(0, 0);
    resetMethod.visitEnd();
    return extension;
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) FieldNode(org.objectweb.asm.tree.FieldNode) Label(org.objectweb.asm.Label) ClassVisitor(org.objectweb.asm.ClassVisitor) Method(org.objectweb.asm.commons.Method) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode) FieldVisitor(org.objectweb.asm.FieldVisitor) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) MethodNode(org.objectweb.asm.tree.MethodNode) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 2 with SynchronizedClassNode

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

the class PreparedMatch method prepareNewInnerClass.

/**
 * Prepares a <i>new</i> inner class (i.e. child of the weave class for this match) so it can be loaded into a
 * classloader. New inner classes can access new fields (but NOT new methods) in their parent, and anonymous inner
 * classes need to have thier names rewritten so they don't conflict with those in the original or target. This
 * rewrites new inner classes so all of this works.
 *
 * <p>
 * New inner classes should be validated with {@link ClassMatch} before calling this method.
 * </p>
 *
 * <p>
 * This method is not to be used with <i>matched</i> inner classes; they have more restrictions and will be modified
 * through the standard weave process.
 * </p>
 *
 * @param newInnerClassNode new inner class
 * @return processed inner class that can be loaded into a classloader
 * @see ClassMatch#validateNewInnerClass(ClassNode)
 */
public ClassNode prepareNewInnerClass(final ClassNode newInnerClassNode) {
    // rewrite new fields
    if (null != extension && null != newInnerClassNode.methods) {
        for (MethodNode method : newInnerClassNode.methods) {
            extension.rewriteNewFieldCalls(method);
        }
    }
    ClassNode anonClass = new SynchronizedClassNode(WeaveUtils.ASM_API_LEVEL);
    // remaps anonymous inner class names and maps weave -> original
    Map<String, String> typeMap = new HashMap<>(anonymousInnerClassTypeMap);
    typeMap.put(weaveName, originalName);
    ClassVisitor remapper = new ClassRemapper(anonClass, new SimpleRemapper(typeMap));
    // inlines new methods and rewrites new fields to use the extension class
    ClassVisitor rewriteNewVisitor = new ClassVisitor(WeaveUtils.ASM_API_LEVEL, remapper) {

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            super.visit(version, makePublic(access), name, signature, superName, interfaces);
        }

        @Override
        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
            return super.visitField(makePublic(access), name, desc, signature, value);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            return super.visitMethod(makePublic(access), name, desc, signature, exceptions);
        }
    };
    // note the delegation order - we will rewrite new methods/fields BEFORE remapping types
    newInnerClassNode.accept(rewriteNewVisitor);
    return anonClass;
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) InnerClassNode(org.objectweb.asm.tree.InnerClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) SimpleRemapper(org.objectweb.asm.commons.SimpleRemapper) MethodNode(org.objectweb.asm.tree.MethodNode) HashMap(java.util.HashMap) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassRemapper(org.objectweb.asm.commons.ClassRemapper) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode)

Example 3 with SynchronizedClassNode

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

the class PackageValidationResult method computeUtilityClassBytes.

/**
 * Compute and return a map of (name -> bytes) for all utility classes from this validation result.
 *
 * @see NewClassAppender
 */
public Map<String, byte[]> computeUtilityClassBytes(ClassCache cache) {
    Map<String, byte[]> utilClassBytes = new HashMap<>(utilClasses.size());
    for (Map.Entry<String, ClassNode> entry : utilClasses.entrySet()) {
        // Run post-processors on our utility classes to ensure that we capture API supportability metrics properly
        ClassNode result = new SynchronizedClassNode(WeaveUtils.ASM_API_LEVEL);
        ClassVisitor postprocessChain = weavePackage.getConfig().getPostprocessor().postprocess(entry.getValue().name, result, Collections.<String>emptySet(), weavePackage, true);
        entry.getValue().accept(postprocessChain);
        utilClassBytes.put(entry.getKey(), WeaveUtils.convertToClassBytes(result, cache));
    }
    return utilClassBytes;
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClassVisitor(org.objectweb.asm.ClassVisitor) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode)

Example 4 with SynchronizedClassNode

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

the class PackageValidationResult method weave.

/**
 * Weave the target class and return a {@link PackageWeaveResult}.
 */
public PackageWeaveResult weave(String className, String[] superNames, String[] interfaceNames, ClassNode targetNode, ClassCache cache, Map<Method, Collection<String>> skipMethods) {
    ClassNode composite = targetNode;
    final Map<String, List<Method>> weavedMethods = new HashMap<>();
    // Locks during weaving are due to the non-thread safe nature of {@link ClassNode}.
    // first apply exact matches
    {
        PreparedMatch exactMatch = exactMatches.get(className);
        if (null != exactMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(exactMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = exactMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    {
        // matcher for abstract class
        PreparedMatch exactMatch = baseMatches.get(className);
        if (null != exactMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(exactMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = exactMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    // then apply super classes
    for (int i = 0; i < superNames.length; ++i) {
        PreparedMatch baseMatch = baseMatches.get(superNames[i]);
        if (null != baseMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(baseMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = baseMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    // then apply interfaces
    for (int i = 0; i < interfaceNames.length; ++i) {
        PreparedMatch baseMatch = baseMatches.get(interfaceNames[i]);
        if (null != baseMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(baseMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = baseMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    final Map<String, byte[]> annotationProxyClasses = new HashMap<>();
    // class annotation matches
    if (!allAnnotationClasses.isEmpty()) {
        Set<String> targetAnnotationsClasses = getAnnotationClasses(targetNode);
        Set<String> targetInterfacesAnnotationClasses = Collections.emptySet();
        if (!baseAnnotationClasses.isEmpty()) {
            targetInterfacesAnnotationClasses = getAllInterfaceAnnotationClasses(targetNode, cache);
        }
        // check for exact annotation matches
        for (Map.Entry<String, ClassNode> entry : allAnnotationClasses.entrySet()) {
            if (targetAnnotationsClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
            }
        }
        // check for base annotation matches
        for (Map.Entry<String, ClassNode> entry : baseAnnotationClasses.entrySet()) {
            if (targetInterfacesAnnotationClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
            }
        }
    }
    // method annotation matches
    if (!allMethodAnnotationClasses.isEmpty()) {
        Set<String> targetMethodAnnotationsClasses = getMethodAnnotationClasses(targetNode);
        for (Map.Entry<String, ClassNode> entry : allMethodAnnotationClasses.entrySet()) {
            if (targetMethodAnnotationsClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
                // due to having multiple matching annotations that have the same underlying weave code.
                break;
            }
        }
    }
    if (weavePackage != null) {
        // Run any postprocessors that were passed in. It's important that we do this before the inliner runs below
        ClassNode result = new SynchronizedClassNode(WeaveUtils.ASM_API_LEVEL);
        ClassVisitor postprocessChain = weavePackage.getConfig().getPostprocessor().postprocess(className, result, Collections.<String>emptySet(), weavePackage, false);
        composite.accept(postprocessChain);
        composite = result;
    }
    return new PackageWeaveResult(this, className, composite, weavedMethods, annotationProxyClasses);
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClassWeave(com.newrelic.weave.ClassWeave) PreparedMatch(com.newrelic.weave.PreparedMatch) ClassVisitor(org.objectweb.asm.ClassVisitor) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 5 with SynchronizedClassNode

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

the class WeavePackage method preprocess.

/**
 * Run the pre-processor on a specific class in the package. Part of package initialization.
 *
 * @param input class to process
 * @return processed class
 */
private ClassNode preprocess(ClassNode input) {
    ClassNode result = new SynchronizedClassNode(WeaveUtils.ASM_API_LEVEL);
    // user configured preprocessors go first
    ClassVisitor preprocessChain = config.getPreprocessor().preprocess(result, utilClasses.keySet(), this);
    preprocessChain = MethodProcessors.fixInvocationInstructions(preprocessChain, weaveMatches);
    preprocessChain = MethodProcessors.replaceGetImplementationTitle(preprocessChain, this.getName());
    if (renames.size() > 0) {
        preprocessChain = ReferenceUtils.getRenamingVisitor(renames, preprocessChain);
    }
    input.accept(preprocessChain);
    return result;
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) ClassVisitor(org.objectweb.asm.ClassVisitor) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode)

Aggregations

SynchronizedClassNode (com.newrelic.weave.utils.SynchronizedClassNode)5 ClassVisitor (org.objectweb.asm.ClassVisitor)5 ClassNode (org.objectweb.asm.tree.ClassNode)5 HashMap (java.util.HashMap)4 Map (java.util.Map)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 MethodNode (org.objectweb.asm.tree.MethodNode)2 ClassWeave (com.newrelic.weave.ClassWeave)1 PreparedMatch (com.newrelic.weave.PreparedMatch)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 List (java.util.List)1 FieldVisitor (org.objectweb.asm.FieldVisitor)1 Label (org.objectweb.asm.Label)1 ClassRemapper (org.objectweb.asm.commons.ClassRemapper)1 Method (org.objectweb.asm.commons.Method)1 SimpleRemapper (org.objectweb.asm.commons.SimpleRemapper)1 AbstractInsnNode (org.objectweb.asm.tree.AbstractInsnNode)1 FieldNode (org.objectweb.asm.tree.FieldNode)1 InnerClassNode (org.objectweb.asm.tree.InnerClassNode)1