Search in sources :

Example 31 with Method

use of org.objectweb.asm.commons.Method in project cdap by caskdata.

the class ContainerLauncherGenerator method generateMainClass.

/**
   * Generates a class that has a static main method which delegates the call to a static method in the given delegator
   * class with method signature {@code public static void launch(String className, String[] args)}
   *
   * @param className the classname of the generated class
   * @param mainDelegator the class to delegate the main call to
   * @param output for writing the generated bytes
   */
private static void generateMainClass(String className, Type mainDelegator, JarOutputStream output) throws IOException {
    String internalName = className.replace('.', '/');
    ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, internalName, null, Type.getInternalName(Object.class), null);
    // Generate the default constructor, which just call super()
    Method constructor = Methods.getMethod(void.class, "<init>");
    GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, constructor, null, null, classWriter);
    mg.loadThis();
    mg.invokeConstructor(Type.getType(Object.class), constructor);
    mg.returnValue();
    mg.endMethod();
    // Generate the main method
    // public static void main(String[] args) throws Exception {
    //   System.out.println("Launch class .....");
    //   <MainDelegator>.launch(<className>, args);
    // }
    Method mainMethod = Methods.getMethod(void.class, "main", String[].class);
    mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, mainMethod, null, new Type[] { Type.getType(Exception.class) }, classWriter);
    mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
    mg.visitLdcInsn("Launch class " + className + " by calling " + mainDelegator.getClassName() + ".launch");
    mg.invokeVirtual(Type.getType(PrintStream.class), Methods.getMethod(void.class, "println", String.class));
    // The main classname is stored as string literal in the generated class
    mg.visitLdcInsn(className);
    mg.loadArg(0);
    mg.invokeStatic(mainDelegator, Methods.getMethod(void.class, "launch", String.class, String[].class));
    mg.returnValue();
    mg.endMethod();
    classWriter.visitEnd();
    output.putNextEntry(new JarEntry(internalName + ".class"));
    output.write(classWriter.toByteArray());
}
Also used : PrintStream(java.io.PrintStream) Type(org.objectweb.asm.Type) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) Method(org.objectweb.asm.commons.Method) JarEntry(java.util.jar.JarEntry) ClassWriter(org.objectweb.asm.ClassWriter)

Example 32 with Method

use of org.objectweb.asm.commons.Method 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, new Type[0]);
    // 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)

Aggregations

Method (org.objectweb.asm.commons.Method)32 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)24 Type (org.objectweb.asm.Type)16 Label (org.objectweb.asm.Label)8 ClassWriter (org.objectweb.asm.ClassWriter)7 MethodVisitor (org.objectweb.asm.MethodVisitor)7 IOException (java.io.IOException)6 ClassReader (org.objectweb.asm.ClassReader)5 Schema (co.cask.cdap.api.data.schema.Schema)4 Set (java.util.Set)3 ClassVisitor (org.objectweb.asm.ClassVisitor)3 TypeToken (com.google.common.reflect.TypeToken)2 InvocationHandler (java.lang.reflect.InvocationHandler)2 SchemaHash (co.cask.cdap.api.data.schema.SchemaHash)1 MetricsContext (co.cask.cdap.api.metrics.MetricsContext)1 Encoder (co.cask.cdap.common.io.Encoder)1 Sets (com.google.common.collect.Sets)1 JClassType (com.google.gwt.core.ext.typeinfo.JClassType)1 InterceptorType (com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorType)1 File (java.io.File)1