diff --git a/compiler/fir/native/build.gradle.kts b/compiler/fir/native/build.gradle.kts index c62fef6710b..e4ff8d98941 100644 --- a/compiler/fir/native/build.gradle.kts +++ b/compiler/fir/native/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { implementation(project(":compiler:fir:resolve")) implementation(project(":compiler:fir:fir2ir")) implementation(project(":compiler:ir.serialization.common")) + implementation(project(":compiler:ir.serialization.native")) } diff --git a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeKotlinMangler.kt b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeKotlinMangler.kt index 9f76612a245..936d2a7c8cc 100644 --- a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeKotlinMangler.kt +++ b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeKotlinMangler.kt @@ -6,14 +6,13 @@ package org.jetbrains.kotlin.fir.backend.native import org.jetbrains.kotlin.backend.common.serialization.mangle.* +import org.jetbrains.kotlin.backend.konan.serialization.ANNOTATIONS_TO_TREAT_AS_EXPORTED +import org.jetbrains.kotlin.backend.konan.serialization.ObjCFunctionNameMangleComputer import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.backend.FirMangler import org.jetbrains.kotlin.fir.backend.FirExportCheckerVisitor import org.jetbrains.kotlin.fir.backend.FirMangleComputer +import org.jetbrains.kotlin.fir.backend.FirMangler import org.jetbrains.kotlin.fir.backend.native.interop.* -import org.jetbrains.kotlin.fir.backend.native.interop.hasObjCFactoryAnnotation -import org.jetbrains.kotlin.fir.backend.native.interop.hasObjCMethodAnnotation -import org.jetbrains.kotlin.fir.backend.native.interop.isObjCClassMethod import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.resolve.ScopeSession @@ -21,7 +20,8 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.toSymbol -import org.jetbrains.kotlin.name.NativeRuntimeNames +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.native.interop.ObjCMethodInfo class FirNativeKotlinMangler : FirMangler() { override fun getMangleComputer(mode: MangleMode, compatibleMode: Boolean): KotlinMangleComputer { @@ -41,31 +41,37 @@ class FirNativeExportCheckerVisitor : FirExportCheckerVisitor() { override fun FirDeclaration.isPlatformSpecificExported(): Boolean { if (this is FirCallableDeclaration && isSubstitutionOrIntersectionOverride) return false - - if (annotations.hasAnnotation(NativeRuntimeNames.Annotations.symbolNameClassId, moduleData.session)) { - // Treat any `@SymbolName` declaration as exported. - return true - } - if (annotations.hasAnnotation(NativeRuntimeNames.Annotations.gcUnsafeCallClassId, moduleData.session)) { - // Treat any `@GCUnsafeCall` declaration as exported. - return true - } - if (annotations.hasAnnotation(NativeRuntimeNames.Annotations.exportForCppRuntimeClassId, moduleData.session)) { - // Treat any `@ExportForCppRuntime` declaration as exported. - return true - } - if (annotations.hasAnnotation(NativeRuntimeNames.Annotations.cNameClassId, moduleData.session)) { - // Treat `@CName` declaration as exported. - return true - } - if (annotations.hasAnnotation(NativeRuntimeNames.Annotations.exportForCompilerClassId, moduleData.session)) { - return true - } - - return false + return ANNOTATIONS_TO_TREAT_AS_EXPORTED.any { hasAnnotation(it, moduleData.session) } } } +private class FirObjCFunctionNameMangleComputer( + private val function: FirFunction +) : ObjCFunctionNameMangleComputer() { + + private val session = function.moduleData.session + + override fun getObjCMethodInfo(): ObjCMethodInfo? { + val scopeSession = ScopeSession() + return function.getInitMethodIfObjCConstructor(session, scopeSession) + ?.getObjCMethodInfoFromOverriddenFunctions(session, scopeSession) + } + + override fun getExtensionReceiverClassName(): Name? = function.receiverParameter?.getTypeName(session)?.let(Name::identifier) + + override fun isObjCConstructor(): Boolean = function is FirConstructor && function.isObjCConstructor(session) + + override fun isPropertyAccessor(): Boolean = function is FirPropertyAccessor + + override fun hasObjCMethodAnnotation(): Boolean = function.hasObjCMethodAnnotation(session) + + override fun hasObjCFactoryAnnotation(): Boolean = function.hasObjCFactoryAnnotation(session) + + override fun isObjCClassMethod(): Boolean = function.isObjCClassMethod(session) + + override fun getValueParameterName(valueParameter: FirValueParameter): Name = valueParameter.name +} + class FirNativeKotlinMangleComputer( builder: StringBuilder, mode: MangleMode, @@ -73,42 +79,9 @@ class FirNativeKotlinMangleComputer( override fun copy(newMode: MangleMode): FirNativeKotlinMangleComputer = FirNativeKotlinMangleComputer(builder, newMode) - /** - * mimics FunctionDescriptor.platformSpecificFunctionName() - */ - override fun FirFunction.platformSpecificFunctionName(): String? { - val session = moduleData.session - val scopeSession = ScopeSession() - getInitMethodIfObjCConstructor(session, scopeSession) - ?.getObjCMethodInfoFromOverriddenFunctions(session, scopeSession) - ?.let { - return buildString { - receiverParameter?.let { - append(it.getTypeName(session)) - append(MangleConstant.FQN_SEPARATOR) - } - - append(MangleConstant.OBJC_MARK) - append(it.selector) - if ((this@platformSpecificFunctionName is FirConstructor) && isObjCConstructor(session)) { - append(MangleConstant.OBJC_CONSTRUCTOR_MARK) - } - - if (this@platformSpecificFunctionName is FirPropertyAccessor) { - append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK) - } - } - } - return null - } - - override fun FirFunction.specialValueParamPrefix(param: FirValueParameter): String { - val session = moduleData.session - return if (this.hasObjCMethodAnnotation(session) || this.hasObjCFactoryAnnotation(session) || this.isObjCClassMethod(session)) - "${param.name}:" - else - "" - } + override fun makePlatformSpecificFunctionNameMangleComputer( + function: FirFunction + ): PlatformSpecificFunctionNameMangleComputer = FirObjCFunctionNameMangleComputer(function) } private fun FirReceiverParameter.getTypeName(session: FirSession): String { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/BaseKotlinMangleComputer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/BaseKotlinMangleComputer.kt index 9e053d5d5b5..ef198efcb34 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/BaseKotlinMangleComputer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/BaseKotlinMangleComputer.kt @@ -42,12 +42,12 @@ abstract class BaseKotlinMangleComputer(4) - protected open fun FunctionDeclaration.platformSpecificFunctionName(): String? = null + protected open fun makePlatformSpecificFunctionNameMangleComputer( + function: FunctionDeclaration + ): PlatformSpecificFunctionNameMangleComputer = PlatformSpecificFunctionNameMangleComputer.Default protected open fun FunctionDeclaration.platformSpecificSuffix(): String? = null - protected open fun FunctionDeclaration.specialValueParamPrefix(param: ValueParameter): String = "" - protected open fun addReturnType(): Boolean = false protected open fun addReturnTypeSpecialCase(function: FunctionDeclaration): Boolean = false @@ -145,7 +145,7 @@ abstract class BaseKotlinMangleComputer { + + fun computePlatformSpecificFunctionName(): String? + + fun computePlatformSpecificValueParameterPrefix(valueParameter: ValueParameter): String + + object Default : PlatformSpecificFunctionNameMangleComputer { + + override fun computePlatformSpecificFunctionName(): String? = null + + override fun computePlatformSpecificValueParameterPrefix(valueParameter: Any): String = "" + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanMangler.kt b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanMangler.kt index c2556dbb141..322a48ed9ce 100644 --- a/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanMangler.kt +++ b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanMangler.kt @@ -17,13 +17,11 @@ import org.jetbrains.kotlin.backend.common.serialization.mangle.ir.IrMangleCompu import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.objcinterop.* -import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.name.NativeRuntimeNames import org.jetbrains.kotlin.name.NativeStandardInteropNames -private val annotationsToTreatAsExported = listOf( +val ANNOTATIONS_TO_TREAT_AS_EXPORTED = listOf( NativeRuntimeNames.Annotations.symbolNameClassId, NativeRuntimeNames.Annotations.gcUnsafeCallClassId, NativeRuntimeNames.Annotations.exportForCppRuntimeClassId, @@ -31,9 +29,6 @@ private val annotationsToTreatAsExported = listOf( NativeRuntimeNames.Annotations.exportForCompilerClassId, ) -private val IrConstructor.isObjCConstructor: Boolean - get() = hasAnnotation(NativeStandardInteropNames.objCConstructorClassId) - abstract class AbstractKonanIrMangler( private val withReturnType: Boolean, private val allowOutOfScopeTypeParameters: Boolean = false @@ -46,7 +41,7 @@ abstract class AbstractKonanIrMangler( override fun IrDeclaration.isPlatformSpecificExport(): Boolean { if (this is IrSimpleFunction) if (isFakeOverride) return false - return annotationsToTreatAsExported.any(this::hasAnnotation) + return ANNOTATIONS_TO_TREAT_AS_EXPORTED.any(this::hasAnnotation) } private inner class KonanIrExportChecker(compatibleMode: Boolean) : IrExportCheckerVisitor(compatibleMode) { @@ -65,43 +60,13 @@ abstract class AbstractKonanIrMangler( override fun addReturnType(): Boolean = withReturnType - override fun IrFunction.platformSpecificFunctionName(): String? { - (if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo() - ?.let { - return buildString { - if (extensionReceiverParameter != null) { - append(extensionReceiverParameter!!.type.getClass()!!.name) - append(MangleConstant.FQN_SEPARATOR) - } - - append(MangleConstant.OBJC_MARK) - append(it.selector) - if (this@platformSpecificFunctionName is IrConstructor && this@platformSpecificFunctionName.isObjCConstructor) { - append(MangleConstant.OBJC_CONSTRUCTOR_MARK) - } - - if ((this@platformSpecificFunctionName as? IrSimpleFunction)?.correspondingPropertySymbol != null) { - append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK) - } - } - } - return null - } + override fun makePlatformSpecificFunctionNameMangleComputer(function: IrFunction) = IrObjCFunctionNameMangleComputer(function) override fun IrFunction.platformSpecificFunctionMarks(): List = when (origin) { IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION -> listOfSuspendFunctionMark else -> emptyList() } - override fun IrFunction.specialValueParamPrefix(param: IrValueParameter): String { - // TODO: there are clashes originating from ObjectiveC interop. - // kotlinx.cinterop.ObjCClassOf.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt - // and - // kotlinx.cinterop.ObjCClassOf.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt - - return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else "" - } - companion object { val listOfSuspendFunctionMark = listOf(MangleConstant.SUSPEND_FUNCTION_MARK) } @@ -124,7 +89,7 @@ abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return false } - return annotationsToTreatAsExported.any { annotations.hasAnnotation(it.asSingleFqName()) } + return ANNOTATIONS_TO_TREAT_AS_EXPORTED.any { annotations.hasAnnotation(it.asSingleFqName()) } } @@ -132,32 +97,8 @@ abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl private class KonanDescriptorMangleComputer(builder: StringBuilder, mode: MangleMode) : DescriptorMangleComputer(builder, mode) { override fun copy(newMode: MangleMode): DescriptorMangleComputer = KonanDescriptorMangleComputer(builder, newMode) - override fun FunctionDescriptor.platformSpecificFunctionName(): String? { - (if (this is ConstructorDescriptor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo() - ?.let { - return buildString { - if (extensionReceiverParameter != null) { - append(extensionReceiverParameter!!.type.constructor.declarationDescriptor!!.name) - append(MangleConstant.FQN_SEPARATOR) - } - - append(MangleConstant.OBJC_MARK) - append(it.selector) - if (this@platformSpecificFunctionName is ConstructorDescriptor && this@platformSpecificFunctionName.isObjCConstructor) { - append(MangleConstant.OBJC_CONSTRUCTOR_MARK) - } - - if (this@platformSpecificFunctionName is PropertyAccessorDescriptor) { - append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK) - } - } - } - return null - } - - override fun FunctionDescriptor.specialValueParamPrefix(param: ValueParameterDescriptor): String { - return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else "" - } + override fun makePlatformSpecificFunctionNameMangleComputer(function: FunctionDescriptor) = + DescriptorObjCFunctionNameMangleComputer(function) } } diff --git a/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/ObjCFunctionNameMangleComputer.kt b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/ObjCFunctionNameMangleComputer.kt new file mode 100644 index 00000000000..8d4f2373ae6 --- /dev/null +++ b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/ObjCFunctionNameMangleComputer.kt @@ -0,0 +1,114 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.konan.serialization + +import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant +import org.jetbrains.kotlin.backend.common.serialization.mangle.PlatformSpecificFunctionNameMangleComputer +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.objcinterop.* +import org.jetbrains.kotlin.ir.types.getClass +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.NativeStandardInteropNames +import org.jetbrains.kotlin.native.interop.ObjCMethodInfo + +abstract class ObjCFunctionNameMangleComputer : PlatformSpecificFunctionNameMangleComputer { + + abstract fun getObjCMethodInfo(): ObjCMethodInfo? + + abstract fun getExtensionReceiverClassName(): Name? + + abstract fun isObjCConstructor(): Boolean + + abstract fun isPropertyAccessor(): Boolean + + abstract fun hasObjCMethodAnnotation(): Boolean + + abstract fun hasObjCFactoryAnnotation(): Boolean + + abstract fun isObjCClassMethod(): Boolean + + abstract fun getValueParameterName(valueParameter: ValueParameter): Name + + final override fun computePlatformSpecificFunctionName(): String? { + val objcMethodInfo = getObjCMethodInfo() ?: return null + return buildString { + getExtensionReceiverClassName()?.let { + append(it) + append(MangleConstant.FQN_SEPARATOR) + } + append(MangleConstant.OBJC_MARK) + append(objcMethodInfo.selector) + if (isObjCConstructor()) { + append(MangleConstant.OBJC_CONSTRUCTOR_MARK) + } + if (isPropertyAccessor()) { + append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK) + } + } + } + + final override fun computePlatformSpecificValueParameterPrefix(valueParameter: ValueParameter): String = + if (hasObjCMethodAnnotation() || hasObjCFactoryAnnotation() || isObjCClassMethod()) { + "${getValueParameterName(valueParameter)}:" + } else { + "" + } +} + +@ObsoleteDescriptorBasedAPI +class DescriptorObjCFunctionNameMangleComputer( + private val function: FunctionDescriptor +) : ObjCFunctionNameMangleComputer() { + + override fun getObjCMethodInfo(): ObjCMethodInfo? = + (if (function is ConstructorDescriptor && function.isObjCConstructor) function.getObjCInitMethod() else function) + ?.getObjCMethodInfo() + + override fun getExtensionReceiverClassName(): Name? = + function.extensionReceiverParameter?.run { type.constructor.declarationDescriptor!!.name } + + override fun isObjCConstructor(): Boolean = + function is ConstructorDescriptor && function.isObjCConstructor + + override fun isPropertyAccessor(): Boolean = + function is PropertyAccessorDescriptor + + override fun hasObjCMethodAnnotation(): Boolean = function.annotations.hasAnnotation(objCMethodFqName) + + override fun hasObjCFactoryAnnotation(): Boolean = function.annotations.hasAnnotation(objCFactoryFqName) + + override fun isObjCClassMethod(): Boolean = function.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() } + + override fun getValueParameterName(valueParameter: ValueParameterDescriptor): Name = valueParameter.name +} + +class IrObjCFunctionNameMangleComputer(private val function: IrFunction) : ObjCFunctionNameMangleComputer() { + override fun getObjCMethodInfo(): ObjCMethodInfo? = + (if (function is IrConstructor && function.isObjCConstructor) function.getObjCInitMethod() else function)?.getObjCMethodInfo() + + override fun getExtensionReceiverClassName(): Name? = + function.extensionReceiverParameter?.run { type.getClass()!!.name } + + override fun isObjCConstructor(): Boolean = + function is IrConstructor && function.isObjCConstructor + + override fun isPropertyAccessor(): Boolean = + (function as? IrSimpleFunction)?.correspondingPropertySymbol != null + + override fun hasObjCMethodAnnotation(): Boolean = function.hasAnnotation(NativeStandardInteropNames.objCMethodClassId) + + override fun hasObjCFactoryAnnotation(): Boolean = function.hasAnnotation(NativeStandardInteropNames.objCFactoryClassId) + + override fun isObjCClassMethod(): Boolean = function.isObjCClassMethod() + + override fun getValueParameterName(valueParameter: IrValueParameter): Name = valueParameter.name +} \ No newline at end of file