Support constructor calls

This commit is contained in:
Andrey Breslav
2013-10-06 23:41:20 +04:00
parent e8ac8cd7fa
commit 3199a8f690
4 changed files with 82 additions and 11 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
} }
JSR -> LabelValue((insn as JumpInsnNode).label) JSR -> LabelValue((insn as JumpInsnNode).label)
GETSTATIC -> eval.getStaticField(FieldDescription(insn as FieldInsnNode)) GETSTATIC -> eval.getStaticField(FieldDescription(insn as FieldInsnNode))
NEW -> eval.newInstance(Type.getType((insn as TypeInsnNode).desc)) NEW -> eval.newInstance(Type.getObjectType((insn as TypeInsnNode).desc))
else -> throw UnsupportedByteCodeException("$insn") else -> throw UnsupportedByteCodeException("$insn")
} }
} }
+19 -3
View File
@@ -30,11 +30,11 @@ class NotInitialized(override val asmType: Type): Value {
override fun toString() = "NotInitialized: $asmType" override fun toString() = "NotInitialized: $asmType"
} }
abstract class AbstractValue<V>( abstract class AbstractValueBase<V>(
public val value: V,
override val asmType: Type override val asmType: Type
) : Value { ) : Value {
override val valid = true override val valid = true
abstract val value: V
override fun toString() = "$value: $asmType" override fun toString() = "$value: $asmType"
@@ -49,11 +49,19 @@ abstract class AbstractValue<V>(
} }
} }
abstract class AbstractValue<V>(
override val value: V,
asmType: Type
) : AbstractValueBase<V>(asmType)
class IntValue(value: Int, asmType: Type): AbstractValue<Int>(value, asmType) class IntValue(value: Int, asmType: Type): AbstractValue<Int>(value, asmType)
class LongValue(value: Long): AbstractValue<Long>(value, Type.LONG_TYPE) 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) {
override var value: Any? = null
}
class LabelValue(value: LabelNode): AbstractValue<LabelNode>(value, Type.VOID_TYPE) class LabelValue(value: LabelNode): AbstractValue<LabelNode>(value, Type.VOID_TYPE)
@@ -74,4 +82,12 @@ 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? get() = (this as AbstractValue<*>).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
}
@@ -169,6 +169,12 @@ class TestData {
static class C { static class C {
int y = 15; int y = 15;
C(int y) {
this.y = y;
}
C() {}
int getY() { int getY() {
return y; return y;
} }
@@ -195,4 +201,11 @@ class TestData {
return C.newC().getY(); return C.newC().getY();
} }
static int constructorCallNoArgs() {
return new C().y;
}
static int constructorCallWithArgs() {
return new C(10).y;
}
} }
+49 -7
View File
@@ -10,6 +10,7 @@ import junit.framework.TestSuite
import junit.framework.TestCase 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
fun suite(): TestSuite { fun suite(): TestSuite {
val suite = TestSuite() val suite = TestSuite()
@@ -102,11 +103,14 @@ object REFLECTION_EVAL : Eval {
override fun loadClass(classType: Type): Value { override fun loadClass(classType: Type): Value {
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
override fun loadString(str: String): Value = ObjectValue(str, Type.getType(javaClass<String>())) override fun loadString(str: String): Value = ObjectValue(str, Type.getType(javaClass<String>()))
override fun newInstance(classType: Type): Value { override fun newInstance(classType: Type): Value {
throw UnsupportedOperationException() val _class = findClass(classType.getInternalName())
return NewObjectValue(_class, classType)
} }
override fun checkCast(value: Value, targetType: Type): Value { override fun checkCast(value: Value, targetType: Type): Value {
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
@@ -155,9 +159,11 @@ object REFLECTION_EVAL : Eval {
return objectToValue(result, methodDesc.returnType) return objectToValue(result, methodDesc.returnType)
} }
fun findClass(memberDesc: MemberDescription): Class<Any?> { fun findClass(memberDesc: MemberDescription): Class<Any?> = findClass(memberDesc.ownerInternalName)
val owner = lookup.findClass(memberDesc.ownerInternalName)
assertNotNull("Class not found: ${memberDesc.ownerInternalName}", owner) fun findClass(internalName: String): Class<Any?> {
val owner = lookup.findClass(internalName)
assertNotNull("Class not found: ${internalName}", owner)
return owner!! return owner!!
} }
@@ -185,7 +191,22 @@ object REFLECTION_EVAL : Eval {
} }
override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List<Value>, invokespecial: Boolean): Value { override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List<Value>, invokespecial: Boolean): Value {
// TODO: INVOKESPECIAL if (invokespecial) {
if (methodDesc.name == "<init>") {
// Constructor call
val _class = (instance as NewObjectValue)._class
val ctor = _class.findConstructor(methodDesc)
assertNotNull("Constructor not found: $methodDesc", ctor)
val args = arguments.map { v -> v.obj }.copyToArray()
val result = ctor!!.newInstance(*args)
instance.value = result
return objectToValue(result, instance.asmType)
}
else {
// TODO
throw UnsupportedOperationException("invokespecial is not suported yet")
}
}
val obj = instance.obj val obj = instance.obj
val method = obj.javaClass.findMethod(methodDesc) val method = obj.javaClass.findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method) assertNotNull("Method not found: $methodDesc", method)
@@ -216,6 +237,24 @@ fun Class<Any?>.findMethod(methodDesc: MethodDescription): Method? {
return null return null
} }
[suppress("UNCHECKED_CAST")]
fun Class<Any?>.findConstructor(methodDesc: MethodDescription): Constructor<Any?>? {
for (declared in getDeclaredConstructors()) {
if (methodDesc.matches(declared)) return declared as Constructor<Any?>
}
return null
}
fun MethodDescription.matches(ctor: Constructor<*>): Boolean {
val methodParams = ctor.getParameterTypes()!!
if (parameterTypes.size() != methodParams.size) return false
for ((i, p) in parameterTypes.withIndices()) {
if (!p.matches(methodParams[i])) return false
}
return true;
}
fun MethodDescription.matches(method: Method): Boolean { fun MethodDescription.matches(method: Method): Boolean {
if (name != method.getName()) return false if (name != method.getName()) return false
@@ -234,8 +273,11 @@ fun Class<Any?>.findField(fieldDesc: FieldDescription): Field? {
if (fieldDesc.matches(declared)) return declared if (fieldDesc.matches(declared)) return declared
} }
val fromSuperClass = (getSuperclass() as Class<Any?>).findField(fieldDesc) val superclass = getSuperclass()
if (fromSuperClass != null) return fromSuperClass if (superclass != null) {
val fromSuperClass = (superclass as Class<Any?>).findField(fieldDesc)
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)