diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 5cdf454a519..f295d24d353 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1539,20 +1539,7 @@ public class ExpressionCodegen extends JetVisitor 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 implem else { result.put(Type.VOID_TYPE, v); } + + removeDescriptorFromFrameMap(statement, blockEnd, leaveTasks); } return new StackValueWithLeaveTask(answer, new ExtensionFunction0() { @@ -1583,34 +1572,97 @@ public class ExpressionCodegen extends JetVisitor 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(), "", "()V", false); + v.store(index, OBJECT_TYPE); + } + } + + private void removeDescriptorFromFrameMap( + @NotNull JetElement statement, + @NotNull Label blockEnd, @NotNull List> 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() { + @Override + public Void fun(StackValue value) { + myFrameMap.leave(descriptor); + return null; + } + }); + } + } + + private void removeLocalVariableFromFrameMap( + @NotNull JetVariableDeclaration statement, + final Label blockEnd, + @NotNull List> 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(), "", "()V", false); - v.store(index, OBJECT_TYPE); - } - leaveTasks.add(new Function() { @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 implem }); } - private void generateLocalFunctionDeclaration( - @NotNull JetNamedFunction namedFunction, - @NotNull List> leaveTasks - ) { - final DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, namedFunction); - myFrameMap.enter(descriptor, OBJECT_TYPE); - - leaveTasks.add(new Function() { - @Override - public Void fun(StackValue value) { - myFrameMap.leave(descriptor); - return null; - } - }); - } - public boolean isShouldMarkLineNumbers() { return shouldMarkLineNumbers; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 7218c24d257..bd772d304fd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -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"); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java index aa5dd6d7a08..7a2ad64748f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java @@ -154,6 +154,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer { int from = insnList.indexOf(localVariableNode.start) + 1; int to = insnList.indexOf(localVariableNode.end) - 1; + Frame 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; diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index ec84171e480..b84c2acc3e7 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -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) { diff --git a/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out b/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out index cc8710e395f..4dc7e966b8e 100644 --- a/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out +++ b/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out @@ -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 - 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameLocalVariable.out b/idea/testData/debugger/tinyApp/outs/frameLocalVariable.out new file mode 100644 index 00000000000..d851902da5c --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/frameLocalVariable.out @@ -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) { + 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 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLocalVariable.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLocalVariable.kt new file mode 100644 index 00000000000..27f9870a508 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameLocalVariable.kt @@ -0,0 +1,9 @@ +package frameLocalVariable + +fun main(args: Array) { + val val1 = 1 + //Breakpoint! + val val2 = 1 +} + +// PRINT_FRAME \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index d68fa5efd53..d37cb54aed0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -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");