fun makeGlobalStruct()

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()
        }
    }