JVM IR: Cache inline class replacements at the module level
This commit is contained in:
committed by
Alexander Udalov
parent
f40f9611c3
commit
e4609a9968
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory
|
|||||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.MemoizedInlineClassReplacements
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
@@ -90,6 +91,8 @@ class JvmBackendContext(
|
|||||||
|
|
||||||
val staticDefaultStubs = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
val staticDefaultStubs = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
||||||
|
|
||||||
|
val inlineClassReplacements = MemoizedInlineClassReplacements()
|
||||||
|
|
||||||
internal fun getTopLevelClass(fqName: FqName): IrClassSymbol {
|
internal fun getTopLevelClass(fqName: FqName): IrClassSymbol {
|
||||||
val descriptor = state.module.getPackage(fqName.parent()).memberScope.getContributedClassifier(
|
val descriptor = state.module.getPackage(fqName.parent()).memberScope.getContributedClassifier(
|
||||||
fqName.shortName(), NoLookupLocation.FROM_BACKEND
|
fqName.shortName(), NoLookupLocation.FROM_BACKEND
|
||||||
|
|||||||
+14
-16
@@ -53,7 +53,6 @@ val jvmInlineClassPhase = makeIrFilePhase(
|
|||||||
* types to the types of their underlying field.
|
* types to the types of their underlying field.
|
||||||
*/
|
*/
|
||||||
private class JvmInlineClassLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
private class JvmInlineClassLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||||
private val manager = MemoizedInlineClassReplacements()
|
|
||||||
private val valueMap = mutableMapOf<IrValueSymbol, IrValueDeclaration>()
|
private val valueMap = mutableMapOf<IrValueSymbol, IrValueDeclaration>()
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
@@ -63,7 +62,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||||
// The arguments to the primary constructor are in scope in the initializers of IrFields.
|
// The arguments to the primary constructor are in scope in the initializers of IrFields.
|
||||||
declaration.primaryConstructor?.let {
|
declaration.primaryConstructor?.let {
|
||||||
manager.getReplacementFunction(it)?.let { replacement ->
|
context.inlineClassReplacements.getReplacementFunction(it)?.let { replacement ->
|
||||||
valueMap.putAll(replacement.valueParameterMap)
|
valueMap.putAll(replacement.valueParameterMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +93,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
if (function.isPrimaryInlineClassConstructor)
|
if (function.isPrimaryInlineClassConstructor)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val replacement = manager.getReplacementFunction(function)
|
val replacement = context.inlineClassReplacements.getReplacementFunction(function)
|
||||||
if (replacement == null) {
|
if (replacement == null) {
|
||||||
function.transformChildrenVoid()
|
function.transformChildrenVoid()
|
||||||
return null
|
return null
|
||||||
@@ -118,7 +117,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
return listOf(worker)
|
return listOf(worker)
|
||||||
|
|
||||||
// Replace the function body with a wrapper
|
// Replace the function body with a wrapper
|
||||||
context.createIrBuilder(function.symbol).run {
|
context.createIrBuilder(function.symbol, function.startOffset, function.endOffset).run {
|
||||||
val call = irCall(worker).apply {
|
val call = irCall(worker).apply {
|
||||||
passTypeArgumentsFrom(function)
|
passTypeArgumentsFrom(function)
|
||||||
for (parameter in function.explicitParameters) {
|
for (parameter in function.explicitParameters) {
|
||||||
@@ -140,7 +139,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
|
|
||||||
valueMap.putAll(replacement.valueParameterMap)
|
valueMap.putAll(replacement.valueParameterMap)
|
||||||
worker.valueParameters.forEach { it.transformChildrenVoid() }
|
worker.valueParameters.forEach { it.transformChildrenVoid() }
|
||||||
worker.body = context.createIrBuilder(worker.symbol).irBlockBody(worker) {
|
worker.body = context.createIrBuilder(worker.symbol, worker.startOffset, worker.endOffset).irBlockBody(worker) {
|
||||||
val thisVar = irTemporaryVarDeclaration(
|
val thisVar = irTemporaryVarDeclaration(
|
||||||
worker.returnType, nameHint = "\$this", isMutable = false
|
worker.returnType, nameHint = "\$this", isMutable = false
|
||||||
)
|
)
|
||||||
@@ -220,7 +219,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||||
val replacement = manager.getReplacementFunction(expression.symbol.owner)
|
val replacement = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner)
|
||||||
?: return super.visitFunctionReference(expression)
|
?: return super.visitFunctionReference(expression)
|
||||||
val function = replacement.function
|
val function = replacement.function
|
||||||
|
|
||||||
@@ -236,7 +235,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
||||||
val function = expression.symbol.owner
|
val function = expression.symbol.owner
|
||||||
val replacement = manager.getReplacementFunction(function)
|
val replacement = context.inlineClassReplacements.getReplacementFunction(function)
|
||||||
?: return super.visitFunctionAccess(expression)
|
?: return super.visitFunctionAccess(expression)
|
||||||
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
|
||||||
.irCall(replacement.function).apply {
|
.irCall(replacement.function).apply {
|
||||||
@@ -274,10 +273,10 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
|
|
||||||
val klass = left.type.classOrNull!!.owner
|
val klass = left.type.classOrNull!!.owner
|
||||||
val equalsMethod = if (rightIsUnboxed) {
|
val equalsMethod = if (rightIsUnboxed) {
|
||||||
manager.getSpecializedEqualsMethod(klass, context.irBuiltIns)
|
this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(klass, context.irBuiltIns)
|
||||||
} else {
|
} else {
|
||||||
val equals = klass.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() }
|
val equals = klass.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() }
|
||||||
manager.getReplacementFunction(equals)!!.function
|
this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!.function
|
||||||
}
|
}
|
||||||
|
|
||||||
return irCall(equalsMethod).apply {
|
return irCall(equalsMethod).apply {
|
||||||
@@ -361,7 +360,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
expression.returnTargetSymbol.owner.safeAs<IrFunction>()?.let { target ->
|
expression.returnTargetSymbol.owner.safeAs<IrFunction>()?.let { target ->
|
||||||
manager.getReplacementFunction(target)?.let {
|
context.inlineClassReplacements.getReplacementFunction(target)?.let {
|
||||||
return context.createIrBuilder(it.function.symbol, expression.startOffset, expression.endOffset).irReturn(
|
return context.createIrBuilder(it.function.symbol, expression.startOffset, expression.endOffset).irReturn(
|
||||||
expression.value.transform(this, null)
|
expression.value.transform(this, null)
|
||||||
)
|
)
|
||||||
@@ -432,7 +431,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
|
|
||||||
// Add a static bridge method to the primary constructor.
|
// Add a static bridge method to the primary constructor.
|
||||||
// This is a placeholder for null-checks and default arguments.
|
// This is a placeholder for null-checks and default arguments.
|
||||||
val function = manager.getReplacementFunction(irConstructor)!!.function
|
val function = context.inlineClassReplacements.getReplacementFunction(irConstructor)!!.function
|
||||||
with(context.createIrBuilder(function.symbol)) {
|
with(context.createIrBuilder(function.symbol)) {
|
||||||
val argument = function.valueParameters[0]
|
val argument = function.valueParameters[0]
|
||||||
function.body = irExprBody(
|
function.body = irExprBody(
|
||||||
@@ -443,7 +442,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildBoxFunction(irClass: IrClass) {
|
private fun buildBoxFunction(irClass: IrClass) {
|
||||||
val function = manager.getBoxFunction(irClass)
|
val function = context.inlineClassReplacements.getBoxFunction(irClass)
|
||||||
with(context.createIrBuilder(function.symbol)) {
|
with(context.createIrBuilder(function.symbol)) {
|
||||||
function.body = irExprBody(
|
function.body = irExprBody(
|
||||||
irCall(irClass.primaryConstructor!!.symbol).apply {
|
irCall(irClass.primaryConstructor!!.symbol).apply {
|
||||||
@@ -456,11 +455,10 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildUnboxFunction(irClass: IrClass) {
|
private fun buildUnboxFunction(irClass: IrClass) {
|
||||||
val function = manager.getUnboxFunction(irClass)
|
val function = context.inlineClassReplacements.getUnboxFunction(irClass)
|
||||||
val builder = context.createIrBuilder(function.symbol)
|
|
||||||
val field = getInlineClassBackingField(irClass)
|
val field = getInlineClassBackingField(irClass)
|
||||||
|
|
||||||
function.body = builder.irBlockBody {
|
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||||
val thisVal = irGet(function.dispatchReceiverParameter!!)
|
val thisVal = irGet(function.dispatchReceiverParameter!!)
|
||||||
+irReturn(irGetField(thisVal, field))
|
+irReturn(irGetField(thisVal, field))
|
||||||
}
|
}
|
||||||
@@ -469,7 +467,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildSpecializedEqualsMethod(irClass: IrClass) {
|
private fun buildSpecializedEqualsMethod(irClass: IrClass) {
|
||||||
val function = manager.getSpecializedEqualsMethod(irClass, context.irBuiltIns)
|
val function = context.inlineClassReplacements.getSpecializedEqualsMethod(irClass, context.irBuiltIns)
|
||||||
val left = function.valueParameters[0]
|
val left = function.valueParameters[0]
|
||||||
val right = function.valueParameters[1]
|
val right = function.valueParameters[1]
|
||||||
val type = left.type.unboxInlineClass()
|
val type = left.type.unboxInlineClass()
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user