JVM_IR: copy code from JvmDefaultParameterInjector to JvmTailrecLowering

Some weird edge case for inline classes wrapping primitives?
This commit is contained in:
pyos
2021-09-28 13:23:33 +02:00
committed by Mikhael Bogdanov
parent cb505d1101
commit 73adcd7b62
2 changed files with 27 additions and 33 deletions
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.transformStatement import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.explicitParameters import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
open class TailrecLowering(val context: BackendContext) : BodyLoweringPass { open class TailrecLowering(val context: BackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) { override fun lower(irBody: IrBody, container: IrDeclaration) {
if (container is IrFunction) { if (container is IrFunction) {
// TODO Shouldn't this be done after local declarations lowering?
// Lower local declarations // Lower local declarations
irBody.acceptChildrenVoid(object : IrElementVisitorVoid { irBody.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
@@ -62,26 +61,22 @@ open class TailrecLowering(val context: BackendContext) : BodyLoweringPass {
} }
} }
private fun lowerTailRecursionCalls(function: IrFunction) = open val useProperComputationOrderOfTailrecDefaultParameters: Boolean
lowerTailRecursionCalls(context, function, useProperComputationOrderOfTailrecDefaultParameters(), ::followFunctionReference) get() = true
open fun useProperComputationOrderOfTailrecDefaultParameters() = true
open fun followFunctionReference(reference: IrFunctionReference): Boolean = false open fun followFunctionReference(reference: IrFunctionReference): Boolean = false
open fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression =
IrConstImpl.defaultValueForType(startOffset, endOffset, type)
} }
private fun lowerTailRecursionCalls( private fun TailrecLowering.lowerTailRecursionCalls(irFunction: IrFunction) {
context: BackendContext, val tailRecursionCalls = collectTailRecursionCalls(irFunction, ::followFunctionReference)
irFunction: IrFunction,
properComputationOrderOfTailrecDefaultParameters: Boolean,
followFunctionReference: (IrFunctionReference) -> Boolean
) {
val tailRecursionCalls = collectTailRecursionCalls(irFunction, followFunctionReference)
if (tailRecursionCalls.isEmpty()) { if (tailRecursionCalls.isEmpty()) {
return return
} }
val oldBody = irFunction.body as IrBlockBody val oldBody = irFunction.body as? IrBlockBody ?: return
val oldBodyStatements = ArrayList(oldBody.statements) val oldBodyStatements = ArrayList(oldBody.statements)
val builder = context.createIrBuilder(irFunction.symbol).at(oldBody) val builder = context.createIrBuilder(irFunction.symbol).at(oldBody)
@@ -104,14 +99,9 @@ private fun lowerTailRecursionCalls(
val parameterToNew = parameters.associateWith { val parameterToNew = parameters.associateWith {
createTmpVariable(irGet(parameterToVariable[it]!!), nameHint = it.symbol.suggestVariableName()) createTmpVariable(irGet(parameterToVariable[it]!!), nameHint = it.symbol.suggestVariableName())
} }
val transformer = BodyTransformer( val transformer = BodyTransformer(
builder, irFunction, loop, this@lowerTailRecursionCalls, builder, irFunction, loop, parameterToNew, parameterToVariable, tailRecursionCalls
parameterToNew, parameterToVariable, tailRecursionCalls,
properComputationOrderOfTailrecDefaultParameters,
followFunctionReference
) )
oldBodyStatements.forEach { oldBodyStatements.forEach {
+it.transformStatement(transformer) +it.transformStatement(transformer)
} }
@@ -123,14 +113,13 @@ private fun lowerTailRecursionCalls(
} }
private class BodyTransformer( private class BodyTransformer(
val builder: IrBuilderWithScope, private val lowering: TailrecLowering,
val irFunction: IrFunction, private val builder: IrBuilderWithScope,
val loop: IrLoop, irFunction: IrFunction,
val parameterToNew: Map<IrValueParameter, IrValueDeclaration>, private val loop: IrLoop,
val parameterToVariable: Map<IrValueParameter, IrVariable>, parameterToNew: Map<IrValueParameter, IrValueDeclaration>,
val tailRecursionCalls: Set<IrCall>, private val parameterToVariable: Map<IrValueParameter, IrVariable>,
val properComputationOrderOfTailrecDefaultParameters: Boolean, private val tailRecursionCalls: Set<IrCall>,
val followFunctionReference: (IrFunctionReference) -> Boolean
) : VariableRemapper(parameterToNew) { ) : VariableRemapper(parameterToNew) {
val parameters = irFunction.explicitParameters val parameters = irFunction.explicitParameters
@@ -144,7 +133,7 @@ private class BodyTransformer(
} }
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
if (followFunctionReference(expression)) { if (lowering.followFunctionReference(expression)) {
expression.symbol.owner.body?.transformChildrenVoid(this) expression.symbol.owner.body?.transformChildrenVoid(this)
} }
return super.visitFunctionReference(expression) return super.visitFunctionReference(expression)
@@ -163,13 +152,12 @@ private class BodyTransformer(
defaultValuedParameters.associateWithTo(parameterToArgument) { defaultValuedParameters.associateWithTo(parameterToArgument) {
// Note that we intentionally keep the original type of the parameter for the variable even though that violates type safety // Note that we intentionally keep the original type of the parameter for the variable even though that violates type safety
// if it's non-null. This ensures that capture parameters have the same types for all copies of `x`. // if it's non-null. This ensures that capture parameters have the same types for all copies of `x`.
// TODO: on the JVM, this might not be correct for inline classes - copy code from JvmDefaultParameterInjector? irTemporary(lowering.nullConst(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type))
irTemporary(IrConstImpl.defaultValueForType(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type.makeNullable()), irType = it.type)
} }
// Now replace those variables with ones containing actual default values. Unused null-valued temporaries will hopefully // Now replace those variables with ones containing actual default values. Unused null-valued temporaries will hopefully
// be optimized out later. // be optimized out later.
val remapper = VariableRemapper(parameterToArgument) val remapper = VariableRemapper(parameterToArgument)
defaultValuedParameters.let { if (properComputationOrderOfTailrecDefaultParameters) it else it.asReversed() } defaultValuedParameters.let { if (lowering.useProperComputationOrderOfTailrecDefaultParameters) it else it.asReversed() }
.associateWithTo(parameterToArgument) { parameter -> .associateWithTo(parameterToArgument) { parameter ->
val originalDefaultValue = parameter.defaultValue?.expression ?: throw Error("no argument specified for $parameter") val originalDefaultValue = parameter.defaultValue?.expression ?: throw Error("no argument specified for $parameter")
irTemporary(originalDefaultValue.deepCopyWithVariables().patchDeclarationParents(parent).transform(remapper, null)) irTemporary(originalDefaultValue.deepCopyWithVariables().patchDeclarationParents(parent).transform(remapper, null))
@@ -8,14 +8,20 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.lower.TailrecLowering import org.jetbrains.kotlin.backend.common.lower.TailrecLowering
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.types.IrType
class JvmTailrecLowering(context: JvmBackendContext) : TailrecLowering(context) { class JvmTailrecLowering(context: JvmBackendContext) : TailrecLowering(context) {
override fun useProperComputationOrderOfTailrecDefaultParameters(): Boolean = override val useProperComputationOrderOfTailrecDefaultParameters: Boolean =
context.ir.context.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ProperComputationOrderOfTailrecDefaultParameters) context.ir.context.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ProperComputationOrderOfTailrecDefaultParameters)
override fun followFunctionReference(reference: IrFunctionReference): Boolean = override fun followFunctionReference(reference: IrFunctionReference): Boolean =
reference.origin == JvmLoweredStatementOrigin.INLINE_LAMBDA reference.origin == JvmLoweredStatementOrigin.INLINE_LAMBDA
override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression =
type.defaultValue(startOffset, endOffset, context as JvmBackendContext)
} }