Cast method arguments to method parameter types

This commit is contained in:
Natalia Ukhorskaya
2014-04-07 14:45:47 +04:00
parent 56e0746814
commit 92edc8299e
8 changed files with 144 additions and 39 deletions
@@ -173,7 +173,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
CHECKCAST -> {
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
if (eval.isInstanceOf(value, targetType)) {
ObjectValue(value.obj, targetType)
ObjectValue(value.obj(), targetType)
}
else {
throwEvalException(ClassCastException("Value '$value' cannot be cast to $targetType"))
@@ -200,8 +200,8 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
IFGT -> value.int > 0
IFLE -> value.int <= 0
IFGE -> value.int >= 0
IFNULL -> value.obj == null
IFNONNULL -> value.obj != null
IFNULL -> value.obj() == null
IFNONNULL -> value.obj() != null
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode")
}
}
@@ -310,8 +310,8 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
IF_ICMPLE -> value1.int <= value2.int
IF_ICMPGE -> value1.int >= value2.int
IF_ACMPEQ -> value1.obj == value2.obj
IF_ACMPNE -> value1.obj != value2.obj
IF_ACMPEQ -> value1.obj() == value2.obj()
IF_ACMPNE -> value1.obj() != value2.obj()
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode")
}
}
@@ -151,7 +151,7 @@ fun interpreterLoop(
val expectedType = Type.getReturnType(m.desc)
if (expectedType.getSort() == Type.OBJECT) {
val coerced = if (value != NULL_VALUE && value.asmType != expectedType)
ObjectValue(value.obj, expectedType)
ObjectValue(value.obj(), expectedType)
else value
return ValueReturned(coerced)
}
+13 -6
View File
@@ -94,7 +94,7 @@ class JDIEval(
}
override fun setArrayElement(array: Value, index: Value, newValue: Value) {
array.array().setValue(index.int, newValue.asJdiValue(vm))
array.array().setValue(index.int, newValue.asJdiValue(vm, array.asmType.arrayElementType))
}
private fun findField(fieldDesc: FieldDescription): jdi.Field {
@@ -131,7 +131,7 @@ class JDIEval(
throwEvalException(NoSuchFieldError("Can't a field in a non-class: $field"))
}
val jdiValue = newValue.asJdiValue(vm)
val jdiValue = newValue.asJdiValue(vm, field.`type`().asType())
mayThrow { _class.setValue(field, jdiValue) }
}
@@ -158,7 +158,7 @@ class JDIEval(
val _class = method.declaringType()
if (_class !is jdi.ClassType) throwEvalException(NoSuchMethodError("Static method is a non-class type: $method"))
val args = arguments.map { v -> v.asJdiValue(vm) }
val args = mapArguments(arguments, method.argumentTypes())
val result = mayThrow { _class.invokeMethod(thread, method, args, 0) }
return result.asValue()
}
@@ -174,7 +174,7 @@ class JDIEval(
val field = findField(fieldDesc)
val obj = instance.jdiObj.checkNull()
val jdiValue = newValue.asJdiValue(vm)
val jdiValue = newValue.asJdiValue(vm, field.`type`().asType())
mayThrow { obj.setValue(field, jdiValue) }
}
@@ -184,7 +184,7 @@ class JDIEval(
// Constructor call
val ctor = findMethod(methodDesc)
val _class = (instance as NewObjectValue).asmType.asReferenceType() as jdi.ClassType
val args = arguments.map { v -> v.asJdiValue(vm) }
val args = mapArguments(arguments, ctor.argumentTypes())
val result = mayThrow { _class.newInstance(thread, ctor, args, 0) }
instance.value = result
return result.asValue()
@@ -197,10 +197,17 @@ class JDIEval(
val method = findMethod(methodDesc)
val obj = instance.jdiObj.checkNull()
val args = arguments.map { v -> v.asJdiValue(vm) }
val args = mapArguments(arguments, method.argumentTypes())
val result = mayThrow { obj.invokeMethod(thread, method, args, 0) }
return result.asValue()
}
private fun mapArguments(arguments: List<Value>, expecetedTypes: List<jdi.Type>): List<jdi.Value?> {
return arguments.zip(expecetedTypes).map {
val (arg, expectedType) = it
arg.asJdiValue(vm, expectedType.asType())
}
}
}
fun <T> mayThrow(f: () -> T): T {
@@ -52,16 +52,16 @@ fun jdi.Value?.asValue(): Value {
fun jdi.Type.asType(): Type = Type.getType(this.signature())
val Value.jdiObj: jdi.ObjectReference?
get() = this.obj as jdi.ObjectReference?
get() = this.obj() as jdi.ObjectReference?
val Value.jdiClass: jdi.ClassObjectReference?
get() = this.jdiObj as jdi.ClassObjectReference?
fun Value.asJdiValue(vm: jdi.VirtualMachine): jdi.Value? {
fun Value.asJdiValue(vm: jdi.VirtualMachine, expectedType: Type): jdi.Value? {
return when (this) {
NULL_VALUE -> null
VOID_VALUE -> vm.mirrorOfVoid()
is IntValue -> when (asmType) {
is IntValue -> when (expectedType) {
Type.BOOLEAN_TYPE -> vm.mirrorOf(boolean)
Type.BYTE_TYPE -> vm.mirrorOf(int.toByte())
Type.SHORT_TYPE -> vm.mirrorOf(int.toShort())
@@ -73,7 +73,7 @@ fun Value.asJdiValue(vm: jdi.VirtualMachine): jdi.Value? {
is FloatValue -> vm.mirrorOf(value)
is DoubleValue -> vm.mirrorOf(value)
is ObjectValue -> value as jdi.ObjectReference
is NewObjectValue -> this.obj as jdi.ObjectReference
is NewObjectValue -> this.obj() as jdi.ObjectReference
else -> throw JDIFailureException("Unknown value: $this")
}
}
+14 -8
View File
@@ -89,15 +89,21 @@ val Value.int: Int get() = (this as IntValue).value
val Value.long: Long get() = (this as LongValue).value
val Value.float: Float get() = (this as FloatValue).value
val Value.double: Double get() = (this as DoubleValue).value
val Value.obj: Any?
get(): Any? {
if (this is NewObjectValue) {
val v = value
if (v == null) throw IllegalStateException("Trying to access an unitialized object: $this")
return v
}
return (this as AbstractValue<*>).value
fun Value.obj(expectedType: Type = asmType): Any? {
if (this is NewObjectValue) {
val v = value
if (v == null) throw IllegalStateException("Trying to access an unitialized object: $this")
return v
}
return when {
expectedType == asmType -> (this as AbstractValue<*>).value
expectedType == Type.BOOLEAN_TYPE -> this.boolean
expectedType == Type.SHORT_TYPE -> (this as IntValue).int.toShort()
expectedType == Type.BYTE_TYPE -> (this as IntValue).int.toByte()
expectedType == Type.CHAR_TYPE -> (this as IntValue).int.toChar()
else -> (this as AbstractValue<*>).value
}
}
fun <T: Any> T?.checkNull(): T {
if (this == null) {
@@ -115,7 +115,7 @@ fun suite(): TestSuite {
}
if (expected is ValueReturned && value is ValueReturned && value.result is ObjectValue) {
assertEquals(expected.result.obj.toString(), value.result.jdiObj.callToString())
assertEquals(expected.result.obj().toString(), value.result.jdiObj.callToString())
}
else {
assertEquals(expected, value)
@@ -48,6 +48,91 @@ class TestData {
return "str";
}
static Integer integerValueOf() { return 1; }
static Byte byteValueOf() { return 1; }
static Short shortValueOf() { return 1; }
static Long longValueOf() { return 1L; }
static Float floatValueOf() { return 1.0f; }
static Double doubleValueOf() { return 1.0; }
static Character charValueOf() { return 1; }
static Boolean booleanValueOf() { return true; }
static void castFieldTypes() {
CastFieldType.i = 1;
CastFieldType.b = 1;
CastFieldType.s = 1;
CastFieldType.c = 1;
CastFieldType.bool = true;
CastFieldType.l = 1;
CastFieldType.f = 1.0f;
CastFieldType.d = 1.0;
CastFieldType klass = new CastFieldType();
klass.im = 1;
klass.bm = 1;
klass.sm = 1;
klass.cm = 1;
klass.boolm = true;
klass.lm = 1;
klass.fm = 1;
klass.dm = 1;
Integer i = klass.im;
Byte b = klass.bm;
Short s = klass.sm;
Character c = klass.cm;
Boolean bool = klass.boolm;
Long l = klass.lm;
Float f = klass.fm;
Double d = klass.dm;
}
static class CastFieldType {
static int i = 1;
static byte b = 1;
static short s = 1;
static char c = 1;
static boolean bool = true;
static long l = 1;
static float f = 1;
static double d = 1;
int im = 1;
byte bm = 1;
short sm = 1;
char cm = 1;
boolean boolm = true;
long lm = 1;
float fm = 1;
double dm = 1;
}
static void castArrayElementType() {
int[] i = new int[1];
i[0] = 1;
short[] s = new short[1];
s[0] = 1;
byte[] b = new byte[1];
b[0] = 1;
char[] c = new char[1];
c[0] = 1;
boolean[] bool = new boolean[1];
bool[0] = true;
long[] l = new long[1];
l[0] = 1;
float[] f = new float[1];
f[0] = 1;
double[] d = new double[1];
d[0] = 1;
}
static int variable() {
int i = 153;
return i;
+21 -14
View File
@@ -96,7 +96,7 @@ object REFLECTION_EVAL : Eval {
override fun isInstanceOf(value: Value, targetType: Type): Boolean {
val _class = findClass(targetType)
return _class.isInstance(value.obj)
return _class.isInstance(value.obj())
}
[suppress("UNCHECKED_CAST")]
@@ -109,13 +109,13 @@ object REFLECTION_EVAL : Eval {
}
override fun getArrayLength(array: Value): Value {
return int(JArray.getLength(array.obj.checkNull()))
return int(JArray.getLength(array.obj().checkNull()))
}
override fun getArrayElement(array: Value, index: Value): Value {
val asmType = array.asmType
val elementType = if (asmType.getDimensions() == 1) asmType.getElementType() else Type.getType(asmType.getDescriptor().substring(1))
val arr = array.obj.checkNull()
val arr = array.obj().checkNull()
val ind = index.int
return when (elementType.getSort()) {
Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind))
@@ -136,10 +136,10 @@ object REFLECTION_EVAL : Eval {
}
override fun setArrayElement(array: Value, index: Value, newValue: Value) {
val arr = array.obj.checkNull()
val arr = array.obj().checkNull()
val ind = index.int
if (array.asmType.getDimensions() > 1) {
JArray.set(arr, ind, newValue.obj)
JArray.set(arr, ind, newValue.obj())
return
}
val elementType = array.asmType.getElementType()
@@ -154,7 +154,7 @@ object REFLECTION_EVAL : Eval {
Type.DOUBLE -> JArray.setDouble(arr, ind, newValue.double)
Type.OBJECT,
Type.ARRAY -> {
JArray.set(arr, ind, newValue.obj)
JArray.set(arr, ind, newValue.obj())
}
else -> throw UnsupportedOperationException("Unsupported array element type: $elementType")
}
@@ -183,7 +183,7 @@ object REFLECTION_EVAL : Eval {
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
val field = findStaticField(fieldDesc)
val obj = newValue.obj
val obj = newValue.obj(fieldDesc.fieldType)
mayThrow {field.set(null, obj)}
}
@@ -199,7 +199,7 @@ object REFLECTION_EVAL : Eval {
assertTrue(methodDesc.isStatic)
val method = findClass(methodDesc).findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method)
val args = arguments.map { v -> v.obj }.copyToArray()
val args = mapArguments(arguments, methodDesc.parameterTypes).copyToArray()
val result = mayThrow {method!!.invoke(null, *args)}
return objectToValue(result, methodDesc.returnType)
}
@@ -213,17 +213,17 @@ object REFLECTION_EVAL : Eval {
}
override fun getField(instance: Value, fieldDesc: FieldDescription): Value {
val obj = instance.obj.checkNull()
val obj = instance.obj().checkNull()
val field = findInstanceField(obj, fieldDesc)
return objectToValue(mayThrow {field.get(obj)}, fieldDesc.fieldType)
}
override fun setField(instance: Value, fieldDesc: FieldDescription, newValue: Value) {
val obj = instance.obj.checkNull()
val obj = instance.obj().checkNull()
val field = findInstanceField(obj, fieldDesc)
val newObj = newValue.obj
val newObj = newValue.obj(fieldDesc.fieldType)
mayThrow {field.set(obj, newObj)}
}
@@ -242,7 +242,7 @@ object REFLECTION_EVAL : Eval {
val _class = findClass((instance as NewObjectValue).asmType)
val ctor = _class.findConstructor(methodDesc)
assertNotNull("Constructor not found: $methodDesc", ctor)
val args = arguments.map { v -> v.obj }.copyToArray()
val args = mapArguments(arguments, methodDesc.parameterTypes).copyToArray()
val result = mayThrow {ctor!!.newInstance(*args)}
instance.value = result
return objectToValue(result, instance.asmType)
@@ -252,13 +252,20 @@ object REFLECTION_EVAL : Eval {
throw UnsupportedOperationException("invokespecial is not suported yet")
}
}
val obj = instance.obj.checkNull()
val obj = instance.obj().checkNull()
val method = obj.javaClass.findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method)
val args = arguments.map { v -> v.obj }.copyToArray()
val args = mapArguments(arguments, methodDesc.parameterTypes).copyToArray()
val result = mayThrow {method!!.invoke(obj, *args)}
return objectToValue(result, methodDesc.returnType)
}
private fun mapArguments(arguments: List<Value>, expecetedTypes: List<Type>): List<Any?> {
return arguments.zip(expecetedTypes).map {
val (arg, expectedType) = it
arg.obj(expectedType)
}
}
}
class ReflectionLookup(val classLoader: ClassLoader) {