Support constructor calls
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user