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)
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user