wasm_milkir

WebAssembly dialect adapter for MilkIR extension operations

wasm
webassembly
milkir
compiler
dialect
moon add Milky2018/wasm_milkir@0.6.2
Download zip
Author
Version
0.6.2
License
Apache-2.0
Last updated
2 days ago
Downloads
93

Dependencies

README

#wasm_milkir

WebAssembly dialect adapter for MilkIR extension operations.

wasm_milkir provides the Wasm-specific opcode set, extension descriptors, and builder helpers used with MilkIR. Frontends encode Wasm operations through typed WasmOpcode constructors, then a lowering adapter checks and decodes those extensions before machine lowering.

Typed Wasm builders only emit IR data; they do not attach validator closures to the MilkIR function. Generic MilkIR finalization checks the extension envelope and its explicit signature, while verify_function applies context-free schema contracts. Operations whose contracts depend on module or linker metadata must use an explicit WasmValidationContext and verify_function_with_context. Wasm lowering requires the same context and validates it immediately before instruction selection.

Typed constructors, serialized opcode names, and immediate layouts are defined once in wasm_opcodes.schema. During development, dev_build runs the deterministic tools/generate_wasm_opcodes.py generator to refresh the committed dialect_generated.mbt source. Published packages include that generated MoonBit source, so downstream builds neither load the schema at runtime nor execute development build rules.

#Packages

  • Milky2018/wasm_milkir: Wasm opcode encoding/decoding and builder helpers for Milky2018/milkir.

#How it fits

MilkIR represents common SSA operations directly. This package represents WebAssembly operations that need additional immediates or lowering semantics as typed MilkIR extensions. The extension descriptor lets a lowering pipeline validate the encoded operation before decoding it.

Common arithmetic, calls, references, and SIMD operations use MilkIR's semantic opcode families directly. In particular, the Wasm frontend consumes SIMD memidx, alignment, and offset fields while constructing the effective address; the resulting MilkIR VectorOp carries only vector load/store semantics.

Linear-memory base pointers use MilkIR GlobalValue declarations rather than a Wasm extension opcode. memory_base_context_field identifies the memory index, the declaration records Heap(memidx) provenance, and the frontend chooses Stable only when the embedding guarantees that the base cannot move during the function invocation. Contextual validation checks that the memory exists; wasm_machv resolves the opaque field through its embedding environment.

#Example: map Wasm reference types to MilkIR

///|
test "map Wasm reference spelling to generic MilkIR references" {
inspect(wasm_funcref_type().to_string(), content="callable_ref")
inspect(wasm_externref_type().to_string(), content="opaque_ref")
}

#Example: encode a Wasm memory operation

///|
test "build a Wasm memory.size extension instruction" {
let builder = @milkir.FunctionBuilder::FunctionBuilder("memory_size")
let symbols = RuntimeSymbols::with_runtime_prefix("example.runtime")
let vmctx = builder.add_param(I64)
builder.add_result(I32)
let size = memory_size(builder, symbols, vmctx, 0)
builder.return_([size])
let func = builder.get_function()
inspect(func.blocks.length(), content="1")
verify_function(func)
match func.blocks[0].instructions[1].opcode {
Call(Direct(symbol, _)) =>
inspect(symbol.name, content="example.runtime.memory_size")
_ => inspect(false, content="true")
}
}

#Example: validate and decode a Wasm extension

///|
test "validate and decode a typed Wasm extension operation" {
let opcode = WasmOpcode::RefTest(3, true)
let ext = encode(opcode)
let desc = descriptor(opcode)
inspect(ext.matches_descriptor(desc), content="true")
inspect(decode(ext) == Some(opcode), content="true")
let malformed = @milkir.ExtOp(
"wasm",
"ref_test",
FixedArray::makei(2, fn(i) { if i == 0 { 3 } else { 2 } }),
)
debug_inspect(
decode_error(malformed),
content=(
#|Some("malformed Wasm MilkIR extension 'ref_test': immediate 1 is a bool flag encoded as 0 or 1, got 2")
),
)
}

#
RuntimeSymbols

type RuntimeSymbols derive(Eq,
Debug
)

Embedding-specific external names for WebAssembly runtime helpers.

#
RuntimeSymbols::symbol_name

fn RuntimeSymbols::symbol_name(self : RuntimeSymbols, helper : WasmRuntimeHelper) -> String

#
RuntimeSymbols::with_runtime_prefix

fn RuntimeSymbols::with_runtime_prefix(prefix : String) -> RuntimeSymbols

#
WasmDefinedTypeContract

pub(all) enum WasmDefinedTypeContract {
Function(WasmFunctionContract)
Struct(Array[WasmFieldContract])
Array(WasmFieldContract)
} derive(Eq,
Debug
)

The contextual contract for a WebAssembly indexed type.

#
WasmFieldContract

pub(all) struct WasmFieldContract {
storage : WasmStorageContract
mutable_ : Bool
defaultable : Bool
} derive(Eq,
Debug
)

The contextual contract for one WebAssembly struct field or array element.

#
WasmFunctionContract

pub(all) struct WasmFunctionContract {
params : Array[
Type
]
results : Array[
Type
]
} derive(Eq,
Debug
)

The lowered MilkIR carrier contract for a WebAssembly function type.

#
WasmOpcode

pub(all) enum WasmOpcode {
WasmCall(Int)
WasmCallIndirect(Int, Int)
CallRef(Int)
ReturnCall(Int)
ReturnCallIndirect(Int, Int)
ReturnCallRef(Int)
GetFuncRef(Int)
StructNew(Int)
StructNewDefault(Int)
StructGet(Int, Int)
StructGetS(Int, Int, Int)
StructGetU(Int, Int, Int)
StructSet(Int, Int)
ArrayNew(Int)
ArrayNewDefault(Int)
ArrayNewFixed(Int, Int)
ArrayGet(Int)
ArrayGetS(Int, Int)
ArrayGetU(Int, Int)
ArraySet(Int)
ArrayLen
ArrayFill(Int)
ArrayCopy(Int, Int)
ArrayNewData(Int, Int)
ArrayNewElem(Int, Int)
ArrayInitData(Int, Int)
ArrayInitElem(Int, Int)
I31New
I31GetS
I31GetU
RefTest(Int, Bool)
RefCast(Int, Bool)
AnyConvertExtern
ExternConvertAny
RefEq
Throw(Int)
ThrowRef
TryTableBegin(Int)
TryTableEnd(Int)
GetExceptionTag
GetExceptionValue(Int)
GetExceptionValueCount
Delegate(Int)
SpillLocalsForThrow(Int)
GetSpilledLocal(Int)
} derive(Eq, Hash,
Debug
)

#
WasmRuntimeHelper

pub(all) enum WasmRuntimeHelper {
MemoryGrow
MemorySize
MemoryFill
MemoryCopy
MemoryInit
DataDrop
TableGrow
TableFill
TableCopy
TableInit
ElemDrop
CancelPoll
GcRefTest
GcRefCast
GcStructGet
GcStructSet
GcArrayGet
GcArraySet
GcArrayLen
GcArrayFill
GcArrayCopy
GcArrayNewData
GcArrayNewElem
GcArrayInitData
GcArrayInitElem
GcTypeCheckSubtype
GcRegisterStructInline
GcRegisterArrayInline
GcAllocStructSlow
GcAllocArrayFromValuesSlow
GcAllocArraySlow
GcStructGetV128
GcStructSetV128
GcArrayGetV128
GcArraySetV128
GcArrayFillV128
GcAllocStructWideSlow
GcAllocArrayWideSlow
GcAllocArrayFromSlotsSlow
ExceptionTryBegin
ExceptionTryEnd
ExceptionThrow
ExceptionThrowTag
ExceptionThrowRef
ExceptionDelegate
ExceptionGetTag
ExceptionGetValue
ExceptionGetValueCount
ExceptionSigsetjmp
ExceptionSpillLocals
ExceptionGetSpilledLocal
} derive(Eq,
Debug
)

Runtime operations required by WebAssembly lowering.

The helper identity stays typed throughout lowering. An embedding assigns its external symbol spelling only when the operation enters MilkIR or MachV.

#
WasmStorageContract

pub(all) enum WasmStorageContract {
Value(
Type
)
Packed8
Packed16
} derive(Eq,
Debug
)

The lowered MilkIR carrier and packed representation of a WebAssembly field.

#
WasmTableContract

pub(all) struct WasmTableContract {
index_type :
Type

element_type :
Type

} derive(Eq,
Debug
)

The contextual contract for a WebAssembly table.

#
WasmValidationContext

type WasmValidationContext

Module and linker metadata required to validate Wasm extension operations.

The context is supplied explicitly at the Wasm adapter seam and is never stored in MilkIR. Linked direct functions use their remapped global index; indexed types, tables, tags, and segments use module-local indices.

#
WasmValidationContext::empty

Construct a context that rejects every module-indexed operation.

This is useful for lowering functions that contain only context-free Wasm operations; it is not a fallback for module-produced MilkIR.

#
WasmValidationContext::new

Construct an explicit contextual-validation adapter.

#
WasmValidationContext::validate_extension

Validate one Wasm extension against module and linker metadata.

#
WasmValidationContext::validate_global_value

#
WasmValidationResolvers

pub(all) struct WasmValidationResolvers {
function_contract : (Int) -> WasmFunctionContract?
defined_type_contract : (Int) -> WasmDefinedTypeContract?
table_contract : (Int) -> WasmTableContract?
tag_contract : (Int) -> WasmFunctionContract?
memory_exists : (Int) -> Bool
data_segment_exists : (Int) -> Bool
element_segment_type : (Int) ->
Type
?
}

Resolver interface used to construct a contextual-validation adapter.

#
EXTERNREF_TAG

let EXTERNREF_TAG : Int64

Tag for externref values: bit 62 set.

#
FUNCREF_TAG

let FUNCREF_TAG : Int64

Tag for funcref pointer values: bit 61 set.

#
NULL_REF

let NULL_REF : Int64

Null reference value in the lowered reference representation.

#
WASM_DIALECT

let WASM_DIALECT : String

Serialized dialect name used by Wasm MilkIR extension operations.

#
array_copy

fn array_copy(builder :
FunctionBuilder
, dst_type_idx : Int, src_type_idx : Int, dst :
Value
, dst_offset :
Value
, src :
Value
, src_offset :
Value
, count :
Value
) -> Unit

#
array_get_s

fn array_get_s(builder :
FunctionBuilder
, type_idx : Int, array_ref :
Value
, index :
Value
, byte_width : Int) ->
Value

#
array_get_u

fn array_get_u(builder :
FunctionBuilder
, type_idx : Int, array_ref :
Value
, index :
Value
, byte_width : Int) ->
Value

#
array_init_data

fn array_init_data(builder :
FunctionBuilder
, type_idx : Int, data_idx : Int, array_ref :
Value
, arr_offset :
Value
, data_offset :
Value
, length :
Value
) -> Unit

#
array_init_elem

fn array_init_elem(builder :
FunctionBuilder
, type_idx : Int, elem_idx : Int, array_ref :
Value
, arr_offset :
Value
, elem_offset :
Value
, length :
Value
) -> Unit

#
array_new_data

fn array_new_data(builder :
FunctionBuilder
, type_idx : Int, data_idx : Int, data_offset :
Value
, length :
Value
) ->
Value

#
array_new_default

#
array_new_elem

fn array_new_elem(builder :
FunctionBuilder
, type_idx : Int, elem_idx : Int, elem_offset :
Value
, length :
Value
) ->
Value

#
array_new_fixed

fn array_new_fixed(builder :
FunctionBuilder
, type_idx : Int, count : Int, elements : Array[
Value
]) ->
Value

#
array_set

#
call_indirect_multi

#
data_drop

fn data_drop(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, data_idx : Int) -> Unit

#
decode_error

fn decode_error(ext :
ExtOp
) -> String?

#
decode_memory_base_context_field

fn decode_memory_base_context_field(field :
ContextField
) -> Int?

#
decode_opcode

fn decode_opcode(opcode :
Opcode
) -> WasmOpcode?

#
delegate

fn delegate(builder :
FunctionBuilder
, depth : Int) -> Unit

#
descriptor_by_name

fn descriptor_by_name(name : String) ->
ExtOpDescriptor
?

#
elem_drop

fn elem_drop(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, elem_idx : Int) -> Unit

#
emit_throw

fn emit_throw(builder :
FunctionBuilder
, tag_idx : Int, values : Array[
Value
]) -> Unit

#
emit_throw_ref

#
encode

#
get_exception_value

#
get_exception_value_count

#
get_func_ref

#
get_spilled_local

#
memory_base_context_field

fn memory_base_context_field(memory_index : Int) ->
ContextField

#
memory_copy

fn memory_copy(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, dst_memidx : Int, src_memidx : Int, dst :
Value
, src :
Value
, size :
Value
) -> Unit

#
memory_grow

fn memory_grow(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, memidx : Int, delta :
Value
, max_pages? : Int, is_memory64? : Bool) ->
Value

#
memory_init

fn memory_init(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, memidx : Int, data_idx : Int, dst :
Value
, src :
Value
, size :
Value
) -> Unit

#
memory_size

fn memory_size(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, memidx : Int, is_memory64? : Bool) ->
Value

#
ref_cast

fn ref_cast(builder :
FunctionBuilder
, type_idx : Int, nullable : Bool, ref_val :
Value
, result_type :
Type
) ->
Value

#
ref_test

fn ref_test(builder :
FunctionBuilder
, type_idx : Int, nullable : Bool, ref_val :
Value
) ->
Value

#
return_call_indirect_multi

fn return_call_indirect_multi(builder :
FunctionBuilder
, type_idx : Int, table_idx : Int, callee :
Value
, args : Array[
Value
]) -> Unit

#
return_call_multi

fn return_call_multi(builder :
FunctionBuilder
, func_idx : Int, args : Array[
Value
]) -> Unit

#
return_call_ref_multi

fn return_call_ref_multi(builder :
FunctionBuilder
, type_idx : Int, func_ref :
Value
, args : Array[
Value
]) -> Unit

#
spill_locals_for_throw

fn spill_locals_for_throw(builder :
FunctionBuilder
, locals : Array[
Value
]) -> Unit

#
struct_get

fn struct_get(builder :
FunctionBuilder
, type_idx : Int, field_idx : Int, struct_ref :
Value
, field_type :
Type
) ->
Value

#
struct_get_s

fn struct_get_s(builder :
FunctionBuilder
, type_idx : Int, field_idx : Int, struct_ref :
Value
, byte_width : Int) ->
Value

#
struct_get_u

fn struct_get_u(builder :
FunctionBuilder
, type_idx : Int, field_idx : Int, struct_ref :
Value
, byte_width : Int) ->
Value

#
struct_new_default

fn struct_new_default(builder :
FunctionBuilder
, type_idx : Int) ->
Value

#
struct_set

fn struct_set(builder :
FunctionBuilder
, type_idx : Int, field_idx : Int, struct_ref :
Value
, value :
Value
) -> Unit

#
table_copy

fn table_copy(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, dst_table_idx : Int, src_table_idx : Int, dst :
Value
, src :
Value
, size :
Value
) -> Unit

#
table_grow

fn table_grow(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, table_idx : Int, delta :
Value
, init_value :
Value
, is_table64? : Bool) ->
Value

#
table_init

fn table_init(builder :
FunctionBuilder
, runtime_symbols : RuntimeSymbols, vmctx :
Value
, table_idx : Int, elem_idx : Int, dst :
Value
, src :
Value
, size :
Value
) -> Unit

#
try_table_begin

fn try_table_begin(builder :
FunctionBuilder
, handler_id : Int) ->
Value

#
try_table_end

fn try_table_end(builder :
FunctionBuilder
, handler_id : Int) -> Unit

#
validate_extension

fn validate_extension(view :
ExtensionInstView
) -> String?

Validate one read-only Wasm extension instruction at an adapter seam.

#
validate_global_value

fn validate_global_value(data :
GlobalValueData
) -> String?

#
verify_function

Verify core MilkIR invariants and every extension against the Wasm schema.

#
verify_function_with_context

fn verify_function_with_context(func :
Function
, context : WasmValidationContext) -> Unit raise
VerifyError

Verify core MilkIR, local Wasm schema, and module-contextual contracts.

#
wasm_externref_type

fn wasm_externref_type() ->
Type

#
wasm_funcref_type

fn wasm_funcref_type() ->
Type

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io