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 -> { CHECKCAST -> {
val targetType = Type.getObjectType((insn as TypeInsnNode).desc) val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
if (eval.isInstanceOf(value, targetType)) { if (eval.isInstanceOf(value, targetType)) {
ObjectValue(value.obj, targetType) ObjectValue(value.obj(), targetType)
} }
else { else {
throwEvalException(ClassCastException("Value '$value' cannot be cast to $targetType")) 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 IFGT -> value.int > 0
IFLE -> value.int <= 0 IFLE -> value.int <= 0
IFGE -> value.int >= 0 IFGE -> value.int >= 0
IFNULL -> value.obj == null IFNULL -> value.obj() == null
IFNONNULL -> value.obj != null IFNONNULL -> value.obj() != null
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode") 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_ICMPLE -> value1.int <= value2.int
IF_ICMPGE -> value1.int >= value2.int IF_ICMPGE -> value1.int >= value2.int
IF_ACMPEQ -> value1.obj == value2.obj IF_ACMPEQ -> value1.obj() == value2.obj()
IF_ACMPNE -> value1.obj != value2.obj IF_ACMPNE -> value1.obj() != value2.obj()
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode") else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode")
} }
} }
@@ -151,7 +151,7 @@ fun interpreterLoop(
val expectedType = Type.getReturnType(m.desc) val expectedType = Type.getReturnType(m.desc)
if (expectedType.getSort() == Type.OBJECT) { if (expectedType.getSort() == Type.OBJECT) {
val coerced = if (value != NULL_VALUE && value.asmType != expectedType) val coerced = if (value != NULL_VALUE && value.asmType != expectedType)
ObjectValue(value.obj, expectedType) ObjectValue(value.obj(), expectedType)
else value else value
return ValueReturned(coerced) return ValueReturned(coerced)
} }
+13 -6
View File
@@ -94,7 +94,7 @@ class JDIEval(
} }
override fun setArrayElement(array: Value, index: Value, newValue: Value) { 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 { private fun findField(fieldDesc: FieldDescription): jdi.Field {
@@ -131,7 +131,7 @@ class JDIEval(
throwEvalException(NoSuchFieldError("Can't a field in a non-class: $field")) 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) } mayThrow { _class.setValue(field, jdiValue) }
} }
@@ -158,7 +158,7 @@ class JDIEval(
val _class = method.declaringType() val _class = method.declaringType()
if (_class !is jdi.ClassType) throwEvalException(NoSuchMethodError("Static method is a non-class type: $method")) 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) } val result = mayThrow { _class.invokeMethod(thread, method, args, 0) }
return result.asValue() return result.asValue()
} }
@@ -174,7 +174,7 @@ class JDIEval(
val field = findField(fieldDesc) val field = findField(fieldDesc)
val obj = instance.jdiObj.checkNull() val obj = instance.jdiObj.checkNull()
val jdiValue = newValue.asJdiValue(vm) val jdiValue = newValue.asJdiValue(vm, field.`type`().asType())
mayThrow { obj.setValue(field, jdiValue) } mayThrow { obj.setValue(field, jdiValue) }
} }
@@ -184,7 +184,7 @@ class JDIEval(
// Constructor call // Constructor call
val ctor = findMethod(methodDesc) val ctor = findMethod(methodDesc)
val _class = (instance as NewObjectValue).asmType.asReferenceType() as jdi.ClassType 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) } val result = mayThrow { _class.newInstance(thread, ctor, args, 0) }
instance.value = result instance.value = result
return result.asValue() return result.asValue()
@@ -197,10 +197,17 @@ class JDIEval(
val method = findMethod(methodDesc) val method = findMethod(methodDesc)
val obj = instance.jdiObj.checkNull() 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) } val result = mayThrow { obj.invokeMethod(thread, method, args, 0) }
return result.asValue() 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 { fun <T> mayThrow(f: () -> T): T {
@@ -52,16 +52,16 @@ fun jdi.Value?.asValue(): Value {
fun jdi.Type.asType(): Type = Type.getType(this.signature()) fun jdi.Type.asType(): Type = Type.getType(this.signature())
val Value.jdiObj: jdi.ObjectReference? val Value.jdiObj: jdi.ObjectReference?
get() = this.obj as jdi.ObjectReference? get() = this.obj() as jdi.ObjectReference?
val Value.jdiClass: jdi.ClassObjectReference? val Value.jdiClass: jdi.ClassObjectReference?
get() = this.jdiObj as 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) { return when (this) {
NULL_VALUE -> null NULL_VALUE -> null
VOID_VALUE -> vm.mirrorOfVoid() VOID_VALUE -> vm.mirrorOfVoid()
is IntValue -> when (asmType) { is IntValue -> when (expectedType) {
Type.BOOLEAN_TYPE -> vm.mirrorOf(boolean) Type.BOOLEAN_TYPE -> vm.mirrorOf(boolean)
Type.BYTE_TYPE -> vm.mirrorOf(int.toByte()) Type.BYTE_TYPE -> vm.mirrorOf(int.toByte())
Type.SHORT_TYPE -> vm.mirrorOf(int.toShort()) 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 FloatValue -> vm.mirrorOf(value)
is DoubleValue -> vm.mirrorOf(value) is DoubleValue -> vm.mirrorOf(value)
is ObjectValue -> value as jdi.ObjectReference 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") 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.long: Long get() = (this as LongValue).value
val Value.float: Float get() = (this as FloatValue).value val Value.float: Float get() = (this as FloatValue).value
val Value.double: Double get() = (this as DoubleValue).value val Value.double: Double get() = (this as DoubleValue).value
val Value.obj: Any? fun Value.obj(expectedType: Type = asmType): Any? {
get(): Any? { if (this is NewObjectValue) {
if (this is NewObjectValue) { val v = value
val v = value if (v == null) throw IllegalStateException("Trying to access an unitialized object: $this")
if (v == null) throw IllegalStateException("Trying to access an unitialized object: $this") return v
return v
}
return (this as AbstractValue<*>).value
} }
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 { fun <T: Any> T?.checkNull(): T {
if (this == null) { if (this == null) {
@@ -115,7 +115,7 @@ fun suite(): TestSuite {
} }
if (expected is ValueReturned && value is ValueReturned && value.result is ObjectValue) { 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 { else {
assertEquals(expected, value) assertEquals(expected, value)
@@ -48,6 +48,91 @@ class TestData {
return "str"; 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() { static int variable() {
int i = 153; int i = 153;
return i; return i;
+21 -14
View File
@@ -96,7 +96,7 @@ object REFLECTION_EVAL : Eval {
override fun isInstanceOf(value: Value, targetType: Type): Boolean { override fun isInstanceOf(value: Value, targetType: Type): Boolean {
val _class = findClass(targetType) val _class = findClass(targetType)
return _class.isInstance(value.obj) return _class.isInstance(value.obj())
} }
[suppress("UNCHECKED_CAST")] [suppress("UNCHECKED_CAST")]
@@ -109,13 +109,13 @@ object REFLECTION_EVAL : Eval {
} }
override fun getArrayLength(array: Value): Value { 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 { override fun getArrayElement(array: Value, index: Value): Value {
val asmType = array.asmType val asmType = array.asmType
val elementType = if (asmType.getDimensions() == 1) asmType.getElementType() else Type.getType(asmType.getDescriptor().substring(1)) 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 val ind = index.int
return when (elementType.getSort()) { return when (elementType.getSort()) {
Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind)) Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind))
@@ -136,10 +136,10 @@ object REFLECTION_EVAL : Eval {
} }
override fun setArrayElement(array: Value, index: Value, newValue: Value) { override fun setArrayElement(array: Value, index: Value, newValue: Value) {
val arr = array.obj.checkNull() val arr = array.obj().checkNull()
val ind = index.int val ind = index.int
if (array.asmType.getDimensions() > 1) { if (array.asmType.getDimensions() > 1) {
JArray.set(arr, ind, newValue.obj) JArray.set(arr, ind, newValue.obj())
return return
} }
val elementType = array.asmType.getElementType() val elementType = array.asmType.getElementType()
@@ -154,7 +154,7 @@ object REFLECTION_EVAL : Eval {
Type.DOUBLE -> JArray.setDouble(arr, ind, newValue.double) Type.DOUBLE -> JArray.setDouble(arr, ind, newValue.double)
Type.OBJECT, Type.OBJECT,
Type.ARRAY -> { Type.ARRAY -> {
JArray.set(arr, ind, newValue.obj) JArray.set(arr, ind, newValue.obj())
} }
else -> throw UnsupportedOperationException("Unsupported array element type: $elementType") else -> throw UnsupportedOperationException("Unsupported array element type: $elementType")
} }
@@ -183,7 +183,7 @@ object REFLECTION_EVAL : Eval {
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) { override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
val field = findStaticField(fieldDesc) val field = findStaticField(fieldDesc)
val obj = newValue.obj val obj = newValue.obj(fieldDesc.fieldType)
mayThrow {field.set(null, obj)} mayThrow {field.set(null, obj)}
} }
@@ -199,7 +199,7 @@ object REFLECTION_EVAL : Eval {
assertTrue(methodDesc.isStatic) assertTrue(methodDesc.isStatic)
val method = findClass(methodDesc).findMethod(methodDesc) val method = findClass(methodDesc).findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method) 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)} val result = mayThrow {method!!.invoke(null, *args)}
return objectToValue(result, methodDesc.returnType) return objectToValue(result, methodDesc.returnType)
} }
@@ -213,17 +213,17 @@ object REFLECTION_EVAL : Eval {
} }
override fun getField(instance: Value, fieldDesc: FieldDescription): Value { override fun getField(instance: Value, fieldDesc: FieldDescription): Value {
val obj = instance.obj.checkNull() val obj = instance.obj().checkNull()
val field = findInstanceField(obj, fieldDesc) val field = findInstanceField(obj, fieldDesc)
return objectToValue(mayThrow {field.get(obj)}, fieldDesc.fieldType) return objectToValue(mayThrow {field.get(obj)}, fieldDesc.fieldType)
} }
override fun setField(instance: Value, fieldDesc: FieldDescription, newValue: Value) { 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 field = findInstanceField(obj, fieldDesc)
val newObj = newValue.obj val newObj = newValue.obj(fieldDesc.fieldType)
mayThrow {field.set(obj, newObj)} mayThrow {field.set(obj, newObj)}
} }
@@ -242,7 +242,7 @@ object REFLECTION_EVAL : Eval {
val _class = findClass((instance as NewObjectValue).asmType) val _class = findClass((instance as NewObjectValue).asmType)
val ctor = _class.findConstructor(methodDesc) val ctor = _class.findConstructor(methodDesc)
assertNotNull("Constructor not found: $methodDesc", ctor) 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)} val result = mayThrow {ctor!!.newInstance(*args)}
instance.value = result instance.value = result
return objectToValue(result, instance.asmType) return objectToValue(result, instance.asmType)
@@ -252,13 +252,20 @@ object REFLECTION_EVAL : Eval {
throw UnsupportedOperationException("invokespecial is not suported yet") throw UnsupportedOperationException("invokespecial is not suported yet")
} }
} }
val obj = instance.obj.checkNull() val obj = instance.obj().checkNull()
val method = obj.javaClass.findMethod(methodDesc) val method = obj.javaClass.findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method) 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)} val result = mayThrow {method!!.invoke(obj, *args)}
return objectToValue(result, methodDesc.returnType) 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) { class ReflectionLookup(val classLoader: ClassLoader) {