use of org.objectweb.asm.commons.Method in project aries by apache.
the class AbstractWovenProxyAdapter method writeStaticInitMethod.
/**
* Create fields and an initialiser for {@link java.lang.reflect.Method}
* objects in our class
*/
private final void writeStaticInitMethod() {
for (String methodStaticFieldName : transformedMethods.keySet()) {
// add a private static field for the method
cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(), null, null).visitEnd();
}
GeneratorAdapter staticAdapter = new GeneratorAdapter(staticInitMethodFlags, staticInitMethod, null, null, cv);
for (Entry<String, TypeMethod> entry : transformedMethods.entrySet()) {
// Add some more code to the static initializer
TypeMethod m = entry.getValue();
Type[] targetMethodParameters = m.method.getArgumentTypes();
String methodStaticFieldName = entry.getKey();
Label beginPopulate = staticAdapter.newLabel();
Label endPopulate = staticAdapter.newLabel();
Label catchHandler = staticAdapter.newLabel();
staticAdapter.visitTryCatchBlock(beginPopulate, endPopulate, catchHandler, THROWABLE_INAME);
staticAdapter.mark(beginPopulate);
staticAdapter.push(m.declaringClass);
// push the method name string arg onto the stack
staticAdapter.push(m.method.getName());
// 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);
staticAdapter.push(t);
staticAdapter.arrayStore(CLASS_TYPE);
index++;
}
// invoke the getMethod
staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE, new Type[] { STRING_TYPE, CLASS_ARRAY_TYPE }));
// store the reflected method in the static field
staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
Label afterCatch = staticAdapter.newLabel();
staticAdapter.mark(endPopulate);
staticAdapter.goTo(afterCatch);
staticAdapter.mark(catchHandler);
// We don't care about the exception, so pop it off
staticAdapter.pop();
// store the reflected method in the static field
staticAdapter.visitInsn(ACONST_NULL);
staticAdapter.putStatic(typeBeingWoven, methodStaticFieldName, METHOD_TYPE);
staticAdapter.mark(afterCatch);
}
staticAdapter.returnValue();
staticAdapter.endMethod();
}
use of org.objectweb.asm.commons.Method in project aries by apache.
the class AbstractWovenProxyAdapter method writeCreateNewProxyInstanceAndConstructor.
/**
* We write createNewProxyInstance separately because it isn't final, and is
* overridden on each class, we also write a constructor for this method to
* use if we don't have one.
*/
private final void writeCreateNewProxyInstanceAndConstructor() {
GeneratorAdapter methodAdapter = getMethodGenerator(ACC_PUBLIC, new Method("org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance", WOVEN_PROXY_IFACE_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
// /////////////////////////////////////////////////////
// Implement the method
// Create and instantiate a new instance, then return it
methodAdapter.newInstance(typeBeingWoven);
methodAdapter.dup();
methodAdapter.loadArgs();
methodAdapter.invokeConstructor(typeBeingWoven, new Method("<init>", Type.VOID_TYPE, DISPATCHER_LISTENER_METHOD_ARGS));
methodAdapter.returnValue();
methodAdapter.endMethod();
//////////////////////////////////////////////////////////
// Write a protected no-args constructor for this class
methodAdapter = getMethodGenerator(ACC_PROTECTED | ACC_SYNTHETIC, ARGS_CONSTRUCTOR);
if (implementWovenProxy) {
methodAdapter.loadThis();
if (superHasNoArgsConstructor)
methodAdapter.invokeConstructor(superType, NO_ARGS_CONSTRUCTOR);
else {
if (hasNoArgsConstructor)
methodAdapter.invokeConstructor(typeBeingWoven, NO_ARGS_CONSTRUCTOR);
else
throw new RuntimeException(new UnableToProxyException(typeBeingWoven.getClassName(), String.format("The class %s and its superclass %s do not have no-args constructors and cannot be woven.", typeBeingWoven.getClassName(), superType.getClassName())));
}
methodAdapter.loadThis();
methodAdapter.loadArg(0);
methodAdapter.putField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
methodAdapter.loadThis();
methodAdapter.loadArg(1);
methodAdapter.putField(typeBeingWoven, LISTENER_FIELD, LISTENER_TYPE);
} else {
//We just invoke the super with args
methodAdapter.loadThis();
methodAdapter.loadArgs();
methodAdapter.invokeConstructor(superType, ARGS_CONSTRUCTOR);
}
//Throw an NPE if the dispatcher is null, return otherwise
methodAdapter.loadArg(0);
Label returnValue = methodAdapter.newLabel();
methodAdapter.ifNonNull(returnValue);
methodAdapter.newInstance(NPE_TYPE);
methodAdapter.dup();
methodAdapter.push("The dispatcher must never be null!");
methodAdapter.invokeConstructor(NPE_TYPE, NPE_CONSTRUCTOR);
methodAdapter.throwException();
methodAdapter.mark(returnValue);
methodAdapter.returnValue();
methodAdapter.endMethod();
//////////////////////////////////////////////////////////
}
use of org.objectweb.asm.commons.Method in project aries by apache.
the class AbstractWovenProxyAdapter method visitMethod.
/**
* This method is called on each method implemented on this object (but not
* for superclass methods) Each of these methods is visited in turn and the
* code here generates the byte code for the calls to the InovcationListener
* around the existing method
*/
public final MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
LOGGER.debug(Constants.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc, signature, exceptions });
Method currentMethod = new Method(name, desc);
getKnownMethods().add(currentMethod);
MethodVisitor methodVisitorToReturn = null;
// compiler generated ones.
if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_NATIVE | ACC_BRIDGE)) == 0 && !!!name.equals("<init>") && !!!name.equals("<clinit>")) {
// found a method we should weave
//Create a field name and store it for later
String methodStaticFieldName = "methodField" + getSanitizedUUIDString();
transformedMethods.put(methodStaticFieldName, new TypeMethod(currentMethodDeclaringType, currentMethod));
// Surround the MethodVisitor with our weaver so we can manipulate the code
methodVisitorToReturn = getWeavingMethodVisitor(access, name, desc, signature, exceptions, currentMethod, methodStaticFieldName, currentMethodDeclaringType, currentMethodDeclaringTypeIsInterface);
} else if (name.equals("<clinit>")) {
//there is an existing clinit method, change the fields we use
//to write our init code to static_init_UUID instead
staticInitMethod = new Method("static_init_" + UU_ID, Type.VOID_TYPE, NO_ARGS);
staticInitMethodFlags = staticInitMethodFlags | ACC_FINAL;
methodVisitorToReturn = new AdviceAdapter(Opcodes.ASM5, cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc) {
@Override
protected void onMethodEnter() {
//add into the <clinit> a call to our synthetic static_init_UUID
invokeStatic(typeBeingWoven, staticInitMethod);
super.onMethodEnter();
}
};
} else {
if (currentMethod.getArgumentTypes().length == 0 && name.equals("<init>"))
hasNoArgsConstructor = true;
//This isn't a method we want to weave, so just get the default visitor
methodVisitorToReturn = cv.visitMethod(access, name, desc, signature, exceptions);
}
LOGGER.debug(Constants.LOG_EXIT, "visitMethod", methodVisitorToReturn);
return methodVisitorToReturn;
}
use of org.objectweb.asm.commons.Method in project aries by apache.
the class ProxySubclassAdapter method visit.
/*
* This method visits the class to generate the new subclass.
*
* The following things happen here: 1. The class is renamed to a dynamic
* name 2. The existing class name is changed to be the superclass name so
* that the generated class extends the original class. 3. A private field
* is added to store an invocation handler 4. A constructor is added that
* takes an invocation handler as an argument 5. The constructor method
* instantiates an instance of the superclass 6. The constructor method sets
* the invocation handler so the invoke method can be called from all the
* subsequently rewritten methods 7. Add a getInvocationHandler() method 8.
* store a static Class object of the superclass so we can reflectively find
* methods later
*/
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
LOGGER.debug(Constants.LOG_ENTRY, "visit", new Object[] { version, access, name, signature, superName, interfaces });
// store the superclass binary name
this.superclassBinaryName = name.replaceAll("/", "\\.");
try {
this.superclassClass = Class.forName(superclassBinaryName, false, loader);
} catch (ClassNotFoundException cnfe) {
throw new TypeNotPresentException(superclassBinaryName, cnfe);
}
// from the superclass anyway
if ((access & ACC_ABSTRACT) != 0) {
//If the super was abstract the subclass should not be!
access &= ~ACC_ABSTRACT;
}
cv.visit(ProxyUtils.getWeavingJavaVersion(), access, newClassName, signature, name, null);
// add a private field for the invocation handler
// this isn't static in case we have multiple instances of the same
// proxy
cv.visitField(ACC_PRIVATE, IH_FIELD, Type.getDescriptor(InvocationHandler.class), null, null);
// create a static adapter for generating a static initialiser method in
// the generated subclass
staticAdapter = new GeneratorAdapter(ACC_STATIC, new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);
// add a zero args constructor method
Method m = new Method("<init>", Type.VOID_TYPE, NO_ARGS);
GeneratorAdapter methodAdapter = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cv);
// loadthis
methodAdapter.loadThis();
// List the constructors in the superclass.
Constructor<?>[] constructors = superclassClass.getDeclaredConstructors();
// Check that we've got at least one constructor, and get the 1st one in the list.
if (constructors.length > 0) {
// We now need to construct the proxy class as though it is going to invoke the superclasses constructor.
// We do this because we can no longer call the java.lang.Object() zero arg constructor as the JVM now throws a VerifyError.
// So what we do is build up the calling of the superclasses constructor using nulls and default values. This means that the
// class bytes can be verified by the JVM, and then in the ProxySubclassGenerator, we load the class without invoking the
// constructor.
Method constructor = Method.getMethod(constructors[0]);
Type[] argTypes = constructor.getArgumentTypes();
if (argTypes.length == 0) {
methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, NO_ARGS));
} else {
for (Type type : argTypes) {
switch(type.getSort()) {
case Type.ARRAY:
// We need to process any array or multidimentional arrays.
String elementDesc = type.getElementType().getDescriptor();
String typeDesc = type.getDescriptor();
// Iterate over the number of arrays and load 0 for each one. Keep a count of the number of
// arrays as we will need to run different code fo multi dimentional arrays.
int index = 0;
while (!elementDesc.equals(typeDesc)) {
typeDesc = typeDesc.substring(1);
methodAdapter.visitInsn(Opcodes.ICONST_0);
index++;
}
// If we're just a single array, then call the newArray method, otherwise use the MultiANewArray instruction.
if (index == 1) {
methodAdapter.newArray(type.getElementType());
} else {
methodAdapter.visitMultiANewArrayInsn(type.getDescriptor(), index);
}
break;
case Type.BOOLEAN:
methodAdapter.push(true);
break;
case Type.BYTE:
methodAdapter.push(Type.VOID_TYPE);
break;
case Type.CHAR:
methodAdapter.push(Type.VOID_TYPE);
break;
case Type.DOUBLE:
methodAdapter.push(0.0);
break;
case Type.FLOAT:
methodAdapter.push(0.0f);
break;
case Type.INT:
methodAdapter.push(0);
break;
case Type.LONG:
methodAdapter.push(0l);
break;
case Type.SHORT:
methodAdapter.push(0);
break;
default:
case Type.OBJECT:
methodAdapter.visitInsn(Opcodes.ACONST_NULL);
break;
}
}
methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, argTypes));
}
}
methodAdapter.returnValue();
methodAdapter.endMethod();
// add a method for getting the invocation handler
Method setter = new Method("setInvocationHandler", Type.VOID_TYPE, new Type[] { IH_TYPE });
m = new Method("getInvocationHandler", IH_TYPE, NO_ARGS);
methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, m, null, null, cv);
// load this to get the field
methodAdapter.loadThis();
// get the ih field and return
methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
methodAdapter.returnValue();
methodAdapter.endMethod();
// add a method for setting the invocation handler
methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, setter, null, null, cv);
// load this to put the field
methodAdapter.loadThis();
// load the method arguments (i.e. the invocation handler) to the stack
methodAdapter.loadArgs();
// set the ih field using the method argument
methodAdapter.putField(newClassType, IH_FIELD, IH_TYPE);
methodAdapter.returnValue();
methodAdapter.endMethod();
// loop through the class hierarchy to get any needed methods off the
// supertypes
// start by finding the methods declared on the class of interest (the
// superclass of our dynamic subclass)
java.lang.reflect.Method[] observedMethods = superclassClass.getDeclaredMethods();
// add the methods to a set of observedMethods
ProxySubclassMethodHashSet<String> setOfObservedMethods = new ProxySubclassMethodHashSet<String>(observedMethods.length);
setOfObservedMethods.addMethodArray(observedMethods);
// get the next superclass in the hierarchy
Class<?> nextSuperClass = superclassClass.getSuperclass();
while (nextSuperClass != null) {
// set the fields for the current class
setCurrentAnalysisClassFields(nextSuperClass);
// add a static field and static initializer code to the generated
// subclass
// for each of the superclasses in the hierarchy
addClassStaticField(currentlyAnalysedClassName);
LOGGER.debug("Class currently being analysed: {} {}", currentlyAnalysedClassName, currentlyAnalysedClass);
// now find the methods declared on the current class and add them
// to a set of foundMethods
java.lang.reflect.Method[] foundMethods = currentlyAnalysedClass.getDeclaredMethods();
ProxySubclassMethodHashSet<String> setOfFoundMethods = new ProxySubclassMethodHashSet<String>(foundMethods.length);
setOfFoundMethods.addMethodArray(foundMethods);
// remove from the set of foundMethods any methods we saw on a
// subclass
// because we want to use the lowest level declaration of a method
setOfFoundMethods.removeAll(setOfObservedMethods);
try {
// read the current class and use a
// ProxySubclassHierarchyAdapter
// to process only methods on that class that are in the list
ClassLoader loader = currentlyAnalysedClass.getClassLoader();
if (loader == null) {
loader = this.loader;
}
InputStream is = loader.getResourceAsStream(currentlyAnalysedClass.getName().replaceAll("\\.", "/") + ".class");
if (is == null) {
//use SystemModuleClassLoader as fallback
ClassLoader classLoader = new SystemModuleClassLoader();
is = classLoader.getResourceAsStream(currentlyAnalysedClass.getName().replaceAll("\\.", "/") + ".class");
}
ClassReader cr = new ClassReader(is);
ClassVisitor hierarchyAdapter = new ProxySubclassHierarchyAdapter(this, setOfFoundMethods);
cr.accept(hierarchyAdapter, ClassReader.SKIP_DEBUG);
} catch (IOException e) {
throw new TypeNotPresentException(currentlyAnalysedClassName, e);
}
// now add the foundMethods to the overall list of observed methods
setOfObservedMethods.addAll(setOfFoundMethods);
// get the next class up in the hierarchy and go again
nextSuperClass = currentlyAnalysedClass.getSuperclass();
}
// we've finished looking at the superclass hierarchy
// set the fields for the immediate superclass of our dynamic subclass
setCurrentAnalysisClassFields(superclassClass);
// add the class static field
addClassStaticField(currentlyAnalysedClassName);
// we do the lowest class last because we are already visiting the class
// when in this adapter code
// now we are ready to visit all the methods on the lowest class
// which will happen by the ASM ClassVisitor implemented in this adapter
LOGGER.debug(Constants.LOG_EXIT, "visit");
}
use of org.objectweb.asm.commons.Method in project aries by apache.
the class AbstractWovenProxyMethodAdapter method writeDispatcher.
/**
* Write out the bytecode instructions necessary to do the dispatch.
* We know the dispatcher is non-null, and we need a try/catch around the
* invocation and listener calls.
*/
protected final void writeDispatcher() {
// Setup locals we will use in the dispatch
setupLocals();
//Write the try catch block
visitTryCatchBlock(beginTry, endTry, endTry, THROWABLE_INAME);
mark(beginTry);
//Start dispatching, get the target object and store it
loadThis();
getField(typeBeingWoven, DISPATCHER_FIELD, DISPATCHER_TYPE);
invokeInterface(DISPATCHER_TYPE, new Method("call", OBJECT_TYPE, NO_ARGS));
storeLocal(dispatchTarget);
//Pre-invoke, invoke, post-invoke, return
writePreInvoke();
//Start the real method
push(true);
storeLocal(inNormalMethod);
//Dispatch the method and store the result (null for void)
loadLocal(dispatchTarget);
checkCast(methodDeclaringType);
loadArgs();
if (isMethodDeclaringTypeInterface && !isDefaultMethod) {
invokeInterface(methodDeclaringType, currentTransformMethod);
} else {
invokeVirtual(methodDeclaringType, currentTransformMethod);
}
if (isVoid) {
visitInsn(ACONST_NULL);
}
storeLocal(normalResult);
// finish the real method and post-invoke
push(false);
storeLocal(inNormalMethod);
writePostInvoke();
//Return, with the return value if necessary
if (!!!isVoid) {
loadLocal(normalResult);
}
returnValue();
//End of our try, start of our catch
mark(endTry);
writeMethodCatchHandler();
}
Aggregations