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)
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")
}
}
+19 -3
View File
@@ -30,11 +30,11 @@ class NotInitialized(override val asmType: Type): Value {
override fun toString() = "NotInitialized: $asmType"
}
abstract class AbstractValue<V>(
public val value: V,
abstract class AbstractValueBase<V>(
override val asmType: Type
) : Value {
override val valid = true
abstract val value: V
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 LongValue(value: Long): AbstractValue<Long>(value, Type.LONG_TYPE)
class FloatValue(value: Float): AbstractValue<Float>(value, Type.FLOAT_TYPE)
class DoubleValue(value: Double): AbstractValue<Double>(value, Type.DOUBLE_TYPE)
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)
@@ -74,4 +82,12 @@ 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() = (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 {
int y = 15;
C(int y) {
this.y = y;
}
C() {}
int getY() {
return y;
}
@@ -195,4 +201,11 @@ class TestData {
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 java.lang.reflect.Method
import java.lang.reflect.Field
import java.lang.reflect.Constructor
fun suite(): TestSuite {
val suite = TestSuite()
@@ -102,11 +103,14 @@ object REFLECTION_EVAL : Eval {
override fun loadClass(classType: Type): Value {
throw UnsupportedOperationException()
}
override fun loadString(str: String): Value = ObjectValue(str, Type.getType(javaClass<String>()))
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 {
throw UnsupportedOperationException()
}
@@ -155,9 +159,11 @@ object REFLECTION_EVAL : Eval {
return objectToValue(result, methodDesc.returnType)
}
fun findClass(memberDesc: MemberDescription): Class<Any?> {
val owner = lookup.findClass(memberDesc.ownerInternalName)
assertNotNull("Class not found: ${memberDesc.ownerInternalName}", owner)
fun findClass(memberDesc: MemberDescription): Class<Any?> = findClass(memberDesc.ownerInternalName)
fun findClass(internalName: String): Class<Any?> {
val owner = lookup.findClass(internalName)
assertNotNull("Class not found: ${internalName}", owner)
return owner!!
}
@@ -185,7 +191,22 @@ object REFLECTION_EVAL : Eval {
}
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 method = obj.javaClass.findMethod(methodDesc)
assertNotNull("Method not found: $methodDesc", method)
@@ -216,6 +237,24 @@ fun Class<Any?>.findMethod(methodDesc: MethodDescription): Method? {
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 {
if (name != method.getName()) return false
@@ -234,8 +273,11 @@ fun Class<Any?>.findField(fieldDesc: FieldDescription): Field? {
if (fieldDesc.matches(declared)) return declared
}
val fromSuperClass = (getSuperclass() as Class<Any?>).findField(fieldDesc)
if (fromSuperClass != null) return fromSuperClass
val superclass = getSuperclass()
if (superclass != null) {
val fromSuperClass = (superclass as Class<Any?>).findField(fieldDesc)
if (fromSuperClass != null) return fromSuperClass
}
for (supertype in getInterfaces()) {
val fromSuper = (supertype as Class<Any?>).findField(fieldDesc)