}
Class<?> returnType = method.getReturnType();
TypeId<?> resultType = TypeId.get(returnType);
MethodId<T, ?> superMethod = superclassType.getMethod(resultType, name, argTypes);
MethodId<?, ?> methodId = generatedType.getMethod(resultType, name, argTypes);
Code code = dexMaker.declare(methodId, PUBLIC);
Local<G> localThis = code.getThis(generatedType);
Local<InvocationHandler> localHandler = code.newLocal(handlerType);
Local<Object> invokeResult = code.newLocal(TypeId.OBJECT);
Local<Integer> intValue = code.newLocal(TypeId.INT);
Local<Object[]> args = code.newLocal(objectArrayType);
Local<Integer> argsLength = code.newLocal(TypeId.INT);
Local<Object> temp = code.newLocal(TypeId.OBJECT);
Local<?> resultHolder = code.newLocal(resultType);
Local<Method[]> methodArray = code.newLocal(methodArrayType);
Local<Method> thisMethod = code.newLocal(methodType);
Local<Integer> methodIndex = code.newLocal(TypeId.INT);
Class<?> aBoxedClass = PRIMITIVE_TO_BOXED.get(returnType);
Local<?> aBoxedResult = null;
if (aBoxedClass != null) {
aBoxedResult = code.newLocal(TypeId.get(aBoxedClass));
}
Local<?>[] superArgs2 = new Local<?>[argClasses.length];
Local<?> superResult2 = code.newLocal(resultType);
Local<InvocationHandler> nullHandler = code.newLocal(handlerType);
code.loadConstant(methodIndex, m);
code.sget(allMethods, methodArray);
code.aget(thisMethod, methodArray, methodIndex);
code.loadConstant(argsLength, argTypes.length);
code.newArray(args, argsLength);
code.iget(handlerField, localHandler, localThis);
// if (proxy == null)
code.loadConstant(nullHandler, null);
Label handlerNullCase = new Label();
code.compare(Comparison.EQ, handlerNullCase, nullHandler, localHandler);
// This code is what we execute when we have a valid proxy: delegate to invocation
// handler.
for (int p = 0; p < argTypes.length; ++p) {
code.loadConstant(intValue, p);
Local<?> parameter = code.getParameter(p, argTypes[p]);
Local<?> unboxedIfNecessary = boxIfRequired(code, parameter, temp);
code.aput(args, intValue, unboxedIfNecessary);
}
code.invokeInterface(methodInvoke, invokeResult, localHandler,
localThis, thisMethod, args);
generateCodeForReturnStatement(code, returnType, invokeResult, resultHolder,
aBoxedResult);
// This code is executed if proxy is null: call the original super method.
// This is required to handle the case of construction of an object which leaks the
// "this" pointer.
code.mark(handlerNullCase);
for (int i = 0; i < superArgs2.length; ++i) {
superArgs2[i] = code.getParameter(i, argTypes[i]);
}
if (void.class.equals(returnType)) {
code.invokeSuper(superMethod, null, localThis, superArgs2);
code.returnVoid();
} else {
invokeSuper(superMethod, code, localThis, superArgs2, superResult2);
code.returnValue(superResult2);
}
/*
* And to allow calling the original super method, the following is also generated:
*
* public String super$doSomething$java_lang_String(Bar param0, int param1) {
* int result = super.doSomething(param0, param1);
* return result;
* }
*/
// TODO: don't include a super_ method if the target is abstract!
MethodId<G, ?> callsSuperMethod = generatedType.getMethod(
resultType, superMethodName(method), argTypes);
Code superCode = dexMaker.declare(callsSuperMethod, PUBLIC);
Local<G> superThis = superCode.getThis(generatedType);
Local<?>[] superArgs = new Local<?>[argClasses.length];
for (int i = 0; i < superArgs.length; ++i) {
superArgs[i] = superCode.getParameter(i, argTypes[i]);
}
if (void.class.equals(returnType)) {
superCode.invokeSuper(superMethod, null, superThis, superArgs);
superCode.returnVoid();
} else {
Local<?> superResult = superCode.newLocal(resultType);
invokeSuper(superMethod, superCode, superThis, superArgs, superResult);
superCode.returnValue(superResult);
}
}
}