use of org.apache.xbean.asm9.MethodVisitor in project jodd by oblac.
the class ProxettaClassBuilder method makeProxyConstructor.
/**
* Creates init method that simply calls all advice constructor methods in correct order.
* This created init method is called from each destination's constructor.
*/
protected void makeProxyConstructor() {
MethodVisitor mv = wd.dest.visitMethod(AsmUtil.ACC_PRIVATE | AsmUtil.ACC_FINAL, initMethodName, DESC_VOID, null, null);
mv.visitCode();
if (wd.adviceInits != null) {
for (String name : wd.adviceInits) {
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, wd.thisReference, name, DESC_VOID, false);
}
}
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
use of org.apache.xbean.asm9.MethodVisitor in project jodd by oblac.
the class ProxettaMethodBuilder method createProxyMethod.
/**
* Creates proxy methods over target method, For each matched proxy, new proxy method is created
* by taking advice bytecode and replaces usages of {@link jodd.proxetta.ProxyTarget}.
* <p>
* Invocation chain example: {@code name -> name$p0 -> name$p1 -> name$p4 -> super}.
*/
public void createProxyMethod(final TargetMethodData td) {
final ProxyAspectData aspectData = td.getProxyData();
int access = td.msign.getAccessFlags();
access &= ~ACC_NATIVE;
access &= ~ACC_ABSTRACT;
access = ProxettaAsmUtil.makePrivateFinalAccess(access);
final MethodVisitor mv = wd.dest.visitMethod(access, td.methodName(), td.msign.getDescription(), null, null);
mv.visitCode();
//*** VISIT ADVICE - called for each aspect and each method
aspectData.getAdviceClassReader().accept(new EmptyClassVisitor() {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (!name.equals(executeMethodName)) {
return null;
}
return new HistoryMethodAdapter(mv) {
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(aspectData.adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectData.aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitVarInsn(int opcode, int var) {
var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
if (proxyInfoRequested) {
proxyInfoRequested = false;
if (opcode == ASTORE) {
ProxyTargetReplacement.info(mv, td.msign, var);
}
}
// [F1]
super.visitVarInsn(opcode, var);
}
@Override
public void visitIincInsn(int var, int increment) {
var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
// [F1]
super.visitIincInsn(var, increment);
}
@Override
public void visitInsn(int opcode) {
if (opcode == ARETURN) {
visitReturn(mv, td.msign, true);
return;
}
if (traceNext) {
if ((opcode == POP) || (opcode == POP2)) {
// [F3] - invoke invoked without assignment
return;
}
}
super.visitInsn(opcode);
}
@SuppressWarnings({ "ParameterNameDiffersFromOverriddenParameter" })
@Override
public void visitMethodInsn(int opcode, String string, String mname, String mdesc, boolean isInterface) {
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE) || (opcode == INVOKESPECIAL)) {
if (string.equals(aspectData.adviceReference)) {
string = wd.thisReference;
mname = adviceMethodName(mname, aspectData.aspectIndex);
}
} else if (opcode == INVOKESTATIC) {
if (string.equals(aspectData.adviceReference)) {
string = wd.thisReference;
mname = adviceMethodName(mname, aspectData.aspectIndex);
} else if (string.endsWith('/' + TARGET_CLASS_NAME)) {
if (isInvokeMethod(mname, mdesc)) {
// [R7]
if (td.isLastMethodInChain()) {
if (!wd.isWrapper()) {
// PROXY
loadSpecialMethodArguments(mv, td.msign);
mv.visitMethodInsn(INVOKESPECIAL, wd.superReference, td.msign.getMethodName(), td.msign.getDescription(), isInterface);
} else {
// WRAPPER
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, wd.thisReference, wd.wrapperRef, wd.wrapperType);
loadVirtualMethodArguments(mv, td.msign);
if (wd.wrapInterface) {
mv.visitMethodInsn(INVOKEINTERFACE, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), true);
} else {
mv.visitMethodInsn(INVOKEVIRTUAL, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), isInterface);
}
}
// [F4]
prepareReturnValue(mv, td.msign, aspectData.maxLocalVarOffset);
traceNext = true;
} else {
// calls next proxy method
loadSpecialMethodArguments(mv, td.msign);
mv.visitMethodInsn(INVOKESPECIAL, wd.thisReference, td.nextMethodName(), td.msign.getDescription(), isInterface);
visitReturn(mv, td.msign, false);
}
return;
}
if (isArgumentsCountMethod(mname, mdesc)) {
// [R2]
ProxyTargetReplacement.argumentsCount(mv, td.msign);
return;
}
if (isArgumentTypeMethod(mname, mdesc)) {
// [R3]
int argIndex = this.getArgumentIndex();
ProxyTargetReplacement.argumentType(mv, td.msign, argIndex);
return;
}
if (isArgumentMethod(mname, mdesc)) {
// [R4]
int argIndex = this.getArgumentIndex();
ProxyTargetReplacement.argument(mv, td.msign, argIndex);
return;
}
if (isSetArgumentMethod(mname, mdesc)) {
// [R5]
int argIndex = this.getArgumentIndex();
checkArgumentIndex(td.msign, argIndex);
mv.visitInsn(POP);
storeMethodArgumentFromObject(mv, td.msign, argIndex);
return;
}
if (isCreateArgumentsArrayMethod(mname, mdesc)) {
// [R6]
ProxyTargetReplacement.createArgumentsArray(mv, td.msign);
return;
}
if (isCreateArgumentsClassArrayMethod(mname, mdesc)) {
// [R11]
ProxyTargetReplacement.createArgumentsClassArray(mv, td.msign);
return;
}
if (isTargetMethod(mname, mdesc)) {
// [R9.1]
mv.visitVarInsn(ALOAD, 0);
return;
}
if (isTargetClassMethod(mname, mdesc)) {
// [R9]
ProxyTargetReplacement.targetClass(mv, td.msign);
//ProxyTargetReplacement.targetClass(mv, wd.superReference);
return;
}
if (isTargetMethodNameMethod(mname, mdesc)) {
// [R10]
ProxyTargetReplacement.targetMethodName(mv, td.msign);
return;
}
if (isTargetMethodSignatureMethod(mname, mdesc)) {
ProxyTargetReplacement.targetMethodSignature(mv, td.msign);
return;
}
if (isTargetMethodDescriptionMethod(mname, mdesc)) {
ProxyTargetReplacement.targetMethodDescription(mv, td.msign);
return;
}
if (isInfoMethod(mname, mdesc)) {
// we are NOT replacing info() here! First, we need to figure out
// what is the operand for the very next ASTORE instructions
// since we need to create an object and store it in this
// register - and reuse it, in replacement code.
//ProxyTargetReplacement.info(mv, td.msign);
proxyInfoRequested = true;
return;
}
if (isReturnTypeMethod(mname, mdesc)) {
// [R11]
ProxyTargetReplacement.returnType(mv, td.msign);
return;
}
if (isReturnValueMethod(mname, mdesc)) {
castToReturnType(mv, td.msign);
return;
}
if (isTargetMethodAnnotationMethod(mname, mdesc)) {
String[] args = getLastTwoStringArguments();
// pop current two args
mv.visitInsn(POP);
mv.visitInsn(POP);
ProxyTargetReplacement.targetMethodAnnotation(mv, td.msign, args);
return;
}
if (isTargetClassAnnotationMethod(mname, mdesc)) {
String[] args = getLastTwoStringArguments();
// pop current two args
mv.visitInsn(POP);
mv.visitInsn(POP);
ProxyTargetReplacement.targetClassAnnotation(mv, td.msign.getClassInfo(), args);
return;
}
}
}
super.visitMethodInsn(opcode, string, mname, mdesc, isInterface);
}
};
}
}, 0);
}
use of org.apache.xbean.asm9.MethodVisitor in project tomee by apache.
the class DynamicSubclass method generateBytes.
private static byte[] generateBytes(final Class<?> classToProxy) throws ProxyGenerationException {
final Map<String, MethodVisitor> visitors = new HashMap<>();
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final String proxyClassFileName = getSubclassName(classToProxy).replace('.', '/');
final String classFileName = classToProxy.getName().replace('.', '/');
cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, proxyClassFileName, null, classFileName, null);
cw.visitSource(classFileName + ".java", null);
// push InvocationHandler field
cw.visitField(ACC_FINAL + ACC_PRIVATE, "this$handler", "Ljava/lang/reflect/InvocationHandler;", null, null).visitEnd();
for (final Constructor<?> constructor : classToProxy.getConstructors()) {
if (!Modifier.isPublic(constructor.getModifiers())) {
continue;
}
final MethodVisitor mv = visitConstructor(cw, proxyClassFileName, classFileName, constructor);
visitors.put("<init>" + Type.getConstructorDescriptor(constructor), mv);
}
final Map<String, List<Method>> methodMap = new HashMap<>();
getNonPrivateMethods(classToProxy, methodMap);
// Iterate over the public methods
for (final Map.Entry<String, List<Method>> entry : methodMap.entrySet()) {
for (final Method method : entry.getValue()) {
if (Modifier.isAbstract(method.getModifiers())) {
final MethodVisitor visitor = LocalBeanProxyFactory.visit(cw, method, proxyClassFileName, "this$handler");
visitors.put(method.getName() + Type.getMethodDescriptor(method), visitor);
}
}
}
copyClassAnnotations(classToProxy, cw);
copyMethodAnnotations(classToProxy, visitors);
// This should never be reached, but just in case
for (final MethodVisitor visitor : visitors.values()) {
visitor.visitEnd();
}
return cw.toByteArray();
}
use of org.apache.xbean.asm9.MethodVisitor in project component-runtime by Talend.
the class ProxyGenerator method createConstructor.
private String createConstructor(final ClassWriter cw, final Class<?> classToProxy, final String classFileName, final String proxyClassFileName, final Constructor<?> constructor, final boolean withInterceptors) {
try {
Constructor superDefaultCt;
String parentClassFileName;
String[] exceptions = null;
if (classToProxy.isInterface()) {
parentClassFileName = Type.getInternalName(Object.class);
superDefaultCt = Object.class.getConstructor();
} else {
parentClassFileName = classFileName;
if (constructor == null) {
superDefaultCt = classToProxy.getConstructor();
} else {
superDefaultCt = constructor;
Class<?>[] exceptionTypes = constructor.getExceptionTypes();
exceptions = exceptionTypes.length == 0 ? null : new String[exceptionTypes.length];
for (int i = 0; i < exceptionTypes.length; i++) {
exceptions[i] = Type.getInternalName(exceptionTypes[i]);
}
}
}
final String descriptor = Type.getConstructorDescriptor(superDefaultCt);
final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, exceptions);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
if (constructor != null) {
for (int i = 1; i <= constructor.getParameterTypes().length; i++) {
mv.visitVarInsn(ALOAD, i);
}
}
mv.visitMethodInsn(INVOKESPECIAL, parentClassFileName, "<init>", descriptor, false);
if (withInterceptors) {
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ACONST_NULL);
mv.visitFieldInsn(PUTFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
}
mv.visitInsn(RETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();
return parentClassFileName;
} catch (final NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
use of org.apache.xbean.asm9.MethodVisitor in project component-runtime by Talend.
the class ProxyGenerator method delegateMethod.
private void delegateMethod(final ClassWriter cw, final Method method, final String proxyClassFileName, final int methodIndex) {
final Class<?> returnType = method.getReturnType();
final Class<?>[] parameterTypes = method.getParameterTypes();
final Class<?>[] exceptionTypes = method.getExceptionTypes();
final int modifiers = method.getModifiers();
if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) {
throw new IllegalStateException("It's not possible to proxy a final or static method: " + method.getDeclaringClass().getName() + " " + method.getName());
}
// push the method definition
int modifier = modifiers & (ACC_PUBLIC | ACC_PROTECTED | ACC_VARARGS);
MethodVisitor mv = cw.visitMethod(modifier, method.getName(), Type.getMethodDescriptor(method), null, null);
mv.visitCode();
// push try/catch block, to catch declared exceptions, and to catch java.lang.Throwable
final Label l0 = new Label();
final Label l1 = new Label();
final Label l2 = new Label();
if (exceptionTypes.length > 0) {
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException");
}
// push try code
mv.visitLabel(l0);
final String classNameToOverride = method.getDeclaringClass().getName().replace('.', '/');
mv.visitLdcInsn(Type.getType("L" + classNameToOverride + ";"));
// the following code generates the bytecode for this line of Java:
// Method method = <proxy>.class.getMethod("add", new Class[] { <array of function argument classes> });
// get the method name to invoke, and push to stack
mv.visitLdcInsn(method.getName());
// create the Class[]
createArrayDefinition(mv, parameterTypes.length, Class.class);
int length = 1;
// push parameters into array
for (int i = 0; i < parameterTypes.length; i++) {
// keep copy of array on stack
mv.visitInsn(DUP);
Class<?> parameterType = parameterTypes[i];
// push number onto stack
pushIntOntoStack(mv, i);
if (parameterType.isPrimitive()) {
String wrapperType = getWrapperType(parameterType);
mv.visitFieldInsn(GETSTATIC, wrapperType, "TYPE", "Ljava/lang/Class;");
} else {
mv.visitLdcInsn(Type.getType(parameterType));
}
mv.visitInsn(AASTORE);
if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType)) {
length += 2;
} else {
length++;
}
}
// the following code generates bytecode equivalent to:
// return ((<returntype>) invocationHandler.invoke(this, {methodIndex}, new Object[] { <function arguments
// }))[.<primitive>Value()];
final Label l4 = new Label();
mv.visitLabel(l4);
mv.visitVarInsn(ALOAD, 0);
// get the invocationHandler field from this class
mv.visitFieldInsn(GETFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
// add the Method from the static array as first parameter
mv.visitFieldInsn(GETSTATIC, proxyClassFileName, FIELD_INTERCEPTED_METHODS, Type.getDescriptor(Method[].class));
// push the methodIndex of the current method
if (methodIndex < 128) {
mv.visitIntInsn(BIPUSH, methodIndex);
} else if (methodIndex < 32267) {
// for methods > 127 we need to push a short number as index
mv.visitIntInsn(SIPUSH, methodIndex);
} else {
throw new IllegalStateException("Sorry, we only support Classes with 2^15 methods...");
}
// and now load the Method from the array
mv.visitInsn(AALOAD);
// prepare the parameter array as Object[] and store it on the stack
pushMethodParameterArray(mv, parameterTypes);
// invoke the invocationHandler
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(InterceptorHandler.class), "invoke", "(Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
// cast the result
mv.visitTypeInsn(CHECKCAST, getCastType(returnType));
if (returnType.isPrimitive() && (!Void.TYPE.equals(returnType))) {
// get the primitive value
mv.visitMethodInsn(INVOKEVIRTUAL, getWrapperType(returnType), getPrimitiveMethod(returnType), "()" + Type.getDescriptor(returnType), false);
}
// push return
mv.visitLabel(l1);
if (!Void.TYPE.equals(returnType)) {
mv.visitInsn(getReturnInsn(returnType));
} else {
mv.visitInsn(POP);
mv.visitInsn(RETURN);
}
// catch InvocationTargetException
if (exceptionTypes.length > 0) {
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, length);
Label l5 = new Label();
mv.visitLabel(l5);
for (int i = 0; i < exceptionTypes.length; i++) {
Class<?> exceptionType = exceptionTypes[i];
mv.visitLdcInsn(Type.getType("L" + exceptionType.getCanonicalName().replace('.', '/') + ";"));
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
final Label l6 = new Label();
mv.visitJumpInsn(IFEQ, l6);
final Label l7 = new Label();
mv.visitLabel(l7);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitTypeInsn(CHECKCAST, getCastType(exceptionType));
mv.visitInsn(ATHROW);
mv.visitLabel(l6);
if (i == (exceptionTypes.length - 1)) {
mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
}
}
}
// finish this method
mv.visitMaxs(0, 0);
mv.visitEnd();
}
Aggregations