Run Clean up on eval4j module
This commit is contained in:
@@ -56,7 +56,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun newOperation(insn: AbstractInsnNode): Value? {
|
override fun newOperation(insn: AbstractInsnNode): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.opcode) {
|
||||||
ACONST_NULL -> {
|
ACONST_NULL -> {
|
||||||
return NULL_VALUE
|
return NULL_VALUE
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
is Double -> double(cst)
|
is Double -> double(cst)
|
||||||
is String -> eval.loadString(cst)
|
is String -> eval.loadString(cst)
|
||||||
is Type -> {
|
is Type -> {
|
||||||
val sort = cst.getSort()
|
val sort = cst.sort
|
||||||
when (sort) {
|
when (sort) {
|
||||||
Type.OBJECT, Type.ARRAY -> eval.loadClass(cst)
|
Type.OBJECT, Type.ARRAY -> eval.loadClass(cst)
|
||||||
Type.METHOD -> throw UnsupportedByteCodeException("Mothod handles are not supported")
|
Type.METHOD -> throw UnsupportedByteCodeException("Mothod handles are not supported")
|
||||||
@@ -113,7 +113,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun unaryOperation(insn: AbstractInsnNode, value: Value): Value? {
|
override fun unaryOperation(insn: AbstractInsnNode, value: Value): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.opcode) {
|
||||||
INEG -> int(-value.int)
|
INEG -> int(-value.int)
|
||||||
IINC -> int(value.int + (insn as IincInsnNode).incr)
|
IINC -> int(value.int + (insn as IincInsnNode).incr)
|
||||||
L2I -> int(value.long.toInt())
|
L2I -> int(value.long.toInt())
|
||||||
@@ -187,7 +187,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
ObjectValue(value.obj(), targetType)
|
ObjectValue(value.obj(), targetType)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throwEvalException(ClassCastException("${value.asmType.getClassName()} cannot be cast to ${targetType.getClassName()}"))
|
throwEvalException(ClassCastException("${value.asmType.className} cannot be cast to ${targetType.className}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun binaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value): Value? {
|
override fun binaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.opcode) {
|
||||||
IALOAD, BALOAD, CALOAD, SALOAD,
|
IALOAD, BALOAD, CALOAD, SALOAD,
|
||||||
FALOAD, LALOAD, DALOAD,
|
FALOAD, LALOAD, DALOAD,
|
||||||
AALOAD -> eval.getArrayElement(value1, value2)
|
AALOAD -> eval.getArrayElement(value1, value2)
|
||||||
@@ -280,7 +280,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
l1 == l2 -> 0
|
l1 == l2 -> 0
|
||||||
l1 < l2 -> -1
|
l1 < l2 -> -1
|
||||||
// one of them is NaN
|
// one of them is NaN
|
||||||
else -> if (insn.getOpcode() == FCMPG) 1 else -1
|
else -> if (insn.opcode == FCMPG) 1 else -1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
l1 == l2 -> 0
|
l1 == l2 -> 0
|
||||||
l1 < l2 -> -1
|
l1 < l2 -> -1
|
||||||
// one of them is NaN
|
// one of them is NaN
|
||||||
else -> if (insn.getOpcode() == DCMPG) 1 else -1
|
else -> if (insn.opcode == DCMPG) 1 else -1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +328,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value, value3: Value): Value? {
|
override fun ternaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value, value3: Value): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.opcode) {
|
||||||
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE -> {
|
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE -> {
|
||||||
eval.setArrayElement(value1, value2, value3)
|
eval.setArrayElement(value1, value2, value3)
|
||||||
null
|
null
|
||||||
@@ -338,7 +338,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun naryOperation(insn: AbstractInsnNode, values: List<Value>): Value {
|
override fun naryOperation(insn: AbstractInsnNode, values: List<Value>): Value {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.opcode) {
|
||||||
MULTIANEWARRAY -> {
|
MULTIANEWARRAY -> {
|
||||||
val node = insn as MultiANewArrayInsnNode
|
val node = insn as MultiANewArrayInsnNode
|
||||||
eval.newMultiDimensionalArray(Type.getType(node.desc), values.map { v -> v.int })
|
eval.newMultiDimensionalArray(Type.getType(node.desc), values.map { v -> v.int })
|
||||||
@@ -348,8 +348,8 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
eval.invokeMethod(
|
eval.invokeMethod(
|
||||||
values[0],
|
values[0],
|
||||||
MethodDescription(insn as MethodInsnNode),
|
MethodDescription(insn as MethodInsnNode),
|
||||||
values.subList(1, values.size()),
|
values.subList(1, values.size),
|
||||||
insn.getOpcode() == INVOKESPECIAL
|
insn.opcode == INVOKESPECIAL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
|
|||||||
|
|
||||||
|
|
||||||
override fun returnOperation(insn: AbstractInsnNode, value: Value, expected: Value) {
|
override fun returnOperation(insn: AbstractInsnNode, value: Value, expected: Value) {
|
||||||
when (insn.getOpcode()) {
|
when (insn.opcode) {
|
||||||
IRETURN, LRETURN, FRETURN, DRETURN, ARETURN -> {
|
IRETURN, LRETURN, FRETURN, DRETURN, ARETURN -> {
|
||||||
// Handled by interpreter loop
|
// Handled by interpreter loop
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
|||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
import org.jetbrains.org.objectweb.asm.util.Printer
|
import org.jetbrains.org.objectweb.asm.util.Printer
|
||||||
import java.util.ArrayList
|
import java.util.*
|
||||||
|
|
||||||
public interface InterpreterResult {
|
public interface InterpreterResult {
|
||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
@@ -61,7 +61,7 @@ public interface InterpretationEventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class ThrownFromEvalExceptionBase(cause: Throwable): RuntimeException(cause) {
|
abstract class ThrownFromEvalExceptionBase(cause: Throwable): RuntimeException(cause) {
|
||||||
override fun toString(): String = "Thrown by evaluator: ${getCause()}"
|
override fun toString(): String = "Thrown by evaluator: ${cause}"
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrokenCode(cause: Throwable): ThrownFromEvalExceptionBase(cause)
|
class BrokenCode(cause: Throwable): ThrownFromEvalExceptionBase(cause)
|
||||||
@@ -77,7 +77,7 @@ public fun interpreterLoop(
|
|||||||
eval: Eval,
|
eval: Eval,
|
||||||
handler: InterpretationEventHandler = InterpretationEventHandler.NONE
|
handler: InterpretationEventHandler = InterpretationEventHandler.NONE
|
||||||
): InterpreterResult {
|
): InterpreterResult {
|
||||||
val firstInsn = m.instructions.getFirst()
|
val firstInsn = m.instructions.first
|
||||||
if (firstInsn == null) throw IllegalArgumentException("Empty method")
|
if (firstInsn == null) throw IllegalArgumentException("Empty method")
|
||||||
|
|
||||||
var currentInsn = firstInsn
|
var currentInsn = firstInsn
|
||||||
@@ -122,9 +122,9 @@ public fun interpreterLoop(
|
|||||||
try {
|
try {
|
||||||
val exceptionClass = exception.javaClass
|
val exceptionClass = exception.javaClass
|
||||||
val _class = Class.forName(
|
val _class = Class.forName(
|
||||||
exceptionType.getInternalName().replace('/', '.'),
|
exceptionType.internalName.replace('/', '.'),
|
||||||
true,
|
true,
|
||||||
exceptionClass.getClassLoader()
|
exceptionClass.classLoader
|
||||||
)
|
)
|
||||||
_class.isAssignableFrom(exceptionClass)
|
_class.isAssignableFrom(exceptionClass)
|
||||||
}
|
}
|
||||||
@@ -137,8 +137,8 @@ public fun interpreterLoop(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
val insnOpcode = currentInsn.getOpcode()
|
val insnOpcode = currentInsn.opcode
|
||||||
val insnType = currentInsn.getType()
|
val insnType = currentInsn.type
|
||||||
|
|
||||||
when (insnType) {
|
when (insnType) {
|
||||||
AbstractInsnNode.LABEL,
|
AbstractInsnNode.LABEL,
|
||||||
@@ -168,7 +168,7 @@ public fun interpreterLoop(
|
|||||||
IRETURN, LRETURN, FRETURN, DRETURN, ARETURN -> {
|
IRETURN, LRETURN, FRETURN, DRETURN, ARETURN -> {
|
||||||
val value = frame.getStackTop()
|
val value = frame.getStackTop()
|
||||||
val expectedType = Type.getReturnType(m.desc)
|
val expectedType = Type.getReturnType(m.desc)
|
||||||
if (expectedType.getSort() == Type.OBJECT || expectedType.getSort() == Type.ARRAY) {
|
if (expectedType.sort == Type.OBJECT || expectedType.sort == Type.ARRAY) {
|
||||||
val coerced = if (value != NULL_VALUE && value.asmType != expectedType)
|
val coerced = if (value != NULL_VALUE && value.asmType != expectedType)
|
||||||
ObjectValue(value.obj(), expectedType)
|
ObjectValue(value.obj(), expectedType)
|
||||||
else value
|
else value
|
||||||
@@ -177,7 +177,7 @@ public fun interpreterLoop(
|
|||||||
if (value.asmType != expectedType) {
|
if (value.asmType != expectedType) {
|
||||||
assert(insnOpcode == IRETURN) { "Only ints should be coerced: ${Printer.OPCODES[insnOpcode]}" }
|
assert(insnOpcode == IRETURN) { "Only ints should be coerced: ${Printer.OPCODES[insnOpcode]}" }
|
||||||
|
|
||||||
val coerced = when (expectedType.getSort()) {
|
val coerced = when (expectedType.sort) {
|
||||||
Type.BOOLEAN -> boolean(value.boolean)
|
Type.BOOLEAN -> boolean(value.boolean)
|
||||||
Type.BYTE -> byte(value.int.toByte())
|
Type.BYTE -> byte(value.int.toByte())
|
||||||
Type.SHORT -> short(value.int.toShort())
|
Type.SHORT -> short(value.int.toShort())
|
||||||
@@ -221,7 +221,7 @@ public fun interpreterLoop(
|
|||||||
frame.execute(currentInsn, interpreter)
|
frame.execute(currentInsn, interpreter)
|
||||||
}
|
}
|
||||||
catch (e: ThrownFromEvalExceptionBase) {
|
catch (e: ThrownFromEvalExceptionBase) {
|
||||||
val exception = e.getCause()!!
|
val exception = e.cause!!
|
||||||
val exceptionValue = ObjectValue(exception, Type.getType(exception.javaClass))
|
val exceptionValue = ObjectValue(exception, Type.getType(exception.javaClass))
|
||||||
val handled = handler.exceptionThrown(frame, currentInsn,
|
val handled = handler.exceptionThrown(frame, currentInsn,
|
||||||
exceptionValue)
|
exceptionValue)
|
||||||
@@ -243,7 +243,7 @@ public fun interpreterLoop(
|
|||||||
val handled = handler.instructionProcessed(currentInsn)
|
val handled = handler.instructionProcessed(currentInsn)
|
||||||
if (handled != null) return handled
|
if (handled != null) return handled
|
||||||
|
|
||||||
goto(currentInsn.getNext())
|
goto(currentInsn.next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(e: ResultException) {
|
catch(e: ResultException) {
|
||||||
@@ -251,7 +251,7 @@ public fun interpreterLoop(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T: Value> Frame<T>.getStackTop(i: Int = 0) = this.getStack(this.getStackSize() - 1 - i) ?: throwBrokenCodeException(IllegalArgumentException("Couldn't get value with index = $i from top of stack"))
|
private fun <T: Value> Frame<T>.getStackTop(i: Int = 0) = this.getStack(this.stackSize - 1 - i) ?: throwBrokenCodeException(IllegalArgumentException("Couldn't get value with index = $i from top of stack"))
|
||||||
|
|
||||||
// Copied from org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer.analyze()
|
// Copied from org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer.analyze()
|
||||||
fun computeHandlers(m: MethodNode): Array<out List<TryCatchBlockNode>?> {
|
fun computeHandlers(m: MethodNode): Array<out List<TryCatchBlockNode>?> {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import java.lang.reflect.AccessibleObject
|
|||||||
import com.sun.jdi.Type as jdi_Type
|
import com.sun.jdi.Type as jdi_Type
|
||||||
import com.sun.jdi.Value as jdi_Value
|
import com.sun.jdi.Value as jdi_Value
|
||||||
|
|
||||||
val CLASS = Type.getType(javaClass<Class<*>>())
|
val CLASS = Type.getType(Class::class.java)
|
||||||
val OBJECT = Type.getType(Any::class.java)
|
val OBJECT = Type.getType(Any::class.java)
|
||||||
val BOOTSTRAP_CLASS_DESCRIPTORS = setOf("Ljava/lang/String;", "Ljava/lang/ClassLoader;", "Ljava/lang/Class;")
|
val BOOTSTRAP_CLASS_DESCRIPTORS = setOf("Ljava/lang/String;", "Ljava/lang/ClassLoader;", "Ljava/lang/Class;")
|
||||||
|
|
||||||
@@ -36,14 +36,14 @@ public class JDIEval(
|
|||||||
) : Eval {
|
) : Eval {
|
||||||
|
|
||||||
private val primitiveTypes = mapOf(
|
private val primitiveTypes = mapOf(
|
||||||
Type.BOOLEAN_TYPE.getClassName() to vm.mirrorOf(true).type(),
|
Type.BOOLEAN_TYPE.className to vm.mirrorOf(true).type(),
|
||||||
Type.BYTE_TYPE.getClassName() to vm.mirrorOf(1.toByte()).type(),
|
Type.BYTE_TYPE.className to vm.mirrorOf(1.toByte()).type(),
|
||||||
Type.SHORT_TYPE.getClassName() to vm.mirrorOf(1.toShort()).type(),
|
Type.SHORT_TYPE.className to vm.mirrorOf(1.toShort()).type(),
|
||||||
Type.INT_TYPE.getClassName() to vm.mirrorOf(1.toInt()).type(),
|
Type.INT_TYPE.className to vm.mirrorOf(1.toInt()).type(),
|
||||||
Type.CHAR_TYPE.getClassName() to vm.mirrorOf('1').type(),
|
Type.CHAR_TYPE.className to vm.mirrorOf('1').type(),
|
||||||
Type.LONG_TYPE.getClassName() to vm.mirrorOf(1L).type(),
|
Type.LONG_TYPE.className to vm.mirrorOf(1L).type(),
|
||||||
Type.FLOAT_TYPE.getClassName() to vm.mirrorOf(1.0f).type(),
|
Type.FLOAT_TYPE.className to vm.mirrorOf(1.0f).type(),
|
||||||
Type.DOUBLE_TYPE.getClassName() to vm.mirrorOf(1.0).type()
|
Type.DOUBLE_TYPE.className to vm.mirrorOf(1.0).type()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun loadClass(classType: Type): Value {
|
override fun loadClass(classType: Type): Value {
|
||||||
@@ -51,34 +51,34 @@ public class JDIEval(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun loadClass(classType: Type, classLoader: ClassLoaderReference?): Value {
|
fun loadClass(classType: Type, classLoader: ClassLoaderReference?): Value {
|
||||||
val loadedClasses = vm.classesByName(classType.getInternalName())
|
val loadedClasses = vm.classesByName(classType.internalName)
|
||||||
if (!loadedClasses.isEmpty()) {
|
if (!loadedClasses.isEmpty()) {
|
||||||
val loadedClass = loadedClasses[0]
|
val loadedClass = loadedClasses[0]
|
||||||
if (classType.getDescriptor() in BOOTSTRAP_CLASS_DESCRIPTORS || loadedClass.classLoader() == classLoader) {
|
if (classType.descriptor in BOOTSTRAP_CLASS_DESCRIPTORS || loadedClass.classLoader() == classLoader) {
|
||||||
return loadedClass.classObject().asValue()
|
return loadedClass.classObject().asValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (classLoader == null) {
|
if (classLoader == null) {
|
||||||
return invokeStaticMethod(
|
return invokeStaticMethod(
|
||||||
MethodDescription(
|
MethodDescription(
|
||||||
CLASS.getInternalName(),
|
CLASS.internalName,
|
||||||
"forName",
|
"forName",
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
listOf(vm.mirrorOf(classType.getInternalName().replace('/', '.')).asValue())
|
listOf(vm.mirrorOf(classType.internalName.replace('/', '.')).asValue())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return invokeStaticMethod(
|
return invokeStaticMethod(
|
||||||
MethodDescription(
|
MethodDescription(
|
||||||
CLASS.getInternalName(),
|
CLASS.internalName,
|
||||||
"forName",
|
"forName",
|
||||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
|
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
listOf(
|
listOf(
|
||||||
vm.mirrorOf(classType.getInternalName().replace('/', '.')).asValue(),
|
vm.mirrorOf(classType.internalName.replace('/', '.')).asValue(),
|
||||||
boolean(true),
|
boolean(true),
|
||||||
classLoader.asValue()
|
classLoader.asValue()
|
||||||
)
|
)
|
||||||
@@ -93,7 +93,7 @@ public class JDIEval(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isInstanceOf(value: Value, targetType: Type): Boolean {
|
override fun isInstanceOf(value: Value, targetType: Type): Boolean {
|
||||||
assert(targetType.getSort() == Type.OBJECT || targetType.getSort() == Type.ARRAY) {
|
assert(targetType.sort == Type.OBJECT || targetType.sort == Type.ARRAY) {
|
||||||
"Can't check isInstanceOf() for non-object type $targetType"
|
"Can't check isInstanceOf() for non-object type $targetType"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ public class JDIEval(
|
|||||||
return invokeMethod(
|
return invokeMethod(
|
||||||
_class,
|
_class,
|
||||||
MethodDescription(
|
MethodDescription(
|
||||||
CLASS.getInternalName(),
|
CLASS.internalName,
|
||||||
"isInstance",
|
"isInstance",
|
||||||
"(Ljava/lang/Object;)Z",
|
"(Ljava/lang/Object;)Z",
|
||||||
false
|
false
|
||||||
@@ -119,12 +119,12 @@ public class JDIEval(
|
|||||||
|
|
||||||
private val Type.arrayElementType: Type
|
private val Type.arrayElementType: Type
|
||||||
get(): Type {
|
get(): Type {
|
||||||
assert(getSort() == Type.ARRAY) { "Not an array type: $this" }
|
assert(sort == Type.ARRAY) { "Not an array type: $this" }
|
||||||
return Type.getType(getDescriptor().substring(1))
|
return Type.getType(descriptor.substring(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fillArray(elementType: Type, size: Int, nestedSizes: List<Int>): Value {
|
private fun fillArray(elementType: Type, size: Int, nestedSizes: List<Int>): Value {
|
||||||
val arr = newArray(Type.getType("[" + elementType.getDescriptor()), size)
|
val arr = newArray(Type.getType("[" + elementType.descriptor), size)
|
||||||
if (!nestedSizes.isEmpty()) {
|
if (!nestedSizes.isEmpty()) {
|
||||||
val nestedElementType = elementType.arrayElementType
|
val nestedElementType = elementType.arrayElementType
|
||||||
val nestedSize = nestedSizes[0]
|
val nestedSize = nestedSizes[0]
|
||||||
@@ -151,7 +151,7 @@ public class JDIEval(
|
|||||||
return array.array().getValue(index.int).asValue()
|
return array.array().getValue(index.int).asValue()
|
||||||
}
|
}
|
||||||
catch (e: IndexOutOfBoundsException) {
|
catch (e: IndexOutOfBoundsException) {
|
||||||
throwEvalException(ArrayIndexOutOfBoundsException(e.getMessage()))
|
throwEvalException(ArrayIndexOutOfBoundsException(e.message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ public class JDIEval(
|
|||||||
return array.array().setValue(index.int, newValue.asJdiValue(vm, array.asmType.arrayElementType))
|
return array.array().setValue(index.int, newValue.asJdiValue(vm, array.asmType.arrayElementType))
|
||||||
}
|
}
|
||||||
catch (e: IndexOutOfBoundsException) {
|
catch (e: IndexOutOfBoundsException) {
|
||||||
throwEvalException(ArrayIndexOutOfBoundsException(e.getMessage()))
|
throwEvalException(ArrayIndexOutOfBoundsException(e.message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ public class JDIEval(
|
|||||||
|
|
||||||
private fun findStaticField(fieldDesc: FieldDescription): Field {
|
private fun findStaticField(fieldDesc: FieldDescription): Field {
|
||||||
val field = findField(fieldDesc)
|
val field = findField(fieldDesc)
|
||||||
if (!field.isStatic()) {
|
if (!field.isStatic) {
|
||||||
throwBrokenCodeException(NoSuchFieldError("Field is not static: $fieldDesc"))
|
throwBrokenCodeException(NoSuchFieldError("Field is not static: $fieldDesc"))
|
||||||
}
|
}
|
||||||
return field
|
return field
|
||||||
@@ -189,7 +189,7 @@ public class JDIEval(
|
|||||||
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
|
override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) {
|
||||||
val field = findStaticField(fieldDesc)
|
val field = findStaticField(fieldDesc)
|
||||||
|
|
||||||
if (field.isFinal()) {
|
if (field.isFinal) {
|
||||||
throwBrokenCodeException(NoSuchFieldError("Can't modify a final field: $field"))
|
throwBrokenCodeException(NoSuchFieldError("Can't modify a final field: $field"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ public class JDIEval(
|
|||||||
|
|
||||||
override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List<Value>): Value {
|
override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List<Value>): Value {
|
||||||
val method = findMethod(methodDesc)
|
val method = findMethod(methodDesc)
|
||||||
if (!method.isStatic()) {
|
if (!method.isStatic) {
|
||||||
throwBrokenCodeException(NoSuchMethodError("Method is not static: $methodDesc"))
|
throwBrokenCodeException(NoSuchMethodError("Method is not static: $methodDesc"))
|
||||||
}
|
}
|
||||||
val _class = method.declaringType()
|
val _class = method.declaringType()
|
||||||
@@ -261,7 +261,7 @@ public class JDIEval(
|
|||||||
Type.BYTE_TYPE -> MethodDescription("java/lang/Byte", "byteValue", "()B", false)
|
Type.BYTE_TYPE -> MethodDescription("java/lang/Byte", "byteValue", "()B", false)
|
||||||
Type.FLOAT_TYPE -> MethodDescription("java/lang/Float", "floatValue", "()F", false)
|
Type.FLOAT_TYPE -> MethodDescription("java/lang/Float", "floatValue", "()F", false)
|
||||||
Type.DOUBLE_TYPE -> MethodDescription("java/lang/Double", "doubleValue", "()D", false)
|
Type.DOUBLE_TYPE -> MethodDescription("java/lang/Double", "doubleValue", "()D", false)
|
||||||
else -> throw UnsupportedOperationException("Couldn't unbox non primitive type ${type.getInternalName()}")
|
else -> throw UnsupportedOperationException("Couldn't unbox non primitive type ${type.internalName}")
|
||||||
}
|
}
|
||||||
return invokeMethod(boxedValue, method, listOf(), true)
|
return invokeMethod(boxedValue, method, listOf(), true)
|
||||||
}
|
}
|
||||||
@@ -276,7 +276,7 @@ public class JDIEval(
|
|||||||
Type.CHAR_TYPE -> MethodDescription("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false)
|
Type.CHAR_TYPE -> MethodDescription("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false)
|
||||||
Type.FLOAT_TYPE -> MethodDescription("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false)
|
Type.FLOAT_TYPE -> MethodDescription("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false)
|
||||||
Type.DOUBLE_TYPE -> MethodDescription("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false)
|
Type.DOUBLE_TYPE -> MethodDescription("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false)
|
||||||
else -> throw UnsupportedOperationException("Couldn't box non primitive type ${value.asmType.getInternalName()}")
|
else -> throw UnsupportedOperationException("Couldn't box non primitive type ${value.asmType.internalName}")
|
||||||
}
|
}
|
||||||
return invokeStaticMethod(method, listOf(value))
|
return invokeStaticMethod(method, listOf(value))
|
||||||
}
|
}
|
||||||
@@ -397,7 +397,7 @@ public class JDIEval(
|
|||||||
if (dimensions == 0)
|
if (dimensions == 0)
|
||||||
baseType
|
baseType
|
||||||
else
|
else
|
||||||
Type.getType("[".repeat(dimensions) + baseType.asType().getDescriptor()).asReferenceType(declaringType().classLoader())
|
Type.getType("[".repeat(dimensions) + baseType.asType().descriptor).asReferenceType(declaringType().classLoader())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public fun makeInitialFrame(methodNode: MethodNode, arguments: List<Value>): Fra
|
|||||||
val isStatic = (methodNode.access and ACC_STATIC) != 0
|
val isStatic = (methodNode.access and ACC_STATIC) != 0
|
||||||
|
|
||||||
val params = Type.getArgumentTypes(methodNode.desc)
|
val params = Type.getArgumentTypes(methodNode.desc)
|
||||||
assert(arguments.size() == (if (isStatic) params.size() else params.size() + 1)) {
|
assert(arguments.size == (if (isStatic) params.size else params.size + 1)) {
|
||||||
"Wrong number of arguments for $methodNode: $arguments"
|
"Wrong number of arguments for $methodNode: $arguments"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ public fun makeInitialFrame(methodNode: MethodNode, arguments: List<Value>): Fra
|
|||||||
var index = 0
|
var index = 0
|
||||||
for ((i, arg) in arguments.withIndex()) {
|
for ((i, arg) in arguments.withIndex()) {
|
||||||
frame.setLocal(index++, arg)
|
frame.setLocal(index++, arg)
|
||||||
if (arg.getSize() == 2) {
|
if (arg.size == 2) {
|
||||||
frame.setLocal(index++, NOT_A_VALUE)
|
frame.setLocal(index++, NOT_A_VALUE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.eval4j
|
package org.jetbrains.eval4j
|
||||||
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||||
|
|
||||||
open class MemberDescription protected constructor(
|
open class MemberDescription protected constructor(
|
||||||
val ownerInternalName: String,
|
val ownerInternalName: String,
|
||||||
@@ -64,7 +64,7 @@ fun MethodDescription(insn: MethodInsnNode): MethodDescription =
|
|||||||
insn.owner,
|
insn.owner,
|
||||||
insn.name,
|
insn.name,
|
||||||
insn.desc,
|
insn.desc,
|
||||||
insn.getOpcode() == INVOKESTATIC
|
insn.opcode == INVOKESTATIC
|
||||||
)
|
)
|
||||||
|
|
||||||
val MethodDescription.returnType: Type
|
val MethodDescription.returnType: Type
|
||||||
@@ -86,7 +86,7 @@ fun FieldDescription(insn: FieldInsnNode): FieldDescription =
|
|||||||
insn.owner,
|
insn.owner,
|
||||||
insn.name,
|
insn.name,
|
||||||
insn.desc,
|
insn.desc,
|
||||||
insn.getOpcode() in setOf(GETSTATIC, PUTSTATIC)
|
insn.opcode in setOf(GETSTATIC, PUTSTATIC)
|
||||||
)
|
)
|
||||||
|
|
||||||
val FieldDescription.fieldType: Type
|
val FieldDescription.fieldType: Type
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
|||||||
public interface Value : org.jetbrains.org.objectweb.asm.tree.analysis.Value {
|
public interface Value : org.jetbrains.org.objectweb.asm.tree.analysis.Value {
|
||||||
public val asmType: Type
|
public val asmType: Type
|
||||||
public val valid: Boolean
|
public val valid: Boolean
|
||||||
override fun getSize(): Int = asmType.getSize()
|
override fun getSize(): Int = asmType.size
|
||||||
|
|
||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ object VOID_VALUE: Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun makeNotInitializedValue(t: Type): Value? {
|
fun makeNotInitializedValue(t: Type): Value? {
|
||||||
return when (t.getSort()) {
|
return when (t.sort) {
|
||||||
Type.VOID -> null
|
Type.VOID -> null
|
||||||
else -> NotInitialized(t)
|
else -> NotInitialized(t)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,24 +16,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.eval4j.jdi.test
|
package org.jetbrains.eval4j.jdi.test
|
||||||
|
|
||||||
import org.jetbrains.eval4j.*
|
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
import junit.framework.TestSuite
|
|
||||||
import org.jetbrains.eval4j.test.buildTestSuite
|
|
||||||
import junit.framework.TestCase
|
|
||||||
import org.junit.Assert.*
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import org.jetbrains.eval4j.jdi.*
|
|
||||||
import java.io.File
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
|
||||||
import org.jetbrains.eval4j.test.getTestName
|
|
||||||
import com.sun.jdi.ObjectReference
|
|
||||||
import com.sun.jdi.event.BreakpointEvent
|
import com.sun.jdi.event.BreakpointEvent
|
||||||
import com.sun.jdi.event.ClassPrepareEvent
|
import com.sun.jdi.event.ClassPrepareEvent
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import junit.framework.TestSuite
|
||||||
|
import org.jetbrains.eval4j.*
|
||||||
|
import org.jetbrains.eval4j.jdi.JDIEval
|
||||||
|
import org.jetbrains.eval4j.jdi.asValue
|
||||||
|
import org.jetbrains.eval4j.jdi.jdiObj
|
||||||
|
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||||
|
import org.jetbrains.eval4j.test.buildTestSuite
|
||||||
|
import org.jetbrains.eval4j.test.getTestName
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
val DEBUGEE_CLASS = javaClass<Debugee>()
|
val DEBUGEE_CLASS = Debugee::class.java
|
||||||
|
|
||||||
fun suite(): TestSuite {
|
fun suite(): TestSuite {
|
||||||
val connectors = Bootstrap.virtualMachineManager().launchingConnectors()
|
val connectors = Bootstrap.virtualMachineManager().launchingConnectors()
|
||||||
@@ -42,7 +43,7 @@ fun suite(): TestSuite {
|
|||||||
|
|
||||||
val connectorArgs = connector.defaultArguments()
|
val connectorArgs = connector.defaultArguments()
|
||||||
|
|
||||||
val debugeeName = DEBUGEE_CLASS.getName()
|
val debugeeName = DEBUGEE_CLASS.name
|
||||||
println("Debugee name: $debugeeName")
|
println("Debugee name: $debugeeName")
|
||||||
connectorArgs["main"]!!.setValue(debugeeName)
|
connectorArgs["main"]!!.setValue(debugeeName)
|
||||||
connectorArgs["options"]!!.setValue("-classpath out/production/eval4j${File.pathSeparator}out/test/eval4j")
|
connectorArgs["options"]!!.setValue("-classpath out/production/eval4j${File.pathSeparator}out/test/eval4j")
|
||||||
@@ -111,7 +112,7 @@ fun suite(): TestSuite {
|
|||||||
val args = if ((methodNode.access and Opcodes.ACC_STATIC) == 0) {
|
val args = if ((methodNode.access and Opcodes.ACC_STATIC) == 0) {
|
||||||
// Instance method
|
// Instance method
|
||||||
val newInstance = eval.newInstance(Type.getType(ownerClass))
|
val newInstance = eval.newInstance(Type.getType(ownerClass))
|
||||||
val thisValue = eval.invokeMethod(newInstance, MethodDescription(ownerClass.getName(), "<init>", "()V", false), listOf(), true)
|
val thisValue = eval.invokeMethod(newInstance, MethodDescription(ownerClass.name, "<init>", "()V", false), listOf(), true)
|
||||||
listOf(thisValue)
|
listOf(thisValue)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -16,20 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.eval4j.test
|
package org.jetbrains.eval4j.test
|
||||||
|
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
|
||||||
import java.lang.reflect.Modifier
|
|
||||||
import org.jetbrains.eval4j.*
|
|
||||||
import org.junit.Assert.*
|
|
||||||
import junit.framework.TestSuite
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import java.lang.reflect.Method
|
import junit.framework.TestSuite
|
||||||
import java.lang.reflect.Field
|
import org.jetbrains.eval4j.*
|
||||||
import java.lang.reflect.Constructor
|
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC
|
||||||
import java.lang.reflect.InvocationTargetException
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import java.lang.reflect.Array as JArray
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import java.lang.reflect.*
|
||||||
|
import java.lang.reflect.Array as JArray
|
||||||
|
|
||||||
fun suite(): TestSuite = buildTestSuite {
|
fun suite(): TestSuite = buildTestSuite {
|
||||||
methodNode, ownerClass, expected ->
|
methodNode, ownerClass, expected ->
|
||||||
@@ -59,13 +56,13 @@ fun suite(): TestSuite = buildTestSuite {
|
|||||||
return methodNode.visibleAnnotations?.any {
|
return methodNode.visibleAnnotations?.any {
|
||||||
val annotationDesc = it.desc
|
val annotationDesc = it.desc
|
||||||
annotationDesc != null &&
|
annotationDesc != null &&
|
||||||
Type.getType(annotationDesc) == Type.getType(javaClass<IgnoreInReflectionTests>())
|
Type.getType(annotationDesc) == Type.getType(IgnoreInReflectionTests::class.java)
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Class<*>.getInternalName(): String = Type.getType(this).getInternalName()
|
fun Class<*>.getInternalName(): String = Type.getType(this).internalName
|
||||||
|
|
||||||
fun initFrame(
|
fun initFrame(
|
||||||
owner: String,
|
owner: String,
|
||||||
@@ -83,9 +80,9 @@ fun initFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val args = Type.getArgumentTypes(m.desc)
|
val args = Type.getArgumentTypes(m.desc)
|
||||||
for (i in 0..args.size() - 1) {
|
for (i in 0..args.size - 1) {
|
||||||
current.setLocal(local++, makeNotInitializedValue(args[i]))
|
current.setLocal(local++, makeNotInitializedValue(args[i]))
|
||||||
if (args[i].getSize() == 2) {
|
if (args[i].size == 2) {
|
||||||
current.setLocal(local++, NOT_A_VALUE)
|
current.setLocal(local++, NOT_A_VALUE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +95,7 @@ fun initFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun objectToValue(obj: Any?, expectedType: Type): Value {
|
fun objectToValue(obj: Any?, expectedType: Type): Value {
|
||||||
return when (expectedType.getSort()) {
|
return when (expectedType.sort) {
|
||||||
Type.VOID -> VOID_VALUE
|
Type.VOID -> VOID_VALUE
|
||||||
Type.BOOLEAN -> boolean(obj as Boolean)
|
Type.BOOLEAN -> boolean(obj as Boolean)
|
||||||
Type.BYTE -> byte(obj as Byte)
|
Type.BYTE -> byte(obj as Byte)
|
||||||
@@ -115,13 +112,13 @@ fun objectToValue(obj: Any?, expectedType: Type): Value {
|
|||||||
|
|
||||||
object REFLECTION_EVAL : Eval {
|
object REFLECTION_EVAL : Eval {
|
||||||
|
|
||||||
val lookup = ReflectionLookup(javaClass<ReflectionLookup>().getClassLoader()!!)
|
val lookup = ReflectionLookup(ReflectionLookup::class.java.classLoader!!)
|
||||||
|
|
||||||
override fun loadClass(classType: Type): Value {
|
override fun loadClass(classType: Type): Value {
|
||||||
return ObjectValue(findClass(classType), Type.getType(javaClass<Class<*>>()))
|
return ObjectValue(findClass(classType), Type.getType(Class::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadString(str: String): Value = ObjectValue(str, Type.getType(javaClass<String>()))
|
override fun loadString(str: String): Value = ObjectValue(str, Type.getType(String::class.java))
|
||||||
|
|
||||||
override fun newInstance(classType: Type): Value {
|
override fun newInstance(classType: Type): Value {
|
||||||
return NewObjectValue(classType)
|
return NewObjectValue(classType)
|
||||||
@@ -134,11 +131,11 @@ object REFLECTION_EVAL : Eval {
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun newArray(arrayType: Type, size: Int): Value {
|
override fun newArray(arrayType: Type, size: Int): Value {
|
||||||
return ObjectValue(JArray.newInstance(findClass(arrayType).getComponentType() as Class<Any>, size), arrayType)
|
return ObjectValue(JArray.newInstance(findClass(arrayType).componentType as Class<Any>, size), arrayType)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newMultiDimensionalArray(arrayType: Type, dimensionSizes: List<Int>): Value {
|
override fun newMultiDimensionalArray(arrayType: Type, dimensionSizes: List<Int>): Value {
|
||||||
return ObjectValue(ArrayHelper.newMultiArray(findClass(arrayType.getElementType()), *dimensionSizes.toTypedArray()), arrayType)
|
return ObjectValue(ArrayHelper.newMultiArray(findClass(arrayType.elementType), *dimensionSizes.toTypedArray()), arrayType)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getArrayLength(array: Value): Value {
|
override fun getArrayLength(array: Value): Value {
|
||||||
@@ -147,11 +144,11 @@ object REFLECTION_EVAL : Eval {
|
|||||||
|
|
||||||
override fun getArrayElement(array: Value, index: Value): Value {
|
override fun getArrayElement(array: Value, index: Value): Value {
|
||||||
val asmType = array.asmType
|
val asmType = array.asmType
|
||||||
val elementType = if (asmType.getDimensions() == 1) asmType.getElementType() else Type.getType(asmType.getDescriptor().substring(1))
|
val elementType = if (asmType.dimensions == 1) asmType.elementType else Type.getType(asmType.descriptor.substring(1))
|
||||||
val arr = array.obj().checkNull()
|
val arr = array.obj().checkNull()
|
||||||
val ind = index.int
|
val ind = index.int
|
||||||
return mayThrow {
|
return mayThrow {
|
||||||
when (elementType.getSort()) {
|
when (elementType.sort) {
|
||||||
Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind))
|
Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind))
|
||||||
Type.BYTE -> byte(JArray.getByte(arr, ind))
|
Type.BYTE -> byte(JArray.getByte(arr, ind))
|
||||||
Type.SHORT -> short(JArray.getShort(arr, ind))
|
Type.SHORT -> short(JArray.getShort(arr, ind))
|
||||||
@@ -173,13 +170,13 @@ object REFLECTION_EVAL : Eval {
|
|||||||
override fun setArrayElement(array: Value, index: Value, newValue: Value) {
|
override fun setArrayElement(array: Value, index: Value, newValue: Value) {
|
||||||
val arr = array.obj().checkNull()
|
val arr = array.obj().checkNull()
|
||||||
val ind = index.int
|
val ind = index.int
|
||||||
if (array.asmType.getDimensions() > 1) {
|
if (array.asmType.dimensions > 1) {
|
||||||
JArray.set(arr, ind, newValue.obj())
|
JArray.set(arr, ind, newValue.obj())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val elementType = array.asmType.getElementType()
|
val elementType = array.asmType.elementType
|
||||||
mayThrow {
|
mayThrow {
|
||||||
when (elementType.getSort()) {
|
when (elementType.sort) {
|
||||||
Type.BOOLEAN -> JArray.setBoolean(arr, ind, newValue.boolean)
|
Type.BOOLEAN -> JArray.setBoolean(arr, ind, newValue.boolean)
|
||||||
Type.BYTE -> JArray.setByte(arr, ind, newValue.int.toByte())
|
Type.BYTE -> JArray.setByte(arr, ind, newValue.int.toByte())
|
||||||
Type.SHORT -> JArray.setShort(arr, ind, newValue.int.toShort())
|
Type.SHORT -> JArray.setShort(arr, ind, newValue.int.toShort())
|
||||||
@@ -203,7 +200,7 @@ object REFLECTION_EVAL : Eval {
|
|||||||
return f()
|
return f()
|
||||||
}
|
}
|
||||||
catch (ite: InvocationTargetException) {
|
catch (ite: InvocationTargetException) {
|
||||||
throw ite.getCause() ?: ite
|
throw ite.cause ?: ite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
@@ -228,7 +225,7 @@ object REFLECTION_EVAL : Eval {
|
|||||||
assertTrue(fieldDesc.isStatic)
|
assertTrue(fieldDesc.isStatic)
|
||||||
val field = findClass(fieldDesc).findField(fieldDesc)
|
val field = findClass(fieldDesc).findField(fieldDesc)
|
||||||
assertNotNull("Field not found: $fieldDesc", field)
|
assertNotNull("Field not found: $fieldDesc", field)
|
||||||
assertTrue("Field is not static: $field", (field!!.getModifiers() and Modifier.STATIC) != 0)
|
assertTrue("Field is not static: $field", (field!!.modifiers and Modifier.STATIC) != 0)
|
||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +305,7 @@ object REFLECTION_EVAL : Eval {
|
|||||||
class ReflectionLookup(val classLoader: ClassLoader) {
|
class ReflectionLookup(val classLoader: ClassLoader) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun findClass(asmType: Type): Class<*>? {
|
fun findClass(asmType: Type): Class<*>? {
|
||||||
return when (asmType.getSort()) {
|
return when (asmType.sort) {
|
||||||
Type.BOOLEAN -> java.lang.Boolean.TYPE
|
Type.BOOLEAN -> java.lang.Boolean.TYPE
|
||||||
Type.BYTE -> java.lang.Byte.TYPE
|
Type.BYTE -> java.lang.Byte.TYPE
|
||||||
Type.SHORT -> java.lang.Short.TYPE
|
Type.SHORT -> java.lang.Short.TYPE
|
||||||
@@ -317,8 +314,8 @@ class ReflectionLookup(val classLoader: ClassLoader) {
|
|||||||
Type.LONG -> java.lang.Long.TYPE
|
Type.LONG -> java.lang.Long.TYPE
|
||||||
Type.FLOAT -> java.lang.Float.TYPE
|
Type.FLOAT -> java.lang.Float.TYPE
|
||||||
Type.DOUBLE -> java.lang.Double.TYPE
|
Type.DOUBLE -> java.lang.Double.TYPE
|
||||||
Type.OBJECT -> classLoader.loadClass(asmType.getInternalName().replace('/', '.'))
|
Type.OBJECT -> classLoader.loadClass(asmType.internalName.replace('/', '.'))
|
||||||
Type.ARRAY -> Class.forName(asmType.getDescriptor().replace('/', '.'))
|
Type.ARRAY -> Class.forName(asmType.descriptor.replace('/', '.'))
|
||||||
else -> throw UnsupportedOperationException("Unsupported type: $asmType")
|
else -> throw UnsupportedOperationException("Unsupported type: $asmType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,14 +323,14 @@ class ReflectionLookup(val classLoader: ClassLoader) {
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun Class<Any>.findMethod(methodDesc: MethodDescription): Method? {
|
fun Class<Any>.findMethod(methodDesc: MethodDescription): Method? {
|
||||||
for (declared in getDeclaredMethods()) {
|
for (declared in declaredMethods) {
|
||||||
if (methodDesc.matches(declared)) return declared
|
if (methodDesc.matches(declared)) return declared
|
||||||
}
|
}
|
||||||
|
|
||||||
val fromSuperClass = (getSuperclass() as Class<Any>).findMethod(methodDesc)
|
val fromSuperClass = (superclass as Class<Any>).findMethod(methodDesc)
|
||||||
if (fromSuperClass != null) return fromSuperClass
|
if (fromSuperClass != null) return fromSuperClass
|
||||||
|
|
||||||
for (supertype in getInterfaces()) {
|
for (supertype in interfaces) {
|
||||||
val fromSuper = (supertype as Class<Any>).findMethod(methodDesc)
|
val fromSuper = (supertype as Class<Any>).findMethod(methodDesc)
|
||||||
if (fromSuper != null) return fromSuper
|
if (fromSuper != null) return fromSuper
|
||||||
}
|
}
|
||||||
@@ -343,15 +340,15 @@ fun Class<Any>.findMethod(methodDesc: MethodDescription): Method? {
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun Class<Any>.findConstructor(methodDesc: MethodDescription): Constructor<Any?>? {
|
fun Class<Any>.findConstructor(methodDesc: MethodDescription): Constructor<Any?>? {
|
||||||
for (declared in getDeclaredConstructors()) {
|
for (declared in declaredConstructors) {
|
||||||
if (methodDesc.matches(declared)) return declared as Constructor<Any?>
|
if (methodDesc.matches(declared)) return declared as Constructor<Any?>
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodDescription.matches(ctor: Constructor<*>): Boolean {
|
fun MethodDescription.matches(ctor: Constructor<*>): Boolean {
|
||||||
val methodParams = ctor.getParameterTypes()!!
|
val methodParams = ctor.parameterTypes!!
|
||||||
if (parameterTypes.size() != methodParams.size()) return false
|
if (parameterTypes.size != methodParams.size) return false
|
||||||
for ((i, p) in parameterTypes.withIndex()) {
|
for ((i, p) in parameterTypes.withIndex()) {
|
||||||
if (!p.matches(methodParams[i])) return false
|
if (!p.matches(methodParams[i])) return false
|
||||||
}
|
}
|
||||||
@@ -360,30 +357,30 @@ fun MethodDescription.matches(ctor: Constructor<*>): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun MethodDescription.matches(method: Method): Boolean {
|
fun MethodDescription.matches(method: Method): Boolean {
|
||||||
if (name != method.getName()) return false
|
if (name != method.name) return false
|
||||||
|
|
||||||
val methodParams = method.getParameterTypes()!!
|
val methodParams = method.parameterTypes!!
|
||||||
if (parameterTypes.size() != methodParams.size()) return false
|
if (parameterTypes.size != methodParams.size) return false
|
||||||
for ((i, p) in parameterTypes.withIndex()) {
|
for ((i, p) in parameterTypes.withIndex()) {
|
||||||
if (!p.matches(methodParams[i])) return false
|
if (!p.matches(methodParams[i])) return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnType.matches(method.getReturnType()!!)
|
return returnType.matches(method.returnType!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun Class<Any>.findField(fieldDesc: FieldDescription): Field? {
|
fun Class<Any>.findField(fieldDesc: FieldDescription): Field? {
|
||||||
for (declared in getDeclaredFields()) {
|
for (declared in declaredFields) {
|
||||||
if (fieldDesc.matches(declared)) return declared
|
if (fieldDesc.matches(declared)) return declared
|
||||||
}
|
}
|
||||||
|
|
||||||
val superclass = getSuperclass()
|
val superclass = superclass
|
||||||
if (superclass != null) {
|
if (superclass != null) {
|
||||||
val fromSuperClass = (superclass as Class<Any>).findField(fieldDesc)
|
val fromSuperClass = (superclass as Class<Any>).findField(fieldDesc)
|
||||||
if (fromSuperClass != null) return fromSuperClass
|
if (fromSuperClass != null) return fromSuperClass
|
||||||
}
|
}
|
||||||
|
|
||||||
for (supertype in getInterfaces()) {
|
for (supertype in interfaces) {
|
||||||
val fromSuper = (supertype as Class<Any>).findField(fieldDesc)
|
val fromSuper = (supertype as Class<Any>).findField(fieldDesc)
|
||||||
if (fromSuper != null) return fromSuper
|
if (fromSuper != null) return fromSuper
|
||||||
}
|
}
|
||||||
@@ -392,9 +389,9 @@ fun Class<Any>.findField(fieldDesc: FieldDescription): Field? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun FieldDescription.matches(field: Field): Boolean {
|
fun FieldDescription.matches(field: Field): Boolean {
|
||||||
if (name != field.getName()) return false
|
if (name != field.name) return false
|
||||||
|
|
||||||
return fieldType.matches(field.getType()!!)
|
return fieldType.matches(field.type!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Type.matches(_class: Class<*>): Boolean = this == Type.getType(_class)
|
fun Type.matches(_class: Class<*>): Boolean = this == Type.getType(_class)
|
||||||
@@ -16,29 +16,28 @@
|
|||||||
|
|
||||||
package org.jetbrains.eval4j.test
|
package org.jetbrains.eval4j.test
|
||||||
|
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
import junit.framework.TestSuite
|
||||||
|
import org.jetbrains.eval4j.ExceptionThrown
|
||||||
|
import org.jetbrains.eval4j.InterpreterResult
|
||||||
|
import org.jetbrains.eval4j.ObjectValue
|
||||||
|
import org.jetbrains.eval4j.ValueReturned
|
||||||
|
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||||
|
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||||
|
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
import org.jetbrains.eval4j.*
|
|
||||||
import org.junit.Assert.*
|
|
||||||
import junit.framework.TestSuite
|
|
||||||
import junit.framework.TestCase
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Constructor
|
|
||||||
import java.lang.reflect.InvocationTargetException
|
|
||||||
import java.lang.reflect.Array as JArray
|
import java.lang.reflect.Array as JArray
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
|
||||||
|
|
||||||
fun buildTestSuite(
|
fun buildTestSuite(
|
||||||
create: (MethodNode, Class<*>, InterpreterResult?) -> TestCase
|
create: (MethodNode, Class<*>, InterpreterResult?) -> TestCase
|
||||||
): TestSuite {
|
): TestSuite {
|
||||||
val suite = TestSuite()
|
val suite = TestSuite()
|
||||||
|
|
||||||
val ownerClass = javaClass<TestData>()
|
val ownerClass = TestData::class.java
|
||||||
val inputStream = ownerClass.getClassLoader()!!.getResourceAsStream(ownerClass.getInternalName() + ".class")!!
|
val inputStream = ownerClass.classLoader!!.getResourceAsStream(ownerClass.getInternalName() + ".class")!!
|
||||||
|
|
||||||
ClassReader(inputStream).accept(object : ClassVisitor(ASM5) {
|
ClassReader(inputStream).accept(object : ClassVisitor(ASM5) {
|
||||||
|
|
||||||
@@ -61,27 +60,27 @@ private fun buildTestCase(ownerClass: Class<TestData>,
|
|||||||
methodNode: MethodNode,
|
methodNode: MethodNode,
|
||||||
create: (MethodNode, Class<out Any?>, InterpreterResult?) -> TestCase): TestCase? {
|
create: (MethodNode, Class<out Any?>, InterpreterResult?) -> TestCase): TestCase? {
|
||||||
var expected: InterpreterResult? = null
|
var expected: InterpreterResult? = null
|
||||||
for (method in ownerClass.getDeclaredMethods()) {
|
for (method in ownerClass.declaredMethods) {
|
||||||
if (method.getName() == methodNode.name) {
|
if (method.name == methodNode.name) {
|
||||||
val isStatic = (method.getModifiers() and Modifier.STATIC) != 0
|
val isStatic = (method.modifiers and Modifier.STATIC) != 0
|
||||||
if (method.getParameterTypes()!!.size() > 0) {
|
if (method.parameterTypes!!.size > 0) {
|
||||||
println("Skipping method with parameters: $method")
|
println("Skipping method with parameters: $method")
|
||||||
}
|
}
|
||||||
else if (!isStatic && !method.getName()!!.startsWith("test")) {
|
else if (!isStatic && !method.name!!.startsWith("test")) {
|
||||||
println("Skipping instance method (should be started with 'test') : $method")
|
println("Skipping instance method (should be started with 'test') : $method")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
method.setAccessible(true)
|
method.isAccessible = true
|
||||||
try {
|
try {
|
||||||
val result = method.invoke(if (isStatic) null else ownerClass.newInstance())
|
val result = method.invoke(if (isStatic) null else ownerClass.newInstance())
|
||||||
val returnType = Type.getType(method.getReturnType()!!)
|
val returnType = Type.getType(method.returnType!!)
|
||||||
expected = ValueReturned(objectToValue(result, returnType))
|
expected = ValueReturned(objectToValue(result, returnType))
|
||||||
}
|
}
|
||||||
catch (e: UnsupportedOperationException) {
|
catch (e: UnsupportedOperationException) {
|
||||||
println("Skipping $method: $e")
|
println("Skipping $method: $e")
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
val cause = e.getCause() ?: e
|
val cause = e.cause ?: e
|
||||||
expected = ExceptionThrown(objectToValue(cause, Type.getType(cause.javaClass)) as ObjectValue, ExceptionThrown.ExceptionKind.FROM_EVALUATOR)
|
expected = ExceptionThrown(objectToValue(cause, Type.getType(cause.javaClass)) as ObjectValue, ExceptionThrown.ExceptionKind.FROM_EVALUATOR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user