Search in sources :

Example 91 with ClassVisitor

use of org.objectweb.asm.ClassVisitor in project cdap by caskdata.

the class SparkClassRewriter method rewritePythonRunnerCompanion.

/**
 * Rewrites the PythonRunner companion class to have all System.out/err goes into Logger.
 */
private byte[] rewritePythonRunnerCompanion(InputStream byteCodeStream) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(0);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            // Intercept all methods
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            return new OutputRedirectMethodVisitor(mv, access, name, desc, distributed);
        }
    }, ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
}
Also used : ClassReader(org.objectweb.asm.ClassReader) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 92 with ClassVisitor

use of org.objectweb.asm.ClassVisitor in project cdap by caskdata.

the class SparkClassRewriter method rewriteExecutorClassLoader.

/**
 * Rewrites the ExecutorClassLoader so that it won't use system classloader as parent since CDAP classes
 * are not in system classloader.
 * Also optionally overrides the getResource, getResources and getResourceAsStream methods if they are not
 * defined (for fixing SPARK-11818 for older Spark < 1.6).
 */
private byte[] rewriteExecutorClassLoader(InputStream byteCodeStream) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    final Type classloaderType = Type.getType(ClassLoader.class);
    final Type parentClassLoaderType = Type.getObjectType("org/apache/spark/util/ParentClassLoader");
    final Method parentLoaderMethod = new Method("parentLoader", parentClassLoaderType, EMPTY_ARGS);
    // Map from getResource* methods to the method signature
    // (can be null, since only method that has generic has signature)
    final Map<Method, String> resourceMethods = new HashMap<>();
    Method method = new Method("getResource", Type.getType(URL.class), new Type[] { Type.getType(String.class) });
    resourceMethods.put(method, null);
    method = new Method("getResources", Type.getType(Enumeration.class), new Type[] { Type.getType(String.class) });
    resourceMethods.put(method, Signatures.getMethodSignature(method, new TypeToken<Enumeration<URL>>() {
    }, TypeToken.of(String.class)));
    method = new Method("getResourceAsStream", Type.getType(InputStream.class), new Type[] { Type.getType(String.class) });
    resourceMethods.put(method, null);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        private boolean hasParentLoader;

        private boolean rewriteInit;

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            // Only rewrite `<init>` if the ExecutorClassloader extends from ClassLoader
            if (classloaderType.getInternalName().equals(superName)) {
                rewriteInit = true;
            }
            super.visit(version, access, name, signature, superName, interfaces);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            // If the resource method is declared, no need to generate at the end.
            Method method = new Method(name, desc);
            resourceMethods.remove(method);
            hasParentLoader = hasParentLoader || parentLoaderMethod.equals(method);
            if (!rewriteInit || !"<init>".equals(name)) {
                return mv;
            }
            return new GeneratorAdapter(Opcodes.ASM5, mv, access, name, desc) {

                @Override
                public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
                    // If there is a call to `super()`, skip that instruction and have the onMethodEnter generate the call
                    if (opcode == Opcodes.INVOKESPECIAL && Type.getObjectType(owner).equals(classloaderType) && name.equals("<init>") && Type.getArgumentTypes(desc).length == 0 && Type.getReturnType(desc).equals(Type.VOID_TYPE)) {
                        // Generate `super(null)`. The `this` is already in the stack, so no need to `loadThis()`
                        push((Type) null);
                        invokeConstructor(classloaderType, new Method("<init>", Type.VOID_TYPE, new Type[] { classloaderType }));
                    } else {
                        super.visitMethodInsn(opcode, owner, name, desc, itf);
                    }
                }
            };
        }

        @Override
        public void visitEnd() {
            // All implementations are delegating to the parentLoader
            if (!hasParentLoader) {
                super.visitEnd();
                return;
            }
            for (Map.Entry<Method, String> entry : resourceMethods.entrySet()) {
                // Generate the method.
                // return parentLoader().getResource*(arg)
                Method method = entry.getKey();
                MethodVisitor mv = super.visitMethod(Modifier.PUBLIC, method.getName(), method.getDescriptor(), entry.getValue(), null);
                GeneratorAdapter generator = new GeneratorAdapter(Modifier.PUBLIC, method, mv);
                // call `parentLoader()`
                generator.loadThis();
                generator.invokeVirtual(SPARK_EXECUTOR_CLASSLOADER_TYPE, parentLoaderMethod);
                // Load the argument
                generator.loadArg(0);
                // Call the method on the parent loader.
                generator.invokeVirtual(parentClassLoaderType, method);
                generator.returnValue();
                generator.endMethod();
            }
        }
    }, ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
}
Also used : HashMap(java.util.HashMap) Method(org.objectweb.asm.commons.Method) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) URL(java.net.URL) MethodVisitor(org.objectweb.asm.MethodVisitor) Type(org.objectweb.asm.Type) TypeToken(com.google.common.reflect.TypeToken) ClassReader(org.objectweb.asm.ClassReader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter)

Example 93 with ClassVisitor

use of org.objectweb.asm.ClassVisitor in project cdap by caskdata.

the class SparkClassRewriter method rewritePythonWorkerFactory.

/**
 * Rewrite all System.out and System.err redirected via RedirectedPrintStream.
 * Also update pythonPath field in local mode to include the pyspark library
 */
private byte[] rewritePythonWorkerFactory(InputStream byteCodeStream) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(0);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            // Intercept all methods. Always redirect outputs
            MethodVisitor mv = new OutputRedirectMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, distributed);
            final GeneratorAdapter adapter = new GeneratorAdapter(mv, access, name, desc);
            return new MethodVisitor(Opcodes.ASM5, mv) {

                @Override
                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                    // Rewrite the pythonPath field when setting the field value
                    if (opcode == Opcodes.PUTFIELD && "pythonPath".equals(name)) {
                        Type stringType = Type.getType(String.class);
                        // Generates
                        // if (SparkRuntimeEnv.getProperty("cdap.spark.pyFiles") != null) {
                        // <stringOnStack>.concat(File.pathSeparator).concat(SparkRuntimeEnv.getProperty("cdap.spark.pyFiles"))
                        // }
                        // The result will be back on the stack
                        // The "cdap.spark.pyFiles" property is only set in local mode by SparkRuntimeService
                        Label nullLabel = adapter.newLabel();
                        // The if condition
                        adapter.push("cdap.spark.pyFiles");
                        adapter.invokeStatic(SPARK_RUNTIME_ENV_TYPE, Methods.getMethod(String.class, "getProperty", String.class));
                        adapter.ifNull(nullLabel);
                        // Inside the if block
                        adapter.push(File.pathSeparator);
                        adapter.invokeVirtual(stringType, Methods.getMethod(String.class, "concat", String.class));
                        adapter.push("cdap.spark.pyFiles");
                        adapter.invokeStatic(SPARK_RUNTIME_ENV_TYPE, Methods.getMethod(String.class, "getProperty", String.class));
                        adapter.invokeVirtual(stringType, Methods.getMethod(String.class, "concat", String.class));
                        // End of if block
                        adapter.mark(nullLabel);
                    }
                    super.visitFieldInsn(opcode, owner, name, desc);
                }
            };
        }
    }, ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
}
Also used : Type(org.objectweb.asm.Type) Label(org.objectweb.asm.Label) ClassReader(org.objectweb.asm.ClassReader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 94 with ClassVisitor

use of org.objectweb.asm.ClassVisitor in project cdap by caskdata.

the class Classes method rewriteMethodToNoop.

/**
 * Rewrites methods in the given class bytecode to noop methods.
 */
public static byte[] rewriteMethodToNoop(final String className, InputStream byteCodeStream, final Set<String> methods) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
            MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions);
            if (!methods.contains(name)) {
                return methodVisitor;
            }
            // We can only rewrite method that returns void
            if (!Type.getReturnType(desc).equals(Type.VOID_TYPE)) {
                LOG.warn("Cannot patch method {} in {} due to non-void return type: {}", name, className, desc);
                return methodVisitor;
            }
            // Rewrite the method to noop.
            GeneratorAdapter adapter = new GeneratorAdapter(methodVisitor, access, name, desc);
            adapter.returnValue();
            // VisitMaxs with 0 so that COMPUTE_MAXS from ClassWriter will compute the right values.
            adapter.visitMaxs(0, 0);
            return new MethodVisitor(Opcodes.ASM5) {
            };
        }
    }, 0);
    return cw.toByteArray();
}
Also used : ClassReader(org.objectweb.asm.ClassReader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 95 with ClassVisitor

use of org.objectweb.asm.ClassVisitor in project cdap by caskdata.

the class ArtifactInspector method isPlugin.

/**
 * Detects if a class is annotated with {@link Plugin} without loading the class.
 *
 * @param className name of the class
 * @param classLoader ClassLoader for loading the class file of the given class
 * @return true if the given class is annotated with {@link Plugin}
 */
private boolean isPlugin(String className, ClassLoader classLoader) {
    try (InputStream is = classLoader.getResourceAsStream(className.replace('.', '/') + ".class")) {
        if (is == null) {
            return false;
        }
        // Use ASM to inspect the class bytecode to see if it is annotated with @Plugin
        final boolean[] isPlugin = new boolean[1];
        ClassReader cr = new ClassReader(is);
        cr.accept(new ClassVisitor(Opcodes.ASM5) {

            @Override
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                if (Plugin.class.getName().equals(Type.getType(desc).getClassName()) && visible) {
                    isPlugin[0] = true;
                }
                return super.visitAnnotation(desc, visible);
            }
        }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
        return isPlugin[0];
    } catch (IOException e) {
        // If failed to open the class file, then it cannot be a plugin
        LOG.warn("Failed to open class file for {}", className, e);
        return false;
    }
}
Also used : InputStream(java.io.InputStream) AnnotationVisitor(org.objectweb.asm.AnnotationVisitor) ClassReader(org.objectweb.asm.ClassReader) ClassVisitor(org.objectweb.asm.ClassVisitor) IOException(java.io.IOException) Plugin(co.cask.cdap.api.annotation.Plugin)

Aggregations

ClassVisitor (org.objectweb.asm.ClassVisitor)133 ClassReader (org.objectweb.asm.ClassReader)97 ClassWriter (org.objectweb.asm.ClassWriter)80 MethodVisitor (org.objectweb.asm.MethodVisitor)45 IOException (java.io.IOException)19 InputStream (java.io.InputStream)19 Type (org.objectweb.asm.Type)14 TraceClassVisitor (org.objectweb.asm.util.TraceClassVisitor)14 File (java.io.File)11 PrintWriter (java.io.PrintWriter)11 AnnotationVisitor (org.objectweb.asm.AnnotationVisitor)10 Label (org.objectweb.asm.Label)10 FileInputStream (java.io.FileInputStream)9 Test (org.junit.Test)9 FileOutputStream (java.io.FileOutputStream)6 FieldVisitor (org.objectweb.asm.FieldVisitor)6 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)6 ArrayList (java.util.ArrayList)5 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)5 FieldList (net.bytebuddy.description.field.FieldList)5