fun linkAndCompileWasmIrToBinary()

in compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/wasmCompiler.kt [199:364]


fun linkAndCompileWasmIrToBinary(moduleConfiguration: WasmIrModuleConfiguration): WasmCompilerResult {
    val wasmCompiledFileFragments = moduleConfiguration.wasmCompiledFileFragments

    val configuration = moduleConfiguration.configuration
    val baseFileName = moduleConfiguration.baseFileName

    val isWasmJsTarget = configuration.get(WasmConfigurationKeys.WASM_TARGET) != WasmTarget.WASI

    val exceptionTagType: ExceptionTagType = when {
        configuration.getBoolean(WasmConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS) ->
            ExceptionTagType.TRAP
        isWasmJsTarget -> ExceptionTagType.JS_TAG
        else -> ExceptionTagType.WASM_TAG
    }

    val multimoduleParameters = moduleConfiguration.multimoduleOptions

    val wasmCompiledModuleFragment = WasmCompiledModuleFragment(wasmCompiledFileFragments, isWasmJsTarget)

    val wasmCommandModuleInitialization = configuration.get(WasmConfigurationKeys.WASM_COMMAND_MODULE) ?: false

    val linkedModule = wasmCompiledModuleFragment.linkWasmCompiledFragments(
        multimoduleOptions = multimoduleParameters,
        exceptionTagType = exceptionTagType,
        wasmCommandModuleInitialization = wasmCommandModuleInitialization,
    )

    val wasmStartFunctionDefined = linkedModule.exports.any { it.name == wasmStartExportName }
    val wasmInitializeFunctionDefined = linkedModule.exports.any { it.name == wasmInitializeExportName }

    val debuggerParameters = moduleConfiguration.debuggerOptions
    val dwarfGeneratorForBinary = runIf(debuggerParameters.generateDwarf) {
        DwarfGenerator()
    }
    val sourceMapGeneratorForBinary = runIf(debuggerParameters.generateSourceMaps) {
        SourceMapGenerator("$baseFileName.wasm", configuration)
    }
    val sourceMapGeneratorForText = runIf(moduleConfiguration.generateWat && debuggerParameters.generateSourceMaps) {
        SourceMapGenerator("$baseFileName.wat", configuration)
    }

    val wat = if (moduleConfiguration.generateWat) {
        val watGenerator = WasmIrToText(linkedModule, sourceMapGeneratorForText)
        watGenerator.appendWasmModule()
        watGenerator.toString()
    } else {
        null
    }

    val writer = ByteWriterWithOffsetWrite()

    val wasmIrToBinary =
        WasmIrToBinary(
            writer,
            linkedModule,
            moduleConfiguration.moduleName,
            debuggerParameters.emitNameSection,
            DebugInformationGeneratorImpl.createIfNeeded(
                sourceMapGenerator = sourceMapGeneratorForBinary,
                dwarfGenerator = dwarfGeneratorForBinary,
            )
        )

    wasmIrToBinary.appendWasmModule()

    val jsWrapper: String
    val dynamicJsModules = mutableListOf<DynamicJsModule>()

    if (isWasmJsTarget) {
        val jsModuleImports = mutableSetOf<String>()
        val jsFuns = mutableSetOf<JsCodeSnippet>()
        val jsModuleAndQualifierReferences = mutableSetOf<JsModuleAndQualifierReference>()
        wasmCompiledFileFragments.forEach { fragment ->
            jsModuleImports.addAll(fragment.jsModuleImports.values.distinct())
            jsFuns.addAll(fragment.jsFuns.values)
            jsModuleAndQualifierReferences.addAll(fragment.jsModuleAndQualifierReferences)
        }

        val useJsTag = !configuration.getBoolean(WasmConfigurationKeys.WASM_NO_JS_TAG)

        val jsBuiltinsComposed =
            wasmCompiledFileFragments.flatMap { fragment ->
                fragment.jsBuiltinsPolyfills.values.toList()
            }.joinToString("\n")

        if (jsBuiltinsComposed.isNotEmpty()) {
            dynamicJsModules.add(
                DynamicJsModule(
                    name = "js-builtins",
                    content = jsBuiltinsComposed
                )
            )
        }

        val wholeProgramMode: Boolean
        val isStdlibModule: Boolean
        val stdlibModule: WasmModuleDependencyImport?
        if (multimoduleParameters != null) {
            wholeProgramMode = false
            val stdlibModuleNameForImport = multimoduleParameters.stdlibModuleNameForImport
            isStdlibModule = stdlibModuleNameForImport == null
            stdlibModule = multimoduleParameters.dependencyModules.find { it.name == stdlibModuleNameForImport }
        } else {
            wholeProgramMode = true
            isStdlibModule = false
            stdlibModule = null
        }

        val importObject = generateImportObject(
            jsModuleImports = jsModuleImports,
            jsModuleAndQualifierReferences = jsModuleAndQualifierReferences,
            dependencyModules = multimoduleParameters?.dependencyModules ?: emptySet(),
            baseFileName = baseFileName,
            jsFuns = jsFuns,
            stdlibModule = stdlibModule,
            isStdlibModule = isStdlibModule,
            useJsTag = useJsTag,
            wholeProgramMode = wholeProgramMode
        )

        if (importObject.isNotEmpty()) {
            dynamicJsModules.add(
                DynamicJsModule(
                    name = "import-object",
                    content = importObject
                )
            )
        }

        jsWrapper = generateWebAssemblyJsInstanceInitializer(
            jsModuleImports = jsModuleImports,
            wasmFilePath = "./$baseFileName.wasm",
            exports = linkedModule.exports,
            useDebuggerCustomFormatters = debuggerParameters.useDebuggerCustomFormatters,
            baseFileName = baseFileName,
            isStdlibModule = isStdlibModule,
            wholeProgramMode = wholeProgramMode,
            wasmStartFunctionDefined = wasmStartFunctionDefined,
            wasmInitializeFunctionDefined = wasmInitializeFunctionDefined
        )

    } else {
        jsWrapper =
            wasmCompiledModuleFragment.generateAsyncWasiWrapper(
                wasmFilePath = "./$baseFileName.wasm",
                exports = linkedModule.exports,
                useDebuggerCustomFormatters = debuggerParameters.useDebuggerCustomFormatters,
                wasmStartFunctionDefined = wasmStartFunctionDefined,
                wasmInitializeFunctionDefined = wasmInitializeFunctionDefined
            )
    }

    return WasmCompilerResult(
        wat = wat,
        jsWrapper = jsWrapper.normalizeEmptyLines(),
        wasm = writer.getBinaryData(),
        debugInformation = DebugInformation(
            sourceMapGeneratorForBinary?.generate(),
            sourceMapGeneratorForText?.generate(),
        ),
        dts = moduleConfiguration.typeScriptFragment?.raw,
        useDebuggerCustomFormatters = debuggerParameters.useDebuggerCustomFormatters,
        dynamicJsModules = dynamicJsModules.map { it.copy(content = it.content.normalizeEmptyLines()) },
        baseFileName = baseFileName,
    )
}