Debugger: Hide call-site 'this' in inline functions in Kotlin variables mode (KT-30610)

This commit is contained in:
Yan Zhulanow
2019-03-27 22:02:00 +03:00
parent 6dcaa64793
commit b7ea4ccc7e
8 changed files with 59 additions and 7 deletions
@@ -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";
@@ -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))
}
}
@@ -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
}
@@ -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)
@@ -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)
@@ -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
@@ -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
@@ -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");