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();
}
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();
}
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();
}
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();
}
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;
}
}
Aggregations