[K/N] Modularise :kotlin-native:native.backend to extract objc header generation (2/2)
^KT-63905 Fixed
This commit is contained in:
committed by
Space Team
parent
ae9f3d66c2
commit
0713866c1e
@@ -29,12 +29,6 @@ sourceSets {
|
||||
cli_bc {
|
||||
kotlin.srcDir 'cli.bc/src'
|
||||
}
|
||||
|
||||
test {
|
||||
kotlin {
|
||||
srcDir 'functionalTest/src'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileCompilerKotlin {
|
||||
@@ -43,6 +37,7 @@ compileCompilerKotlin {
|
||||
'-opt-in=kotlin.RequiresOptIn',
|
||||
"-opt-in=kotlinx.cinterop.BetaInteropApi",
|
||||
"-opt-in=kotlinx.cinterop.ExperimentalForeignApi",
|
||||
"-opt-in=org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi",
|
||||
'-Xskip-prerelease-check']
|
||||
}
|
||||
|
||||
@@ -159,6 +154,8 @@ dependencies {
|
||||
kotlin_script_runtime_jar project(":kotlin-script-runtime")
|
||||
|
||||
compilerApi project(":kotlin-native:utilities:basic-utils")
|
||||
compilerApi project(":native:objcexport-header-generator")
|
||||
compilerApi project(":native:base")
|
||||
|
||||
compilerImplementation project(":kotlin-compiler")
|
||||
compilerApi project(":native:kotlin-native-utils")
|
||||
@@ -187,11 +184,6 @@ dependencies {
|
||||
cli_bcApi sourceSets.compiler.output
|
||||
|
||||
cli_bcApiElements sourceSets.cli_bc.output
|
||||
|
||||
testImplementation(project(path: ":compiler:tests-common", configuration: "tests-jar"))
|
||||
testImplementation(libs.junit.jupiter.api)
|
||||
testImplementation(libs.junit.jupiter.params)
|
||||
testRuntimeOnly(libs.junit.jupiter.engine)
|
||||
}
|
||||
|
||||
classes.dependsOn 'compilerClasses', 'cli_bcClasses'
|
||||
@@ -251,27 +243,4 @@ RepoArtifacts.sourcesJar(project) {
|
||||
it.from(sourceSets["compiler"].allSource)
|
||||
}
|
||||
|
||||
RepoArtifacts.javadocJar(project)
|
||||
|
||||
/*
|
||||
Configure 'test' task
|
||||
*/
|
||||
|
||||
TasksKt.projectTest(project, JUnitMode.JUnit5)
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
dependsOn ':kotlin-native:dist'
|
||||
systemProperty("org.jetbrains.kotlin.native.home", distDir.canonicalPath)
|
||||
workingDir(rootProject.projectDir)
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
target {
|
||||
compilations {
|
||||
test.associateWith(compiler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RepoArtifacts.javadocJar(project)
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
|
||||
import org.jetbrains.kotlin.ir.declarations.isSingleFieldValueClass
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.atMostOne
|
||||
|
||||
fun IrType.getInlinedClassNative(): IrClass? = IrTypeInlineClassesSupport.getInlinedClass(this)
|
||||
|
||||
fun IrType.isInlinedNative(): Boolean = IrTypeInlineClassesSupport.isInlined(this)
|
||||
|
||||
fun IrClass.isInlined(): Boolean = IrTypeInlineClassesSupport.isInlined(this)
|
||||
|
||||
fun IrClass.isNativePrimitiveType() = IrTypeInlineClassesSupport.isTopLevelClass(this) &&
|
||||
KonanPrimitiveType.byFqNameParts[packageFqName]?.get(name) != null
|
||||
|
||||
fun IrType.computePrimitiveBinaryTypeOrNull(): PrimitiveBinaryType? =
|
||||
this.computeBinaryType().primitiveBinaryTypeOrNull()
|
||||
|
||||
fun IrType.computeBinaryType(): BinaryType<IrClass> = IrTypeInlineClassesSupport.computeBinaryType(this)
|
||||
|
||||
fun IrClass.inlinedClassIsNullable(): Boolean = this.defaultType.makeNullable().getInlinedClassNative() == this // TODO: optimize
|
||||
|
||||
fun IrClass.isUsedAsBoxClass(): Boolean = IrTypeInlineClassesSupport.isUsedAsBoxClass(this)
|
||||
|
||||
fun IrType.binaryTypeIsReference(): Boolean = this.computePrimitiveBinaryTypeOrNull() == null
|
||||
|
||||
internal inline fun <R> IrType.unwrapToPrimitiveOrReference(
|
||||
eachInlinedClass: (inlinedClass: IrClass, nullable: Boolean) -> Unit,
|
||||
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
|
||||
ifReference: (type: IrType) -> R
|
||||
): R = IrTypeInlineClassesSupport.unwrapToPrimitiveOrReference(this, eachInlinedClass, ifPrimitive, ifReference)
|
||||
|
||||
internal object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType>() {
|
||||
|
||||
override fun isNullable(type: IrType): Boolean = type.isNullable()
|
||||
|
||||
override fun makeNullable(type: IrType): IrType = type.makeNullable()
|
||||
|
||||
override tailrec fun erase(type: IrType): IrClass {
|
||||
val classifier = type.classifierOrFail
|
||||
return when (classifier) {
|
||||
is IrClassSymbol -> classifier.owner
|
||||
is IrTypeParameterSymbol -> erase(classifier.owner.superTypes.first())
|
||||
else -> error(classifier)
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeFullErasure(type: IrType): Sequence<IrClass> = when (val classifier = type.classifierOrFail) {
|
||||
is IrClassSymbol -> sequenceOf(classifier.owner)
|
||||
is IrTypeParameterSymbol -> classifier.owner.superTypes.asSequence().flatMap { computeFullErasure(it) }
|
||||
is IrScriptSymbol -> classifier.unexpectedSymbolKind<IrClassifierSymbol>()
|
||||
}
|
||||
|
||||
override fun hasInlineModifier(clazz: IrClass): Boolean = clazz.isSingleFieldValueClass
|
||||
|
||||
override fun getNativePointedSuperclass(clazz: IrClass): IrClass? {
|
||||
var superClass: IrClass? = clazz
|
||||
while (superClass != null && InteropFqNames.nativePointed.toSafe() != superClass.fqNameWhenAvailable)
|
||||
superClass = superClass.getSuperClassNotAny()
|
||||
return superClass
|
||||
}
|
||||
|
||||
override fun getInlinedClassUnderlyingType(clazz: IrClass): IrType =
|
||||
clazz.constructors.firstOrNull { it.isPrimary }?.valueParameters?.single()?.type
|
||||
?: clazz.declarations.filterIsInstance<IrProperty>().atMostOne { it.backingField?.takeUnless { it.isStatic } != null }?.backingField?.type
|
||||
?: clazz.inlineClassRepresentation!!.underlyingType
|
||||
|
||||
override fun getPackageFqName(clazz: IrClass) =
|
||||
clazz.packageFqName
|
||||
|
||||
override fun getName(clazz: IrClass): Name? =
|
||||
clazz.name
|
||||
|
||||
override fun isTopLevelClass(clazz: IrClass): Boolean = clazz.isTopLevel
|
||||
}
|
||||
-25
@@ -41,31 +41,6 @@ internal val IrFunction.isTypedIntrinsic: Boolean
|
||||
internal val IrConstructor.isConstantConstructorIntrinsic: Boolean
|
||||
get() = annotations.hasAnnotation(KonanFqNames.constantConstructorIntrinsic)
|
||||
|
||||
internal val arrayTypes = setOf(
|
||||
"kotlin.Array",
|
||||
"kotlin.ByteArray",
|
||||
"kotlin.CharArray",
|
||||
"kotlin.ShortArray",
|
||||
"kotlin.IntArray",
|
||||
"kotlin.LongArray",
|
||||
"kotlin.FloatArray",
|
||||
"kotlin.DoubleArray",
|
||||
"kotlin.BooleanArray",
|
||||
"kotlin.native.ImmutableBlob",
|
||||
"kotlin.native.internal.NativePtrArray"
|
||||
)
|
||||
|
||||
internal val arraysWithFixedSizeItems = setOf(
|
||||
"kotlin.ByteArray",
|
||||
"kotlin.CharArray",
|
||||
"kotlin.ShortArray",
|
||||
"kotlin.IntArray",
|
||||
"kotlin.LongArray",
|
||||
"kotlin.FloatArray",
|
||||
"kotlin.DoubleArray",
|
||||
"kotlin.BooleanArray"
|
||||
)
|
||||
|
||||
internal val IrClass.isArray: Boolean
|
||||
get() = this.fqNameForIrSerialization.asString() in arrayTypes
|
||||
|
||||
|
||||
+29
-6
@@ -1075,10 +1075,10 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
is MethodBridge.ReturnValue.Mapped -> if (LLVMTypeOf(targetResult!!) == llvm.voidType) {
|
||||
returnBridge.bridge.makeNothing(llvm)
|
||||
} else {
|
||||
when (returnBridge.bridge) {
|
||||
when (val bridge = returnBridge.bridge) {
|
||||
is ReferenceBridge -> return autoreleaseAndRet(kotlinReferenceToRetainedObjC(targetResult))
|
||||
is BlockPointerBridge -> return autoreleaseAndRet(kotlinFunctionToRetainedObjCBlockPointer(returnBridge.bridge, targetResult))
|
||||
is ValueTypeBridge -> kotlinToObjC(targetResult, returnBridge.bridge.objCValueType)
|
||||
is BlockPointerBridge -> return autoreleaseAndRet(kotlinFunctionToRetainedObjCBlockPointer(bridge, targetResult))
|
||||
is ValueTypeBridge -> kotlinToObjC(targetResult, bridge.objCValueType)
|
||||
}
|
||||
}
|
||||
MethodBridge.ReturnValue.WithError.Success -> llvm.int8(1) // true
|
||||
@@ -1198,11 +1198,11 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
if (LLVMTypeOf(kotlinValue) == llvm.voidType) {
|
||||
bridge.bridge.makeNothing(llvm)
|
||||
} else {
|
||||
when (bridge.bridge) {
|
||||
when (val typeBridge = bridge.bridge) {
|
||||
is ReferenceBridge -> kotlinReferenceToRetainedObjC(kotlinValue).also { objCReferenceArgsToRelease += it }
|
||||
is BlockPointerBridge -> kotlinFunctionToRetainedObjCBlockPointer(bridge.bridge, kotlinValue) // TODO: use stack-allocated block here.
|
||||
is BlockPointerBridge -> kotlinFunctionToRetainedObjCBlockPointer(typeBridge, kotlinValue) // TODO: use stack-allocated block here.
|
||||
.also { objCReferenceArgsToRelease += it }
|
||||
is ValueTypeBridge -> kotlinToObjC(kotlinValue, bridge.bridge.objCValueType)
|
||||
is ValueTypeBridge -> kotlinToObjC(kotlinValue, typeBridge.objCValueType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2006,3 +2006,26 @@ private fun NativeGenerationState.is64BitNSInteger(): Boolean {
|
||||
}
|
||||
return llvm.nsIntegerTypeWidth == 64L
|
||||
}
|
||||
|
||||
private fun MethodBridge.parametersAssociated(
|
||||
irFunction: IrFunction
|
||||
): List<Pair<MethodBridgeParameter, IrValueParameter?>> {
|
||||
val kotlinParameters = irFunction.allParameters.iterator()
|
||||
|
||||
return this.paramBridges.map {
|
||||
when (it) {
|
||||
is MethodBridgeValueParameter.Mapped,
|
||||
MethodBridgeReceiver.Instance,
|
||||
is MethodBridgeValueParameter.SuspendCompletion ->
|
||||
it to kotlinParameters.next()
|
||||
|
||||
MethodBridgeReceiver.Static, MethodBridgeSelector, MethodBridgeValueParameter.ErrorOutParameter ->
|
||||
it to null
|
||||
|
||||
MethodBridgeReceiver.Factory -> {
|
||||
kotlinParameters.next()
|
||||
it to null
|
||||
}
|
||||
}
|
||||
}.also { assert(!kotlinParameters.hasNext()) }
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.llvm.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.LlvmParameterAttribute
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
|
||||
internal val ObjCValueType.defaultParameterAttributes: List<LlvmParameterAttribute>
|
||||
get() = when (this) {
|
||||
ObjCValueType.BOOL -> listOf(LlvmParameterAttribute.SignExt)
|
||||
ObjCValueType.UNICHAR -> listOf(LlvmParameterAttribute.ZeroExt)
|
||||
ObjCValueType.CHAR -> listOf(LlvmParameterAttribute.SignExt)
|
||||
ObjCValueType.SHORT -> listOf(LlvmParameterAttribute.SignExt)
|
||||
ObjCValueType.UNSIGNED_CHAR -> listOf(LlvmParameterAttribute.ZeroExt)
|
||||
ObjCValueType.UNSIGNED_SHORT -> listOf(LlvmParameterAttribute.ZeroExt)
|
||||
else -> emptyList()
|
||||
}
|
||||
+35
-6
@@ -11,14 +11,15 @@ import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.CodeGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.ObjCExportBlockCodeGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.ObjCExportCodeGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageUtil
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.konan.exec.Command
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.file.createTempFile
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
internal class ObjCExportedInterface(
|
||||
val generatedClasses: Set<ClassDescriptor>,
|
||||
@@ -52,7 +53,7 @@ internal fun produceObjCExportInterface(
|
||||
val ignoreInterfaceMethodCollisions = config.configuration.getBoolean(BinaryOptions.objcExportIgnoreInterfaceMethodCollisions)
|
||||
val reportNameCollisions = config.configuration.getBoolean(BinaryOptions.objcExportReportNameCollisions)
|
||||
|
||||
val problemCollector = ObjCExportHeaderGeneratorImpl.ProblemCollector(context)
|
||||
val problemCollector = ObjCExportCompilerProblemCollector(context)
|
||||
|
||||
val namer = ObjCExportNamerImpl(
|
||||
moduleDescriptors.toSet(),
|
||||
@@ -66,11 +67,36 @@ internal fun produceObjCExportInterface(
|
||||
ignoreInterfaceMethodCollisions = ignoreInterfaceMethodCollisions,
|
||||
reportNameCollisions = reportNameCollisions,
|
||||
)
|
||||
val headerGenerator = ObjCExportHeaderGeneratorImpl(context, moduleDescriptors, mapper, namer, problemCollector, objcGenerics)
|
||||
val shouldExportKDoc = context.shouldExportKDoc()
|
||||
val additionalImports = context.config.configuration.getNotNull(KonanConfigKeys.FRAMEWORK_IMPORT_HEADERS)
|
||||
val headerGenerator = ObjCExportHeaderGenerator.createInstance(
|
||||
moduleDescriptors, mapper, namer, problemCollector, objcGenerics, shouldExportKDoc = shouldExportKDoc,
|
||||
additionalImports = additionalImports)
|
||||
headerGenerator.translateModule()
|
||||
return headerGenerator.buildInterface()
|
||||
}
|
||||
|
||||
private class ObjCExportCompilerProblemCollector(val context: PhaseContext) : ObjCExportProblemCollector {
|
||||
override fun reportWarning(text: String) {
|
||||
context.reportCompilationWarning(text)
|
||||
}
|
||||
|
||||
override fun reportWarning(declaration: DeclarationDescriptor, text: String) {
|
||||
val psi = (declaration as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
||||
?: return reportWarning(
|
||||
"$text\n (at ${DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(declaration)})"
|
||||
)
|
||||
|
||||
val location = MessageUtil.psiElementToMessageLocation(psi)
|
||||
|
||||
context.messageCollector.report(CompilerMessageSeverity.WARNING, text, location)
|
||||
}
|
||||
|
||||
override fun reportException(throwable: Throwable) {
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate framework directory with headers, module and info.plist.
|
||||
*/
|
||||
@@ -189,3 +215,6 @@ private fun ObjCExportedInterface.generateWorkaroundForSwiftSR10177(generationSt
|
||||
// In this case resulting framework will likely be unusable due to compile errors when importing it.
|
||||
}
|
||||
}
|
||||
|
||||
internal val PhaseContext.objCExportTopLevelNamePrefix: String
|
||||
get() = abbreviate(config.fullExportedNamePrefix)
|
||||
|
||||
Reference in New Issue
Block a user