in kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cexport/CAdapterApiExporter.kt [164:395]
fun makeGlobalStruct() {
val top = elements.scopes.first()
outputStreamWriter = headerFile.printWriter()
val exportedSymbol = "${prefix}_symbols"
exportedSymbols += exportedSymbol
output("#ifndef KONAN_${prefix.uppercase()}_H")
output("#define KONAN_${prefix.uppercase()}_H")
// TODO: use namespace for C++ case?
output("""
#ifdef __cplusplus
extern "C" {
#endif""".trimIndent())
output("""
#ifdef __cplusplus
typedef bool ${prefix}_KBoolean;
#else
typedef _Bool ${prefix}_KBoolean;
#endif
""".trimIndent())
output("typedef unsigned short ${prefix}_KChar;")
output("typedef signed char ${prefix}_KByte;")
output("typedef short ${prefix}_KShort;")
output("typedef int ${prefix}_KInt;")
output("typedef long long ${prefix}_KLong;")
output("typedef unsigned char ${prefix}_KUByte;")
output("typedef unsigned short ${prefix}_KUShort;")
output("typedef unsigned int ${prefix}_KUInt;")
output("typedef unsigned long long ${prefix}_KULong;")
output("typedef float ${prefix}_KFloat;")
output("typedef double ${prefix}_KDouble;")
val typedef_KVector128 = "typedef float __attribute__ ((__vector_size__ (16))) ${prefix}_KVector128;"
if (target.family == Family.MINGW) {
// Separate `output` for each line to ensure Windows EOL (LFCR), otherwise generated file will have inconsistent line ending.
output("#ifndef _MSC_VER")
output(typedef_KVector128)
output("#else")
output("#include <xmmintrin.h>")
output("typedef __m128 ${prefix}_KVector128;")
output("#endif")
} else {
output(typedef_KVector128)
}
output("typedef void* ${prefix}_KNativePtr;")
output("struct ${prefix}_KType;")
output("typedef struct ${prefix}_KType ${prefix}_KType;")
output("")
defineUsedTypes(top, 0)
output("")
makeScopeDefinitions(top, DefinitionKind.C_HEADER_DECLARATION, 0)
output("")
output("typedef struct {")
output("/* Service functions. */", 1)
output("void (*DisposeStablePointer)(${prefix}_KNativePtr ptr);", 1)
output("void (*DisposeString)(const char* string);", 1)
output("${prefix}_KBoolean (*IsInstance)(${prefix}_KNativePtr ref, const ${prefix}_KType* type);", 1)
predefinedTypes.forEach {
val nullableIt = it.makeNullable()
val argument = if (!it.isUnit()) typeTranslator.translateType(it) else "void"
output("${typeTranslator.translateType(nullableIt)} (*${it.createNullableNameForPredefinedType})($argument);", 1)
if (!it.isUnit())
output("$argument (*${it.createGetNonNullValueOfPredefinedType})(${typeTranslator.translateType(nullableIt)});", 1)
}
output("")
output("/* User functions. */", 1)
makeScopeDefinitions(top, DefinitionKind.C_HEADER_STRUCT, 1)
output("} ${prefix}_ExportedSymbols;")
output("extern ${prefix}_ExportedSymbols* $exportedSymbol(void);")
output("""
#ifdef __cplusplus
} /* extern "C" */
#endif""".trimIndent())
output("#endif /* KONAN_${prefix.uppercase()}_H */")
outputStreamWriter.close()
outputStreamWriter = cppAdapterFile.printWriter()
// Include header into C++ source.
headerFile.forEachLine { it -> output(it) }
output("""
|struct KObjHeader;
|typedef struct KObjHeader KObjHeader;
|struct KTypeInfo;
|typedef struct KTypeInfo KTypeInfo;
|
|struct FrameOverlay;
|typedef struct FrameOverlay FrameOverlay;
|
|#define RUNTIME_NOTHROW __attribute__((nothrow))
|
|#if __has_attribute(retain)
|#define RUNTIME_EXPORT __attribute__((used,retain))
|#else
|#define RUNTIME_EXPORT __attribute__((used))
|#endif
|
|#define RUNTIME_NORETURN __attribute__((noreturn))
|
|extern "C" {
|void UpdateStackRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|KObjHeader* AllocInstance(const KTypeInfo*, KObjHeader**) RUNTIME_NOTHROW;
|KObjHeader* DerefStablePointer(void*, KObjHeader**) RUNTIME_NOTHROW;
|void* CreateStablePointer(KObjHeader*) RUNTIME_NOTHROW;
|void DisposeStablePointer(void*) RUNTIME_NOTHROW;
|${prefix}_KBoolean IsInstanceInternal(const KObjHeader*, const KTypeInfo*) RUNTIME_NOTHROW;
|void EnterFrame(KObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|void LeaveFrame(KObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|void SetCurrentFrame(KObjHeader** start) RUNTIME_NOTHROW;
|FrameOverlay* getCurrentFrame() RUNTIME_NOTHROW;
|void Kotlin_initRuntimeIfNeeded();
|void Kotlin_mm_switchThreadStateRunnable() RUNTIME_NOTHROW;
|void Kotlin_mm_switchThreadStateNative() RUNTIME_NOTHROW;
|void HandleCurrentExceptionWhenLeavingKotlinCode();
|
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|char* CreateCStringFromString(const KObjHeader*);
|void DisposeCString(char* cstring);
|} // extern "C"
|
|struct ${prefix}_FrameOverlay {
| ${prefix}_FrameOverlay* previous;
| ${prefix}_KInt parameters;
| ${prefix}_KInt count;
|};
|
|class KObjHolder {
|public:
| KObjHolder() : obj_(nullptr) {
| EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| }
| explicit KObjHolder(const KObjHeader* obj) : obj_(nullptr) {
| EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| UpdateStackRef(&obj_, obj);
| }
| ~KObjHolder() {
| LeaveFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| }
| KObjHeader* obj() { return obj_; }
| KObjHeader** slot() { return &obj_; }
| private:
| ${prefix}_FrameOverlay frame_;
| KObjHeader* obj_;
|
| KObjHeader** frame() { return reinterpret_cast<KObjHeader**>(&frame_); }
|};
|
|class ScopedRunnableState {
|public:
| ScopedRunnableState() noexcept { Kotlin_mm_switchThreadStateRunnable(); }
| ~ScopedRunnableState() { Kotlin_mm_switchThreadStateNative(); }
| ScopedRunnableState(const ScopedRunnableState&) = delete;
| ScopedRunnableState(ScopedRunnableState&&) = delete;
| ScopedRunnableState& operator=(const ScopedRunnableState&) = delete;
| ScopedRunnableState& operator=(ScopedRunnableState&&) = delete;
|};
|
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
| Kotlin_initRuntimeIfNeeded();
| ScopedRunnableState stateGuard;
| DisposeStablePointer(ptr);
|}
|static void DisposeStringImpl(const char* ptr) {
| DisposeCString((char*)ptr);
|}
|static ${prefix}_KBoolean IsInstanceImpl(${prefix}_KNativePtr ref, const ${prefix}_KType* type) {
| Kotlin_initRuntimeIfNeeded();
| ScopedRunnableState stateGuard;
| KObjHolder holder;
| return IsInstanceInternal(DerefStablePointer(ref, holder.slot()), (const KTypeInfo*)type);
|}
""".trimMargin())
predefinedTypes.forEach {
assert(!it.isNothing())
val nullableIt = it.makeNullable()
val needArgument = !it.isUnit()
val (parameter, maybeComma) = if (needArgument)
("${typeTranslator.translateType(it)} value" to ",") else ("" to "")
val argument = if (needArgument) "value, " else ""
output("extern \"C\" KObjHeader* Kotlin_box${it.shortNameForPredefinedType}($parameter$maybeComma KObjHeader**);")
output("static ${typeTranslator.translateType(nullableIt)} ${it.createNullableNameForPredefinedType}Impl($parameter) {")
output("Kotlin_initRuntimeIfNeeded();", 1)
output("ScopedRunnableState stateGuard;", 1)
output("KObjHolder result_holder;", 1)
output("KObjHeader* result = Kotlin_box${it.shortNameForPredefinedType}($argument result_holder.slot());", 1)
output("return ${typeTranslator.translateType(nullableIt)} { .pinned = CreateStablePointer(result) };", 1)
output("}")
if (!it.isUnit()) {
output("extern \"C\" ${typeTranslator.translateType(it)} Kotlin_unbox${it.shortNameForPredefinedType}(KObjHeader*);")
output("static ${typeTranslator.translateType(it)} ${it.createGetNonNullValueOfPredefinedType}Impl(${typeTranslator.translateType(nullableIt)} value) {")
output("Kotlin_initRuntimeIfNeeded();", 1)
output("ScopedRunnableState stateGuard;", 1)
output("KObjHolder value_holder;", 1)
output("return Kotlin_unbox${it.shortNameForPredefinedType}(DerefStablePointer(value.pinned, value_holder.slot()));", 1)
output("}")
}
}
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_DECLARATION, 0)
output("static ${prefix}_ExportedSymbols __konan_symbols = {")
output(".DisposeStablePointer = DisposeStablePointerImpl,", 1)
output(".DisposeString = DisposeStringImpl,", 1)
output(".IsInstance = IsInstanceImpl,", 1)
predefinedTypes.forEach {
output(".${it.createNullableNameForPredefinedType} = ${it.createNullableNameForPredefinedType}Impl,", 1)
if (!it.isUnit()) {
output(".${it.createGetNonNullValueOfPredefinedType} = ${it.createGetNonNullValueOfPredefinedType}Impl,", 1)
}
}
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1)
output("};")
output("RUNTIME_EXPORT ${prefix}_ExportedSymbols* $exportedSymbol(void) { return &__konan_symbols;}")
outputStreamWriter.close()
if (defFile != null) {
outputStreamWriter = defFile.printWriter()
output("EXPORTS")
exportedSymbols.forEach { output(it) }
outputStreamWriter.close()
}
}