fun parseModule()

in wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmBinaryToIR.kt [79:401]


    fun parseModule(): WasmModule {
        if (b.readUInt32() != 0x6d736100u)
            error("InvalidMagicNumber")

        val version = b.readUInt32()
        if (version != validVersion)
            error("InvalidVersion(version.toLong(), listOf(validVersion.toLong()))")

        var maxSectionId = 0
        while (true) {
            val sectionId = try {
                b.readVarUInt7().toInt()
            } catch (e: Throwable) { // Unexpected end
                break
            }
            if (sectionId > 12) error("InvalidSectionId(sectionId)")
            require(sectionId == 12 || maxSectionId == 12 || sectionId == 0 || sectionId > maxSectionId) {
                "Section ID $sectionId came after $maxSectionId"
            }
            maxSectionId = maxOf(sectionId, maxSectionId)

            val sectionLength = b.readVarUInt32AsInt()
            b.limitSize(sectionLength, "Wasm section $sectionId of size $sectionLength") {
                when (sectionId) {
                    // Skip custom section
                    0 -> b.readBytes(sectionLength)

                    // Type section
                    1 -> {
                        forEachVectorElement {
                            when (val type = readTypeDeclaration()) {
                                is WasmFunctionType ->
                                    functionTypes += type
                                is WasmStructDeclaration ->
                                    gcTypes += type
                                is WasmArrayDeclaration -> {}
                            }
                        }
                    }

                    // Import section
                    2 -> {
                        forEachVectorElement {
                            val importPair = WasmImportDescriptor(readString(), WasmSymbol(readString()))
                            when (val kind = b.readByte().toInt()) {
                                0 -> {
                                    val index = b.readVarUInt32AsInt()
                                    importedFunctions += WasmFunction.Imported(
                                        name = "",
                                        type = FunctionHeapType(index),
                                        importPair = importPair,
                                    ).also { importsInOrder.add(it) }
                                }
                                // Table
                                1 -> {
                                    val elementType = readRefType()
                                    val limits = readLimits()
                                    importedTables.add(WasmTable(limits, elementType, importPair).also { importsInOrder.add(it) })
                                }
                                2 -> {
                                    val limits = readLimits()
                                    importedMemories.add(WasmMemory(limits, importPair).also { importsInOrder.add(it) })
                                }
                                3 -> {
                                    importedGlobals.add(
                                        WasmGlobal(
                                            name = "",
                                            type = readValueType(),
                                            isMutable = b.readVarUInt1(),
                                            init = emptyList(),
                                            importPair = importPair
                                        ).also { importsInOrder.add(it) }
                                    )
                                }
                                4 -> {
                                    val tag = readTag(importPair)
                                    importedTags.add(tag)
                                    importsInOrder.add(tag)
                                }
                                else -> error(
                                    "Unsupported import kind $kind"
                                )
                            }
                        }
                    }

                    // Function section
                    3 -> {
                        forEachVectorElement {
                            val index = b.readVarUInt32AsInt()
                            val functionType = functionTypes[index]
                            definedFunctions.add(
                                WasmFunction.Defined(
                                    "",
                                    FunctionHeapType(index),
                                    locals = functionType.parameterTypes.mapIndexed { index, wasmType ->
                                        WasmLocal(index, "", wasmType, true)
                                    }.toMutableList()
                                )
                            )
                        }
                    }


                    // Table section
                    4 -> {
                        forEachVectorElement {
                            val elementType = readRefType()
                            val limits = readLimits()
                            table.add(
                                WasmTable(limits, elementType)
                            )
                        }
                    }

                    // Memory section
                    5 -> {
                        forEachVectorElement {
                            val limits = readLimits()
                            memory.add(WasmMemory(limits))
                        }
                    }

                    // Tag section
                    13 -> {
                        forEachVectorElement {
                            tags.add(readTag())
                        }
                    }

                    // Globals section
                    6 -> {
                        forEachVectorElement {
                            val expr = mutableListOf<WasmInstr>()
                            globals.add(
                                WasmGlobal(
                                    name = "",
                                    type = readValueType(),
                                    isMutable = b.readVarUInt1(),
                                    init = expr
                                )
                            )
                            readExpression(expr)
                        }
                    }

                    // Export section
                    7 -> {
                        forEachVectorElement {
                            val name = readString()
                            val kind = b.readByte().toInt()
                            val index = b.readVarUInt32AsInt()
                            exports.add(
                                when (kind) {
                                    0 -> WasmExport.Function(name, funByIdx(index))
                                    1 -> WasmExport.Table(name, tableByIdx(index))
                                    2 -> WasmExport.Memory(name, memoryByIdx(index))
                                    3 -> WasmExport.Global(name, globalByIdx(index))
                                    4 -> WasmExport.Tag(name, tagByIdx(index))
                                    else -> error("Invalid export kind $kind")
                                }
                            )
                        }
                    }

                    // Start section
                    8 -> {
                        require(startFunction == null) { "Start function is already defined" }
                        startFunction = funByIdx(b.readVarUInt32AsInt())
                    }

                    // Element section
                    9 -> {
                        forEachVectorElement {
                            val firstByte = b.readUByte().toInt()

                            val mode: WasmElement.Mode = when (firstByte) {
                                0, 4 -> {
                                    val offset = readExpression()
                                    WasmElement.Mode.Active(tableByIdx(0), offset)
                                }

                                1, 5 ->
                                    WasmElement.Mode.Passive

                                2, 6 -> {
                                    val tableIdx = b.readVarUInt32()
                                    val offset = readExpression()
                                    WasmElement.Mode.Active(tableByIdx(tableIdx.toInt()), offset)
                                }

                                3, 7 ->
                                    WasmElement.Mode.Declarative

                                else ->
                                    error("Invalid element first byte $firstByte")
                            }

                            val type = if (firstByte < 5) {
                                if (firstByte in 1..3) {
                                    val elemKind = b.readByte()
                                    require(elemKind == 0.toByte())
                                }
                                WasmFuncRef
                            } else {
                                readValueType()
                            }

                            val values: List<WasmTable.Value> = mapVector {
                                if (firstByte < 4) {
                                    WasmTable.Value.Function(funByIdx(b.readVarUInt32AsInt()))
                                } else {
                                    val exprBody = mutableListOf<WasmInstr>()
                                    readExpression(exprBody)
                                    WasmTable.Value.Expression(exprBody)
                                }
                            }

                            elements += WasmElement(
                                type,
                                values,
                                mode,
                            )
                        }
                    }

                    // Code section
                    10 -> {
                        forEachVectorElement { functionId ->
                            val function = definedFunctions[functionId.toInt()]
                            val size = b.readVarUInt32AsInt()
                            b.limitSize(size, "function body size") {
                                mapVector {
                                    val count = b.readVarUInt32AsInt()
                                    val valueType = readValueType()

                                    val firstLocalId =
                                        function.locals.lastOrNull()?.id?.plus(1) ?: 0

                                    repeat(count) { thisIdx ->
                                        function.locals.add(
                                            WasmLocal(
                                                firstLocalId + thisIdx,
                                                "",
                                                valueType,
                                                false
                                            )
                                        )
                                    }
                                }

                                readExpression(function.instructions, function.locals)
                            }
                        }
                    }

                    // Data section
                    11 -> {
                        forEachVectorElement {
                            val mode = when (val firstByte = b.readByte().toInt()) {
                                0 -> WasmDataMode.Active(0, readExpression())
                                1 -> WasmDataMode.Passive
                                2 -> WasmDataMode.Active(b.readVarUInt32AsInt(), readExpression())
                                else -> error("Unsupported data mode $firstByte")
                            }
                            val size = b.readVarUInt32AsInt()
                            val bytes = b.readBytes(size)
                            data += WasmData(mode, bytes)
                        }
                    }

                    // Data count section
                    12 -> {
                        b.readVarUInt32() // Data count
                        dataCount = true
                    }
                }
            }
        }

        val definedDeclarations = BinaryToIrResolver()
        functionTypes.forEach { type ->
            definedDeclarations.functionTypes.add(type)
        }
        gcTypes.forEach { type ->
            definedDeclarations.gcTypes.add(type)
        }
        importedFunctions.forEach { function ->
            definedDeclarations.functions.add(function)
        }
        definedFunctions.forEach { function ->
            definedDeclarations.functions.add(function)
        }
        importedGlobals.forEach { global ->
            definedDeclarations.globalFields.add(global)
        }
        globals.forEach { global ->
            definedDeclarations.globalFields.add(global)
        }

        return WasmModule(
            resolver = definedDeclarations,
            recGroups = (functionTypes + gcTypes).map { listOf(it) },
            importsInOrder = importsInOrder,
            importedFunctions = importedFunctions,
            importedMemories = importedMemories,
            importedTables = importedTables,
            importedGlobals = importedGlobals,
            importedTags = importedTags,
            definedFunctions = definedFunctions,
            tables = table,
            memories = memory,
            globals = globals,
            exports = exports,
            startFunction = startFunction,
            elements = elements,
            data = data,
            dataCount = dataCount,
            tags = tags
        ).also {
            it.calculateIds()
        }
    }