[JVM_IR] Generate line numbers in synthetic bridges.

The current backend does that for some bridges. We do it consistently
for all bridges.

The line number used differs. For the JVM_IR backend, we use the
line number of the class to which the bridge is added. For the
JVM backend, that does not appear to be the case for bridges
in lambdas. I prefer the line number for a lambda invoke bridge
to be the line for the lambda instead os some surrounding class.
This commit is contained in:
Mads Ager
2020-09-15 11:53:36 +02:00
committed by max-kammerer
parent acf1a15f3e
commit ac742123fd
10 changed files with 84 additions and 34 deletions
@@ -385,6 +385,8 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
private fun IrClass.addBridge(bridge: Bridge, target: IrSimpleFunction): IrSimpleFunction = private fun IrClass.addBridge(bridge: Bridge, target: IrSimpleFunction): IrSimpleFunction =
addFunction { addFunction {
startOffset = this@addBridge.startOffset
endOffset = this@addBridge.startOffset
modality = Modality.OPEN modality = Modality.OPEN
origin = IrDeclarationOrigin.BRIDGE origin = IrDeclarationOrigin.BRIDGE
// Internal functions can be overridden by non-internal functions, which changes their names since the names of internal // Internal functions can be overridden by non-internal functions, which changes their names since the names of internal
@@ -396,7 +398,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
isSuspend = bridge.overridden.isSuspend isSuspend = bridge.overridden.isSuspend
}.apply { }.apply {
copyParametersWithErasure(this@addBridge, bridge.overridden) copyParametersWithErasure(this@addBridge, bridge.overridden)
body = context.createIrBuilder(symbol).run { irExprBody(delegatingCall(this@apply, target)) } body = context.createIrBuilder(symbol, startOffset, endOffset).run { irExprBody(delegatingCall(this@apply, target)) }
// The generated bridge method overrides all of the symbols which were overridden by its overrides. // The generated bridge method overrides all of the symbols which were overridden by its overrides.
// This is technically wrong, but it's necessary to generate a method which maps to the same signature. // This is technically wrong, but it's necessary to generate a method which maps to the same signature.
@@ -411,6 +413,8 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
private fun IrClass.addSpecialBridge(specialBridge: SpecialBridge, target: IrSimpleFunction): IrSimpleFunction = private fun IrClass.addSpecialBridge(specialBridge: SpecialBridge, target: IrSimpleFunction): IrSimpleFunction =
addFunction { addFunction {
startOffset = this@addSpecialBridge.startOffset
endOffset = this@addSpecialBridge.startOffset
modality = if (specialBridge.isFinal) Modality.FINAL else Modality.OPEN modality = if (specialBridge.isFinal) Modality.FINAL else Modality.OPEN
origin = if (specialBridge.isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL origin = if (specialBridge.isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL
name = Name.identifier(specialBridge.signature.name) name = Name.identifier(specialBridge.signature.name)
@@ -423,7 +427,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
specialBridge.substitutedParameterTypes specialBridge.substitutedParameterTypes
) )
body = context.createIrBuilder(symbol).irBlockBody { body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
specialBridge.methodInfo?.let { info -> specialBridge.methodInfo?.let { info ->
valueParameters.take(info.argumentsToCheck).forEach { valueParameters.take(info.argumentsToCheck).forEach {
+parameterTypeCheck(it, target.valueParameters[it.index].type, info.defaultValueGenerator(this@apply)) +parameterTypeCheck(it, target.valueParameters[it.index].type, info.defaultValueGenerator(this@apply))
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters
import org.jetbrains.kotlin.codegen.syntheticAccessorToSuperSuffix
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -292,6 +291,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
val source = this val source = this
return factory.buildFun { return factory.buildFun {
startOffset = parent.startOffset
endOffset = parent.startOffset
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
name = source.accessorName(expression.superQualifierSymbol) name = source.accessorName(expression.superQualifierSymbol)
visibility = DescriptorVisibilities.PUBLIC visibility = DescriptorVisibilities.PUBLIC
@@ -306,7 +307,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
accessor.returnType = source.returnType.remapTypeParameters(source, accessor) accessor.returnType = source.returnType.remapTypeParameters(source, accessor)
accessor.body = IrExpressionBodyImpl( accessor.body = IrExpressionBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.startOffset,
createSimpleFunctionCall(accessor, source.symbol, expression.superQualifierSymbol) createSimpleFunctionCall(accessor, source.symbol, expression.superQualifierSymbol)
) )
} }
@@ -314,7 +315,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private fun createSimpleFunctionCall(accessor: IrFunction, targetSymbol: IrSimpleFunctionSymbol, superQualifierSymbol: IrClassSymbol?) = private fun createSimpleFunctionCall(accessor: IrFunction, targetSymbol: IrSimpleFunctionSymbol, superQualifierSymbol: IrClassSymbol?) =
IrCallImpl( IrCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset,
accessor.endOffset,
accessor.returnType, accessor.returnType,
targetSymbol, targetSymbol.owner.typeParameters.size, targetSymbol, targetSymbol.owner.typeParameters.size,
superQualifierSymbol = superQualifierSymbol superQualifierSymbol = superQualifierSymbol
@@ -324,6 +326,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private fun makeGetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol = private fun makeGetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol =
context.irFactory.buildFun { context.irFactory.buildFun {
startOffset = parent.startOffset
endOffset = parent.startOffset
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
name = fieldSymbol.owner.accessorNameForGetter() name = fieldSymbol.owner.accessorNameForGetter()
visibility = DescriptorVisibilities.PUBLIC visibility = DescriptorVisibilities.PUBLIC
@@ -346,11 +350,11 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private fun createAccessorBodyForGetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { private fun createAccessorBodyForGetter(targetField: IrField, accessor: IrSimpleFunction): IrBody {
val maybeDispatchReceiver = val maybeDispatchReceiver =
if (targetField.isStatic) null if (targetField.isStatic) null
else IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.valueParameters[0].symbol) else IrGetValueImpl(accessor.startOffset, accessor.endOffset, accessor.valueParameters[0].symbol)
return IrExpressionBodyImpl( return IrExpressionBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.endOffset,
IrGetFieldImpl( IrGetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.endOffset,
targetField.symbol, targetField.symbol,
targetField.type, targetField.type,
maybeDispatchReceiver maybeDispatchReceiver
@@ -360,6 +364,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private fun makeSetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol = private fun makeSetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol =
context.irFactory.buildFun { context.irFactory.buildFun {
startOffset = parent.startOffset
endOffset = parent.startOffset
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
name = fieldSymbol.owner.accessorNameForSetter() name = fieldSymbol.owner.accessorNameForSetter()
visibility = DescriptorVisibilities.PUBLIC visibility = DescriptorVisibilities.PUBLIC
@@ -384,15 +390,15 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private fun createAccessorBodyForSetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { private fun createAccessorBodyForSetter(targetField: IrField, accessor: IrSimpleFunction): IrBody {
val maybeDispatchReceiver = val maybeDispatchReceiver =
if (targetField.isStatic) null if (targetField.isStatic) null
else IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.valueParameters[0].symbol) else IrGetValueImpl(accessor.startOffset, accessor.endOffset, accessor.valueParameters[0].symbol)
val value = IrGetValueImpl( val value = IrGetValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.endOffset,
accessor.valueParameters[if (targetField.isStatic) 0 else 1].symbol accessor.valueParameters[if (targetField.isStatic) 0 else 1].symbol
) )
return IrExpressionBodyImpl( return IrExpressionBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.endOffset,
IrSetFieldImpl( IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.startOffset, accessor.endOffset,
targetField.symbol, targetField.symbol,
maybeDispatchReceiver, maybeDispatchReceiver,
value, value,
-13
View File
@@ -16,37 +16,24 @@ fun box() {
A.foo() A.foo()
} }
// The JVM version hits get getProp line numbers twice. That appears
// to be because the synthetic accessibility bridges (access$getProp0$cp)
// have line numbers (of the start of the surrounding class) in the JVM
// version and they do not have line numbers in the JVM_IR version.
// LINENUMBERS // LINENUMBERS
// test.kt:14 box // test.kt:14 box
// test.kt:5 <clinit> // test.kt:5 <clinit>
// test.kt:6 <clinit> // test.kt:6 <clinit>
// test.kt:5 getProp0 // test.kt:5 getProp0
// LINENUMBERS JVM
// test.kt:5 getProp0 // test.kt:5 getProp0
// LINENUMBERS
// test.kt:14 box // test.kt:14 box
// test.kt:15 box // test.kt:15 box
// test.kt:6 getProp1 // test.kt:6 getProp1
// LINENUMBERS JVM
// test.kt:6 getProp1 // test.kt:6 getProp1
// LINENUMBERS
// test.kt:15 box // test.kt:15 box
// test.kt:16 box // test.kt:16 box
// test.kt:8 foo // test.kt:8 foo
// test.kt:5 getProp0 // test.kt:5 getProp0
// LINENUMBERS JVM
// test.kt:5 getProp0 // test.kt:5 getProp0
// LINENUMBERS
// test.kt:8 foo // test.kt:8 foo
// test.kt:6 getProp1 // test.kt:6 getProp1
// LINENUMBERS JVM
// test.kt:6 getProp1 // test.kt:6 getProp1
// LINENUMBERS
// test.kt:8 foo // test.kt:8 foo
// test.kt:16 box // test.kt:16 box
// test.kt:17 box // test.kt:17 box
@@ -30,8 +30,6 @@ fun box() {
A.s A.s
} }
// JVM backend has extra steps for getX and getS.
// LINENUMBERS // LINENUMBERS
// test.kt:29 box // test.kt:29 box
// test.kt:7 <clinit> // test.kt:7 <clinit>
@@ -46,14 +44,10 @@ fun box() {
// test.kt:21 <clinit> // test.kt:21 <clinit>
// test.kt:22 <clinit> // test.kt:22 <clinit>
// test.kt:11 getX // test.kt:11 getX
// LINENUMBERS JVM
// test.kt:11 getX // test.kt:11 getX
// LINENUMBERS
// test.kt:29 box // test.kt:29 box
// test.kt:30 box // test.kt:30 box
// test.kt:5 getS // test.kt:5 getS
// LINENUMBERS JVM
// test.kt:5 getS // test.kt:5 getS
// LINENUMBERS
// test.kt:30 box // test.kt:30 box
// test.kt:31 box // test.kt:31 box
@@ -10,10 +10,19 @@ fun f(block: () -> Unit) {
fun g() {} fun g() {}
// The synthetic invoke bridge method generated for in the callable reference has line numbers
// in the JVM_IR backend (as all bridges). In the JVM backend, only some bridges have line numbers.
// For some reason, when the bridge does not have line numbers, there is no method entry event
// for the invoke method bridged to. Therefore, the entry line number for invoke only shows
// up for JVM_IR.
// LINENUMBERS // LINENUMBERS
// test.kt:3 box // test.kt:3 box
// test.kt:4 box // test.kt:4 box
// test.kt:8 f // test.kt:8 f
// LINENUMBERS JVM_IR
// test.kt:4 invoke
// LINENUMBERS
// test.kt:11 g // test.kt:11 g
// test.kt:4 invoke // test.kt:4 invoke
// test.kt:8 f // test.kt:8 f
@@ -0,0 +1,21 @@
LineBreakpoint created at functionCallStoredToVariable.kt:7
LineBreakpoint created at functionCallStoredToVariable.kt:14
LineBreakpoint created at functionCallStoredToVariable.kt:21
LineBreakpoint created at functionCallStoredToVariable.kt:28
Run Java
Connected to the target VM
functionCallStoredToVariable.kt:7
functionCallStoredToVariable.kt:4
functionCallStoredToVariable.kt:14
functionCallStoredToVariable.kt:11
functionCallStoredToVariable.kt:43
functionCallStoredToVariable.kt:21
functionCallStoredToVariable.kt:22
functionCallStoredToVariable.kt:25
functionCallStoredToVariable.kt:28
functionCallStoredToVariable.kt:29
functionCallStoredToVariable.kt:25
functionCallStoredToVariable.kt:47
Disconnected from the target VM
Process finished with exit code 0
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at accessors.kt:10 LineBreakpoint created at accessors.kt:10
Run Java Run Java
Connected to the target VM Connected to the target VM
@@ -0,0 +1,32 @@
LineBreakpoint created at syntheticMethods.kt:6
Run Java
Connected to the target VM
syntheticMethods.kt:6
syntheticMethods.kt:17
syntheticMethods.kt:19
syntheticMethods.kt:20
syntheticMethods.kt:17
syntheticMethods.kt:7
syntheticMethods.kt:-1
syntheticMethods.kt:7
syntheticMethods.kt:25
syntheticMethods.kt:31
syntheticMethods.kt:25
syntheticMethods.kt:26
syntheticMethods.kt:25
syntheticMethods.kt:31
syntheticMethods.kt:25
syntheticMethods.kt:28
syntheticMethods.kt:8
syntheticMethods.kt:36
syntheticMethods.kt:42
syntheticMethods.kt:36
syntheticMethods.kt:37
syntheticMethods.kt:36
syntheticMethods.kt:42
syntheticMethods.kt:36
syntheticMethods.kt:39
syntheticMethods.kt:9
Disconnected from the target VM
Process finished with exit code 0
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at syntheticMethods.kt:6 LineBreakpoint created at syntheticMethods.kt:6
Run Java Run Java
Connected to the target VM Connected to the target VM
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
KotlinFieldBreakpoint created at fwBackingField.kt:5 KotlinFieldBreakpoint created at fwBackingField.kt:5
KotlinFieldBreakpoint created at fwBackingField.kt:8 KotlinFieldBreakpoint created at fwBackingField.kt:8
KotlinFieldBreakpoint created at fwBackingField.kt:18 KotlinFieldBreakpoint created at fwBackingField.kt:18