JVM_IR: fix a couple of inline class reflection issues.

1. Postpone the computation of the signature for property
   reference getters for extension properties until codegen time.

2. Generate metadata for static replacement functions instead
   of the original functions.
This commit is contained in:
Mads Ager
2019-12-23 08:53:14 +01:00
committed by Alexander Udalov
parent 2ebb797e61
commit e7835fecfc
8 changed files with 37 additions and 22 deletions
@@ -8,9 +8,10 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.ir.util.collectRealOverrides
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
/** /**
@@ -20,15 +21,9 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes
object SignatureString : IntrinsicMethod() { object SignatureString : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val function = (expression.getValueArgument(0) as IrFunctionReference).symbol.owner val function = (expression.getValueArgument(0) as IrFunctionReference).symbol.owner
val resolved = if (function is IrSimpleFunction) function.collectRealOverrides().first() else function
// TODO do not use descriptors val method = codegen.context.methodSignatureMapper.mapAsmMethod(resolved)
val declaration = codegen.context.referenceFunction(
DescriptorUtils.unwrapFakeOverride(function.descriptor).original
).owner
val method = codegen.context.methodSignatureMapper.mapAsmMethod(declaration)
val descriptor = method.name + method.descriptor val descriptor = method.name + method.descriptor
return object : PromisedValue(codegen, AsmTypes.JAVA_STRING_TYPE, codegen.context.irBuiltIns.stringType) { return object : PromisedValue(codegen, AsmTypes.JAVA_STRING_TYPE, codegen.context.irBuiltIns.stringType) {
override fun materialize() { override fun materialize() {
codegen.mv.aconst(descriptor) codegen.mv.aconst(descriptor)
@@ -19,10 +19,12 @@ import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.createType import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -64,14 +66,11 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val IrField.signature: String private val IrField.signature: String
get() = "${JvmAbi.getterName(name.asString())}()${context.methodSignatureMapper.mapReturnType(this)}" get() = "${JvmAbi.getterName(name.asString())}()${context.methodSignatureMapper.mapReturnType(this)}"
private val IrMemberAccessExpression.signature: String
get() = getter?.let { getter ->
localPropertyIndices[getter]?.let { "<v#$it>" }
} ?: getter?.owner?.signature ?: field!!.owner.signature
private val arrayItemGetter = private val arrayItemGetter =
context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" } context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" }
private val signatureStringIntrinsic = context.ir.symbols.signatureStringIntrinsic
private val kPropertyStarType = IrSimpleTypeImpl( private val kPropertyStarType = IrSimpleTypeImpl(
context.irBuiltIns.kPropertyClass, context.irBuiltIns.kPropertyClass,
false, false,
@@ -95,6 +94,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context) calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context)
} }
private fun IrBuilderWithScope.computeSignatureString(expression: IrCallableReference): IrExpression {
return expression.getter?.let { getter ->
localPropertyIndices[getter]?.let { irString("<v#$it>") }
?: if (getter.owner.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) {
// Default property accessor. Compute the signature now, so that we will not get into trouble
// if the getter is transformed to a static method by inline classes lowering.
irString(getter.owner.signature)
} else {
// Delay the computation of the signature until after inline classes lowering to make sure
// we mangle the function names correctly for things like extension methods on inline classes.
irCall(signatureStringIntrinsic).apply {
putValueArgument(0, IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expression.type, getter, 0, null))
}
}
} ?: irString(expression.field!!.owner.signature)
}
private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) = private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) =
addFunction { addFunction {
setSourceRange(this@addOverride) setSourceRange(this@addOverride)
@@ -204,7 +220,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
putValueArgument(0, irCall(referenceKind.reflectedSymbol.constructors.single()).apply { putValueArgument(0, irCall(referenceKind.reflectedSymbol.constructors.single()).apply {
putValueArgument(0, buildReflectedContainerReference(expression)) putValueArgument(0, buildReflectedContainerReference(expression))
putValueArgument(1, irString(expression.symbol.descriptor.name.asString())) putValueArgument(1, irString(expression.symbol.descriptor.name.asString()))
putValueArgument(2, irString(expression.signature)) putValueArgument(2, computeSignatureString(expression))
}) })
} }
} }
@@ -266,7 +282,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true) referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
referenceClass.addOverride(getName) { irString(expression.symbol.descriptor.name.asString()) } referenceClass.addOverride(getName) { irString(expression.symbol.descriptor.name.asString()) }
referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) } referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) }
referenceClass.addOverride(getSignature) { irString(expression.signature) } referenceClass.addOverride(getSignature) { computeSignatureString(expression) }
val receiverField = referenceClass.addField { val receiverField = referenceClass.addField {
name = backingFieldFromSuper.name name = backingFieldFromSuper.name
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -169,8 +170,11 @@ class MemoizedInlineClassReplacements {
private fun createStaticReplacement(function: IrFunction): IrReplacementFunction { private fun createStaticReplacement(function: IrFunction): IrReplacementFunction {
val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>() val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
val replacement = buildReplacement(function) { val replacement = buildReplacement(function) {
if (function !is IrSimpleFunction || function.overriddenSymbols.isEmpty()) // Generate metadata for the replacement function instead of the original.
if (function is IrFunctionBase) {
metadata = function.metadata metadata = function.metadata
function.metadata = null
}
for ((index, parameter) in function.explicitParameters.withIndex()) { for ((index, parameter) in function.explicitParameters.withIndex()) {
val name = when (parameter) { val name = when (parameter) {
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KMutableProperty2
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR // IGNORE_BACKEND: JS_IR, JS, NATIVE
// WITH_REFLECT // WITH_REFLECT
import kotlin.test.assertEquals import kotlin.test.assertEquals