[K/N] More clear separation of CAdapterGenerator

Separated CAdapterBindingsBuilder into
CAdapterCodegen and CAdapterApiExporter. It makes C export much more
comprehensible and allows to split it into more clear phases.
This commit is contained in:
Sergey Bogolepov
2022-12-08 17:43:46 +02:00
committed by Space Team
parent c33013e159
commit 287337007f
7 changed files with 157 additions and 146 deletions
@@ -108,8 +108,7 @@ internal val buildCExportsPhase = konanUnitPhase(
op = { op = {
val prefix = config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_") val prefix = config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_")
val cAdapterTypeTranslator = CAdapterTypeTranslator(prefix, this.builtIns) val cAdapterTypeTranslator = CAdapterTypeTranslator(prefix, this.builtIns)
this.cAdapterExportedElements = CAdapterGenerator(this, this.moduleDescriptor, cAdapterTypeTranslator) this.cAdapterExportedElements = CAdapterGenerator(this, cAdapterTypeTranslator).buildExports(this.moduleDescriptor)
.buildExports(this.symbolTable!!)
}, },
name = "BuildCExports", name = "BuildCExports",
description = "Build C exports", description = "Build C exports",
@@ -5,44 +5,31 @@
package org.jetbrains.kotlin.backend.konan.cexport package org.jetbrains.kotlin.backend.konan.cexport
import kotlinx.cinterop.cValuesOf import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import llvm.*
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.CodeGenerator
import org.jetbrains.kotlin.backend.konan.llvm.ContextUtils
import org.jetbrains.kotlin.backend.konan.llvm.ExceptionHandler
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.llvm.addLlvmFunctionWithDefaultAttributes
import org.jetbrains.kotlin.backend.konan.llvm.generateFunction
import org.jetbrains.kotlin.backend.konan.lower.getObjectClassInstanceFunction
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.isOverridable
import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import java.io.PrintWriter import java.io.PrintWriter
internal class CAdapterBindingsBuilder( /**
val codegen: CodeGenerator, * Third phase of C export:
val elements: CAdapterExportedElements, * 1. Create a C++ file with runtime bindings
) : ContextUtils { * 2. Create a header file with API
override val generationState = codegen.generationState * 3. (MinGW only) create EXPORTS def file.
*/
internal class CAdapterApiExporter(
private val generationState: NativeGenerationState,
private val elements: CAdapterExportedElements,
) {
private val typeTranslator = elements.typeTranslator private val typeTranslator = elements.typeTranslator
private val builtIns = elements.typeTranslator.builtIns private val builtIns = elements.typeTranslator.builtIns
private val scopes = elements.scopes
internal val prefix = context.config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_") private val prefix = elements.typeTranslator.prefix
private lateinit var outputStreamWriter: PrintWriter private lateinit var outputStreamWriter: PrintWriter
// Primitive built-ins and unsigned types // Primitive built-ins and unsigned types
@@ -57,92 +44,6 @@ internal class CAdapterBindingsBuilder(
builtIns.builtInsModule.findClassAcrossModuleDependencies(it.classId)!!.defaultType builtIns.builtInsModule.findClassAcrossModuleDependencies(it.classId)!!.defaultType
} }
fun build() {
val top = scopes.pop()
assert(scopes.isEmpty() && top.kind == ScopeKind.TOP)
// Now, let's generate C world adapters for all functions.
top.generateCAdapters(::buildCAdapter)
// Then generate data structure, describing generated adapters.
makeGlobalStruct(top)
}
private fun buildCAdapter(exportedElement: ExportedElement): Unit = with(exportedElement) {
when {
isFunction -> {
val function = declaration as FunctionDescriptor
val irFunction = irSymbol.owner as IrFunction
cname = "_konan_function_${owner.nextFunctionIndex()}"
val llvmCallable = codegen.llvmFunction(irFunction)
// If function is virtual, we need to resolve receiver properly.
val bridge = generateFunction(codegen, llvmCallable.functionType, cname) {
val callee = if (!DescriptorUtils.isTopLevelDeclaration(function) &&
irFunction.isOverridable
) {
val receiver = param(0)
lookupVirtualImpl(receiver, irFunction)
} else {
// KT-45468: Alias insertion may not be handled by LLVM properly, in case callee is in the cache.
// Hence, insert not an alias but a wrapper, hoping it will be optimized out later.
llvmCallable
}
val numParams = LLVMCountParams(llvmCallable.llvmValue)
val args = (0 until numParams).map { index -> param(index) }
callee.attributeProvider.addFunctionAttributes(this.function)
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
ret(result)
}
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
}
isClass -> {
val irClass = irSymbol.owner as IrClass
cname = "_konan_function_${owner.nextFunctionIndex()}"
// Produce type getter.
val getTypeFunction = addLlvmFunctionWithDefaultAttributes(
context,
llvm.module,
"${cname}_type",
kGetTypeFuncType
)
val builder = LLVMCreateBuilderInContext(llvm.llvmContext)!!
val bb = LLVMAppendBasicBlockInContext(llvm.llvmContext, getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, irClass.typeInfoPtr.llvm)
LLVMDisposeBuilder(builder)
// Produce instance getter if needed.
if (isSingletonObject) {
generateFunction(codegen, kGetObjectFuncType, "${cname}_instance") {
val value = call(
codegen.llvmFunction(context.getObjectClassInstanceFunction(irClass)),
emptyList(),
Lifetime.GLOBAL,
ExceptionHandler.Caller,
false,
returnSlot
)
ret(value)
}
}
}
isEnumEntry -> {
// Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}"
generateFunction(codegen, kGetObjectFuncType, cname) {
val irEnumEntry = irSymbol.owner as IrEnumEntry
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
ret(value)
}
}
}
}
private val kGetTypeFuncType = LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
// Abstraction leak for slot :(.
private val kGetObjectFuncType = LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!
private fun output(string: String, indent: Int = 0) { private fun output(string: String, indent: Int = 0) {
if (indent != 0) outputStreamWriter.print(" " * indent) if (indent != 0) outputStreamWriter.print(" " * indent)
outputStreamWriter.println(string) outputStreamWriter.println(string)
@@ -249,9 +150,11 @@ internal class CAdapterBindingsBuilder(
} }
} }
val exportedSymbols = mutableListOf<String>() private val exportedSymbols = mutableListOf<String>()
private fun makeGlobalStruct(top: ExportedElementScope) { // TODO: Pass temp and output files explicitly and untie from `NativeGenerationState`.
fun makeGlobalStruct() {
val top = elements.scopes.first()
val headerFile = generationState.outputFiles.cAdapterHeader val headerFile = generationState.outputFiles.cAdapterHeader
outputStreamWriter = headerFile.printWriter() outputStreamWriter = headerFile.printWriter()
@@ -285,7 +188,7 @@ internal class CAdapterBindingsBuilder(
output("typedef double ${prefix}_KDouble;") output("typedef double ${prefix}_KDouble;")
val typedef_KVector128 = "typedef float __attribute__ ((__vector_size__ (16))) ${prefix}_KVector128;" val typedef_KVector128 = "typedef float __attribute__ ((__vector_size__ (16))) ${prefix}_KVector128;"
if (context.config.target.family == Family.MINGW) { if (generationState.config.target.family == Family.MINGW) {
// Separate `output` for each line to ensure Windows EOL (LFCR), otherwise generated file will have inconsistent line ending. // Separate `output` for each line to ensure Windows EOL (LFCR), otherwise generated file will have inconsistent line ending.
output("#ifndef _MSC_VER") output("#ifndef _MSC_VER")
output(typedef_KVector128) output(typedef_KVector128)
@@ -476,7 +379,7 @@ internal class CAdapterBindingsBuilder(
output("RUNTIME_USED ${prefix}_ExportedSymbols* $exportedSymbol(void) { return &__konan_symbols;}") output("RUNTIME_USED ${prefix}_ExportedSymbols* $exportedSymbol(void) { return &__konan_symbols;}")
outputStreamWriter.close() outputStreamWriter.close()
if (context.config.target.family == Family.MINGW) { if (generationState.config.target.family == Family.MINGW) {
outputStreamWriter = generationState.outputFiles outputStreamWriter = generationState.outputFiles
.cAdapterDef .cAdapterDef
.printWriter() .printWriter()
@@ -0,0 +1,119 @@
/*
* Copyright 2010-2022 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.cexport
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.CodeGenerator
import org.jetbrains.kotlin.backend.konan.llvm.ContextUtils
import org.jetbrains.kotlin.backend.konan.llvm.ExceptionHandler
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.llvm.addLlvmFunctionWithDefaultAttributes
import org.jetbrains.kotlin.backend.konan.llvm.generateFunction
import org.jetbrains.kotlin.backend.konan.lower.getObjectClassInstanceFunction
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.isOverridable
import org.jetbrains.kotlin.resolve.DescriptorUtils
/**
* Second phase of C Export: build bitcode bridges from C wrappers to Kotlin functions.
*/
internal class CAdapterCodegen(
private val codegen: CodeGenerator,
override val generationState: NativeGenerationState,
) : ContextUtils {
fun buildAllAdaptersRecursively(elements: CAdapterExportedElements) {
val top = elements.scopes.single()
assert(top.kind == ScopeKind.TOP)
top.generateCAdapters(this::buildCAdapter)
}
private fun ExportedElementScope.generateCAdapters(builder: (ExportedElement) -> Unit) {
this.elements.forEach { builder(it) }
this.scopes.forEach { it.generateCAdapters(builder) }
}
private fun buildCAdapter(exportedElement: ExportedElement): Unit = with(exportedElement) {
when {
isFunction -> {
val function = declaration as FunctionDescriptor
val irFunction = irSymbol.owner as IrFunction
cname = "_konan_function_${owner.nextFunctionIndex()}"
val llvmCallable = codegen.llvmFunction(irFunction)
// If function is virtual, we need to resolve receiver properly.
val bridge = generateFunction(codegen, llvmCallable.functionType, cname) {
val callee = if (!DescriptorUtils.isTopLevelDeclaration(function) &&
irFunction.isOverridable
) {
val receiver = param(0)
lookupVirtualImpl(receiver, irFunction)
} else {
// KT-45468: Alias insertion may not be handled by LLVM properly, in case callee is in the cache.
// Hence, insert not an alias but a wrapper, hoping it will be optimized out later.
llvmCallable
}
val numParams = LLVMCountParams(llvmCallable.llvmValue)
val args = (0 until numParams).map { index -> param(index) }
callee.attributeProvider.addFunctionAttributes(this.function)
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
ret(result)
}
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
}
isClass -> {
val irClass = irSymbol.owner as IrClass
cname = "_konan_function_${owner.nextFunctionIndex()}"
// Produce type getter.
val getTypeFunction = addLlvmFunctionWithDefaultAttributes(
context,
llvm.module,
"${cname}_type",
kGetTypeFuncType
)
val builder = LLVMCreateBuilderInContext(llvm.llvmContext)!!
val bb = LLVMAppendBasicBlockInContext(llvm.llvmContext, getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, irClass.typeInfoPtr.llvm)
LLVMDisposeBuilder(builder)
// Produce instance getter if needed.
if (isSingletonObject) {
generateFunction(codegen, kGetObjectFuncType, "${cname}_instance") {
val value = call(
codegen.llvmFunction(context.getObjectClassInstanceFunction(irClass)),
emptyList(),
Lifetime.GLOBAL,
ExceptionHandler.Caller,
false,
returnSlot
)
ret(value)
}
}
}
isEnumEntry -> {
// Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}"
generateFunction(codegen, kGetObjectFuncType, cname) {
val irEnumEntry = irSymbol.owner as IrEnumEntry
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
ret(value)
}
}
}
}
private val kGetTypeFuncType = LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
// Abstraction leak for slot :(.
private val kGetObjectFuncType = LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.konan.exec.*
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.file.* import org.jetbrains.kotlin.konan.file.*
// Fourth phase of C export: compile runtime bindings to bitcode.
fun produceCAdapterBitcode(clang: ClangArgs, cppFileName: String, bitcodeFileName: String) { fun produceCAdapterBitcode(clang: ClangArgs, cppFileName: String, bitcodeFileName: String) {
val clangCommand = clang.clangCXX("-std=c++17", cppFileName, "-emit-llvm", "-c", "-o", bitcodeFileName) val clangCommand = clang.clangCXX("-std=c++17", cppFileName, "-emit-llvm", "-c", "-o", bitcodeFileName)
Command(clangCommand).execute() Command(clangCommand).execute()
@@ -5,26 +5,24 @@
package org.jetbrains.kotlin.backend.konan.cexport package org.jetbrains.kotlin.backend.konan.cexport
import llvm.*
import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.descriptors.allParameters
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.*
import org.jetbrains.kotlin.backend.konan.driver.phases.PsiToIrContext import org.jetbrains.kotlin.backend.konan.driver.phases.PsiToIrContext
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.isChildOf import org.jetbrains.kotlin.name.isChildOf
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.* import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.isUnit
internal enum class ScopeKind { internal enum class ScopeKind {
TOP, TOP,
@@ -96,11 +94,6 @@ internal class ExportedElementScope(val kind: ScopeKind, val name: String) {
return "$kind: $name ${elements.joinToString(", ")} ${scopes.joinToString("\n")}" return "$kind: $name ${elements.joinToString(", ")} ${scopes.joinToString("\n")}"
} }
fun generateCAdapters(builder: (ExportedElement) -> Unit) {
elements.forEach { builder(it) }
scopes.forEach { it.generateCAdapters(builder) }
}
// collects names of inner scopes to make sure function<->scope name clashes would be detected, and functions would be mangled with "_" suffix // collects names of inner scopes to make sure function<->scope name clashes would be detected, and functions would be mangled with "_" suffix
fun collectInnerScopeName(innerScope: ExportedElementScope) { fun collectInnerScopeName(innerScope: ExportedElementScope) {
scopeNames += innerScope.name scopeNames += innerScope.name
@@ -396,17 +389,18 @@ private fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescript
getPackage(it).fragments.filter { it.module == this } getPackage(it).fragments.filter { it.module == this }
} }
/**
* First phase of C export: walk given declaration descriptors and create [CAdapterExportedElements] from them.
*/
internal class CAdapterGenerator( internal class CAdapterGenerator(
private val context: PsiToIrContext, private val context: PsiToIrContext,
private val moduleDescriptor: ModuleDescriptor,
private val typeTranslator: CAdapterTypeTranslator, private val typeTranslator: CAdapterTypeTranslator,
) : DeclarationDescriptorVisitor<Boolean, Void?> { ) : DeclarationDescriptorVisitor<Boolean, Void?> {
private val scopes = mutableListOf<ExportedElementScope>() private val scopes = mutableListOf<ExportedElementScope>()
internal val prefix = typeTranslator.prefix internal val prefix = typeTranslator.prefix
private val paramNamesRecorded = mutableMapOf<String, Int>() private val paramNamesRecorded = mutableMapOf<String, Int>()
private var symbolTableOrNull: SymbolTable? = null internal val symbolTable get() = context.symbolTable!!
internal val symbolTable get() = symbolTableOrNull!!
internal fun paramsToUniqueNames(params: List<ParameterDescriptor>): Map<ParameterDescriptor, String> { internal fun paramsToUniqueNames(params: List<ParameterDescriptor>): Map<ParameterDescriptor, String> {
paramNamesRecorded.clear() paramNamesRecorded.clear()
@@ -536,17 +530,7 @@ internal class CAdapterGenerator(
private val moduleDescriptors = mutableSetOf<ModuleDescriptor>() private val moduleDescriptors = mutableSetOf<ModuleDescriptor>()
fun buildExports(symbolTable: SymbolTable): CAdapterExportedElements { fun buildExports(moduleDescriptor: ModuleDescriptor): CAdapterExportedElements {
this.symbolTableOrNull = symbolTable
try {
buildExports()
return CAdapterExportedElements(typeTranslator, scopes)
} finally {
this.symbolTableOrNull = null
}
}
private fun buildExports() {
scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin")) scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin"))
moduleDescriptors += moduleDescriptor moduleDescriptors += moduleDescriptor
moduleDescriptors += moduleDescriptor.getExportedDependencies(context.config) moduleDescriptors += moduleDescriptor.getExportedDependencies(context.config)
@@ -557,6 +541,7 @@ internal class CAdapterGenerator(
}) })
moduleDescriptor.getPackage(FqName.ROOT).accept(this, null) moduleDescriptor.getPackage(FqName.ROOT).accept(this, null)
return CAdapterExportedElements(typeTranslator, scopes)
} }
private val simpleNameMapping = mapOf( private val simpleNameMapping = mapOf(
@@ -15,5 +15,5 @@ internal val BuildCExports = createSimpleNamedCompilerPhase<PsiToIrContext, Fron
) { context, input -> ) { context, input ->
val prefix = context.config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_") val prefix = context.config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_")
val typeTranslator = CAdapterTypeTranslator(prefix, context.builtIns) val typeTranslator = CAdapterTypeTranslator(prefix, context.builtIns)
CAdapterGenerator(context, input.moduleDescriptor, typeTranslator).buildExports(context.symbolTable!!) CAdapterGenerator(context, typeTranslator).buildExports(input.moduleDescriptor)
} }
@@ -10,7 +10,8 @@ import llvm.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
import org.jetbrains.kotlin.backend.common.lower.inline.InlinerExpressionLocationHint import org.jetbrains.kotlin.backend.common.lower.inline.InlinerExpressionLocationHint
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.cexport.CAdapterBindingsBuilder import org.jetbrains.kotlin.backend.konan.cexport.CAdapterApiExporter
import org.jetbrains.kotlin.backend.konan.cexport.CAdapterCodegen
import org.jetbrains.kotlin.backend.konan.cgen.CBridgeOrigin import org.jetbrains.kotlin.backend.konan.cgen.CBridgeOrigin
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
@@ -327,7 +328,10 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
} }
} }
private fun appendCAdapters() { private fun appendCAdapters() {
CAdapterBindingsBuilder(codegen, context.cAdapterExportedElements).build() val elements = context.cAdapterExportedElements
CAdapterCodegen(codegen, generationState).buildAllAdaptersRecursively(elements)
// TODO: It is not a part of IrToBitcode. Maybe move it somewhere?
CAdapterApiExporter(generationState, elements).makeGlobalStruct()
} }
private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) { private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) {