Evaluate Expression: box and unbox arguments before running JDIEval
This commit is contained in:
@@ -212,19 +212,23 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) {
|
||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
if (name == compiledData.funName) {
|
||||
val args = context.getArgumentsForEval4j(compiledData.parameters.getParameterNames(), Type.getArgumentTypes(desc))
|
||||
val argumentTypes = Type.getArgumentTypes(desc)
|
||||
val args = context.getArgumentsForEval4j(compiledData.parameters.getParameterNames(), argumentTypes)
|
||||
|
||||
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
|
||||
override fun visitEnd() {
|
||||
val breakpoints = virtualMachine.eventRequestManager().breakpointRequests()
|
||||
breakpoints?.forEach { it.disable() }
|
||||
|
||||
val eval = JDIEval(virtualMachine,
|
||||
context.getClassLoader(),
|
||||
context.getSuspendContext().getThread()?.getThreadReference()!!,
|
||||
context.getSuspendContext().getInvokePolicy())
|
||||
|
||||
resultValue = interpreterLoop(
|
||||
this,
|
||||
makeInitialFrame(this, args),
|
||||
JDIEval(virtualMachine,
|
||||
context.getClassLoader(),
|
||||
context.getSuspendContext().getThread()?.getThreadReference()!!,
|
||||
context.getSuspendContext().getInvokePolicy())
|
||||
makeInitialFrame(this, args.zip(argumentTypes).map { boxOrUnboxArgumentIfNeeded(eval, it.first, it.second) }),
|
||||
eval
|
||||
)
|
||||
|
||||
breakpoints?.forEach { it.enable() }
|
||||
@@ -239,6 +243,29 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}")
|
||||
}
|
||||
|
||||
private fun boxOrUnboxArgumentIfNeeded(eval: JDIEval, argumentValue: Value, parameterType: Type): Value {
|
||||
val argumentType = argumentValue.asmType
|
||||
|
||||
if (AsmUtil.isPrimitive(parameterType) && !AsmUtil.isPrimitive(argumentType)) {
|
||||
try {
|
||||
val unboxedType = AsmUtil.unboxType(argumentType)
|
||||
if (parameterType == unboxedType) {
|
||||
return eval.unboxType(argumentValue, parameterType)
|
||||
}
|
||||
}
|
||||
catch(ignored: UnsupportedOperationException) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!AsmUtil.isPrimitive(parameterType) && AsmUtil.isPrimitive(argumentType)) {
|
||||
if (parameterType == AsmUtil.boxType(argumentType)) {
|
||||
return eval.boxType(argumentValue)
|
||||
}
|
||||
}
|
||||
|
||||
return argumentValue
|
||||
}
|
||||
|
||||
private fun InterpreterResult.toJdiValue(vm: VirtualMachine): com.sun.jdi.Value? {
|
||||
val jdiValue = when (this) {
|
||||
is ValueReturned -> result
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at boxParam.kt:13
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! boxParam.BoxParamPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
boxParam.kt:13
|
||||
Compile bytecode for nullableInt?.plus(1)
|
||||
Compile bytecode for nullableByte?.plus(1)
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at unboxParam.kt:12
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! unboxParam.UnboxParamPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
unboxParam.kt:12
|
||||
Compile bytecode for fooInt(nullableInt)
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,14 @@
|
||||
package boxParam
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val nullableInt: Int? = 1
|
||||
val nullableByte: Byte? = 1
|
||||
|
||||
// EXPRESSION: nullableInt?.plus(1)
|
||||
// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer;
|
||||
|
||||
// EXPRESSION: nullableByte?.plus(1)
|
||||
// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer;
|
||||
//Breakpoint!
|
||||
val i = 1
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package unboxParam
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val nullableInt = fooNullableInt()
|
||||
if (nullableInt == null) {
|
||||
return
|
||||
}
|
||||
|
||||
// EXPRESSION: fooInt(nullableInt)
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val a = fooInt(nullableInt)
|
||||
}
|
||||
|
||||
fun fooNullableInt(): Int? = 1
|
||||
|
||||
fun fooInt(param: Int) = param
|
||||
+12
@@ -55,6 +55,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("boxParam.kt")
|
||||
public void testBoxParam() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/boxParam.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callableBug.kt")
|
||||
public void testCallableBug() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/callableBug.kt");
|
||||
@@ -217,6 +223,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unboxParam.kt")
|
||||
public void testUnboxParam() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/unboxParam.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unsafeCall.kt")
|
||||
public void testUnsafeCall() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/unsafeCall.kt");
|
||||
|
||||
Reference in New Issue
Block a user