Invoker adapter interface support

This commit is contained in:
Clisprail
2014-04-29 01:42:38 +02:00
parent f5e09e5631
commit 98ac8ab301
4 changed files with 60 additions and 23 deletions
@@ -22,16 +22,27 @@ public class AddInvokerAdapter implements Opcodes, Injectable {
private String argsDesc; private String argsDesc;
private String returnDesc; private String returnDesc;
private String methodName; private String methodName;
private boolean isInterface;
private String instanceCast;
private String mName;
private String mDesc;
private boolean isStatic;
public AddInvokerAdapter(final ClassNode methodLocation, public AddInvokerAdapter(final ClassNode methodLocation,
final ClassNode into, final MethodNode mn, final String argsDesc, final ClassNode into, final MethodNode mn, final String mName, final String mDesc, final String argsDesc,
final String returnDesc, final String methodName) { final String returnDesc, final String methodName,
boolean isInterface, String instanceCast) {
this.into = into; this.into = into;
this.methodLocation = methodLocation; this.methodLocation = methodLocation;
this.mName = mName;
this.mDesc = mDesc;
this.mn = mn; this.mn = mn;
this.argsDesc = argsDesc; this.argsDesc = argsDesc;
this.returnDesc = returnDesc; this.returnDesc = returnDesc;
this.methodName = methodName; this.methodName = methodName;
this.isInterface = isInterface;
this.instanceCast = instanceCast;
} }
@Override @Override
@@ -39,28 +50,41 @@ public class AddInvokerAdapter implements Opcodes, Injectable {
MethodNode m = new MethodNode(ACC_PUBLIC, this.methodName, MethodNode m = new MethodNode(ACC_PUBLIC, this.methodName,
this.argsDesc + this.returnDesc, null, null); this.argsDesc + this.returnDesc, null, null);
boolean isStatic = (this.mn.access & ACC_STATIC) != 0; if(!isInterface) {
isStatic = (this.mn.access & ACC_STATIC) != 0;
if (!Modifier.isPublic(mn.access)) {
if (Modifier.isPrivate(mn.access)) {
mn.access = mn.access & (~ACC_PRIVATE);
}
if (Modifier.isProtected(mn.access)) {
mn.access = mn.access & (~ACC_PROTECTED);
}
mn.access = mn.access | ACC_PUBLIC;
}
}
if(!Modifier.isPublic(mn.access)) { if(!isStatic || isInterface) {
if(Modifier.isPrivate(mn.access)) { m.visitVarInsn(ALOAD, 0);
mn.access = mn.access & (~ACC_PRIVATE);
}
if(Modifier.isProtected(mn.access)) {
mn.access = mn.access & (~ACC_PROTECTED);
}
mn.access = mn.access | ACC_PUBLIC;
} }
if (!isStatic)
m.visitVarInsn(ALOAD, 0);
if (!this.argsDesc.equals("()")) if (!this.argsDesc.equals("()")) {
for (int i = 1; i < this.argsDesc.length() - 1; i++) for (int i = 1; i < this.argsDesc.length() - 1; i++) {
m.visitVarInsn(ASMUtils.getLoadOpcode(this.argsDesc.substring( m.visitVarInsn(ASMUtils.getLoadOpcode(this.argsDesc.substring(
i, i + 1)), i); i, i + 1)), i);
}
}
if(instanceCast != null) {
m.visitTypeInsn(CHECKCAST, instanceCast);
}
m.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, if(isInterface) {
methodLocation.name, mn.name, mn.desc); m.visitMethodInsn(INVOKEINTERFACE, instanceCast, mName, mDesc);
} else {
m.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, methodLocation.name, mn.name, mn.desc);
}
if (this.returnDesc.contains("L")) { if (this.returnDesc.contains("L")) {
if (!this.returnDesc.contains("[")) { if (!this.returnDesc.contains("[")) {
m.visitTypeInsn(CHECKCAST, this.returnDesc m.visitTypeInsn(CHECKCAST, this.returnDesc
@@ -20,21 +20,31 @@ public class Invoker implements Injectable {
private String argsDesc; private String argsDesc;
private String returnDesc; private String returnDesc;
private String methodName; private String methodName;
private boolean isInterface;
private String instanceCast;
private String mName;
private String mDesc;
public Invoker(String methodLoc, String invMethName, String argsDesc, public Invoker(String methodLoc, String invMethName, String argsDesc,
String returnDesc, String methodName) { String returnDesc, String methodName) {
this(methodLoc, methodLoc, invMethName, argsDesc, returnDesc, this(methodLoc, methodLoc, invMethName, argsDesc, returnDesc,
methodName); methodName, false, null);
} }
public Invoker(String into, String methodLoc, String invMethName, public Invoker(String into, String methodLoc, String invMethName,
String argsDesc, String returnDesc, String methodName) { String argsDesc, String returnDesc, String methodName, boolean isInterface, String instanceCast) {
this.into = ASMUtils.getClass(into); this.into = ASMUtils.getClass(into);
this.methodLocation = ASMUtils.getClass(methodLoc); this.methodLocation = ASMUtils.getClass(methodLoc);
this.mn = getMethod(this.methodLocation, invMethName, argsDesc); this.mn = getMethod(this.methodLocation, invMethName, argsDesc);
this.returnDesc = returnDesc; this.returnDesc = returnDesc;
this.methodName = methodName; this.methodName = methodName;
this.argsDesc = argsDesc; this.argsDesc = argsDesc;
this.isInterface = isInterface;
this.instanceCast = instanceCast;
this.mName = invMethName;
this.mDesc = argsDesc + returnDesc;
} }
private static MethodNode getMethod(ClassNode into, String name, String desc) { private static MethodNode getMethod(ClassNode into, String name, String desc) {
@@ -63,8 +73,8 @@ public class Invoker implements Injectable {
* @return AddInvokerAdapter * @return AddInvokerAdapter
*/ */
public AddInvokerAdapter getAdapter() { public AddInvokerAdapter getAdapter() {
return new AddInvokerAdapter(this.methodLocation, this.into, this.mn, return new AddInvokerAdapter(this.methodLocation, this.into, this.mn, this.mName, this.mDesc,
this.argsDesc, this.returnDesc, this.methodName); this.argsDesc, this.returnDesc, this.methodName, this.isInterface, this.instanceCast);
} }
} }
@@ -185,7 +185,7 @@ public class JSONHookParser extends HookParser {
String clazz = o.containsKey("class") ? this.get(o, "class") : interfaces.get(this.get(o, "accessor")); String clazz = o.containsKey("class") ? this.get(o, "class") : interfaces.get(this.get(o, "accessor"));
String into = o.containsKey("into") ? this.get(o, "into") : clazz; String into = o.containsKey("into") ? this.get(o, "into") : clazz;
i[j] = new Invoker(into, clazz, this.get(o, "invokemethod"), this.get(o, "argdesc"), this.get(o, "desc"), this.get(o, "method")); i[j] = new Invoker(into, clazz, this.get(o, "invokemethod"), this.get(o, "argdesc"), this.get(o, "desc"), this.get(o, "method"), false, null);
} }
return i; return i;
} }
@@ -345,9 +345,12 @@ public class XMLHookParser extends HookParser {
final String argsDesc = getValue("argsdesc", addInvoker); final String argsDesc = getValue("argsdesc", addInvoker);
String returnDesc = isSet("desc", addInvoker) ? resolveDesc(getValue( String returnDesc = isSet("desc", addInvoker) ? resolveDesc(getValue(
"desc", addInvoker)) : null; "desc", addInvoker)) : null;
final boolean isInterface = isSet("interface", addInvoker) ? Boolean.parseBoolean(getValue("interface", addInvoker)) : false;
final String instanceCast = isSet("instancecast", addInvoker) ? getValue("instancecast", addInvoker) : null;
final Invoker invoker = new Invoker(into, className, invMethodName, final Invoker invoker = new Invoker(into, className, invMethodName,
argsDesc, returnDesc, methodName); argsDesc, returnDesc, methodName, isInterface, instanceCast);
invokerList.add(invoker); invokerList.add(invoker);
} }
return invokerList.toArray(new Invoker[invokerList.size()]); return invokerList.toArray(new Invoker[invokerList.size()]);