From b7ea4ccc7e2269cc26d895b844f6bc7c141e0b6d Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 27 Mar 2019 22:02:00 +0300 Subject: [PATCH] Debugger: Hide call-site 'this' in inline functions in Kotlin variables mode (KT-30610) --- .../org/jetbrains/kotlin/codegen/AsmUtil.java | 2 ++ .../kotlin/codegen/inline/MethodInliner.kt | 2 +- .../kotlin/idea/debugger/KotlinStackFrame.kt | 18 ++++++++++++++++ .../evaluate/variables/VariableFinder.kt | 5 +---- ...eFunCallInsideInlineFunKotlinVariables.out | 2 -- .../frame/inlineFunThisKotlinVariables.kt | 21 +++++++++++++++++++ .../frame/inlineFunThisKotlinVariables.out | 11 ++++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 5 +++++ 8 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.out diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 70b377bb2aa..d8d76f23019 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -104,6 +104,8 @@ public class AsmUtil { public static final String LABELED_THIS_FIELD = THIS + "_"; + public static final String INLINE_DECLARATION_SITE_THIS = "this_"; + public static final String LABELED_THIS_PARAMETER = "$" + THIS + "$"; public static final String CAPTURED_THIS_FIELD = "this$0"; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 79e8f40fcaa..5bc71e90407 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -487,7 +487,7 @@ class MethodInliner( ) { if (isInliningLambda || GENERATE_DEBUG_INFO) { val varSuffix = if (inliningContext.isRoot && !isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else "" - val varName = if (!varSuffix.isEmpty() && name == "this") name + "_" else name + val varName = if (!varSuffix.isEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index)) } } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt index fbcdc569c97..520ce7ef912 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinStackFrame.kt @@ -111,6 +111,24 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe return true } + return removeCallSiteThisInInlineFunction(evaluationContext, children) + } + + private fun removeCallSiteThisInInlineFunction(evaluationContext: EvaluationContextImpl, children: XValueChildrenList): Boolean { + val frameProxy = evaluationContext.frameProxy + + val variables = frameProxy?.safeVisibleVariables() ?: return false + val inlineDepth = VariableFinder.getInlineDepth(variables) + val declarationSiteThis = variables.firstOrNull { v -> + val name = v.name() + name.endsWith(INLINE_FUN_VAR_SUFFIX) && name.dropInlineSuffix() == AsmUtil.INLINE_DECLARATION_SITE_THIS + } + + if (inlineDepth > 0 && declarationSiteThis != null) { + ExistingInstanceThis.find(children)?.remove() + return true + } + return false } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt index 795c48b1229..f38acbc27db 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt @@ -75,10 +75,7 @@ class VariableFinder(private val context: ExecutionContext) { return EvaluateExceptionUtil.createEvaluateException(message) } - // org.jetbrains.kotlin.codegen.inline.MethodInliner.prepareNode - private const val OUTER_THIS_FOR_INLINE = AsmUtil.THIS + '_' - - val inlinedThisRegex = getLocalVariableNameRegexInlineAware(OUTER_THIS_FOR_INLINE) + val inlinedThisRegex = getLocalVariableNameRegexInlineAware(AsmUtil.INLINE_DECLARATION_SITE_THIS) private fun getCapturedVariableNameRegex(capturedName: String): Regex { val escapedName = Regex.escape(capturedName) diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out index 7d45041e2c7..d82de89c039 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/frameInlineFunCallInsideInlineFunKotlinVariables.out @@ -7,8 +7,6 @@ frameInlineFunCallInsideInlineFunKotlinVariables.kt:8 Compile bytecode for element Compile bytecode for this.prop frame = bar:8, C {frameInlineFunCallInsideInlineFunKotlinVariables} - this = this = {frameInlineFunCallInsideInlineFunKotlinVariables.C@uniqueID} - - Class has no fields local = this: frameInlineFunCallInsideInlineFunKotlinVariables.A = {frameInlineFunCallInsideInlineFunKotlinVariables.A@uniqueID} (sp = null) field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 11) local = element: double = 1.0 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 7) diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt new file mode 100644 index 00000000000..842fcd99ff7 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt @@ -0,0 +1,21 @@ +package inlineFunThisKotlinVariables + +class Same { + fun useInline() { + Different().inlineFun() + } +} + +class Different { + inline fun inlineFun() { + //Breakpoint! + println(1) + } +} + +fun main() { + Same().useInline() +} + +// PRINT_FRAME +// SHOW_KOTLIN_VARIABLES \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.out new file mode 100644 index 00000000000..b5d203c2710 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.out @@ -0,0 +1,11 @@ +LineBreakpoint created at inlineFunThisKotlinVariables.kt:12 +Run Java +Connected to the target VM +inlineFunThisKotlinVariables.kt:12 + frame = useInline:12, Same {inlineFunThisKotlinVariables} + local = this: inlineFunThisKotlinVariables.Different = {inlineFunThisKotlinVariables.Different@uniqueID} (sp = null) + - Class has no fields +Disconnected from the target VM + +Process finished with exit code 0 +1 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 54c2ea517f1..9a2c7e02cfd 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -800,6 +800,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/hideSyntheticThis.kt"); } + @TestMetadata("inlineFunThisKotlinVariables.kt") + public void testInlineFunThisKotlinVariables() throws Exception { + runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt"); + } + @TestMetadata("lambdaFun1.kt") public void testLambdaFun1() throws Exception { runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/lambdaFun1.kt");