Local variable shouldn't be visible in debugger before initialization
This commit is contained in:
@@ -1539,20 +1539,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statement instanceof JetMultiDeclaration) {
|
putDescriptorIntoFrameMap(statement);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isExpression = !iterator.hasNext() && !isStatement;
|
boolean isExpression = !iterator.hasNext() && !isStatement;
|
||||||
if (isExpression && labelBeforeLastExpression != null) {
|
if (isExpression && labelBeforeLastExpression != null) {
|
||||||
@@ -1567,6 +1554,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
else {
|
else {
|
||||||
result.put(Type.VOID_TYPE, v);
|
result.put(Type.VOID_TYPE, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StackValueWithLeaveTask(answer, new ExtensionFunction0<StackValueWithLeaveTask, Unit>() {
|
return new StackValueWithLeaveTask(answer, new ExtensionFunction0<StackValueWithLeaveTask, Unit>() {
|
||||||
@@ -1583,34 +1572,97 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateLocalVariableDeclaration(
|
@NotNull
|
||||||
@NotNull JetVariableDeclaration variableDeclaration,
|
private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) {
|
||||||
final @NotNull Label blockEnd,
|
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
|
@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;
|
assert variableDescriptor != null;
|
||||||
|
|
||||||
|
final Type type = getVariableType(variableDescriptor);
|
||||||
|
|
||||||
final Label scopeStart = new Label();
|
final Label scopeStart = new Label();
|
||||||
v.mark(scopeStart);
|
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>() {
|
leaveTasks.add(new Function<StackValue, Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void fun(StackValue answer) {
|
public Void fun(StackValue answer) {
|
||||||
int index = myFrameMap.leave(variableDescriptor);
|
int index = myFrameMap.leave(variableDescriptor);
|
||||||
|
|
||||||
if (sharedVarType != null) {
|
if (isSharedVarType(type)) {
|
||||||
v.aconst(null);
|
v.aconst(null);
|
||||||
v.store(index, OBJECT_TYPE);
|
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() {
|
public boolean isShouldMarkLineNumbers() {
|
||||||
return shouldMarkLineNumbers;
|
return shouldMarkLineNumbers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1235,7 +1235,7 @@ public abstract class StackValue {
|
|||||||
if (primitiveType == null) throw new UnsupportedOperationException();
|
if (primitiveType == null) throw new UnsupportedOperationException();
|
||||||
|
|
||||||
String typeName = primitiveType.getTypeName().getIdentifier();
|
String typeName = primitiveType.getTypeName().getIdentifier();
|
||||||
return Type.getObjectType("kotlin/jvm/internal/Ref$" + typeName + "Ref");
|
return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -154,6 +154,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
|||||||
int from = insnList.indexOf(localVariableNode.start) + 1;
|
int from = insnList.indexOf(localVariableNode.start) + 1;
|
||||||
int to = insnList.indexOf(localVariableNode.end) - 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++) {
|
for (int i = from; i <= to; i++) {
|
||||||
if (i < 0 || i >= insnList.size()) continue;
|
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 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
|
@NotNull
|
||||||
private static Type reflectInternal(@NotNull String className) {
|
private static Type reflectInternal(@NotNull String className) {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ fun foo(f: () -> Unit) {
|
|||||||
// RESULT: Cannot find local variable: name = val1
|
// RESULT: Cannot find local variable: name = val1
|
||||||
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
|
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
|
||||||
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
|
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'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
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
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package frameLocalVariable
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val val1 = 1
|
||||||
|
//Breakpoint!
|
||||||
|
val val2 = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINT_FRAME
|
||||||
+6
@@ -294,6 +294,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doSingleBreakpointTest(fileName);
|
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")
|
@TestMetadata("frameObject.kt")
|
||||||
public void testFrameObject() throws Exception {
|
public void testFrameObject() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameObject.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameObject.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user