JVM IR: Remove IrReplacementFunction
This commit is contained in:
committed by
Georgy Bronnikov
parent
73b4f897b6
commit
66cbe3b1a8
+39
-39
@@ -14,7 +14,10 @@ import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.inlineClassFieldName
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineClassFieldGetter
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isPrimaryInlineClassConstructor
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
@@ -55,6 +58,12 @@ val jvmInlineClassPhase = makeIrFilePhase(
|
||||
private class JvmInlineClassLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
private val valueMap = mutableMapOf<IrValueSymbol, IrValueDeclaration>()
|
||||
|
||||
private fun addBindingsFor(original: IrFunction, replacement: IrFunction) {
|
||||
for ((param, newParam) in original.explicitParameters.zip(replacement.explicitParameters)) {
|
||||
valueMap[param.symbol] = newParam
|
||||
}
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
}
|
||||
@@ -62,9 +71,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||
// The arguments to the primary constructor are in scope in the initializers of IrFields.
|
||||
declaration.primaryConstructor?.let {
|
||||
context.inlineClassReplacements.getReplacementFunction(it)?.let { replacement ->
|
||||
valueMap.putAll(replacement.valueParameterMap)
|
||||
}
|
||||
context.inlineClassReplacements.getReplacementFunction(it)?.let { replacement -> addBindingsFor(it, replacement) }
|
||||
}
|
||||
|
||||
declaration.transformDeclarationsFlat { memberDeclaration ->
|
||||
@@ -101,6 +108,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
return null
|
||||
}
|
||||
|
||||
addBindingsFor(function, replacement)
|
||||
return when (function) {
|
||||
is IrSimpleFunction -> transformSimpleFunctionFlat(function, replacement)
|
||||
is IrConstructor -> transformConstructorFlat(function, replacement)
|
||||
@@ -108,23 +116,20 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrReplacementFunction): List<IrDeclaration> {
|
||||
val worker = replacement.function
|
||||
valueMap.putAll(replacement.valueParameterMap)
|
||||
worker.valueParameters.forEach { it.transformChildrenVoid() }
|
||||
worker.body = function.body?.transform(this, null)?.patchDeclarationParents(worker)
|
||||
(worker as? IrAttributeContainer)?.copyAttributes(function)
|
||||
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
replacement.valueParameters.forEach { it.transformChildrenVoid() }
|
||||
replacement.body = function.body?.transform(this, null)?.patchDeclarationParents(replacement)
|
||||
(replacement as? IrAttributeContainer)?.copyAttributes(function)
|
||||
|
||||
// Don't create a wrapper for functions which are only used in an unboxed context
|
||||
if (function.overriddenSymbols.isEmpty() || worker.dispatchReceiverParameter != null)
|
||||
return listOf(worker)
|
||||
if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null)
|
||||
return listOf(replacement)
|
||||
|
||||
// Replace the function body with a wrapper
|
||||
context.createIrBuilder(function.symbol, function.startOffset, function.endOffset).run {
|
||||
val call = irCall(worker).apply {
|
||||
val call = irCall(replacement).apply {
|
||||
passTypeArgumentsFrom(function)
|
||||
for (parameter in function.explicitParameters) {
|
||||
val newParameter = replacement.valueParameterMap[parameter.symbol] ?: continue
|
||||
for ((parameter, newParameter) in function.explicitParameters.zip(replacement.explicitParameters)) {
|
||||
putArgument(newParameter, irGet(parameter))
|
||||
}
|
||||
}
|
||||
@@ -132,19 +137,18 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
function.body = irExprBody(call)
|
||||
}
|
||||
|
||||
return listOf(worker, function)
|
||||
return listOf(replacement, function)
|
||||
}
|
||||
|
||||
// Secondary constructors for boxed types get translated to static functions returning
|
||||
// unboxed arguments. We remove the original constructor.
|
||||
private fun transformConstructorFlat(constructor: IrConstructor, replacement: IrReplacementFunction): List<IrDeclaration> {
|
||||
val worker = replacement.function
|
||||
|
||||
valueMap.putAll(replacement.valueParameterMap)
|
||||
worker.valueParameters.forEach { it.transformChildrenVoid() }
|
||||
worker.body = context.createIrBuilder(worker.symbol, worker.startOffset, worker.endOffset).irBlockBody(worker) {
|
||||
private fun transformConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
replacement.valueParameters.forEach { it.transformChildrenVoid() }
|
||||
replacement.body = context.createIrBuilder(replacement.symbol, replacement.startOffset, replacement.endOffset).irBlockBody(
|
||||
replacement
|
||||
) {
|
||||
val thisVar = irTemporaryVarDeclaration(
|
||||
worker.returnType, nameHint = "\$this", isMutable = false
|
||||
replacement.returnType, nameHint = "\$this", isMutable = false
|
||||
)
|
||||
valueMap[constructor.constructedClass.thisReceiver!!.symbol] = thisVar
|
||||
|
||||
@@ -189,13 +193,13 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
}
|
||||
}, null)
|
||||
.transform(this@JvmInlineClassLowering, null)
|
||||
.patchDeclarationParents(worker)
|
||||
.patchDeclarationParents(replacement)
|
||||
}
|
||||
|
||||
+irReturn(irGet(thisVar))
|
||||
}
|
||||
|
||||
return listOf(worker)
|
||||
return listOf(replacement)
|
||||
}
|
||||
|
||||
private fun typedArgumentList(function: IrFunction, expression: IrMemberAccessExpression) =
|
||||
@@ -207,31 +211,27 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
private fun IrMemberAccessExpression.buildReplacement(
|
||||
originalFunction: IrFunction,
|
||||
original: IrMemberAccessExpression,
|
||||
replacement: IrReplacementFunction
|
||||
replacement: IrSimpleFunction
|
||||
) {
|
||||
copyTypeArgumentsFrom(original)
|
||||
val valueParameterMap = originalFunction.explicitParameters.zip(replacement.explicitParameters).toMap()
|
||||
for ((parameter, argument) in typedArgumentList(originalFunction, original)) {
|
||||
if (argument == null) continue
|
||||
val newParameter = replacement.valueParameterMap[parameter.symbol] ?: continue
|
||||
putArgument(
|
||||
replacement.function,
|
||||
newParameter,
|
||||
argument.transform(this@JvmInlineClassLowering, null)
|
||||
)
|
||||
val newParameter = valueParameterMap.getValue(parameter)
|
||||
putArgument(replacement, newParameter, argument.transform(this@JvmInlineClassLowering, null))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val replacement = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner)
|
||||
val function = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner)
|
||||
?: return super.visitFunctionReference(expression)
|
||||
val function = replacement.function
|
||||
|
||||
return IrFunctionReferenceImpl(
|
||||
expression.startOffset, expression.endOffset, expression.type,
|
||||
function.symbol, function.typeParameters.size,
|
||||
function.valueParameters.size, expression.reflectionTarget, expression.origin
|
||||
).apply {
|
||||
buildReplacement(expression.symbol.owner, expression, replacement)
|
||||
buildReplacement(expression.symbol.owner, expression, function)
|
||||
}.copyAttributes(expression)
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
val replacement = context.inlineClassReplacements.getReplacementFunction(function)
|
||||
?: return super.visitFunctionAccess(expression)
|
||||
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
||||
.irCall(replacement.function).apply {
|
||||
.irCall(replacement).apply {
|
||||
buildReplacement(function, expression, replacement)
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(klass, context.irBuiltIns)
|
||||
} else {
|
||||
val equals = klass.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() }
|
||||
this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!.function
|
||||
this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!
|
||||
}
|
||||
|
||||
return irCall(equalsMethod).apply {
|
||||
@@ -363,7 +363,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
expression.returnTargetSymbol.owner.safeAs<IrFunction>()?.let { target ->
|
||||
context.inlineClassReplacements.getReplacementFunction(target)?.let {
|
||||
return context.createIrBuilder(it.function.symbol, expression.startOffset, expression.endOffset).irReturn(
|
||||
return context.createIrBuilder(it.symbol, expression.startOffset, expression.endOffset).irReturn(
|
||||
expression.value.transform(this, null)
|
||||
)
|
||||
}
|
||||
@@ -433,7 +433,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
|
||||
// Add a static bridge method to the primary constructor.
|
||||
// This is a placeholder for null-checks and default arguments.
|
||||
val function = context.inlineClassReplacements.getReplacementFunction(irConstructor)!!.function
|
||||
val function = context.inlineClassReplacements.getReplacementFunction(irConstructor)!!
|
||||
with(context.createIrBuilder(function.symbol)) {
|
||||
val argument = function.valueParameters[0]
|
||||
function.body = irExprBody(
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ private class JvmStringConcatenationLowering(val context: JvmBackendContext) : F
|
||||
val toStringReplacement = backendContext.inlineClassReplacements.getReplacementFunction(toStringFunction)
|
||||
?: return expression
|
||||
|
||||
return irCall(toStringReplacement.function).apply {
|
||||
return irCall(toStringReplacement).apply {
|
||||
putValueArgument(0, expression)
|
||||
}
|
||||
}
|
||||
|
||||
+18
-50
@@ -19,24 +19,14 @@ 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.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class IrReplacementFunction(
|
||||
val function: IrFunction,
|
||||
val valueParameterMap: Map<IrValueParameterSymbol, IrValueParameter>
|
||||
)
|
||||
|
||||
/**
|
||||
* Keeps track of replacement functions and inline class box/unbox functions.
|
||||
*/
|
||||
@@ -46,7 +36,7 @@ class MemoizedInlineClassReplacements {
|
||||
/**
|
||||
* Get a replacement for a function or a constructor.
|
||||
*/
|
||||
val getReplacementFunction: (IrFunction) -> IrReplacementFunction? =
|
||||
val getReplacementFunction: (IrFunction) -> IrSimpleFunction? =
|
||||
storageManager.createMemoizedFunctionWithNullableValues {
|
||||
when {
|
||||
!it.hasMangledParameters ||
|
||||
@@ -135,18 +125,12 @@ class MemoizedInlineClassReplacements {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMethodReplacement(function: IrFunction): IrReplacementFunction? {
|
||||
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
||||
val overrides = function.overriddenSymbols.mapNotNull {
|
||||
getReplacementFunction(it.owner)?.function?.symbol as? IrSimpleFunctionSymbol
|
||||
}
|
||||
if (function.origin == IrDeclarationOrigin.FAKE_OVERRIDE && overrides.isEmpty())
|
||||
return null
|
||||
|
||||
val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
val replacement = buildReplacement(function) {
|
||||
metadata = function.metadata
|
||||
overriddenSymbols += overrides
|
||||
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
||||
buildReplacement(function) {
|
||||
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
||||
overriddenSymbols = function.overriddenSymbols.map {
|
||||
getReplacementFunction(it.owner)?.symbol ?: it
|
||||
}
|
||||
|
||||
val newValueParameters = ArrayList<IrValueParameter>()
|
||||
for ((index, parameter) in function.explicitParameters.withIndex()) {
|
||||
@@ -162,24 +146,14 @@ class MemoizedInlineClassReplacements {
|
||||
// Assuming that constructors and non-override functions are always replaced with the unboxed
|
||||
// equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
|
||||
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
parameterMap[parameter.symbol] = newParameter
|
||||
}
|
||||
valueParameters = newValueParameters
|
||||
}
|
||||
return IrReplacementFunction(replacement, parameterMap)
|
||||
}
|
||||
|
||||
private fun createStaticReplacement(function: IrFunction): IrReplacementFunction {
|
||||
val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
val replacement = buildReplacement(function) {
|
||||
// Generate metadata for the replacement function instead of the original.
|
||||
if (function is IrFunctionBase<*>) {
|
||||
metadata = function.metadata
|
||||
function.metadata = null
|
||||
}
|
||||
|
||||
|
||||
valueParameters += function.explicitParameters.mapIndexed { index, parameter ->
|
||||
private fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
|
||||
buildReplacement(function) {
|
||||
val newValueParameters = ArrayList<IrValueParameter>()
|
||||
for ((index, parameter) in function.explicitParameters.withIndex()) {
|
||||
val name = when (parameter) {
|
||||
function.dispatchReceiverParameter -> Name.identifier("arg$index")
|
||||
function.extensionReceiverParameter -> Name.identifier("\$this\$${function.name}")
|
||||
@@ -191,16 +165,12 @@ class MemoizedInlineClassReplacements {
|
||||
else -> parameter.origin
|
||||
}
|
||||
val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null, origin = parameterOrigin)
|
||||
valueParameters += newParameter
|
||||
newValueParameters += newParameter
|
||||
// See comment next to a similar line above.
|
||||
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
parameterMap[parameter.symbol] = newParameter
|
||||
|
||||
newParameter
|
||||
}
|
||||
valueParameters = newValueParameters
|
||||
}
|
||||
return IrReplacementFunction(replacement, parameterMap)
|
||||
}
|
||||
|
||||
private fun buildReplacement(function: IrFunction, body: IrFunctionImpl.() -> Unit) =
|
||||
buildFunWithDescriptorForInlining(function.descriptor) {
|
||||
@@ -213,12 +183,10 @@ class MemoizedInlineClassReplacements {
|
||||
}.apply {
|
||||
parent = function.parent
|
||||
annotations += function.annotations
|
||||
if (function is IrConstructor) {
|
||||
copyTypeParameters(function.constructedClass.typeParameters + function.typeParameters)
|
||||
} else {
|
||||
copyTypeParametersFrom(function)
|
||||
correspondingPropertySymbol = function.safeAs<IrSimpleFunction>()?.correspondingPropertySymbol
|
||||
}
|
||||
copyTypeParameters(function.allTypeParameters)
|
||||
correspondingPropertySymbol = function.safeAs<IrSimpleFunction>()?.correspondingPropertySymbol
|
||||
metadata = function.metadata
|
||||
function.safeAs<IrFunctionBase<*>>()?.metadata = null
|
||||
body()
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -1,5 +1,6 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
abstract class GenericBase<T> {
|
||||
abstract fun foo(x: T): T
|
||||
@@ -21,4 +22,4 @@ fun box(): String {
|
||||
if (Derived().foo("OK") != "OK") throw AssertionError()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user