Aligned SAM conversion lowering with the JVM's one
Also refactored other places with erasure
This commit is contained in:
Igor Chevdar
2021-09-08 23:55:11 +05:00
parent 72752473bf
commit 8464b15d27
6 changed files with 40 additions and 66 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny
import org.jetbrains.kotlin.backend.konan.ir.getSuperInterfaces import org.jetbrains.kotlin.backend.konan.ir.getSuperInterfaces
import org.jetbrains.kotlin.backend.konan.llvm.isVoidAsReturnType import org.jetbrains.kotlin.backend.konan.llvm.isVoidAsReturnType
import org.jetbrains.kotlin.backend.konan.llvm.longName import org.jetbrains.kotlin.backend.konan.llvm.longName
import org.jetbrains.kotlin.backend.konan.lower.erasedUpperBound
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
@@ -150,21 +150,14 @@ private fun IrFunction.bridgeDirectionToAt(overriddenFunction: IrFunction, index
return if (otherKind == kind) return if (otherKind == kind)
BridgeDirection.NONE BridgeDirection.NONE
else when (kind) { else when (kind) {
TypeKind.VOID, TypeKind.REFERENCE -> BridgeDirection(irClass?.erasure(), BridgeDirectionKind.UNBOX) TypeKind.VOID, TypeKind.REFERENCE -> BridgeDirection(irClass?.erasedUpperBound, BridgeDirectionKind.UNBOX)
TypeKind.VALUE_TYPE -> BridgeDirection( TypeKind.VALUE_TYPE -> BridgeDirection(
irClass?.erasure().takeIf { otherKind == TypeKind.VOID } /* Otherwise erase to [Any?] */, irClass?.erasedUpperBound.takeIf { otherKind == TypeKind.VOID } /* Otherwise erase to [Any?] */,
BridgeDirectionKind.BOX) BridgeDirectionKind.BOX)
TypeKind.ABSENT -> error("TypeKind.ABSENT should be on both sides") TypeKind.ABSENT -> error("TypeKind.ABSENT should be on both sides")
} }
} }
private tailrec fun IrType.erasure(): IrClass =
when (val classifier = classifierOrFail) {
is IrClassSymbol -> classifier.owner
is IrTypeParameterSymbol -> classifier.owner.superTypes.first().erasure()
else -> error(classifier)
}
internal class BridgeDirections(private val array: Array<BridgeDirection>) { internal class BridgeDirections(private val array: Array<BridgeDirection>) {
constructor(irFunction: IrSimpleFunction, overriddenFunction: IrSimpleFunction) constructor(irFunction: IrSimpleFunction, overriddenFunction: IrSimpleFunction)
: this(Array<BridgeDirection>(ParameterIndex.allParametersCount(irFunction)) { : this(Array<BridgeDirection>(ParameterIndex.allParametersCount(irFunction)) {
@@ -1519,7 +1519,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef { private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"} context.log{"evaluateCast : ${ir2string(value)}"}
val dstClass = value.typeOperand.getClass()!! val dstClass = value.typeOperand.getClass()
?: error("No class for ${value.typeOperand.render()} from \n${functionGenerationContext.irFunction?.render()}")
val srcArg = evaluateExpression(value.argument) val srcArg = evaluateExpression(value.argument)
assert(srcArg.type == codegen.kObjHeaderPtr) assert(srcArg.type == codegen.kObjHeaderPtr)
@@ -211,7 +211,7 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
if (!typeSafeBarrierDescription.checkParameter(i)) if (!typeSafeBarrierDescription.checkParameter(i))
continue continue
val type = originalValueParameters[i].type.erasureForTypeOperation() val type = originalValueParameters[i].type.erasure()
// Note: erasing to single type is not entirely correct if type parameter has multiple upper bounds. // Note: erasing to single type is not entirely correct if type parameter has multiple upper bounds.
// In this case the compiler could generate multiple type checks, one for each upper bound. // In this case the compiler could generate multiple type checks, one for each upper bound.
// But let's keep it simple here for now; JVM backend doesn't do this anyway. // But let's keep it simple here for now; JVM backend doesn't do this anyway.
@@ -264,4 +264,4 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
+irReturn(delegatingCall) +irReturn(delegatingCall)
} }
return bridge return bridge
} }
@@ -111,7 +111,7 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
return super.visitTypeOperator(expression) return super.visitTypeOperator(expression)
} }
reference.transformChildrenVoid() reference.transformChildrenVoid()
return transformFunctionReference(reference, expression.typeOperand) return transformFunctionReference(reference, expression.typeOperand.erasure())
} }
return super.visitTypeOperator(expression) return super.visitTypeOperator(expression)
} }
@@ -377,8 +377,7 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
val adaptedParameter = adaptedParameters[index] val adaptedParameter = adaptedParameters[index]
if (originalParameter.defaultValue != null) return false if (originalParameter.defaultValue != null) return false
if (originalParameter.isVararg) { if (originalParameter.isVararg) {
if (originalParameter.varargElementType!!.erasureForTypeOperation() if (originalParameter.varargElementType!!.erasure() == adaptedParameter.type.erasure())
== adaptedParameter.type.erasureForTypeOperation())
return true return true
} }
++index ++index
@@ -17,42 +17,44 @@ import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal fun IrType.erasureForTypeOperation(): IrType { // TODO: Similar to IrType.erasedUpperBound from jvm.ir
internal fun IrType.erasure(): IrType {
if (this !is IrSimpleType) return this if (this !is IrSimpleType) return this
return when (val classifier = classifier) { val upperBound = when (val classifier = classifier) {
is IrClassSymbol -> this is IrClassSymbol -> classifier.defaultType
is IrTypeParameterSymbol -> { is IrTypeParameterSymbol -> {
val upperBound = classifier.owner.superTypes.firstOrNull() // Pick the (necessarily unique) non-interface upper bound if it exists
?: TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}") classifier.owner.superTypes.firstOrNull {
it.classOrNull?.owner?.isInterface == false
if (this.hasQuestionMark) { } ?:
// `T?` // Otherwise, choose either the first IrClass supertype or recurse.
upperBound.erasureForTypeOperation().makeNullable() // In the first case, all supertypes are interface types and the choice was arbitrary.
} else { // In the second case, there is only a single supertype.
upperBound.erasureForTypeOperation() classifier.owner.superTypes.first().erasure()
}
} }
else -> TODO(classifier.toString()) else -> TODO(classifier.toString())
} }
return if (this.hasQuestionMark)
upperBound.makeNullable()
else
upperBound
} }
internal val IrType.erasedUpperBound get() = this.erasure().getClass() ?: error(this.render())
internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) { internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildren(this, null) irFile.transformChildren(this, null)
} }
private fun IrType.erasure(): IrType = this.erasureForTypeOperation()
private fun lowerCast(expression: IrTypeOperatorCall): IrExpression { private fun lowerCast(expression: IrTypeOperatorCall): IrExpression {
builder.at(expression) builder.at(expression)
val typeOperand = expression.typeOperand.erasure() val typeOperand = expression.typeOperand.erasure()
@@ -5,18 +5,21 @@
package org.jetbrains.kotlin.backend.konan.optimizations package org.jetbrains.kotlin.backend.konan.optimizations
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.allParameters import org.jetbrains.kotlin.backend.common.ir.allParameters
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions import org.jetbrains.kotlin.backend.konan.getInlinedClassNative
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.actualCallee
import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName import org.jetbrains.kotlin.backend.konan.ir.isAny
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.ir.isObjCObjectType
import org.jetbrains.kotlin.backend.konan.ir.isVirtualCall
import org.jetbrains.kotlin.backend.konan.isNonGeneratedAnnotation
import org.jetbrains.kotlin.backend.konan.logMultiple
import org.jetbrains.kotlin.backend.konan.lower.erasedUpperBound
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -28,9 +31,6 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -566,27 +566,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
) )
} }
private fun IrType.erasure(): IrType {
if (this !is IrSimpleType) return this
val classifier = this.classifier
return when (classifier) {
is IrClassSymbol -> this
is IrTypeParameterSymbol -> {
val upperBound = classifier.owner.superTypes.singleOrNull() ?:
TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}")
if (this.hasQuestionMark) {
// `T?`
upperBound.erasure().makeNullable()
} else {
upperBound.erasure()
}
}
else -> TODO(classifier.toString())
}
}
private fun expressionToEdge(expression: IrExpression) = expressionToScopedEdge(expression).value private fun expressionToEdge(expression: IrExpression) = expressionToScopedEdge(expression).value
private fun expressionToScopedEdge(expression: IrExpression) = private fun expressionToScopedEdge(expression: IrExpression) =
@@ -595,7 +574,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
Scoped( Scoped(
DataFlowIR.Edge( DataFlowIR.Edge(
it.value, it.value,
symbolTable.mapClassReferenceType(expression.typeOperand.erasure().getClass()!!) symbolTable.mapClassReferenceType(expression.typeOperand.erasedUpperBound)
), it.scope) ), it.scope)
} }
else { else {