All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.wasm.ir.WasmExpressionBuilder.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2020 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.wasm.ir

import org.jetbrains.kotlin.wasm.ir.source.location.SourceLocation

/**
 * Class for building a wasm instructions list.
 *
 * Note in most of the methods, location is a required parameter, and it's expected to be passed explicitly.
 * The goals are:
 * - Avoid missing a location
 * - Avoid providing a wrong location
 *   - It's hard to achieve fully, but:
 *     - at least, an API user has to think about what to pass a location
 *     - it's not taken from some context-like thing implicitly, so you will not get it implicitly from a wrong context/scope.
 */
abstract class WasmExpressionBuilder {
    abstract fun buildInstr(op: WasmOp, location: SourceLocation, vararg immediates: WasmImmediate)

    abstract var numberOfNestedBlocks: Int

    fun buildConstI32(value: Int, location: SourceLocation) {
        buildInstr(WasmOp.I32_CONST, location, WasmImmediate.ConstI32(value))
    }

    fun buildConstI64(value: Long, location: SourceLocation) {
        buildInstr(WasmOp.I64_CONST, location, WasmImmediate.ConstI64(value))
    }

    fun buildConstF32(value: Float, location: SourceLocation) {
        buildInstr(WasmOp.F32_CONST, location, WasmImmediate.ConstF32(value.toRawBits().toUInt()))
    }

    fun buildConstF64(value: Double, location: SourceLocation) {
        buildInstr(WasmOp.F64_CONST, location, WasmImmediate.ConstF64(value.toRawBits().toULong()))
    }

    fun buildConstI32Symbol(value: WasmSymbol, location: SourceLocation) {
        buildInstr(WasmOp.I32_CONST, location, WasmImmediate.SymbolI32(value))
    }

    fun buildUnreachable(location: SourceLocation) {
        buildInstr(WasmOp.UNREACHABLE, location)
    }

    @Suppress("UNUSED_PARAMETER")
    inline fun buildBlock(label: String?, resultType: WasmType? = null, body: (Int) -> Unit) {
        numberOfNestedBlocks++
        buildInstr(WasmOp.BLOCK, SourceLocation.NoLocation("BLOCK"), WasmImmediate.BlockType.Value(resultType))
        body(numberOfNestedBlocks)
        buildEnd()
    }

    @Suppress("UNUSED_PARAMETER")
    inline fun buildLoop(label: String?, resultType: WasmType? = null, body: (Int) -> Unit) {
        numberOfNestedBlocks++
        buildInstr(WasmOp.LOOP, SourceLocation.NoLocation("LOOP"), WasmImmediate.BlockType.Value(resultType))
        body(numberOfNestedBlocks)
        buildEnd()
    }

    private fun buildInstrWithNoLocation(op: WasmOp, vararg immediates: WasmImmediate) {
        buildInstr(op, SourceLocation.NoLocation(op.mnemonic), *immediates)
    }

    @Suppress("UNUSED_PARAMETER")
    fun buildIf(label: String?, resultType: WasmType? = null) {
        numberOfNestedBlocks++
        buildInstrWithNoLocation(WasmOp.IF, WasmImmediate.BlockType.Value(resultType))
    }

    fun buildElse() {
        buildInstrWithNoLocation(WasmOp.ELSE)
    }

    fun buildBlock(resultType: WasmType? = null): Int {
        numberOfNestedBlocks++
        buildInstrWithNoLocation(WasmOp.BLOCK, WasmImmediate.BlockType.Value(resultType))
        return numberOfNestedBlocks
    }

    fun buildEnd() {
        numberOfNestedBlocks--
        buildInstrWithNoLocation(WasmOp.END)
    }

    fun buildBrInstr(brOp: WasmOp, absoluteBlockLevel: Int, location: SourceLocation) {
        val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
        assert(relativeLevel >= 0) { "Negative relative block index" }
        buildInstr(brOp, location, WasmImmediate.LabelIdx(relativeLevel))
    }

    fun buildBrOnCastInstr(
        brOp: WasmOp,
        absoluteBlockLevel: Int,
        fromIsNullable: Boolean,
        toIsNullable: Boolean,
        from: WasmHeapType,
        to: WasmHeapType,
        location: SourceLocation,
    ) {
        val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
        assert(relativeLevel >= 0) { "Negative relative block index" }

        val fromTypeFlag = if (fromIsNullable) 0b01 else 0
        val toTypeFlag = if (toIsNullable) 0b10 else 0
        val flags = fromTypeFlag or toTypeFlag

        buildInstr(
            brOp,
            location,
            WasmImmediate.ConstU8(flags.toUByte()),
            WasmImmediate.LabelIdx(relativeLevel),
            WasmImmediate.HeapType(from),
            WasmImmediate.HeapType(to)
        )
    }

    fun buildBr(absoluteBlockLevel: Int, location: SourceLocation) {
        buildBrInstr(WasmOp.BR, absoluteBlockLevel, location)
    }

    fun buildThrow(tagIdx: Int, location: SourceLocation) {
        buildInstr(WasmOp.THROW, location, WasmImmediate.TagIdx(tagIdx))
    }

    @Suppress("UNUSED_PARAMETER")
    fun buildTry(label: String?, resultType: WasmType? = null) {
        numberOfNestedBlocks++
        buildInstrWithNoLocation(WasmOp.TRY, WasmImmediate.BlockType.Value(resultType))
    }

    @Suppress("UNUSED_PARAMETER")
    fun buildTryTable(
        label: String?,
        catches: List,
        resultType: WasmType? = null
    ) {
        numberOfNestedBlocks++
        buildInstrWithNoLocation(
            WasmOp.TRY_TABLE,
            WasmImmediate.BlockType.Value(resultType),
            WasmImmediate.ConstI32(catches.size),
            *catches.toTypedArray()
        )
    }

    fun createNewCatch(tagIdx: Int, absoluteBlockLevel: Int) =
        createNewCatchImmediate(WasmImmediate.Catch.CatchType.CATCH, absoluteBlockLevel, tagIdx)

    fun createNewCatchAll(absoluteBlockLevel: Int) =
        createNewCatchImmediate(WasmImmediate.Catch.CatchType.CATCH_ALL, absoluteBlockLevel)

    private fun createNewCatchImmediate(
        catchType: WasmImmediate.Catch.CatchType,
        absoluteBlockLevel: Int,
        tagIdx: Int? = null
    ): WasmImmediate.Catch {
        val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
        assert(relativeLevel >= 0) { "Negative relative block index" }

        return WasmImmediate.Catch(
            catchType,
            listOfNotNull(
                tagIdx?.let(WasmImmediate::TableIdx),
                WasmImmediate.LabelIdx(relativeLevel)
            )
        )
    }

    fun buildCatch(tagIdx: Int) {
        buildInstrWithNoLocation(WasmOp.CATCH, WasmImmediate.TagIdx(tagIdx))
    }

    fun buildCatchAll() {
        buildInstrWithNoLocation(WasmOp.CATCH_ALL)
    }

    fun buildBrIf(absoluteBlockLevel: Int, location: SourceLocation) {
        buildBrInstr(WasmOp.BR_IF, absoluteBlockLevel, location)
    }

    fun buildCall(symbol: WasmSymbol, location: SourceLocation) {
        buildInstr(WasmOp.CALL, location, WasmImmediate.FuncIdx(symbol))
    }

    fun buildCallIndirect(
        symbol: WasmSymbol,
        tableIdx: WasmSymbolReadOnly = WasmSymbol(0),
        location: SourceLocation
    ) {
        buildInstr(
            WasmOp.CALL_INDIRECT,
            location,
            WasmImmediate.TypeIdx(symbol),
            WasmImmediate.TableIdx(tableIdx)
        )
    }

    fun buildGetLocal(local: WasmLocal, location: SourceLocation) {
        buildInstr(WasmOp.LOCAL_GET, location, WasmImmediate.LocalIdx(local))
    }

    fun buildSetLocal(local: WasmLocal, location: SourceLocation) {
        buildInstr(WasmOp.LOCAL_SET, location, WasmImmediate.LocalIdx(local))
    }

    fun buildGetGlobal(global: WasmSymbol, location: SourceLocation) {
        buildInstr(WasmOp.GLOBAL_GET, location, WasmImmediate.GlobalIdx(global))
    }

    fun buildSetGlobal(global: WasmSymbol, location: SourceLocation) {
        buildInstr(WasmOp.GLOBAL_SET, location, WasmImmediate.GlobalIdx(global))
    }

    fun buildStructGet(struct: WasmSymbol, fieldId: WasmSymbol, location: SourceLocation) {
        buildInstr(
            WasmOp.STRUCT_GET,
            location,
            WasmImmediate.GcType(struct),
            WasmImmediate.StructFieldIdx(fieldId)
        )
    }

    fun buildStructNew(struct: WasmSymbol, location: SourceLocation) {
        buildInstr(WasmOp.STRUCT_NEW, location, WasmImmediate.GcType(struct))
    }

    fun buildStructSet(struct: WasmSymbol, fieldId: WasmSymbol, location: SourceLocation) {
        buildInstr(
            WasmOp.STRUCT_SET,
            location,
            WasmImmediate.GcType(struct),
            WasmImmediate.StructFieldIdx(fieldId)
        )
    }

    fun buildRefCastNullStatic(toType: WasmSymbolReadOnly, location: SourceLocation) {
        buildInstr(WasmOp.REF_CAST_NULL, location, WasmImmediate.HeapType(WasmHeapType.Type(toType)))
    }

    fun buildRefCastStatic(toType: WasmSymbolReadOnly, location: SourceLocation) {
        buildInstr(WasmOp.REF_CAST, location, WasmImmediate.HeapType(WasmHeapType.Type(toType)))
    }

    fun buildRefTestStatic(toType: WasmSymbolReadOnly, location: SourceLocation) {
        buildInstr(WasmOp.REF_TEST, location, WasmImmediate.HeapType(WasmHeapType.Type(toType)))
    }

    fun buildRefNull(type: WasmHeapType, location: SourceLocation) {
        buildInstr(WasmOp.REF_NULL, location, WasmImmediate.HeapType(WasmRefType(type)))
    }

    fun buildDrop(location: SourceLocation) {
        buildInstr(WasmOp.DROP, location)
    }

    fun buildNop(location: SourceLocation) {
        buildInstr(WasmOp.NOP, location)
    }

    inline fun commentPreviousInstr(text: () -> String) {
        buildInstr(WasmOp.PSEUDO_COMMENT_PREVIOUS_INSTR, SourceLocation.NoLocation("Pseudo-instruction"), WasmImmediate.ConstString(text()))
    }

    inline fun commentGroupStart(text: () -> String) {
        buildInstr(WasmOp.PSEUDO_COMMENT_GROUP_START, SourceLocation.NoLocation("Pseudo-instruction"), WasmImmediate.ConstString(text()))
    }

    fun commentGroupEnd() {
        buildInstr(WasmOp.PSEUDO_COMMENT_GROUP_END, SourceLocation.NoLocation("Pseudo-instruction"))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy