|
|
|
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
|
|
|
|
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
|
|
|
|
import org.jetbrains.kotlin.descriptors.*
|
|
|
|
|
import org.jetbrains.kotlin.name.FqName
|
|
|
|
|
import org.jetbrains.kotlin.resolve.annotations.*
|
|
|
|
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
|
|
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
|
|
|
|
|
import org.jetbrains.kotlin.types.TypeUtils
|
|
|
|
@@ -50,6 +51,7 @@ private enum class ElementKind {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private enum class DefinitionKind {
|
|
|
|
|
C_HEADER_DECLARATION,
|
|
|
|
|
C_HEADER_STRUCT,
|
|
|
|
|
C_SOURCE_DECLARATION,
|
|
|
|
|
C_SOURCE_STRUCT
|
|
|
|
@@ -85,7 +87,9 @@ private val cKeywords = setOf(
|
|
|
|
|
// Not exactly keywords, but reserved or standard-defined.
|
|
|
|
|
"and", "not", "or", "xor",
|
|
|
|
|
"bool", "complex", "imaginary"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
private val cnameAnnotation = FqName("konan.internal.CName")
|
|
|
|
|
|
|
|
|
|
private fun org.jetbrains.kotlin.types.KotlinType.isGeneric() =
|
|
|
|
|
constructor.declarationDescriptor is TypeParameterDescriptor
|
|
|
|
@@ -112,11 +116,19 @@ private fun isExportedClass(descriptor: ClassDescriptor): Boolean {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun functionImplName(descriptor: DeclarationDescriptor, default: String, shortName: Boolean): String {
|
|
|
|
|
assert(descriptor is FunctionDescriptor)
|
|
|
|
|
val annotation = descriptor.annotations.findAnnotation(cnameAnnotation) ?: return default
|
|
|
|
|
val key = if (shortName) "shortName" else "fullName"
|
|
|
|
|
val value = annotation.argumentValue(key) as String?
|
|
|
|
|
return value.takeIf { value != null && value.isNotEmpty() } ?: default
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class ExportedElementScope(val kind: ScopeKind, val name: String) {
|
|
|
|
|
val elements = mutableListOf<ExportedElement>()
|
|
|
|
|
val scopes = mutableListOf<ExportedElementScope>()
|
|
|
|
|
private val scopeNames = mutableSetOf<String>()
|
|
|
|
|
private val scopeNamesMap = mutableMapOf<DeclarationDescriptor, String>()
|
|
|
|
|
private val scopeNamesMap = mutableMapOf<Pair<DeclarationDescriptor, Boolean>, String>()
|
|
|
|
|
|
|
|
|
|
override fun toString(): String {
|
|
|
|
|
return "$kind: $name ${elements.joinToString(", ")} ${scopes.joinToString("\n")}"
|
|
|
|
@@ -131,19 +143,20 @@ private class ExportedElementScope(val kind: ScopeKind, val name: String) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun scopeUniqueName(descriptor: DeclarationDescriptor): String {
|
|
|
|
|
scopeNamesMap[descriptor]?.apply { return this }
|
|
|
|
|
fun scopeUniqueName(descriptor: DeclarationDescriptor, shortName: Boolean): String {
|
|
|
|
|
scopeNamesMap[descriptor to shortName]?.apply { return this }
|
|
|
|
|
var computedName = when (descriptor) {
|
|
|
|
|
is ConstructorDescriptor -> "${descriptor.constructedClass.fqNameSafe.shortName().asString()}"
|
|
|
|
|
is PropertyGetterDescriptor -> "get_${descriptor.correspondingProperty.name.asString()}"
|
|
|
|
|
is PropertySetterDescriptor -> "set_${descriptor.correspondingProperty.name.asString()}"
|
|
|
|
|
is FunctionDescriptor -> functionImplName(descriptor, descriptor.fqNameSafe.shortName().asString(), shortName)
|
|
|
|
|
else -> descriptor.fqNameSafe.shortName().asString()
|
|
|
|
|
}
|
|
|
|
|
while (scopeNames.contains(computedName) || cKeywords.contains(computedName)) {
|
|
|
|
|
computedName += "_"
|
|
|
|
|
}
|
|
|
|
|
scopeNames += computedName
|
|
|
|
|
scopeNamesMap[descriptor] = computedName
|
|
|
|
|
scopeNamesMap[descriptor to shortName] = computedName
|
|
|
|
|
return computedName
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -180,7 +193,7 @@ private class ExportedElement(val kind: ElementKind,
|
|
|
|
|
generateFunction(owner.codegen, LLVMGetElementType(llvmFunction.type)!!, cname) {
|
|
|
|
|
val receiver = param(0)
|
|
|
|
|
val numParams = LLVMCountParams(llvmFunction)
|
|
|
|
|
val args = (0 .. numParams - 1).map { index -> param(index) }
|
|
|
|
|
val args = (0..numParams - 1).map { index -> param(index) }
|
|
|
|
|
val callee = lookupVirtualImpl(receiver, function)
|
|
|
|
|
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
|
|
|
|
ret(result)
|
|
|
|
@@ -211,25 +224,33 @@ private class ExportedElement(val kind: ElementKind,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun uniqueName(descriptor: DeclarationDescriptor) = scope.scopeUniqueName(descriptor)
|
|
|
|
|
fun uniqueName(descriptor: DeclarationDescriptor, shortName: Boolean) =
|
|
|
|
|
scope.scopeUniqueName(descriptor, shortName)
|
|
|
|
|
|
|
|
|
|
val isFunction = declaration is FunctionDescriptor
|
|
|
|
|
val isTopLevelFunction: Boolean
|
|
|
|
|
get() {
|
|
|
|
|
if (declaration !is FunctionDescriptor || !declaration.annotations.hasAnnotation(cnameAnnotation))
|
|
|
|
|
return false
|
|
|
|
|
val annotation = declaration.annotations.findAnnotation(cnameAnnotation)!!
|
|
|
|
|
val fullName = annotation.argumentValue("fullName") as String
|
|
|
|
|
return fullName.isNotEmpty()
|
|
|
|
|
}
|
|
|
|
|
val isClass = declaration is ClassDescriptor && declaration.kind != ClassKind.ENUM_ENTRY
|
|
|
|
|
val isEnumClass = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_CLASS
|
|
|
|
|
val isEnumEntry = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_ENTRY
|
|
|
|
|
|
|
|
|
|
fun makeCFunctionSignature(): List<Pair<String, ClassDescriptor>> {
|
|
|
|
|
fun makeCFunctionSignature(shortName: Boolean): List<Pair<String, ClassDescriptor>> {
|
|
|
|
|
if (!isFunction) {
|
|
|
|
|
throw Error("only for functions")
|
|
|
|
|
}
|
|
|
|
|
val descriptor = declaration
|
|
|
|
|
val original = descriptor.original as FunctionDescriptor
|
|
|
|
|
val returned = when {
|
|
|
|
|
original is ConstructorDescriptor -> uniqueName(original) to original.constructedClass
|
|
|
|
|
// Suspend functions actually return 'Any?'.
|
|
|
|
|
original.isSuspend -> uniqueName(original) to
|
|
|
|
|
original is ConstructorDescriptor -> uniqueName(original, shortName) to original.constructedClass
|
|
|
|
|
// Suspend functions actually return 'Any?'.
|
|
|
|
|
original.isSuspend -> uniqueName(original, shortName) to
|
|
|
|
|
TypeUtils.getClassDescriptor(owner.context.builtIns.nullableAnyType)!!
|
|
|
|
|
else -> uniqueName(original) to TypeUtils.getClassDescriptor(original.returnType!!)!!
|
|
|
|
|
else -> uniqueName(original, shortName) to TypeUtils.getClassDescriptor(original.returnType!!)!!
|
|
|
|
|
}
|
|
|
|
|
val params = ArrayList(original.explicitParameters.mapIndexed() { index, it ->
|
|
|
|
|
"p$index /* ${it.name.asString()} */" to TypeUtils.getClassDescriptor(it.type)!!
|
|
|
|
@@ -260,10 +281,18 @@ private class ExportedElement(val kind: ElementKind,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun makeFunctionPointerString(): String {
|
|
|
|
|
val signature = makeCFunctionSignature()
|
|
|
|
|
val signature = makeCFunctionSignature(true)
|
|
|
|
|
return "${owner.translateType(signature[0].second)} (*${signature[0].first})(${signature.drop(1).map { it -> "${owner.translateType(it.second)} ${it.first}" }.joinToString(", ")});"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun makeTopLevelFunctionString(): Pair<String, String> {
|
|
|
|
|
val signature = makeCFunctionSignature(false)
|
|
|
|
|
val name = signature[0].first
|
|
|
|
|
return (name to
|
|
|
|
|
"extern ${owner.translateType(signature[0].second)} $name(${signature.drop(1).map { it -> "${owner.translateType(it.second)} ${it.first}" }.joinToString(", ")});")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun makeFunctionDeclaration(): String {
|
|
|
|
|
assert(isFunction)
|
|
|
|
|
val bridge = makeBridgeSignature()
|
|
|
|
@@ -273,7 +302,7 @@ private class ExportedElement(val kind: ElementKind,
|
|
|
|
|
builder.append("(${bridge.drop(1).joinToString(", ")});\n")
|
|
|
|
|
|
|
|
|
|
// Now the C function body.
|
|
|
|
|
builder.append(translateBody(makeCFunctionSignature()))
|
|
|
|
|
builder.append(translateBody(makeCFunctionSignature(false)))
|
|
|
|
|
return builder.toString()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -319,9 +348,16 @@ private class ExportedElement(val kind: ElementKind,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val cnameImpl: String
|
|
|
|
|
get() = if (isTopLevelFunction)
|
|
|
|
|
functionImplName(declaration, "******" /* Default value must never be used. */, false)
|
|
|
|
|
else
|
|
|
|
|
"${cname}_impl"
|
|
|
|
|
|
|
|
|
|
private fun translateBody(cfunction: List<Pair<String, ClassDescriptor>>): String {
|
|
|
|
|
val visibility = if (isTopLevelFunction) "RUNTIME_USED extern \"C\"" else "static"
|
|
|
|
|
val builder = StringBuilder()
|
|
|
|
|
builder.append("static ${owner.translateType(cfunction[0].second)} ${cname}_impl(${cfunction.drop(1).mapIndexed { index, it -> "${owner.translateType(it.second)} arg${index}" }.joinToString(", ")}) {\n")
|
|
|
|
|
builder.append("$visibility ${owner.translateType(cfunction[0].second)} ${cnameImpl}(${cfunction.drop(1).mapIndexed { index, it -> "${owner.translateType(it.second)} arg${index}" }.joinToString(", ")}) {\n")
|
|
|
|
|
val args = ArrayList(cfunction.drop(1).mapIndexed { index, pair ->
|
|
|
|
|
translateArgument("arg$index", pair.second, Direction.C_TO_KOTLIN, builder)
|
|
|
|
|
})
|
|
|
|
@@ -501,8 +537,8 @@ internal class CAdapterGenerator(
|
|
|
|
|
|
|
|
|
|
override fun visitModuleDeclaration(descriptor: ModuleDescriptor, ignored: Void?): Boolean {
|
|
|
|
|
currentPackageFragments = descriptor.getPackageFragments().sortedWith(
|
|
|
|
|
Comparator {
|
|
|
|
|
o1, o2 -> o1.fqName.toString().compareTo(o2.fqName.toString())
|
|
|
|
|
Comparator { o1, o2 ->
|
|
|
|
|
o1.fqName.toString().compareTo(o2.fqName.toString())
|
|
|
|
|
})
|
|
|
|
|
seenPackageFragments.clear()
|
|
|
|
|
descriptor.getPackage(FqName.ROOT).accept(this, null)
|
|
|
|
@@ -560,6 +596,16 @@ internal class CAdapterGenerator(
|
|
|
|
|
|
|
|
|
|
private fun makeElementDefinition(element: ExportedElement, kind: DefinitionKind, indent: Int) {
|
|
|
|
|
when (kind) {
|
|
|
|
|
DefinitionKind.C_HEADER_DECLARATION -> {
|
|
|
|
|
when {
|
|
|
|
|
element.isTopLevelFunction -> {
|
|
|
|
|
val (name, declaration) = element.makeTopLevelFunctionString()
|
|
|
|
|
exportedSymbols += name
|
|
|
|
|
output(declaration, 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefinitionKind.C_HEADER_STRUCT -> {
|
|
|
|
|
when {
|
|
|
|
|
element.isFunction ->
|
|
|
|
@@ -589,7 +635,7 @@ internal class CAdapterGenerator(
|
|
|
|
|
DefinitionKind.C_SOURCE_STRUCT -> {
|
|
|
|
|
when {
|
|
|
|
|
element.isFunction ->
|
|
|
|
|
output("/* ${element.name} = */ ${element.cname}_impl, ", indent)
|
|
|
|
|
output("/* ${element.name} = */ ${element.cnameImpl}, ", indent)
|
|
|
|
|
element.isClass ->
|
|
|
|
|
output("/* Type for ${element.name} = */ ${element.cname}, ", indent)
|
|
|
|
|
element.isEnumEntry ->
|
|
|
|
@@ -600,9 +646,7 @@ internal class CAdapterGenerator(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun makeScopeDefinitions(scope: ExportedElementScope,
|
|
|
|
|
kind: DefinitionKind,
|
|
|
|
|
indent: Int) {
|
|
|
|
|
private fun makeScopeDefinitions(scope: ExportedElementScope, kind: DefinitionKind, indent: Int) {
|
|
|
|
|
if (kind == DefinitionKind.C_HEADER_STRUCT) output("struct {", indent)
|
|
|
|
|
if (kind == DefinitionKind.C_SOURCE_STRUCT) output(".${scope.name} = {", indent)
|
|
|
|
|
scope.elements.forEach { makeElementDefinition(it, kind, indent + 1) }
|
|
|
|
@@ -632,11 +676,14 @@ internal class CAdapterGenerator(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val exportedSymbols = mutableListOf<String>()
|
|
|
|
|
|
|
|
|
|
private fun makeGlobalStruct(top: ExportedElementScope) {
|
|
|
|
|
val headerFile = context.config.tempFiles.cAdapterHeader
|
|
|
|
|
outputStreamWriter = headerFile.printWriter()
|
|
|
|
|
|
|
|
|
|
val exportedSymbol = "${prefix}_symbols"
|
|
|
|
|
exportedSymbols += exportedSymbol
|
|
|
|
|
|
|
|
|
|
output("#ifndef KONAN_${prefix.toUpperCase()}_H")
|
|
|
|
|
output("#define KONAN_${prefix.toUpperCase()}_H")
|
|
|
|
@@ -660,6 +707,9 @@ internal class CAdapterGenerator(
|
|
|
|
|
output("")
|
|
|
|
|
defineUsedTypes(top, 0)
|
|
|
|
|
|
|
|
|
|
output("")
|
|
|
|
|
makeScopeDefinitions(top, DefinitionKind.C_HEADER_DECLARATION, 0)
|
|
|
|
|
|
|
|
|
|
output("")
|
|
|
|
|
output("typedef struct {")
|
|
|
|
|
output("/* Service functions. */", 1)
|
|
|
|
@@ -684,8 +734,8 @@ internal class CAdapterGenerator(
|
|
|
|
|
println("Produced dynamic library API in ${prefix}_api.h")
|
|
|
|
|
|
|
|
|
|
outputStreamWriter = context.config.tempFiles
|
|
|
|
|
.cAdapterCpp
|
|
|
|
|
.printWriter()
|
|
|
|
|
.cAdapterCpp
|
|
|
|
|
.printWriter()
|
|
|
|
|
|
|
|
|
|
// Include header into C++ source.
|
|
|
|
|
headerFile.forEachLine { it -> output(it) }
|
|
|
|
@@ -750,10 +800,10 @@ internal class CAdapterGenerator(
|
|
|
|
|
|
|
|
|
|
if (context.config.targetManager.target.family == Family.WINDOWS) {
|
|
|
|
|
outputStreamWriter = context.config.tempFiles
|
|
|
|
|
.cAdapterDef
|
|
|
|
|
.printWriter()
|
|
|
|
|
.cAdapterDef
|
|
|
|
|
.printWriter()
|
|
|
|
|
output("EXPORTS")
|
|
|
|
|
output(exportedSymbol)
|
|
|
|
|
exportedSymbols.forEach { output(it) }
|
|
|
|
|
outputStreamWriter.close()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|