diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index c450df0ba6b..86736b6fe58 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -933,7 +933,8 @@ public abstract class StackValue { } } - public static Type sharedTypeForType(Type type) { + @NotNull + public static Type sharedTypeForType(@NotNull Type type) { switch (type.getSort()) { case Type.OBJECT: case Type.ARRAY: diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index da08c7233fb..69866f8fbc0 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -70,6 +70,7 @@ import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl import com.intellij.openapi.project.Project import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.codegen.StackValue private val RECEIVER_NAME = "\$receiver" private val THIS_NAME = "this" @@ -339,18 +340,12 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT if (this0 != null) return this0 } else -> { - val localVariable = frame.visibleVariableByName(name) - if (localVariable != null) { - val eval4jValue = frame.getValue(localVariable).asValue() - if (isValueOfCorrectType(eval4jValue, asmType, checkType)) return eval4jValue - } - val eval4j = JDIEval(frame.virtualMachine()!!, getClassLoader()!!, getSuspendContext().getThread()?.getThreadReference()!!, getSuspendContext().getInvokePolicy()) - fun JDIEval.getField(owner: Value, name: String, asmType: Type?): Value? { + fun JDIEval.getField(owner: Value, name: String, asmType: Type?, checkType: Boolean): Value? { val fieldDescription = FieldDescription(owner.asmType.getInternalName(), name, asmType?.getDescriptor() ?: "", isStatic = false) try { val fieldValue = getField(owner, fieldDescription) @@ -362,14 +357,39 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT } } + fun Value.isSharedVar(expectedType: Type?): Boolean { + return expectedType != null && this.asmType == StackValue.sharedTypeForType(expectedType) + } + + fun JDIEval.getValueForSharedVar(value: Value, expectedType: Type?, checkType: Boolean): Value? { + val sharedVarValue = this.getField(value, "element", expectedType, checkType) + if (sharedVarValue != null && isValueOfCorrectType(sharedVarValue, expectedType, checkType)) { + return sharedVarValue + } + return null + } + + val localVariable = frame.visibleVariableByName(name) + if (localVariable != null) { + val eval4jValue = frame.getValue(localVariable).asValue() + if (eval4jValue.isSharedVar(asmType)) { + val sharedVarValue = eval4j.getValueForSharedVar(eval4jValue, asmType, checkType) + if (sharedVarValue != null) { + return sharedVarValue + } + } + + if (isValueOfCorrectType(eval4jValue, asmType, checkType)) return eval4jValue + } + fun findCapturedVal(name: String): Value? { var result: Value? = null var thisObj: Value? = frame.thisObject().asValue() while (result == null && thisObj != null) { - result = eval4j.getField(thisObj!!, name, asmType) + result = eval4j.getField(thisObj!!, name, asmType, checkType) if (result == null) { - thisObj = eval4j.getField(thisObj!!, AsmUtil.CAPTURED_THIS_FIELD, null) + thisObj = eval4j.getField(thisObj!!, AsmUtil.CAPTURED_THIS_FIELD, null, false) } } return result @@ -377,7 +397,15 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT val capturedValName = getCapturedFieldName(name) val capturedVal = findCapturedVal(capturedValName) - if (capturedVal != null) return capturedVal + if (capturedVal != null) { + if (capturedVal.isSharedVar(asmType)) { + val sharedVarValue = eval4j.getValueForSharedVar(capturedVal, asmType, checkType) + if (sharedVarValue != null) { + return sharedVarValue + } + } + return capturedVal + } } } diff --git a/idea/testData/debugger/tinyApp/outs/frameSharedVar.out b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out index a100d961aba..980d9fad51c 100644 --- a/idea/testData/debugger/tinyApp/outs/frameSharedVar.out +++ b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out @@ -2,6 +2,7 @@ LineBreakpoint created at frameSharedVar.kt:7 !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! frameSharedVar.FrameSharedVarPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' frameSharedVar.kt:6 +Compile bytecode for var1 package frameSharedVar fun main(args: Array) { @@ -17,6 +18,9 @@ fun foo(f: () -> Unit) { } // PRINT_FRAME + +// EXPRESSION: var1 +// RESULT: 1: I frame = invoke():7, FrameSharedVarPackage$@packagePartHASH$main$1 {frameSharedVar} this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 diff --git a/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out b/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out new file mode 100644 index 00000000000..5cf128319d7 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/frameSharedVarLocalVar.out @@ -0,0 +1,31 @@ +LineBreakpoint created at frameSharedVarLocalVar.kt:7 +!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! frameSharedVarLocalVar.FrameSharedVarLocalVarPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +frameSharedVarLocalVar.kt:6 +Compile bytecode for var1 +package frameSharedVarLocalVar + +fun main(args: Array) { + var var1 = 1 + foo { + //Breakpoint! + var1 = 2 + } +} + +inline fun foo(f: () -> Unit) { + f() +} + +// PRINT_FRAME + +// EXPRESSION: var1 +// RESULT: 1: I + frame = main():7, FrameSharedVarLocalVarPackage-@packagePartHASH {frameSharedVarLocalVar} + static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage-@packagePartHASH + local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} + local = var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 + field = element: int = 1 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVar.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVar.kt index 2fad9ce8b0d..dcb8785d123 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVar.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVar.kt @@ -12,4 +12,7 @@ fun foo(f: () -> Unit) { f() } -// PRINT_FRAME \ No newline at end of file +// PRINT_FRAME + +// EXPRESSION: var1 +// RESULT: 1: I \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.kt new file mode 100644 index 00000000000..da63febf6d7 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.kt @@ -0,0 +1,18 @@ +package frameSharedVarLocalVar + +fun main(args: Array) { + var var1 = 1 + foo { + //Breakpoint! + var1 = 2 + } +} + +inline fun foo(f: () -> Unit) { + f() +} + +// PRINT_FRAME + +// EXPRESSION: var1 +// RESULT: 1: I \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index a566793c0a0..f7bb65e07dd 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -266,6 +266,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doSingleBreakpointTest(fileName); } + @TestMetadata("frameSharedVarLocalVar.kt") + public void testFrameSharedVarLocalVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSharedVarLocalVar.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("frameSimple.kt") public void testFrameSimple() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameSimple.kt");