Debugger, BE: Support lambda breakpoints for lambdas passed to '@InlineOnly' functions
This commit is contained in:
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue;
|
|||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||||
import org.jetbrains.kotlin.resolve.constants.KClassValue;
|
import org.jetbrains.kotlin.resolve.constants.KClassValue;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineOnlyKt;
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
|
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
|
||||||
@@ -76,6 +77,7 @@ import static org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.isAccessor;
|
|||||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
||||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
|
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
|
||||||
import static org.jetbrains.kotlin.descriptors.ModalityKt.isOverridable;
|
import static org.jetbrains.kotlin.descriptors.ModalityKt.isOverridable;
|
||||||
|
import static org.jetbrains.kotlin.load.java.JvmAbi.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
|
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||||
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isEffectivelyInlineOnly;
|
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isEffectivelyInlineOnly;
|
||||||
@@ -636,11 +638,19 @@ public class FunctionCodegen {
|
|||||||
frameMap.enter(continuationValueDescriptor, typeMapper.mapType(continuationValueDescriptor));
|
frameMap.enter(continuationValueDescriptor, typeMapper.mapType(continuationValueDescriptor));
|
||||||
}
|
}
|
||||||
if (context.isInlineMethodContext()) {
|
if (context.isInlineMethodContext()) {
|
||||||
functionFakeIndex = newFakeTempIndex(mv, frameMap);
|
functionFakeIndex = newFakeTempIndex(mv, frameMap, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context instanceof InlineLambdaContext) {
|
if (context instanceof InlineLambdaContext) {
|
||||||
lambdaFakeIndex = newFakeTempIndex(mv, frameMap);
|
int lineNumber = -1;
|
||||||
|
if (strategy instanceof ClosureGenerationStrategy) {
|
||||||
|
KtDeclarationWithBody declaration = ((ClosureGenerationStrategy) strategy).getDeclaration();
|
||||||
|
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||||
|
if (declaration instanceof KtFunctionLiteral && isLambdaPassedToInlineOnly((KtFunction) declaration, bindingContext)) {
|
||||||
|
lineNumber = LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lambdaFakeIndex = newFakeTempIndex(mv, frameMap, lineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
methodEntry = new Label();
|
methodEntry = new Label();
|
||||||
@@ -704,8 +714,27 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int newFakeTempIndex(@NotNull MethodVisitor mv, FrameMap frameMap) {
|
private static boolean isLambdaPassedToInlineOnly(KtFunction lambda, BindingContext bindingContext) {
|
||||||
|
ValueParameterDescriptor parameterDescriptor = InlineUtil.getInlineArgumentDescriptor(lambda, bindingContext);
|
||||||
|
if (parameterDescriptor == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallableDescriptor containingCallable = parameterDescriptor.getContainingDeclaration();
|
||||||
|
if (containingCallable instanceof FunctionDescriptor) {
|
||||||
|
return InlineOnlyKt.isInlineOnly((MemberDescriptor) containingCallable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int newFakeTempIndex(@NotNull MethodVisitor mv, @NotNull FrameMap frameMap, int lineNumber) {
|
||||||
int fakeIndex = frameMap.enterTemp(Type.INT_TYPE);
|
int fakeIndex = frameMap.enterTemp(Type.INT_TYPE);
|
||||||
|
if (lineNumber >= 0) {
|
||||||
|
Label label = new Label();
|
||||||
|
mv.visitLabel(label);
|
||||||
|
mv.visitLineNumber(lineNumber, label);
|
||||||
|
}
|
||||||
mv.visitLdcInsn(0);
|
mv.visitLdcInsn(0);
|
||||||
mv.visitVarInsn(ISTORE, fakeIndex);
|
mv.visitVarInsn(ISTORE, fakeIndex);
|
||||||
return fakeIndex;
|
return fakeIndex;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.END
|
|||||||
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.FILE_SECTION
|
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.FILE_SECTION
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.LINE_SECTION
|
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.LINE_SECTION
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.STRATA_SECTION
|
import org.jetbrains.kotlin.codegen.inline.SMAP.Companion.STRATA_SECTION
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@@ -92,6 +93,10 @@ open class NestedSourceMapper(
|
|||||||
private var lastVisitedRange: RangeMapping? = null
|
private var lastVisitedRange: RangeMapping? = null
|
||||||
|
|
||||||
override fun mapLineNumber(lineNumber: Int): Int {
|
override fun mapLineNumber(lineNumber: Int): Int {
|
||||||
|
if (lineNumber in JvmAbi.SYNTHETIC_MARKER_LINE_NUMBERS) {
|
||||||
|
return lineNumber
|
||||||
|
}
|
||||||
|
|
||||||
val mappedLineNumber = visitedLines.get(lineNumber)
|
val mappedLineNumber = visitedLines.get(lineNumber)
|
||||||
|
|
||||||
return if (mappedLineNumber > 0) {
|
return if (mappedLineNumber > 0) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.codegen.inline
|
package org.jetbrains.kotlin.codegen.inline
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LineNumberNode
|
import org.jetbrains.org.objectweb.asm.tree.LineNumberNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -30,7 +31,13 @@ class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP) {
|
|||||||
|
|
||||||
private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequence<RangeMapping> {
|
private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequence<RangeMapping> {
|
||||||
return InsnSequence(node.instructions.first, null).filterIsInstance<LineNumberNode>().map { lineNumber ->
|
return InsnSequence(node.instructions.first, null).filterIsInstance<LineNumberNode>().map { lineNumber ->
|
||||||
val index = classSMAP.intervals.binarySearch(RangeMapping(lineNumber.line, lineNumber.line, 1), Comparator { value, key ->
|
val mapping = RangeMapping(lineNumber.line, lineNumber.line, 1)
|
||||||
|
|
||||||
|
if (lineNumber.line in JvmAbi.SYNTHETIC_MARKER_LINE_NUMBERS) {
|
||||||
|
return@map mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
val index = classSMAP.intervals.binarySearch(mapping, Comparator { value, key ->
|
||||||
if (key.dest in value) 0 else RangeMapping.Comparator.compare(value, key)
|
if (key.dest in value) 0 else RangeMapping.Comparator.compare(value, key)
|
||||||
})
|
})
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
|
|||||||
+1
-1
@@ -8,5 +8,5 @@ inline fun lookAtMe(f: () -> Int) {
|
|||||||
val a = 21
|
val a = 21
|
||||||
a + f()
|
a + f()
|
||||||
}
|
}
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// 2 13 14 3 15 5 8 9 10
|
// 2 13 14 3 15 5 8 9 10
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.load.java;
|
package org.jetbrains.kotlin.load.java;
|
||||||
|
|
||||||
|
import kotlin.collections.CollectionsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
@@ -13,6 +14,8 @@ import org.jetbrains.kotlin.name.FqName;
|
|||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt;
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||||
|
|
||||||
@@ -45,6 +48,20 @@ public final class JvmAbi {
|
|||||||
|
|
||||||
public static final ClassId REFLECTION_FACTORY_IMPL = ClassId.topLevel(new FqName("kotlin.reflect.jvm.internal.ReflectionFactoryImpl"));
|
public static final ClassId REFLECTION_FACTORY_IMPL = ClassId.topLevel(new FqName("kotlin.reflect.jvm.internal.ReflectionFactoryImpl"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Line number is used when inlining function arguments to @InlineOnly functions.
|
||||||
|
All line information is stripped from the inlined implementation of such functions,
|
||||||
|
so if a lambda is on the same line with the call, the debugger can't stop on both 'line' and 'lambda' breakpoints.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
> require(foo) { "foo is false" }
|
||||||
|
*/
|
||||||
|
public static final int LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER = 65100;
|
||||||
|
|
||||||
|
public static final List<Integer> SYNTHETIC_MARKER_LINE_NUMBERS = CollectionsKt.listOf(
|
||||||
|
LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER
|
||||||
|
);
|
||||||
|
|
||||||
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT = "$i$a$";
|
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT = "$i$a$";
|
||||||
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION = "$i$f$";
|
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION = "$i$f$";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user