Support NPE and exceptions thrown from methods being called

This commit is contained in:
Andrey Breslav
2013-10-07 00:32:34 +04:00
parent 4a7fa6632e
commit 1dfbbb9f08
3 changed files with 79 additions and 26 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ class LongValue(value: Long): AbstractValue<Long>(value, Type.LONG_TYPE)
class FloatValue(value: Float): AbstractValue<Float>(value, Type.FLOAT_TYPE) class FloatValue(value: Float): AbstractValue<Float>(value, Type.FLOAT_TYPE)
class DoubleValue(value: Double): AbstractValue<Double>(value, Type.DOUBLE_TYPE) class DoubleValue(value: Double): AbstractValue<Double>(value, Type.DOUBLE_TYPE)
class ObjectValue(value: Any?, asmType: Type): AbstractValue<Any?>(value, asmType) class ObjectValue(value: Any?, asmType: Type): AbstractValue<Any?>(value, asmType)
class NewObjectValue(val _class: Class<Any?>, asmType: Type): AbstractValueBase<Any?>(asmType) { class NewObjectValue(val _class: Class<*>, asmType: Type): AbstractValueBase<Any?>(asmType) {
override var value: Any? = null override var value: Any? = null
} }
@@ -182,6 +182,10 @@ class TestData {
static C newC() { static C newC() {
return new C(); return new C();
} }
static void throwException() {
throw new RuntimeException();
}
} }
static int getInstanceField() { static int getInstanceField() {
@@ -252,4 +256,25 @@ class TestData {
static String classLiteral() { static String classLiteral() {
return String.class.toString(); return String.class.toString();
} }
static int callThrowingMethod() {
try {
C.throwException();
}
catch (RuntimeException e) {
return 1;
}
return 0;
}
static int NPE() {
try {
Object x = null;
x.toString();
}
catch (NullPointerException e) {
return 1;
}
return 0;
}
} }
+53 -25
View File
@@ -11,6 +11,7 @@ import junit.framework.TestCase
import java.lang.reflect.Method import java.lang.reflect.Method
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Constructor import java.lang.reflect.Constructor
import java.lang.reflect.InvocationTargetException
fun suite(): TestSuite { fun suite(): TestSuite {
val suite = TestSuite() val suite = TestSuite()
@@ -132,13 +133,38 @@ object REFLECTION_EVAL : Eval {
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
fun <T> mayThrow(f: () -> T): T {
try {
try {
return f()
}
catch (ite: InvocationTargetException) {
throw ite.getCause() ?: ite
}
}
catch (e: Throwable) {
throw ThrownFromEvalException(ObjectValue(e, Type.getType(e.javaClass)))
}
}
fun Any?.checkNull(): Any {
if (this == null) {
throw ThrownFromEvalException(ObjectValue(NullPointerException(), Type.getType(javaClass<NullPointerException>())))
}
return this
}
override fun getStaticField(fieldDesc: FieldDescription): Value { override fun getStaticField(fieldDesc: FieldDescription): Value {
val result = findStaticField(fieldDesc).get(null) val field = findStaticField(fieldDesc)
val result = mayThrow {field.get(null)}
return objectToValue(result, fieldDesc.fieldType) return objectToValue(result, fieldDesc.fieldType)
} }
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) { override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
findStaticField(fieldDesc).set(null, newValue.obj) val field = findStaticField(fieldDesc)
val obj = newValue.obj
mayThrow {field.set(null, obj)}
} }
fun findStaticField(fieldDesc: FieldDescription): Field { fun findStaticField(fieldDesc: FieldDescription): Field {
@@ -153,36 +179,36 @@ 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 result = method!!.invoke(null, *arguments.map { v -> v.obj }.copyToArray()) val args = arguments.map { v -> v.obj }.copyToArray()
val result = mayThrow {method!!.invoke(null, *args)}
return objectToValue(result, methodDesc.returnType) return objectToValue(result, methodDesc.returnType)
} }
fun findClass(memberDesc: MemberDescription): Class<Any?> = findClass(memberDesc.ownerInternalName) fun findClass(memberDesc: MemberDescription): Class<Any> = findClass(memberDesc.ownerInternalName)
fun findClass(internalName: String): Class<Any?> { fun findClass(internalName: String): Class<Any> {
val owner = lookup.findClass(internalName) val owner = lookup.findClass(internalName)
assertNotNull("Class not found: ${internalName}", owner) assertNotNull("Class not found: ${internalName}", owner)
return owner!! return owner!!
} }
override fun getField(instance: Value, fieldDesc: FieldDescription): Value { override fun getField(instance: Value, fieldDesc: FieldDescription): Value {
val obj = instance.obj val obj = instance.obj.checkNull()
val field = findInstanceField(obj, fieldDesc) val field = findInstanceField(obj, fieldDesc)
return objectToValue(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 val obj = instance.obj.checkNull()
val field = findInstanceField(obj, fieldDesc) val field = findInstanceField(obj, fieldDesc)
field.set(obj, newValue.obj) val newObj = newValue.obj
mayThrow {field.set(obj, newObj)}
} }
fun findInstanceField(obj: Any?, fieldDesc: FieldDescription): Field { fun findInstanceField(obj: Any, fieldDesc: FieldDescription): Field {
if (obj == null) throw NullPointerException() val _class = obj.javaClass
val _class: Class<Any?> = obj.javaClass
val field = _class.findField(fieldDesc) val field = _class.findField(fieldDesc)
assertNotNull("Field not found: $fieldDesc", field) assertNotNull("Field not found: $fieldDesc", field)
return field!! return field!!
@@ -192,11 +218,12 @@ object REFLECTION_EVAL : Eval {
if (invokespecial) { if (invokespecial) {
if (methodDesc.name == "<init>") { if (methodDesc.name == "<init>") {
// Constructor call // Constructor call
val _class = (instance as NewObjectValue)._class [suppress("UNCHECKED_CAST")]
val _class = (instance as NewObjectValue)._class as Class<Any>
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 = arguments.map { v -> v.obj }.copyToArray()
val result = 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)
} }
@@ -205,30 +232,31 @@ object REFLECTION_EVAL : Eval {
throw UnsupportedOperationException("invokespecial is not suported yet") throw UnsupportedOperationException("invokespecial is not suported yet")
} }
} }
val obj = instance.obj 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 result = method!!.invoke(obj, *arguments.map { v -> v.obj }.copyToArray()) val args = arguments.map { v -> v.obj }.copyToArray()
val result = mayThrow {method!!.invoke(obj, *args)}
return objectToValue(result, methodDesc.returnType) return objectToValue(result, methodDesc.returnType)
} }
} }
class ReflectionLookup(val classLoader: ClassLoader) { class ReflectionLookup(val classLoader: ClassLoader) {
[suppress("UNCHECKED_CAST")] [suppress("UNCHECKED_CAST")]
fun findClass(internalName: String): Class<Any?>? = classLoader.loadClass(internalName.replace('/', '.')) as Class<Any?> fun findClass(internalName: String): Class<Any>? = classLoader.loadClass(internalName.replace('/', '.')) as Class<Any>
} }
[suppress("UNCHECKED_CAST")] [suppress("UNCHECKED_CAST")]
fun Class<Any?>.findMethod(methodDesc: MethodDescription): Method? { fun Class<Any>.findMethod(methodDesc: MethodDescription): Method? {
for (declared in getDeclaredMethods()) { for (declared in getDeclaredMethods()) {
if (methodDesc.matches(declared)) return declared if (methodDesc.matches(declared)) return declared
} }
val fromSuperClass = (getSuperclass() as Class<Any?>).findMethod(methodDesc) val fromSuperClass = (getSuperclass() as Class<Any>).findMethod(methodDesc)
if (fromSuperClass != null) return fromSuperClass if (fromSuperClass != null) return fromSuperClass
for (supertype in getInterfaces()) { for (supertype in getInterfaces()) {
val fromSuper = (supertype as Class<Any?>).findMethod(methodDesc) val fromSuper = (supertype as Class<Any>).findMethod(methodDesc)
if (fromSuper != null) return fromSuper if (fromSuper != null) return fromSuper
} }
@@ -236,7 +264,7 @@ fun Class<Any?>.findMethod(methodDesc: MethodDescription): Method? {
} }
[suppress("UNCHECKED_CAST")] [suppress("UNCHECKED_CAST")]
fun Class<Any?>.findConstructor(methodDesc: MethodDescription): Constructor<Any?>? { fun Class<Any>.findConstructor(methodDesc: MethodDescription): Constructor<Any?>? {
for (declared in getDeclaredConstructors()) { for (declared in getDeclaredConstructors()) {
if (methodDesc.matches(declared)) return declared as Constructor<Any?> if (methodDesc.matches(declared)) return declared as Constructor<Any?>
} }
@@ -266,19 +294,19 @@ fun MethodDescription.matches(method: Method): Boolean {
} }
[suppress("UNCHECKED_CAST")] [suppress("UNCHECKED_CAST")]
fun Class<Any?>.findField(fieldDesc: FieldDescription): Field? { fun Class<Any>.findField(fieldDesc: FieldDescription): Field? {
for (declared in getDeclaredFields()) { for (declared in getDeclaredFields()) {
if (fieldDesc.matches(declared)) return declared if (fieldDesc.matches(declared)) return declared
} }
val superclass = getSuperclass() val superclass = getSuperclass()
if (superclass != null) { if (superclass != null) {
val fromSuperClass = (superclass as Class<Any?>).findField(fieldDesc) val fromSuperClass = (superclass as Class<Any>).findField(fieldDesc)
if (fromSuperClass != null) return fromSuperClass if (fromSuperClass != null) return fromSuperClass
} }
for (supertype in getInterfaces()) { for (supertype in getInterfaces()) {
val fromSuper = (supertype as Class<Any?>).findField(fieldDesc) val fromSuper = (supertype as Class<Any>).findField(fieldDesc)
if (fromSuper != null) return fromSuper if (fromSuper != null) return fromSuper
} }