JDI-based Eval for classes and static fields
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
<root>
|
||||||
|
<item name='com.sun.jdi.ClassObjectReference com.sun.jdi.ReferenceType reflectedType()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.sun.jdi.ReferenceType com.sun.jdi.ClassObjectReference classObject()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.sun.jdi.StackFrame com.sun.jdi.Location location()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.sun.jdi.Type java.lang.String signature()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.sun.jdi.Value com.sun.jdi.Type type()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item name='com.sun.jdi.VirtualMachine java.util.List<com.sun.jdi.ReferenceType> classesByName(java.lang.String)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package org.jetbrains.eval4j.jdi
|
||||||
|
|
||||||
|
import org.jetbrains.eval4j.*
|
||||||
|
import org.objectweb.asm.Type
|
||||||
|
import com.sun.jdi
|
||||||
|
|
||||||
|
val CLASS = Type.getType(javaClass<Class<*>>())
|
||||||
|
|
||||||
|
class JDIEval(
|
||||||
|
private val vm: jdi.VirtualMachine,
|
||||||
|
private val classLoader: jdi.ClassLoaderReference,
|
||||||
|
private val thread: jdi.ThreadReference
|
||||||
|
) : Eval {
|
||||||
|
override fun loadClass(classType: Type): Value {
|
||||||
|
return invokeStaticMethod(
|
||||||
|
MethodDescription(
|
||||||
|
CLASS.getInternalName(),
|
||||||
|
"forName",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
listOf(classLoader.asValue())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadString(str: String): Value = vm.mirrorOf(str)!!.asValue()
|
||||||
|
|
||||||
|
override fun newInstance(classType: Type): Value {
|
||||||
|
return NewObjectValue(classType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isInstanceOf(value: Value, targetType: Type): Boolean {
|
||||||
|
assert(targetType.getSort() == Type.OBJECT, "Can't check isInstanceOf() for non-object type $targetType")
|
||||||
|
|
||||||
|
val _class = loadClass(targetType)
|
||||||
|
return invokeMethod(
|
||||||
|
_class,
|
||||||
|
MethodDescription(
|
||||||
|
CLASS.getInternalName(),
|
||||||
|
"isInstance",
|
||||||
|
"(Ljava/lang/Object;)Z",
|
||||||
|
false
|
||||||
|
),
|
||||||
|
listOf(value)).boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(arrayType: Type, size: Int): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun newMultiDimensionalArray(arrayType: Type, dimensionSizes: List<Int>): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun getArrayLength(array: Value): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun getArrayElement(array: Value, index: Value): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun setArrayElement(array: Value, index: Value, newValue: Value) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findField(fieldDesc: FieldDescription): jdi.Field {
|
||||||
|
val _class = loadClass(fieldDesc.ownerType).jdiClass!!.reflectedType()
|
||||||
|
val field = _class.fieldByName(fieldDesc.name)
|
||||||
|
if (field == null) {
|
||||||
|
throwException(NoSuchFieldError("Field not found: $fieldDesc"))
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findStaticField(fieldDesc: FieldDescription): jdi.Field {
|
||||||
|
val field = findField(fieldDesc)
|
||||||
|
if (!field.isStatic()) {
|
||||||
|
throwException(NoSuchFieldError("Field is not static: $fieldDesc"))
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStaticField(fieldDesc: FieldDescription): Value {
|
||||||
|
val field = findStaticField(fieldDesc)
|
||||||
|
return field.declaringType().getValue(field).asValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
|
||||||
|
val field = findStaticField(fieldDesc)
|
||||||
|
|
||||||
|
if (field.isFinal()) {
|
||||||
|
throwException(NoSuchFieldError("Can't modify a final field: $field"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val _class = field.declaringType()
|
||||||
|
if (_class !is jdi.ClassType) {
|
||||||
|
throwException(NoSuchFieldError("Can't a field in a non-class: $field"))
|
||||||
|
}
|
||||||
|
|
||||||
|
_class.setValue(field, newValue.asJdiValue(vm))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List<Value>): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getField(instance: Value, fieldDesc: FieldDescription): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun setField(instance: Value, fieldDesc: FieldDescription, newValue: Value) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List<Value>, invokespecial: Boolean): Value {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user