Local variable shouldn't be visible in debugger before initialization

This commit is contained in:
Natalia Ukhorskaya
2015-01-13 16:42:09 +03:00
parent 89f8442705
commit f5aefc96fb
8 changed files with 128 additions and 49 deletions
@@ -1539,20 +1539,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
if (statement instanceof JetMultiDeclaration) {
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
generateLocalVariableDeclaration(entry, blockEnd, leaveTasks);
}
}
if (statement instanceof JetVariableDeclaration) {
generateLocalVariableDeclaration((JetVariableDeclaration) statement, blockEnd, leaveTasks);
}
if (statement instanceof JetNamedFunction) {
generateLocalFunctionDeclaration((JetNamedFunction) statement, leaveTasks);
}
putDescriptorIntoFrameMap(statement);
boolean isExpression = !iterator.hasNext() && !isStatement;
if (isExpression && labelBeforeLastExpression != null) {
@@ -1567,6 +1554,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
else {
result.put(Type.VOID_TYPE, v);
}
removeDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
}
return new StackValueWithLeaveTask(answer, new ExtensionFunction0<StackValueWithLeaveTask, Unit>() {
@@ -1583,34 +1572,97 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
});
}
private void generateLocalVariableDeclaration(
@NotNull JetVariableDeclaration variableDeclaration,
final @NotNull Label blockEnd,
@NotNull
private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) {
Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
return sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
}
private static boolean isSharedVarType(@NotNull Type type) {
return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
}
private void putDescriptorIntoFrameMap(@NotNull JetElement statement) {
if (statement instanceof JetMultiDeclaration) {
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
putLocalVariableIntoFrameMap(entry);
}
}
if (statement instanceof JetVariableDeclaration) {
putLocalVariableIntoFrameMap((JetVariableDeclaration) statement);
}
if (statement instanceof JetNamedFunction) {
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
myFrameMap.enter(descriptor, OBJECT_TYPE);
}
}
private void putLocalVariableIntoFrameMap(@NotNull JetVariableDeclaration statement) {
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
assert variableDescriptor != null;
Type type = getVariableType(variableDescriptor);
int index = myFrameMap.enter(variableDescriptor, type);
if (isSharedVarType(type)) {
v.anew(type);
v.dup();
v.invokespecial(type.getInternalName(), "<init>", "()V", false);
v.store(index, OBJECT_TYPE);
}
}
private void removeDescriptorFromFrameMap(
@NotNull JetElement statement,
@NotNull Label blockEnd,
@NotNull List<Function<StackValue, Void>> leaveTasks
) {
final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
if (statement instanceof JetMultiDeclaration) {
JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
removeLocalVariableFromFrameMap(entry, blockEnd, leaveTasks);
}
}
if (statement instanceof JetVariableDeclaration) {
removeLocalVariableFromFrameMap((JetVariableDeclaration) statement, blockEnd, leaveTasks);
}
if (statement instanceof JetNamedFunction) {
final DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
leaveTasks.add(new Function<StackValue, Void>() {
@Override
public Void fun(StackValue value) {
myFrameMap.leave(descriptor);
return null;
}
});
}
}
private void removeLocalVariableFromFrameMap(
@NotNull JetVariableDeclaration statement,
final Label blockEnd,
@NotNull List<Function<StackValue, Void>> leaveTasks
) {
final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
assert variableDescriptor != null;
final Type type = getVariableType(variableDescriptor);
final Label scopeStart = new Label();
v.mark(scopeStart);
final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
int index = myFrameMap.enter(variableDescriptor, type);
if (sharedVarType != null) {
v.anew(sharedVarType);
v.dup();
v.invokespecial(sharedVarType.getInternalName(), "<init>", "()V", false);
v.store(index, OBJECT_TYPE);
}
leaveTasks.add(new Function<StackValue, Void>() {
@Override
public Void fun(StackValue answer) {
int index = myFrameMap.leave(variableDescriptor);
if (sharedVarType != null) {
if (isSharedVarType(type)) {
v.aconst(null);
v.store(index, OBJECT_TYPE);
}
@@ -1620,22 +1672,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
});
}
private void generateLocalFunctionDeclaration(
@NotNull JetNamedFunction namedFunction,
@NotNull List<Function<StackValue, Void>> leaveTasks
) {
final DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, namedFunction);
myFrameMap.enter(descriptor, OBJECT_TYPE);
leaveTasks.add(new Function<StackValue, Void>() {
@Override
public Void fun(StackValue value) {
myFrameMap.leave(descriptor);
return null;
}
});
}
public boolean isShouldMarkLineNumbers() {
return shouldMarkLineNumbers;
}
@@ -1235,7 +1235,7 @@ public abstract class StackValue {
if (primitiveType == null) throw new UnsupportedOperationException();
String typeName = primitiveType.getTypeName().getIdentifier();
return Type.getObjectType("kotlin/jvm/internal/Ref$" + typeName + "Ref");
return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
}
}
@@ -154,6 +154,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
int from = insnList.indexOf(localVariableNode.start) + 1;
int to = insnList.indexOf(localVariableNode.end) - 1;
Frame<BasicValue> frameForFromInstr = frames[from];
if (frameForFromInstr != null) {
BasicValue localVarValue = frameForFromInstr.getLocal(localVariableNode.index);
if (localVarValue != null) {
values.add(localVarValue);
}
}
for (int i = from; i <= to; i++) {
if (i < 0 || i >= insnList.size()) continue;
@@ -45,7 +45,8 @@ public class AsmTypes {
public static final String REFLECTION_INTERNAL_PACKAGE = reflectInternal("InternalPackage").getInternalName();
public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef");
public static final String REF_TYPE_PREFIX = "kotlin/jvm/internal/Ref$";
public static final Type OBJECT_REF_TYPE = Type.getObjectType(REF_TYPE_PREFIX + "ObjectRef");
@NotNull
private static Type reflectInternal(@NotNull String className) {
@@ -23,7 +23,6 @@ fun foo(f: () -> Unit) {
// RESULT: Cannot find local variable: name = val1
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
local = a: int = 0 (sp = frameLambdaNotUsed.kt, 7)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,20 @@
LineBreakpoint created at frameLocalVariable.kt:6
!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! frameLocalVariable.FrameLocalVariablePackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
frameLocalVariable.kt:6
package frameLocalVariable
fun main(args: Array<String>) {
val val1 = 1
//Breakpoint!
val val2 = 1
}
// PRINT_FRAME
frame = main():6, FrameLocalVariablePackage$@packagePartHASH {frameLocalVariable}
static = static = frameLocalVariable.FrameLocalVariablePackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameLocalVariable.kt, 3)
local = val1: int = 1 (sp = frameLocalVariable.kt, 4)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,9 @@
package frameLocalVariable
fun main(args: Array<String>) {
val val1 = 1
//Breakpoint!
val val2 = 1
}
// PRINT_FRAME
@@ -294,6 +294,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
doSingleBreakpointTest(fileName);
}
@TestMetadata("frameLocalVariable.kt")
public void testFrameLocalVariable() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLocalVariable.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("frameObject.kt")
public void testFrameObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameObject.kt");