}
if (!bytecodeInvocationAllowed) {
createInterceptorBody(classMethod, methodInfo, staticConstructor);
return;
}
final CodeAttribute b = classMethod.getCodeAttribute();
// create a new interceptor invocation context whenever we invoke a method on a client proxy
// we use a try-catch block in order to make sure that endInterceptorContext() is invoked regardless whether
// the method has succeeded or not
final ExceptionHandler start = b.exceptionBlockStart(Throwable.class.getName());
b.invokestatic(INTERCEPTION_DECORATION_CONTEXT_CLASS_NAME, START_INTERCEPTOR_CONTEXT_METHOD_NAME, EMPTY_PARENTHESES + DescriptorUtils.VOID_CLASS_DESCRIPTOR);
if (useCache()) {
loadCacheableBeanInstance(classMethod.getClassFile(), methodInfo, b);
} else {
loadBeanInstance(classMethod.getClassFile(), methodInfo, b);
}
//now we should have the target bean instance on top of the stack
// we need to dup it so we still have it to compare to the return value
b.dup();
//lets create the method invocation
String methodDescriptor = methodInfo.getDescriptor();
b.loadMethodParameters();
if (method.getDeclaringClass().isInterface()) {
b.invokeinterface(methodInfo.getDeclaringClass(), methodInfo.getName(), methodDescriptor);
} else {
b.invokevirtual(methodInfo.getDeclaringClass(), methodInfo.getName(), methodDescriptor);
}
// end the interceptor context, everything was fine
b.invokestatic(INTERCEPTION_DECORATION_CONTEXT_CLASS_NAME, END_INTERCEPTOR_CONTEXT_METHOD_NAME, EMPTY_PARENTHESES + DescriptorUtils.VOID_CLASS_DESCRIPTOR);
// jump over the catch block
BranchEnd gotoEnd = b.gotoInstruction();
// create catch block
b.exceptionBlockEnd(start);
b.exceptionHandlerStart(start);
b.invokestatic(INTERCEPTION_DECORATION_CONTEXT_CLASS_NAME, END_INTERCEPTOR_CONTEXT_METHOD_NAME, EMPTY_PARENTHESES + DescriptorUtils.VOID_CLASS_DESCRIPTOR);
b.athrow();
// update the correct address to jump over the catch block
b.branchEnd(gotoEnd);
// if this method returns a primitive we just return
if (method.getReturnType().isPrimitive()) {
b.returnInstruction();
} else {
// otherwise we have to check that the proxy is not returning 'this;
// now we need to check if the proxy has return 'this' and if so return
// an
// instance of the proxy.
// currently we have result, beanInstance on the stack.
b.dupX1();
// now we have result, beanInstance, result
// we need to compare result and beanInstance
// first we need to build up the inner conditional that just returns
// the
// result
final BranchEnd returnInstruction = b.ifAcmpeq();
b.returnInstruction();
b.branchEnd(returnInstruction);
// now add the case where the proxy returns 'this';
b.aload(0);
b.checkcast(methodInfo.getMethod().getReturnType().getName());
b.returnInstruction();
}
}