[IR] Refactored bridges building
As a side effect fixes KT-27534 and KT-30284
This commit is contained in:
+24
-37
@@ -24,10 +24,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
@@ -47,6 +43,9 @@ import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
||||
import org.jetbrains.kotlin.library.SerializedIrModule
|
||||
@@ -59,10 +58,13 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
|
||||
private val outerThisFields = mutableMapOf<IrClass, IrField>()
|
||||
private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
|
||||
private val loweredEnums = mutableMapOf<IrClass, LoweredEnum>()
|
||||
private val ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>()
|
||||
|
||||
private data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections)
|
||||
|
||||
private val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
|
||||
|
||||
val loweredInlineFunctions = mutableSetOf<IrFunction>()
|
||||
|
||||
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
|
||||
@@ -119,21 +121,20 @@ internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
assert(overriddenFunction.needBridge) {
|
||||
"Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunction.overriddenFunction.descriptor}"
|
||||
}
|
||||
val bridgeDirections = overriddenFunction.bridgeDirections
|
||||
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
|
||||
createBridge(irFunction, bridgeDirections)
|
||||
}
|
||||
val key = BridgeKey(irFunction, overriddenFunction.bridgeDirections)
|
||||
return bridges.getOrPut(key) { createBridge(key) }
|
||||
}
|
||||
|
||||
private fun createBridge(function: IrSimpleFunction,
|
||||
bridgeDirections: BridgeDirections): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let { descriptor ->
|
||||
private fun createBridge(key: BridgeKey): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let { descriptor ->
|
||||
val (function, bridgeDirections) = key
|
||||
val startOffset = function.startOffset
|
||||
val endOffset = function.endOffset
|
||||
val returnType = when (bridgeDirections.array[0]) {
|
||||
BridgeDirection.TO_VALUE_TYPE,
|
||||
BridgeDirection.NOT_NEEDED -> function.returnType
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
|
||||
}
|
||||
|
||||
fun BridgeDirection.type() =
|
||||
if (this.kind == BridgeDirectionKind.NONE)
|
||||
null
|
||||
else this.irClass?.defaultType ?: context.irBuiltIns.anyNType
|
||||
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_BRIDGE_METHOD(function),
|
||||
@@ -145,7 +146,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = function.isSuspend,
|
||||
returnType = returnType,
|
||||
returnType = bridgeDirections.returnDirection.type() ?: function.returnType,
|
||||
isExpect = false,
|
||||
isFakeOverride = false,
|
||||
isOperator = false,
|
||||
@@ -155,30 +156,16 @@ internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
descriptor.bind(bridge)
|
||||
parent = function.parent
|
||||
|
||||
val dispatchReceiver = when (bridgeDirections.array[1]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!!
|
||||
BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
|
||||
dispatchReceiverParameter = function.dispatchReceiverParameter?.let {
|
||||
it.copyTo(bridge, type = bridgeDirections.dispatchReceiverDirection.type() ?: it.type)
|
||||
}
|
||||
|
||||
val extensionReceiver = when (bridgeDirections.array[2]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!
|
||||
BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
|
||||
extensionReceiverParameter = function.extensionReceiverParameter?.let {
|
||||
it.copyTo(bridge, type = bridgeDirections.extensionReceiverDirection.type() ?: it.type)
|
||||
}
|
||||
|
||||
val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
|
||||
when (bridgeDirections.array[index + 3]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
|
||||
BridgeDirection.NOT_NEEDED -> valueParameter.type
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
|
||||
}
|
||||
valueParameters += function.valueParameters.map {
|
||||
it.copyTo(bridge, type = bridgeDirections.parameterDirectionAt(it.index).type() ?: it.type)
|
||||
}
|
||||
|
||||
dispatchReceiverParameter = dispatchReceiver?.copyTo(bridge)
|
||||
extensionReceiverParameter = extensionReceiver?.copyTo(bridge)
|
||||
valueParameters += function.valueParameters.map { it.copyTo(bridge, type = valueParameterTypes[it.index]) }
|
||||
|
||||
typeParameters += function.typeParameters.map { parameter ->
|
||||
parameter.copyToWithoutSuperTypes(bridge).also { it.superTypes += parameter.superTypes }
|
||||
}
|
||||
|
||||
+109
-48
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors
|
||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.isVoidAsReturnType
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.longName
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
@@ -15,10 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
@@ -75,55 +74,117 @@ internal val IrClass.isArrayWithFixedSizeItems: Boolean
|
||||
|
||||
fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
||||
|
||||
internal fun IrFunction.hasValueTypeAt(index: Int): Boolean {
|
||||
when (index) {
|
||||
0 -> return !isSuspend && returnType.let { (it.isInlinedNative() || it.isUnit()) }
|
||||
1 -> return dispatchReceiverParameter.let { it != null && it.type.isInlinedNative() }
|
||||
2 -> return extensionReceiverParameter.let { it != null && it.type.isInlinedNative() }
|
||||
else -> return this.valueParameters[index - 3].type.isInlinedNative()
|
||||
private enum class TypeKind {
|
||||
ABSENT,
|
||||
VOID,
|
||||
VALUE_TYPE,
|
||||
REFERENCE
|
||||
}
|
||||
|
||||
private data class TypeWithKind(val irType: IrType?, val kind: TypeKind) {
|
||||
companion object {
|
||||
fun fromType(irType: IrType?) = when {
|
||||
irType == null -> TypeWithKind(null, TypeKind.ABSENT)
|
||||
irType.isInlinedNative() -> TypeWithKind(irType, TypeKind.VALUE_TYPE)
|
||||
else -> TypeWithKind(irType, TypeKind.REFERENCE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IrFunction.hasReferenceAt(index: Int): Boolean {
|
||||
when (index) {
|
||||
0 -> return isSuspend || returnType.let { !it.isInlinedNative() && !it.isUnit() }
|
||||
1 -> return dispatchReceiverParameter.let { it != null && !it.type.isInlinedNative() }
|
||||
2 -> return extensionReceiverParameter.let { it != null && !it.type.isInlinedNative() }
|
||||
else -> return !this.valueParameters[index - 3].type.isInlinedNative()
|
||||
private fun IrFunction.typeWithKindAt(index: ParameterIndex) = when (index) {
|
||||
ParameterIndex.RETURN_INDEX -> when {
|
||||
isSuspend -> TypeWithKind(null, TypeKind.REFERENCE)
|
||||
returnType.isVoidAsReturnType() -> TypeWithKind(returnType, TypeKind.VOID)
|
||||
else -> TypeWithKind.fromType(returnType)
|
||||
}
|
||||
ParameterIndex.DISPATCH_RECEIVER_INDEX -> TypeWithKind.fromType(dispatchReceiverParameter?.type)
|
||||
ParameterIndex.EXTENSION_RECEIVER_INDEX -> TypeWithKind.fromType(extensionReceiverParameter?.type)
|
||||
else -> TypeWithKind.fromType(this.valueParameters[index.unmap()].type)
|
||||
}
|
||||
|
||||
private fun IrFunction.needBridgeToAt(target: IrFunction, index: ParameterIndex)
|
||||
= bridgeDirectionToAt(target, index).kind != BridgeDirectionKind.NONE
|
||||
|
||||
@Suppress("EXPERIMENTAL_FEATURE_WARNING")
|
||||
private inline class ParameterIndex(val index: Int) {
|
||||
companion object {
|
||||
val RETURN_INDEX = ParameterIndex(0)
|
||||
val DISPATCH_RECEIVER_INDEX = ParameterIndex(1)
|
||||
val EXTENSION_RECEIVER_INDEX = ParameterIndex(2)
|
||||
|
||||
fun map(index: Int) = ParameterIndex(index + 3)
|
||||
|
||||
fun allParametersCount(irFunction: IrFunction) = irFunction.valueParameters.size + 3
|
||||
|
||||
inline fun forEachIndex(irFunction: IrFunction, block: (ParameterIndex) -> Unit) =
|
||||
(0 until allParametersCount(irFunction)).forEach { block(ParameterIndex(it)) }
|
||||
}
|
||||
|
||||
fun unmap() = index - 3
|
||||
}
|
||||
|
||||
internal fun IrFunction.needBridgeTo(target: IrFunction): Boolean {
|
||||
ParameterIndex.forEachIndex(this) {
|
||||
if (needBridgeToAt(target, it)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
internal enum class BridgeDirectionKind {
|
||||
NONE,
|
||||
BOX,
|
||||
UNBOX
|
||||
}
|
||||
|
||||
internal data class BridgeDirection(val irClass: IrClass?, val kind: BridgeDirectionKind) {
|
||||
companion object {
|
||||
val NONE = BridgeDirection(null, BridgeDirectionKind.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.needBridgeToAt(target: IrFunction, index: Int)
|
||||
= hasValueTypeAt(index) xor target.hasValueTypeAt(index)
|
||||
|
||||
internal fun IrFunction.needBridgeTo(target: IrFunction)
|
||||
= (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) }
|
||||
|
||||
internal enum class BridgeDirection {
|
||||
NOT_NEEDED,
|
||||
FROM_VALUE_TYPE,
|
||||
TO_VALUE_TYPE
|
||||
private fun IrFunction.bridgeDirectionToAt(overriddenFunction: IrFunction, index: ParameterIndex): BridgeDirection {
|
||||
val kind = typeWithKindAt(index).kind
|
||||
val (irClass, otherKind) = overriddenFunction.typeWithKindAt(index)
|
||||
return if (otherKind == kind)
|
||||
BridgeDirection.NONE
|
||||
else when (kind) {
|
||||
TypeKind.VOID, TypeKind.REFERENCE -> BridgeDirection(irClass?.erasure(), BridgeDirectionKind.UNBOX)
|
||||
TypeKind.VALUE_TYPE -> BridgeDirection(
|
||||
irClass?.erasure().takeIf { otherKind == TypeKind.VOID } /* Otherwise erase to [Any?] */,
|
||||
BridgeDirectionKind.BOX)
|
||||
TypeKind.ABSENT -> error("TypeKind.ABSENT should be on both sides")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.bridgeDirectionToAt(target: IrFunction, index: Int)
|
||||
= when {
|
||||
hasValueTypeAt(index) && target.hasReferenceAt(index) -> BridgeDirection.FROM_VALUE_TYPE
|
||||
hasReferenceAt(index) && target.hasValueTypeAt(index) -> BridgeDirection.TO_VALUE_TYPE
|
||||
else -> BridgeDirection.NOT_NEEDED
|
||||
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(val array: Array<BridgeDirection>) {
|
||||
constructor(parametersCount: Int): this(Array<BridgeDirection>(parametersCount + 3, { BridgeDirection.NOT_NEEDED }))
|
||||
internal class BridgeDirections(private val array: Array<BridgeDirection>) {
|
||||
constructor(irFunction: IrSimpleFunction, overriddenFunction: IrSimpleFunction)
|
||||
: this(Array<BridgeDirection>(ParameterIndex.allParametersCount(irFunction)) {
|
||||
irFunction.bridgeDirectionToAt(overriddenFunction, ParameterIndex(it))
|
||||
})
|
||||
|
||||
fun allNotNeeded(): Boolean = array.all { it == BridgeDirection.NOT_NEEDED }
|
||||
fun allNotNeeded(): Boolean = array.all { it.kind == BridgeDirectionKind.NONE }
|
||||
|
||||
private fun getDirectionAt(index: ParameterIndex) = array[index.index]
|
||||
|
||||
val returnDirection get() = getDirectionAt(ParameterIndex.RETURN_INDEX)
|
||||
val dispatchReceiverDirection get() = getDirectionAt(ParameterIndex.DISPATCH_RECEIVER_INDEX)
|
||||
val extensionReceiverDirection get() = getDirectionAt(ParameterIndex.EXTENSION_RECEIVER_INDEX)
|
||||
fun parameterDirectionAt(index: Int) = getDirectionAt(ParameterIndex.map(index))
|
||||
|
||||
override fun toString(): String {
|
||||
val result = StringBuilder()
|
||||
array.forEach {
|
||||
result.append(when (it) {
|
||||
BridgeDirection.FROM_VALUE_TYPE -> 'U' // unbox
|
||||
BridgeDirection.TO_VALUE_TYPE -> 'B' // box
|
||||
BridgeDirection.NOT_NEEDED -> 'N' // none
|
||||
result.append(when (it.kind) {
|
||||
BridgeDirectionKind.BOX -> 'B'
|
||||
BridgeDirectionKind.UNBOX -> 'U'
|
||||
BridgeDirectionKind.NONE -> 'N'
|
||||
})
|
||||
}
|
||||
return result.toString()
|
||||
@@ -139,9 +200,13 @@ internal class BridgeDirections(val array: Array<BridgeDirection>) {
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = 0
|
||||
array.forEach { result = result * 31 + it.ordinal }
|
||||
array.forEach { result = result * 31 + it.hashCode() }
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun none(irFunction: IrSimpleFunction) = BridgeDirections(irFunction, irFunction)
|
||||
}
|
||||
}
|
||||
|
||||
val IrSimpleFunction.allOverriddenFunctions: Set<IrSimpleFunction>
|
||||
@@ -159,19 +224,15 @@ val IrSimpleFunction.allOverriddenFunctions: Set<IrSimpleFunction>
|
||||
return result
|
||||
}
|
||||
|
||||
internal fun IrSimpleFunction.bridgeDirectionsTo(
|
||||
overriddenDescriptor: IrSimpleFunction
|
||||
): BridgeDirections {
|
||||
val ourDirections = BridgeDirections(this.valueParameters.size)
|
||||
for (index in ourDirections.array.indices)
|
||||
ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index)
|
||||
internal fun IrSimpleFunction.bridgeDirectionsTo(overriddenFunction: IrSimpleFunction): BridgeDirections {
|
||||
val ourDirections = BridgeDirections(this, overriddenFunction)
|
||||
|
||||
val target = this.target
|
||||
if (!this.isReal && modality != Modality.ABSTRACT
|
||||
&& target.overrides(overriddenDescriptor)
|
||||
&& ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
|
||||
&& target.overrides(overriddenFunction)
|
||||
&& ourDirections == target.bridgeDirectionsTo(overriddenFunction)) {
|
||||
// Bridge is inherited from superclass.
|
||||
return BridgeDirections(this.valueParameters.size)
|
||||
return BridgeDirections.none(this)
|
||||
}
|
||||
|
||||
return ourDirections
|
||||
|
||||
+3
-1
@@ -33,9 +33,11 @@ internal fun RuntimeAware.getLLVMType(type: IrType): LLVMTypeRef =
|
||||
internal fun RuntimeAware.getLLVMType(type: DataFlowIR.Type) =
|
||||
getLlvmType(type.primitiveBinaryType)
|
||||
|
||||
internal fun IrType.isVoidAsReturnType() = isUnit() || isNothing()
|
||||
|
||||
internal fun RuntimeAware.getLLVMReturnType(type: IrType): LLVMTypeRef {
|
||||
return when {
|
||||
type.isUnit() || type.isNothing() -> voidType
|
||||
type.isVoidAsReturnType() -> voidType
|
||||
else -> getLLVMType(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1459,6 +1459,10 @@ task bridges_special(type: KonanLocalTest) {
|
||||
source = "codegen/bridges/special.kt"
|
||||
}
|
||||
|
||||
task bridges_nativePointed(type: KonanLocalTest) {
|
||||
source = "codegen/bridges/nativePointed.kt"
|
||||
}
|
||||
|
||||
task returnTypeSignature(type: KonanLocalTest) {
|
||||
source = "codegen/bridges/returnTypeSignature.kt"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package codegen.bridges.nativePointed
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import kotlin.test.*
|
||||
|
||||
abstract class C {
|
||||
abstract fun foo(x: Int): CPointer<*>?
|
||||
}
|
||||
|
||||
class CImpl : C() {
|
||||
override fun foo(x: Int) = null
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
val c: C = CImpl()
|
||||
assertNull(c.foo(42))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user