Box arguments if needed

This commit is contained in:
Andrey Breslav
2013-05-13 19:04:43 +04:00
parent bdd4296b0d
commit 39c9cbcd9e
2 changed files with 62 additions and 20 deletions
@@ -103,16 +103,44 @@ public class ProfilingInstrumenterExample extends InterceptionInstrumenterAdapto
public static Object d = new MethodCollector();
public static class MethodCollector {
private final Collection<String> l = new LinkedHashSet<String>();
private final Collection<String> collected = new LinkedHashSet<String>();
public void enter(@ClassName String className, @MethodName String name, @MethodDesc String desc) {
l.add(className + "." + name + desc);
collected.add(className + "." + name + desc);
}
public void dump(PrintStream out) {
for (String s : l) {
for (String s : collected) {
out.println(s);
}
}
}
// What integers are passed as first arguments to any methods?
@MethodInterceptor(className = ".*",
methodName = ".*",
methodDesc = "\\(.+\\).*",
allowMultipleMatches = true)
public static Object e = new FirstArgumentCollector() {
@Override
protected boolean accept(Object arg) {
return arg instanceof Integer;
}
};
public static abstract class FirstArgumentCollector {
private final Collection<Object> collected = new HashSet<Object>();
protected abstract boolean accept(Object arg);
public void enter(Object arg) {
if (accept(arg)) {
collected.add(arg);
}
}
public void dump(PrintStream out) {
out.println("Arguments: " + collected.size());
}
}
}
@@ -466,9 +466,10 @@ public class InterceptionInstrumenter {
org.jetbrains.asm4.commons.Method asmMethod = getAsmMethod(methodData);
int parameterCount = asmMethod.getArgumentTypes().length;
Type[] interceptingMethodParameterTypes = asmMethod.getArgumentTypes();
int parameterCount = interceptingMethodParameterTypes.length;
if (parameterCount > 0) {
Type[] parameterTypes = Type.getArgumentTypes(instrumentedMethodDesc);
Type[] instrumentedMethodParameterTypes = Type.getArgumentTypes(instrumentedMethodDesc);
boolean isStatic = (instrumentedMethodAccess & ACC_STATIC) != 0;
int base = isStatic ? 0 : 1;
int instrumentedMethodParameterIndex = 0;
@@ -495,25 +496,27 @@ public class InterceptionInstrumenter {
ia.aconst(instrumentedMethodDesc);
}
else if (i == methodData.getAllArgsParameterIndex()) {
ia.aconst(parameterTypes.length);
ia.aconst(instrumentedMethodParameterTypes.length);
ia.newarray(OBJECT_TYPE);
int offset = 0;
for (int parameterIndex = 0; parameterIndex < parameterTypes.length; parameterIndex++) {
for (int parameterIndex = 0; parameterIndex < instrumentedMethodParameterTypes.length; parameterIndex++) {
ia.dup();
ia.iconst(parameterIndex);
Type type = parameterTypes[parameterIndex];
Type type = instrumentedMethodParameterTypes[parameterIndex];
ia.load(base + offset, type);
offset += type.getSize();
applyBoxingIfNeeded(ia, type);
boxOrCastIfNeeded(ia, type, OBJECT_TYPE);
ia.astore(OBJECT_TYPE);
}
}
else {
Type type = parameterTypes[instrumentedMethodParameterIndex];
Type type = instrumentedMethodParameterTypes[instrumentedMethodParameterIndex];
ia.load(base + instrumentedMethodParameterOffset, type);
boxOrCastIfNeeded(ia, type, interceptingMethodParameterTypes[i]);
instrumentedMethodParameterIndex++;
instrumentedMethodParameterOffset += type.getSize();
}
@@ -532,37 +535,48 @@ public class InterceptionInstrumenter {
}
}
private static void applyBoxingIfNeeded(InstructionAdapter ia, Type type) {
switch (type.getSort()) {
private static void boxOrCastIfNeeded(InstructionAdapter ia, Type from, Type to) {
if (isPrimitive(to)) {
if (!isPrimitive(from)) {
throw new IllegalArgumentException("Cannot cast " + from + " to " + to);
}
ia.cast(from, to);
return;
}
switch (from.getSort()) {
case Type.BOOLEAN:
box(ia, type, Boolean.class);
box(ia, from, Boolean.class);
break;
case Type.CHAR:
box(ia, type, Character.class);
box(ia, from, Character.class);
break;
case Type.BYTE:
box(ia, type, Byte.class);
box(ia, from, Byte.class);
break;
case Type.SHORT:
box(ia, type, Short.class);
box(ia, from, Short.class);
break;
case Type.INT:
box(ia, type, Integer.class);
box(ia, from, Integer.class);
break;
case Type.FLOAT:
box(ia, type, Float.class);
box(ia, from, Float.class);
break;
case Type.LONG:
box(ia, type, Long.class);
box(ia, from, Long.class);
break;
case Type.DOUBLE:
box(ia, type, Double.class);
box(ia, from, Double.class);
break;
default:
// Nothing to do, it's an object already
}
}
private static boolean isPrimitive(Type to) {
return to.getSort() <= Type.DOUBLE;
}
private static void box(InstructionAdapter ia, Type from, Class<?> boxedClass) {
Type boxedType = Type.getType(boxedClass);
ia.invokestatic(boxedType.getInternalName(), "valueOf", "(" + from.getDescriptor() + ")" + boxedType.getDescriptor());