Generate debug information for 'when' subject variable

NB debugger tests currently don't support language version or individual
language feature settings.
This commit is contained in:
Dmitry Petrov
2018-06-19 15:57:22 +03:00
parent a7492e91c9
commit a4b5d74ae3
7 changed files with 98 additions and 7 deletions
@@ -4513,11 +4513,12 @@ The "returned" value of try expression with no finally is either the last expres
int subjectLocal;
Type subjectType;
VariableDescriptor subjectVariableDescriptor = null;
if (subjectVariable != null) {
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable);
assert variableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName();
subjectType = asmType(variableDescriptor.getType());
subjectLocal = myFrameMap.enter(variableDescriptor, subjectType);
subjectVariableDescriptor = bindingContext.get(BindingContext.VARIABLE, subjectVariable);
assert subjectVariableDescriptor != null : "Unresolved subject variable: " + subjectVariable.getName();
subjectType = asmType(subjectVariableDescriptor.getType());
subjectLocal = myFrameMap.enter(subjectVariableDescriptor, subjectType);
visitProperty(subjectVariable, null);
tempVariables.put(subjectExpression, StackValue.local(subjectLocal, subjectType));
}
@@ -4533,6 +4534,9 @@ The "returned" value of try expression with no finally is either the last expres
subjectType = Type.VOID_TYPE;
}
Label begin = new Label();
v.mark(begin);
Label end = new Label();
boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression);
@@ -4572,7 +4576,16 @@ The "returned" value of try expression with no finally is either the last expres
markLineNumber(expression, isStatement);
v.mark(end);
myFrameMap.leaveTemp(subjectType);
if (subjectVariableDescriptor != null) {
myFrameMap.leave(subjectVariableDescriptor);
v.visitLocalVariable(
subjectVariableDescriptor.getName().asString(), subjectType.getDescriptor(), null,
begin, end, subjectLocal
);
}
else {
myFrameMap.leaveTemp(subjectType);
}
tempVariables.remove(subjectExpression);
return null;
});
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.`when`
import org.jetbrains.kotlin.cfg.WhenChecker
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.ConstantValue
@@ -69,6 +70,9 @@ abstract class SwitchCodegen(
generateSubjectValue()
generateSubjectValueToIndex()
val beginLabel = Label()
v.mark(beginLabel)
generateSwitchInstructionByTransitionsTable()
generateEntries()
@@ -81,6 +85,13 @@ abstract class SwitchCodegen(
codegen.markLineNumber(expression, isStatement)
v.mark(endLabel)
subjectVariableDescriptor?.let {
v.visitLocalVariable(
it.name.asString(), subjectType.descriptor, null,
beginLabel, endLabel, subjectLocal
)
}
}
/**
@@ -115,19 +126,23 @@ abstract class SwitchCodegen(
}
}
private var subjectVariableDescriptor: VariableDescriptor? = null
/**
* Generates subject value on top of the stack.
* If the subject is a variable, it's stored and loaded.
*/
private fun generateSubjectValue() {
if (subjectVariable != null) {
val variableDescriptor = bindingContext[BindingContext.VARIABLE, subjectVariable]
val mySubjectVariable = bindingContext[BindingContext.VARIABLE, subjectVariable]
?: throw AssertionError("Unresolved subject variable: $expression")
subjectLocal = codegen.frameMap.enter(variableDescriptor, subjectType)
subjectLocal = codegen.frameMap.enter(mySubjectVariable, subjectType)
codegen.visitProperty(subjectVariable, null)
StackValue.local(subjectLocal, subjectType).put(subjectType, codegen.v)
subjectVariableDescriptor = mySubjectVariable
} else {
codegen.gen(subjectExpression, subjectType)
subjectVariableDescriptor = null
}
}
@@ -0,0 +1,10 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
fun test(a: Any) =
when (val subject = a) {
is Int -> "Int $subject"
is String -> "String ${subject.length}"
else -> "other"
}
// 1 LOCALVARIABLE subject Ljava/lang/Object;
@@ -0,0 +1,12 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
enum class X { A, B, C }
fun test(a: X) =
when (val subject = a) {
X.A -> 0
X.B -> 1
X.C -> 2
}
// 1 LOCALVARIABLE subject
@@ -0,0 +1,11 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
fun test(a: Int) =
when (val subject = a) {
1 -> 0
2 -> 1
3 -> 2
else -> -1
}
// 1 LOCALVARIABLE subject
@@ -0,0 +1,10 @@
// !LANGUAGE: +VariableDeclarationInWhenSubject
fun test(a: String) =
when (val subject = a) {
"" -> 0
"a" -> 1
else -> -1
}
// 1 LOCALVARIABLE subject
@@ -2811,6 +2811,26 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/when/simpleConstValsInsideWhen.kt");
}
@TestMetadata("subjectValHasLocalVariableSlot.kt")
public void testSubjectValHasLocalVariableSlot() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/when/subjectValHasLocalVariableSlot.kt");
}
@TestMetadata("subjectValInEnumWhenHasLocalVariableSlot.kt")
public void testSubjectValInEnumWhenHasLocalVariableSlot() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/when/subjectValInEnumWhenHasLocalVariableSlot.kt");
}
@TestMetadata("subjectValInIntWhenHasLocalVariableSlot.kt")
public void testSubjectValInIntWhenHasLocalVariableSlot() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/when/subjectValInIntWhenHasLocalVariableSlot.kt");
}
@TestMetadata("subjectValInStringWhenHasLocalVariableSlot.kt")
public void testSubjectValInStringWhenHasLocalVariableSlot() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/when/subjectValInStringWhenHasLocalVariableSlot.kt");
}
@TestMetadata("whenNull.kt")
public void testWhenNull() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/when/whenNull.kt");