use of org.objectweb.asm.commons.Method in project Lucee by lucee.
the class ASMUtil method createProperty.
private static void createProperty(ClassWriter cw, String classType, ASMProperty property) throws PageException {
String name = property.getName();
Type type = property.getASMType();
Class clazz = property.getClazz();
cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd();
int load = loadFor(type);
// int sizeOf=sizeOf(type);
// get<PropertyName>():<type>
Type[] types = new Type[0];
Method method = new Method((clazz == boolean.class ? "get" : "get") + (name), type, types);
GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC, method, null, null, cw);
Label start = new Label();
adapter.visitLabel(start);
adapter.visitVarInsn(Opcodes.ALOAD, 0);
adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString());
adapter.returnValue();
Label end = new Label();
adapter.visitLabel(end);
adapter.visitLocalVariable("this", "L" + classType + ";", null, start, end, 0);
adapter.visitEnd();
adapter.endMethod();
// set<PropertyName>(object):void
types = new Type[] { type };
method = new Method("set" + (name), Types.VOID, types);
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC, method, null, null, cw);
start = new Label();
adapter.visitLabel(start);
adapter.visitVarInsn(Opcodes.ALOAD, 0);
adapter.visitVarInsn(load, 1);
adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString());
adapter.visitInsn(Opcodes.RETURN);
end = new Label();
adapter.visitLabel(end);
adapter.visitLocalVariable("this", "L" + classType + ";", null, start, end, 0);
adapter.visitLocalVariable(name, type.toString(), null, start, end, 1);
// adapter.visitMaxs(0, 0);//.visitMaxs(sizeOf+1, sizeOf+1);// hansx
adapter.visitEnd();
adapter.endMethod();
}
use of org.objectweb.asm.commons.Method in project Lucee by lucee.
the class SourceLastModifiedClassAdapter method execute.
/**
* convert the Page Object to java bytecode
* @param className name of the genrated class (only necessary when Page object has no PageSource reference)
* @return
* @throws TransformerException
*/
public byte[] execute(String className) throws TransformerException {
// not exists in any case, so every usage must have a plan b for not existence
PageSource optionalPS = sourceCode instanceof PageSourceCode ? ((PageSourceCode) sourceCode).getPageSource() : null;
List<LitString> keys = new ArrayList<LitString>();
ClassWriter cw = ASMUtil.getClassWriter();
ArrayList<String> imports = new ArrayList<String>();
getImports(imports, this);
// look for component if necessary
TagCIObject comp = getTagCFObject(null);
// in case we have a sub component
if (className == null) {
if (optionalPS == null)
throw new IllegalArgumentException("when Page object has no PageSource, a className is necessary");
className = optionalPS.getClassName();
}
if (comp != null)
className = createSubClass(className, comp.getName(), sourceCode.getDialect());
className = className.replace('.', '/');
this.className = className;
// parent
// "lucee/runtime/Page";
String parent = PageImpl.class.getName();
if (// "lucee/runtime/ComponentPage";
isComponent(comp))
// "lucee/runtime/ComponentPage";
parent = ComponentPageImpl.class.getName();
else // "lucee/runtime/InterfacePage";
if (isInterface(comp))
parent = InterfacePageImpl.class.getName();
parent = parent.replace('.', '/');
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, className, null, parent, null);
if (optionalPS != null) {
// we use full path when FD is enabled
String path = config.allowRequestTimeout() ? optionalPS.getRealpathWithVirtual() : optionalPS.getPhyscalFile().getAbsolutePath();
// when adding more use ; as delimiter
cw.visitSource(path, null);
// cw.visitSource(optionalPS.getPhyscalFile().getAbsolutePath(),
// "rel:"+optionalPS.getRealpathWithVirtual()); // when adding more use ; as delimiter
} else {
// cw.visitSource("","rel:");
}
// static constructor
// GeneratorAdapter statConstrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,STATIC_CONSTRUCTOR,null,null,cw);
// StaticConstrBytecodeContext statConstr = null;//new BytecodeContext(null,null,this,externalizer,keys,cw,name,statConstrAdapter,STATIC_CONSTRUCTOR,writeLog(),suppressWSbeforeArg);
// constructor
GeneratorAdapter constrAdapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC, CONSTRUCTOR_PS, null, null, cw);
ConstrBytecodeContext constr = new ConstrBytecodeContext(optionalPS, this, keys, cw, className, constrAdapter, CONSTRUCTOR_PS, writeLog(), suppressWSbeforeArg, output, returnValue);
constrAdapter.loadThis();
Type t;
if (isComponent(comp)) {
t = Types.COMPONENT_PAGE_IMPL;
// extends
// Attribute attr = comp.getAttribute("extends");
// if(attr!=null) ExpressionUtil.writeOutSilent(attr.getValue(),constr, Expression.MODE_REF);
// else constrAdapter.push("");
constrAdapter.invokeConstructor(t, CONSTRUCTOR);
} else if (isInterface(comp)) {
t = Types.INTERFACE_PAGE_IMPL;
constrAdapter.invokeConstructor(t, CONSTRUCTOR);
} else {
t = Types.PAGE_IMPL;
constrAdapter.invokeConstructor(t, CONSTRUCTOR);
}
// call _init()
constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
constrAdapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, constr.getClassName(), "initKeys", "()V");
// private static ImportDefintion[] test=new ImportDefintion[]{...};
{
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "imports", "[Llucee/runtime/component/ImportDefintion;", null, null);
fv.visitEnd();
constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
ArrayVisitor av = new ArrayVisitor();
av.visitBegin(constrAdapter, Types.IMPORT_DEFINITIONS, imports.size());
int index = 0;
Iterator<String> it = imports.iterator();
while (it.hasNext()) {
av.visitBeginItem(constrAdapter, index++);
constrAdapter.push(it.next());
ASMConstants.NULL(constrAdapter);
constrAdapter.invokeStatic(Types.IMPORT_DEFINITIONS_IMPL, ID_GET_INSTANCE);
av.visitEndItem(constrAdapter);
}
av.visitEnd();
constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, className, "imports", "[Llucee/runtime/component/ImportDefintion;");
}
// getVersion
GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, VERSION, null, null, cw);
adapter.push(version);
adapter.returnValue();
adapter.endMethod();
// public ImportDefintion[] getImportDefintions()
if (imports.size() > 0) {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, GET_IMPORT_DEFINITIONS, null, null, cw);
adapter.visitVarInsn(Opcodes.ALOAD, 0);
adapter.visitFieldInsn(Opcodes.GETFIELD, className, "imports", "[Llucee/runtime/component/ImportDefintion;");
adapter.returnValue();
adapter.endMethod();
} else {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, GET_IMPORT_DEFINITIONS, null, null, cw);
adapter.visitInsn(Opcodes.ICONST_0);
adapter.visitTypeInsn(Opcodes.ANEWARRAY, "lucee/runtime/component/ImportDefintion");
adapter.returnValue();
adapter.endMethod();
}
// getSourceLastModified
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, LAST_MOD, null, null, cw);
adapter.push(lastModifed);
adapter.returnValue();
adapter.endMethod();
// getSourceLength
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, LENGTH, null, null, cw);
adapter.push(length);
adapter.returnValue();
adapter.endMethod();
// getCompileTime
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, COMPILE_TIME, null, null, cw);
adapter.push(System.currentTimeMillis());
adapter.returnValue();
adapter.endMethod();
// getHash
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, HASH, null, null, cw);
adapter.push(hash);
adapter.returnValue();
adapter.endMethod();
if (comp != null) {
writeOutStaticConstructor(constr, keys, cw, comp, className);
}
// newInstance/initComponent/call
if (isComponent()) {
writeOutNewComponent(constr, keys, cw, comp, className);
writeOutInitComponent(constr, keys, cw, comp, className);
} else if (isInterface()) {
writeOutNewInterface(constr, keys, cw, comp, className);
writeOutInitInterface(constr, keys, cw, comp, className);
} else {
writeOutCall(constr, keys, cw, className);
}
// write UDFProperties to constructor
// writeUDFProperties(bc,funcs,pageType);
// udfCall
Function[] functions = getFunctions();
ConditionVisitor cv;
DecisionIntVisitor div;
// less/equal than 10 functions
if (isInterface()) {
} else if (functions.length <= 10) {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, UDF_CALL, null, new Type[] { Types.THROWABLE }, cw);
BytecodeContext bc = new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, UDF_CALL, writeLog(), suppressWSbeforeArg, output, returnValue);
if (functions.length == 0) {
} else if (functions.length == 1) {
ExpressionUtil.visitLine(bc, functions[0].getStart());
functions[0].getBody().writeOut(bc);
ExpressionUtil.visitLine(bc, functions[0].getEnd());
} else
writeOutUdfCallInner(bc, functions, 0, functions.length);
adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
} else // more than 10 functions
{
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, UDF_CALL, null, new Type[] { Types.THROWABLE }, cw);
BytecodeContext bc = new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, UDF_CALL, writeLog(), suppressWSbeforeArg, output, returnValue);
cv = new ConditionVisitor();
cv.visitBefore();
int count = 0;
for (int i = 0; i < functions.length; i += 10) {
cv.visitWhenBeforeExpr();
div = new DecisionIntVisitor();
div.visitBegin();
adapter.loadArg(2);
div.visitLT();
adapter.push(i + 10);
div.visitEnd(bc);
cv.visitWhenAfterExprBeforeBody(bc);
adapter.visitVarInsn(Opcodes.ALOAD, 0);
adapter.visitVarInsn(Opcodes.ALOAD, 1);
adapter.visitVarInsn(Opcodes.ALOAD, 2);
adapter.visitVarInsn(Opcodes.ILOAD, 3);
adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, createFunctionName(++count), "(Llucee/runtime/PageContext;Llucee/runtime/type/UDF;I)Ljava/lang/Object;");
// adapter.returnValue();
adapter.visitInsn(Opcodes.ARETURN);
cv.visitWhenAfterBody(bc);
}
cv.visitAfter(bc);
adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
count = 0;
Method innerCall;
for (int i = 0; i < functions.length; i += 10) {
innerCall = new Method(createFunctionName(++count), Types.OBJECT, new Type[] { Types.PAGE_CONTEXT, USER_DEFINED_FUNCTION, Types.INT_VALUE });
adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, innerCall, null, new Type[] { Types.THROWABLE }, cw);
writeOutUdfCallInner(new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, innerCall, writeLog(), suppressWSbeforeArg, output, returnValue), functions, i, i + 10 > functions.length ? functions.length : i + 10);
adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
}
}
// threadCall
TagThread[] threads = getThreads();
if (true) {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, THREAD_CALL, null, new Type[] { Types.THROWABLE }, cw);
if (threads.length > 0)
writeOutThreadCallInner(new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, THREAD_CALL, writeLog(), suppressWSbeforeArg, output, returnValue), threads, 0, threads.length);
// adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
}
// less/equal than 10 functions
if (isInterface()) {
} else if (functions.length <= 10) {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, UDF_DEFAULT_VALUE, null, new Type[] { Types.PAGE_EXCEPTION }, cw);
if (functions.length > 0)
writeUdfDefaultValueInner(new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, UDF_DEFAULT_VALUE, writeLog(), suppressWSbeforeArg, output, returnValue), functions, 0, functions.length);
adapter.loadArg(DEFAULT_VALUE);
adapter.returnValue();
adapter.endMethod();
} else {
adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, UDF_DEFAULT_VALUE, null, new Type[] { Types.PAGE_EXCEPTION }, cw);
BytecodeContext bc = new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, UDF_DEFAULT_VALUE, writeLog(), suppressWSbeforeArg, output, returnValue);
cv = new ConditionVisitor();
cv.visitBefore();
int count = 0;
for (int i = 0; i < functions.length; i += 10) {
cv.visitWhenBeforeExpr();
div = new DecisionIntVisitor();
div.visitBegin();
adapter.loadArg(1);
div.visitLT();
adapter.push(i + 10);
div.visitEnd(bc);
cv.visitWhenAfterExprBeforeBody(bc);
adapter.visitVarInsn(Opcodes.ALOAD, 0);
adapter.visitVarInsn(Opcodes.ALOAD, 1);
adapter.visitVarInsn(Opcodes.ILOAD, 2);
adapter.visitVarInsn(Opcodes.ILOAD, 3);
adapter.visitVarInsn(Opcodes.ALOAD, 4);
adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, "udfDefaultValue" + (++count), "(Llucee/runtime/PageContext;IILjava/lang/Object;)Ljava/lang/Object;");
// adapter.returnValue();
adapter.visitInsn(Opcodes.ARETURN);
cv.visitWhenAfterBody(bc);
}
cv.visitAfter(bc);
adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
count = 0;
Method innerDefaultValue;
for (int i = 0; i < functions.length; i += 10) {
innerDefaultValue = new Method("udfDefaultValue" + (++count), Types.OBJECT, new Type[] { Types.PAGE_CONTEXT, Types.INT_VALUE, Types.INT_VALUE, Types.OBJECT });
adapter = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, innerDefaultValue, null, new Type[] { Types.PAGE_EXCEPTION }, cw);
writeUdfDefaultValueInner(new BytecodeContext(optionalPS, constr, this, keys, cw, className, adapter, innerDefaultValue, writeLog(), suppressWSbeforeArg, output, returnValue), functions, i, i + 10 > functions.length ? functions.length : i + 10);
adapter.loadArg(DEFAULT_VALUE);
// adapter.visitInsn(Opcodes.ACONST_NULL);
adapter.returnValue();
adapter.endMethod();
}
}
// CONSTRUCTOR
List<Data> udfProperties = constr.getUDFProperties();
Iterator<Data> it = udfProperties.iterator();
String udfpropsClassName = Types.UDF_PROPERTIES_ARRAY.toString();
// new UDFProperties Array
constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
constrAdapter.push(udfProperties.size());
constrAdapter.newArray(Types.UDF_PROPERTIES);
constrAdapter.visitFieldInsn(Opcodes.PUTFIELD, getClassName(), "udfs", udfpropsClassName);
// set item
Data data;
while (it.hasNext()) {
data = it.next();
constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
constrAdapter.visitFieldInsn(Opcodes.GETFIELD, constr.getClassName(), "udfs", Types.UDF_PROPERTIES_ARRAY.toString());
constrAdapter.push(data.arrayIndex);
data.function.createUDFProperties(constr, data.valueIndex, data.type);
constrAdapter.visitInsn(Opcodes.AASTORE);
}
// setPageSource(pageSource);
constrAdapter.visitVarInsn(Opcodes.ALOAD, 0);
constrAdapter.visitVarInsn(Opcodes.ALOAD, 1);
constrAdapter.invokeVirtual(t, SET_PAGE_SOURCE);
constrAdapter.returnValue();
constrAdapter.endMethod();
// INIT KEYS
{
GeneratorAdapter aInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, INIT_KEYS, null, null, cw);
BytecodeContext bcInit = new BytecodeContext(optionalPS, constr, this, keys, cw, className, aInit, INIT_KEYS, writeLog(), suppressWSbeforeArg, output, returnValue);
registerFields(bcInit, keys);
aInit.returnValue();
aInit.endMethod();
}
// set field subs
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "subs", "[Llucee/runtime/CIPage;", null, null);
fv.visitEnd();
// create sub components/interfaces
if (comp != null && comp.isMain()) {
List<TagCIObject> subs = getSubs(null);
if (!ArrayUtil.isEmpty(subs)) {
Iterator<TagCIObject> _it = subs.iterator();
TagCIObject tc;
while (_it.hasNext()) {
tc = _it.next();
tc.writeOut(this);
}
writeGetSubPages(cw, className, subs, sourceCode.getDialect());
}
}
return cw.toByteArray();
}
use of org.objectweb.asm.commons.Method in project Lucee by lucee.
the class VT method _writeOutEmpty.
/**
* outputs a empty Variable, only scope
* Example: pc.formScope();
* @param adapter
* @throws TemplateException
*/
private Type _writeOutEmpty(BytecodeContext bc) throws TransformerException {
if (ignoredFirstMember && (scope == Scope.SCOPE_LOCAL || scope == Scope.SCOPE_VAR))
return Types.VOID;
GeneratorAdapter adapter = bc.getAdapter();
adapter.loadArg(0);
Method m;
Type t = Types.PAGE_CONTEXT;
if (scope == Scope.SCOPE_ARGUMENTS) {
getFactory().TRUE().writeOut(bc, MODE_VALUE);
m = TypeScope.METHOD_ARGUMENT_BIND;
} else if (scope == Scope.SCOPE_LOCAL) {
t = Types.PAGE_CONTEXT;
getFactory().TRUE().writeOut(bc, MODE_VALUE);
m = TypeScope.METHOD_LOCAL_BIND;
} else if (scope == Scope.SCOPE_VAR) {
t = Types.PAGE_CONTEXT;
getFactory().TRUE().writeOut(bc, MODE_VALUE);
m = TypeScope.METHOD_VAR_BIND;
} else
m = TypeScope.METHODS[scope];
TypeScope.invokeScope(adapter, m, t);
return m.getReturnType();
}
use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class SparkClassRewriter method rewritePythonRunner.
/**
* Rewrites the PythonRunner.main() method to wrap it with call to SparkRuntimeUtils.initSparkMain() method on
* enter and cancel on exit. Also, wrap the PythonRunner.main() call with a try block to catch the
* {@code SparkUserAppException} into a {@link RuntimeException} to avoid Spark calling System.exit in
* {@link SparkSubmit}.
*/
private byte[] rewritePythonRunner(InputStream byteCodeStream) throws IOException {
ClassReader cr = new ClassReader(byteCodeStream);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// Intercept the static void main(String[] args) method.
final Method mainMethod = new Method("main", Type.VOID_TYPE, new Type[] { Type.getType(String[].class) });
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (!mainMethod.equals(new Method(name, desc)) || !Modifier.isStatic(access)) {
return mv;
}
// }
return new AdviceAdapter(Opcodes.ASM5, mv, access, name, desc) {
final Type sparkUserAppExceptionType = Type.getObjectType("org/apache/spark/SparkUserAppException");
final Type cancellableType = Type.getObjectType("org/apache/twill/common/Cancellable");
final Label tryLabel = newLabel();
final Label tryEndLabel = newLabel();
final Label catchLabel = newLabel();
final Label finallyLabel = newLabel();
int cancellable;
@Override
protected void onMethodEnter() {
cancellable = newLocal(cancellableType);
invokeStatic(SPARK_RUNTIME_UTILS_TYPE, new Method("initSparkMain", cancellableType, EMPTY_ARGS));
storeLocal(cancellable);
// try {
visitTryCatchBlock(tryLabel, tryEndLabel, catchLabel, sparkUserAppExceptionType.getInternalName());
visitLabel(tryLabel);
}
@Override
protected void onMethodExit(int opcode) {
// } catch (SparkUserAppException e) {
// throw new RuntimeException(e);
visitLabel(tryEndLabel);
goTo(finallyLabel);
visitLabel(catchLabel);
int exception = newLocal(sparkUserAppExceptionType);
storeLocal(exception);
newInstance(Type.getType(RuntimeException.class));
dup();
loadLocal(exception);
invokeConstructor(Type.getType(RuntimeException.class), Methods.getMethod(void.class, "<init>", Throwable.class));
throwException();
// } finally {
// cancellable.cancel()
// }
visitLabel(finallyLabel);
loadLocal(cancellable);
invokeInterface(cancellableType, new Method("cancel", Type.VOID_TYPE, EMPTY_ARGS));
}
};
}
}, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
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, 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();
}
Aggregations