Evaluate expression: support EE for shared vars

This commit is contained in:
Natalia Ukhorskaya
2014-09-23 16:32:34 +04:00
parent 8ad18df3fa
commit 4994e771d0
7 changed files with 103 additions and 12 deletions
@@ -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:
@@ -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
}
}
}
@@ -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<String>) {
@@ -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<kotlin.Unit>
field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1
@@ -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<String>) {
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
@@ -12,4 +12,7 @@ fun foo(f: () -> Unit) {
f()
}
// PRINT_FRAME
// PRINT_FRAME
// EXPRESSION: var1
// RESULT: 1: I
@@ -0,0 +1,18 @@
package frameSharedVarLocalVar
fun main(args: Array<String>) {
var var1 = 1
foo {
//Breakpoint!
var1 = 2
}
}
inline fun foo(f: () -> Unit) {
f()
}
// PRINT_FRAME
// EXPRESSION: var1
// RESULT: 1: I
@@ -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");