use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.
the class ProxySubclassAdapter method processMethod.
private void processMethod(int access, String name, String desc, String signature, String[] exceptions) {
LOGGER.debug(Constants.LOG_ENTRY, "processMethod", new Object[] { access, name, desc, signature, exceptions });
LOGGER.debug("Processing method: {} with descriptor {}", name, desc);
// identify the target method parameters and return type
Method currentTransformMethod = new Method(name, desc);
Type[] targetMethodParameters = currentTransformMethod.getArgumentTypes();
Type returnType = currentTransformMethod.getReturnType();
// we create a static field for each method we encounter with a name
// like method_parm1_parm2...
StringBuilder methodStaticFieldNameBuilder = new StringBuilder(name);
// the dots first
for (Type t : targetMethodParameters) {
methodStaticFieldNameBuilder.append("_");
methodStaticFieldNameBuilder.append(t.getClassName().replaceAll("\\[\\]", "Array").replaceAll("\\.", ""));
}
String methodStaticFieldName = methodStaticFieldNameBuilder.toString();
// add a private static field for the method
cv.visitField(ACC_PRIVATE | ACC_STATIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(), null, null);
// visit the method using the class writer, delegated through the method
// visitor and generator
// modify the method access so that any native methods aren't
// described as native
// since they won't be native in proxy form
// also stop methods being marked synchronized on the proxy as they will
// be sync
// on the real object
int newAccess = access & (~ACC_NATIVE) & (~ACC_SYNCHRONIZED);
MethodVisitor mv = cv.visitMethod(newAccess, name, desc, signature, exceptions);
// use a GeneratorAdapter to build the invoke call directly in byte code
GeneratorAdapter methodAdapter = new GeneratorAdapter(mv, newAccess, name, desc);
/*
* Stage 1 creates the bytecode for adding the reflected method of the
* superclass to a static field in the subclass: private static Method
* methodName_parm1_parm2... = null; static{ methodName_parm1_parm2... =
* superClass.getDeclaredMethod(methodName,new Class[]{method args}; }
*
* Stage 2 is to call the ih.invoke(this,methodName_parm1_parm2,args) in
* the new subclass methods Stage 3 is to cast the return value to the
* correct type
*/
/*
* Stage 1 use superClass.getMethod(methodName,new Class[]{method args}
* from the Class object on the stack
*/
// load the static superclass Class onto the stack
staticAdapter.getStatic(newClassType, currentClassFieldName, CLASS_TYPE);
// push the method name string arg onto the stack
staticAdapter.push(name);
// create an array of the method parm class[] arg
staticAdapter.push(targetMethodParameters.length);
staticAdapter.newArray(CLASS_TYPE);
int index = 0;
for (Type t : targetMethodParameters) {
staticAdapter.dup();
staticAdapter.push(index);
switch(t.getSort()) {
case Type.BOOLEAN:
staticAdapter.getStatic(Type.getType(java.lang.Boolean.class), "TYPE", CLASS_TYPE);
break;
case Type.BYTE:
staticAdapter.getStatic(Type.getType(java.lang.Byte.class), "TYPE", CLASS_TYPE);
break;
case Type.CHAR:
staticAdapter.getStatic(Type.getType(java.lang.Character.class), "TYPE", CLASS_TYPE);
break;
case Type.DOUBLE:
staticAdapter.getStatic(Type.getType(java.lang.Double.class), "TYPE", CLASS_TYPE);
break;
case Type.FLOAT:
staticAdapter.getStatic(Type.getType(java.lang.Float.class), "TYPE", CLASS_TYPE);
break;
case Type.INT:
staticAdapter.getStatic(Type.getType(java.lang.Integer.class), "TYPE", CLASS_TYPE);
break;
case Type.LONG:
staticAdapter.getStatic(Type.getType(java.lang.Long.class), "TYPE", CLASS_TYPE);
break;
case Type.SHORT:
staticAdapter.getStatic(Type.getType(java.lang.Short.class), "TYPE", CLASS_TYPE);
break;
default:
case Type.OBJECT:
staticAdapter.push(t);
break;
}
staticAdapter.arrayStore(CLASS_TYPE);
index++;
}
// invoke the getMethod
staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE, new Type[] { STRING_TYPE, Type.getType(java.lang.Class[].class) }));
// store the reflected method in the static field
staticAdapter.putStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
/*
* Stage 2 call the ih.invoke(this,supermethod,parms)
*/
// load this to get the ih field
methodAdapter.loadThis();
// load the invocation handler from the field (the location of the
// InvocationHandler.invoke)
methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
// loadThis (the first arg of the InvocationHandler.invoke)
methodAdapter.loadThis();
// load the method to invoke (the second arg of the
// InvocationHandler.invoke)
methodAdapter.getStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
// load all the method arguments onto the stack as an object array (the
// third arg of the InvocationHandler.invoke)
methodAdapter.loadArgArray();
// generate the invoke method
Method invocationHandlerInvokeMethod = new Method("invoke", OBJECT_TYPE, new Type[] { OBJECT_TYPE, METHOD_TYPE, Type.getType(java.lang.Object[].class) });
// call the invoke method of the invocation handler
methodAdapter.invokeInterface(IH_TYPE, invocationHandlerInvokeMethod);
/*
* Stage 3 the returned object is now on the top of the stack We need to
* check the type and cast as necessary
*/
switch(returnType.getSort()) {
case Type.BOOLEAN:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Boolean.class));
methodAdapter.unbox(Type.BOOLEAN_TYPE);
break;
case Type.BYTE:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Byte.class));
methodAdapter.unbox(Type.BYTE_TYPE);
break;
case Type.CHAR:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Character.class));
methodAdapter.unbox(Type.CHAR_TYPE);
break;
case Type.DOUBLE:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Double.class));
methodAdapter.unbox(Type.DOUBLE_TYPE);
break;
case Type.FLOAT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Float.class));
methodAdapter.unbox(Type.FLOAT_TYPE);
break;
case Type.INT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Integer.class));
methodAdapter.unbox(Type.INT_TYPE);
break;
case Type.LONG:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Long.class));
methodAdapter.unbox(Type.LONG_TYPE);
break;
case Type.SHORT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Short.class));
methodAdapter.unbox(Type.SHORT_TYPE);
break;
case Type.VOID:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Void.class));
methodAdapter.unbox(Type.VOID_TYPE);
break;
default:
case Type.OBJECT:
// in this case check the cast and cast the object to the return
// type
methodAdapter.checkCast(returnType);
methodAdapter.cast(OBJECT_TYPE, returnType);
break;
}
// return the (appropriately cast) result of the invocation from the
// stack
methodAdapter.returnValue();
// end the method
methodAdapter.endMethod();
LOGGER.debug(Constants.LOG_EXIT, "processMethod");
}
use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.
the class MethodCopyingClassAdapter method visitMethod.
@Override
public final MethodVisitor visitMethod(final int access, String name, String desc, String sig, String[] exceptions) {
MethodVisitor mv = null;
//abstract ones!.
if (!!!name.equals("<init>") && !!!name.equals("<clinit>") && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_ABSTRACT | ACC_NATIVE | ACC_BRIDGE)) == 0) {
// identify the target method parameters and return type
Method currentTransformMethod = new Method(name, desc);
// We don't want to duplicate a method we already overrode!
if (!!!knownMethods.add(currentTransformMethod))
return null;
// We can't override a final method
if ((access & ACC_FINAL) != 0)
throw new RuntimeException(new FinalModifierException(superToCopy, name));
// package
if ((access & (ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE)) == 0) {
if (!!!samePackage) {
methodHiddenException(name);
}
}
//Safe to copy a call to this method!
Type superType = Type.getType(superToCopy);
// identify the target method parameters and return type
String methodStaticFieldName = "methodField" + AbstractWovenProxyAdapter.getSanitizedUUIDString();
transformedMethods.put(methodStaticFieldName, new TypeMethod(superType, currentTransformMethod));
//Remember we need to copy the fake method *and* weave it, use a
//WovenProxyMethodAdapter as well as a CopyingMethodAdapter
MethodVisitor weaver = wovenProxyAdapter.getWeavingMethodVisitor(access, name, desc, sig, exceptions, currentTransformMethod, methodStaticFieldName, superType, false);
if (weaver instanceof AbstractWovenProxyMethodAdapter) {
//gets around the problem, but if not the class will fail verification.
if (!samePackage && (access & ACC_PROTECTED) != 0) {
methodHiddenException(name);
}
mv = new CopyingMethodAdapter((GeneratorAdapter) weaver, superType, currentTransformMethod);
} else {
//For whatever reason we aren't weaving this method. The call to super.xxx() will always work
mv = new CopyingMethodAdapter(new GeneratorAdapter(access, currentTransformMethod, mv), superType, currentTransformMethod);
}
}
return mv;
}
use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.
the class AbstractWovenProxyAdapter method writeFinalWovenProxyMethods.
/**
* Write the methods we need for wovenProxies on the highest supertype
*/
private final void writeFinalWovenProxyMethods() {
// add private fields for the Callable<Object> dispatcher
// and InvocationListener. These aren't static because we can have
// multiple instances of the same proxy class. These should not be
// serialized, or used in JPA or any other thing we can think of,
// so we annotate them as necessary
generateField(DISPATCHER_FIELD, Type.getDescriptor(Callable.class));
generateField(LISTENER_FIELD, Type.getDescriptor(InvocationListener.class));
// a general methodAdapter field that we will use to with GeneratorAdapters
// to create the methods required to implement WovenProxy
GeneratorAdapter methodAdapter;
// add a method for unwrapping the dispatcher
methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method("org_apache_aries_proxy_weaving_WovenProxy_unwrap", DISPATCHER_TYPE, NO_ARGS));
// /////////////////////////////////////////////////////
// Implement the method
// load this to get the field
methodAdapter.loadThis();
// get the dispatcher field and return
methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
methodAdapter.returnValue();
methodAdapter.endMethod();
// /////////////////////////////////////////////////////
// add a method for checking if the dispatcher is set
methodAdapter = getMethodGenerator(PUBLIC_GENERATED_METHOD_ACCESS, new Method("org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance", Type.BOOLEAN_TYPE, NO_ARGS));
// /////////////////////////////////////////////////////
// Implement the method
// load this to get the field
methodAdapter.loadThis();
// make a label for return true
Label returnTrueLabel = methodAdapter.newLabel();
// get the dispatcher field for the stack
methodAdapter.getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
// check if the dispatcher was non-null and goto return true if it was
methodAdapter.ifNonNull(returnTrueLabel);
methodAdapter.loadThis();
// get the listener field for the stack
methodAdapter.getField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
// check if the listener field was non-null and goto return true if it was
methodAdapter.ifNonNull(returnTrueLabel);
// return false if we haven't jumped anywhere
methodAdapter.push(false);
methodAdapter.returnValue();
// mark the returnTrueLable
methodAdapter.mark(returnTrueLabel);
methodAdapter.push(true);
methodAdapter.returnValue();
// end the method
methodAdapter.endMethod();
// ///////////////////////////////////////////////////////
}
use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.
the class AbstractWovenProxyAdapter method getMethodGenerator.
/**
* Get a generator for a method, this be annotated with the "invisibility"
* annotations (and ensured synthetic)
*
* @param methodSignature
* @return
*/
private final GeneratorAdapter getMethodGenerator(int access, Method method) {
access = access | ACC_SYNTHETIC;
GeneratorAdapter ga = new GeneratorAdapter(access, method, null, null, cv);
for (String s : annotationTypeDescriptors) ga.visitAnnotation(s, true).visitEnd();
ga.visitCode();
return ga;
}
use of org.objectweb.asm.commons.GeneratorAdapter in project aries by apache.
the class TCCLSetterVisitor method visitEnd.
@Override
public void visitEnd() {
if (!woven) {
// if this class wasn't woven, then don't add the synthesized method either.
super.visitEnd();
return;
}
// Add generated static method
Set<String> methodNames = new HashSet<String>();
for (WeavingData wd : weavingData) {
/* Equivalent to:
* private static void $$FCCL$$<className>$<methodName>(Class<?> cls) {
* Util.fixContextClassLoader("java.util.ServiceLoader", "load", cls, WovenClass.class.getClassLoader());
* }
*/
String methodName = getGeneratedMethodName(wd);
if (methodNames.contains(methodName))
continue;
methodNames.add(methodName);
Method method = new Method(methodName, Type.VOID_TYPE, new Type[] { CLASS_TYPE });
GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(ACC_PRIVATE + ACC_STATIC, methodName, method.getDescriptor(), null, null), ACC_PRIVATE + ACC_STATIC, methodName, method.getDescriptor());
//Load the strings, method parameter and target
mv.visitLdcInsn(wd.getClassName());
mv.visitLdcInsn(wd.getMethodName());
mv.loadArg(0);
mv.visitLdcInsn(targetClass);
//Change the class on the stack into a classloader
mv.invokeVirtual(CLASS_TYPE, new Method("getClassLoader", CLASSLOADER_TYPE, new Type[0]));
//Call our util method
mv.invokeStatic(UTIL_CLASS, new Method("fixContextClassloader", Type.VOID_TYPE, new Type[] { String_TYPE, String_TYPE, CLASS_TYPE, CLASSLOADER_TYPE }));
mv.returnValue();
mv.endMethod();
}
super.visitEnd();
}
Aggregations