v.gen.wasm #
code.v emits the WASM instruction stream for a single function body. It is a thin layer over a []u8 buffer with one method per opcode used by the backend, analogous to the arm64 backend's asm.v instruction encoders.
Constants #
const valtype_i32 = u8(0x7f)
WASM value types.
const valtype_i64 = u8(0x7e)
const valtype_f32 = u8(0x7d)
const valtype_f64 = u8(0x7c)
const export_func = u8(0x00)
Export kinds.
const export_mem = u8(0x02)
fn Gen.new #
fn Gen.new(a &flat.FlatAst, tc &types.TypeChecker, used_fns map[string]bool) &Gen
fn Module.new #
fn Module.new() &Module
fn SSAGen.new #
fn SSAGen.new(m &ssa.Module) &SSAGen
new creates a WebAssembly generator for an SSA module.
fn WType.from #
fn WType.from[W](input W) !WType
from returns the WType value of an integer or of a field name, or an error if there is none.
enum WType #
enum WType {
void
i32
i64
f32
f64
}
struct Code #
struct Code {
pub mut:
bytes []u8
}
fn (Code) raw #
fn (mut c Code) raw(b u8)
fn (Code) i32_const #
fn (mut c Code) i32_const(v i64)
fn (Code) i64_const #
fn (mut c Code) i64_const(v i64)
fn (Code) f32_const #
fn (mut c Code) f32_const(v f32)
fn (Code) f64_const #
fn (mut c Code) f64_const(v f64)
fn (Code) local_get #
fn (mut c Code) local_get(idx int)
fn (Code) local_set #
fn (mut c Code) local_set(idx int)
fn (Code) local_tee #
fn (mut c Code) local_tee(idx int)
fn (Code) global_get #
fn (mut c Code) global_get(idx int)
fn (Code) global_set #
fn (mut c Code) global_set(idx int)
fn (Code) load #
fn (mut c Code) load(op u8, align int, offset int)
fn (Code) store #
fn (mut c Code) store(op u8, align int, offset int)
fn (Code) i32_store #
fn (mut c Code) i32_store(offset int)
i32_store / i32_load with natural alignment for a full i32.
fn (Code) i32_store8 #
fn (mut c Code) i32_store8(offset int)
fn (Code) i32_load #
fn (mut c Code) i32_load(offset int)
fn (Code) block_void #
fn (mut c Code) block_void()
fn (Code) loop_void #
fn (mut c Code) loop_void()
fn (Code) if_void #
fn (mut c Code) if_void()
fn (Code) else_ #
fn (mut c Code) else_()
fn (Code) end #
fn (mut c Code) end()
fn (Code) br #
fn (mut c Code) br(depth int)
fn (Code) br_if #
fn (mut c Code) br_if(depth int)
fn (Code) ret #
fn (mut c Code) ret()
fn (Code) call #
fn (mut c Code) call(idx int)
fn (Code) drop #
fn (mut c Code) drop()
struct Gen #
struct Gen {
mut:
a &flat.FlatAst = unsafe { nil }
tc &types.TypeChecker = unsafe { nil }
used_fns map[string]bool
mod &Module = unsafe { nil }
// per-function state
cur Code
local_types []u8
nparams int
var_index map[string]int
var_wtype map[string]WType
var_unsigned map[string]bool
var_widths map[string]int // sub-32-bit int locals: 8 or 16; else 32
frames []Frame
pending_label string // label of a preceding `label:` marker, for the next loop
cur_ret WType
cur_fn_module string
cur_fn_file string
// module-wide; keyed by qualified function name (see qualified_fn_key)
fn_index map[string]int
fn_ret map[string]WType
fn_params map[string][]WType
file_aliases map[string]map[string]string // file -> (import alias -> full import path)
import_paths []string // every `import a.b.c` path (full)
module_imports map[string][]string // module path -> imported module paths ('' = main)
global_index map[string]int // __global name -> wasm global index
global_wtype map[string]WType
global_unsigned map[string]bool
global_widths map[string]int
data_pool []u8
data_off map[string]int
uses_print bool
write_idx int
print_int_idx int
has_main bool
init_fns []int // function indices of init() entry points, in call order
warnings []string
}
fn (Gen) ssa_configuration #
fn (mut g Gen) ssa_configuration() !SSAConfiguration
ssa_configuration collects export and initialization metadata without emitting instructions.
fn (Gen) gen #
fn (mut g Gen) gen()
gen builds the whole module from the flat AST.
fn (Gen) warnings_list #
fn (g &Gen) warnings_list() []string
fn (Gen) write #
fn (mut g Gen) write(path string) !
write serializes the module to path.
struct Module #
struct Module {
mut:
types []FuncType
imports []ImportFunc
funcs []Func
exports []Export
datas []DataSeg
globals []Global
mem_min int = 2
n_import int
start int = -1
table []int
}
fn (Module) add_type #
fn (mut m Module) add_type(params []u8, results []u8) int
add_type registers a signature, deduplicating identical ones.
fn (Module) add_import_func #
fn (mut m Module) add_import_func(module_ string, name string, type_idx int) int
add_import_func registers an imported function and returns its function index. Imports must be added before any defined function so indices stay stable.
fn (Module) add_global #
fn (mut m Module) add_global(valtype u8, init []u8) int
add_global appends a mutable global and returns its index.
fn (Module) reserve_func_index #
fn (m &Module) reserve_func_index(defined_so_far int) int
reserve_func_index returns the function index a later add_func will occupy.
fn (Module) add_func #
fn (mut m Module) add_func(type_idx int, locals []u8, code []u8) int
add_func appends a defined function and returns its global function index.
fn (Module) add_export #
fn (mut m Module) add_export(name string, kind u8, index int)
fn (Module) add_data #
fn (mut m Module) add_data(offset int, bytes []u8)
fn (Module) set_mem_min #
fn (mut m Module) set_mem_min(pages int)
fn (Module) set_start #
fn (mut m Module) set_start(index int)
set_start selects the zero-argument function run when the module is instantiated.
fn (Module) set_table #
fn (mut m Module) set_table(functions []int)
set_table installs the function references used by indirect calls.
fn (Module) compile #
fn (m &Module) compile() []u8
compile serializes the whole module into a .wasm byte buffer.
struct SSAConfiguration #
struct SSAConfiguration {
pub:
exports map[string]string
init_fns []string
main_fn string
used_fns map[string]bool
source_modules map[string]string
source_imports map[string]map[string]string
imports []WasmImport
}
SSAConfiguration carries source-level entry points and export names into SSA code generation.
struct SSAGen #
struct SSAGen {
mut:
m &ssa.Module = unsafe { nil }
mod &Module = unsafe { nil }
configured bool
exports map[string]string
imports map[string]WasmImport
init_fns []string
main_fn string
fn_index map[string]int
fn_table map[string]int
global_addr map[string]int
strings map[int]int
// literal_text_addr holds the address a literal's bytes occupy, keyed by kind
// and text, so a repeat of a literal that has already been laid out reuses it.
literal_text_addr map[string]int
data []u8
stack_global int
heap_global int
stack_bottom int
write_index int
exit_index int
alloc_index int
cur Code
locals []u8
value_local map[int]int
slots map[int]int
phi_snapshots map[int]int
frame_size int
frame_local int
pc_local int
sret_local int = -1
nparams int
cur_ret ssa.TypeID
warnings []string
}
SSAGen lowers SSA to a WebAssembly binary with WASI output support. A dispatch loop represents arbitrary SSA control flow without requiring a reducible graph. Each invocation owns its locals and linear-memory frame.
fn (SSAGen) configure #
fn (mut g SSAGen) configure(exports map[string]string, init_fns []string, main_fn string)
configure supplies entry points and export names collected by the frontend.
fn (SSAGen) declare_imports #
fn (mut g SSAGen) declare_imports(imports []WasmImport)
declare_imports supplies the host functions the frontend resolved from @[wasm_import_namespace] declarations. gen() emits only the ones the reachable functions actually call, so an unused declaration does not force the host to provide it.
fn (SSAGen) gen #
fn (mut g SSAGen) gen() !
gen emits only functions reachable from the selected SSA entry points.
fn (SSAGen) write #
fn (g &SSAGen) write(path string) !
write writes the generated module to path.
fn (SSAGen) warnings_list #
fn (g &SSAGen) warnings_list() []string
warnings_list returns non-fatal export diagnostics.
struct WasmImport #
struct WasmImport {
pub:
namespace string
name string // the name the host exports
qualified string // the SSA name of the extern declaration behind it
params []u8
results []u8
}
WasmImport is a host function that V source declared with @[wasm_import_namespace] on a body-less fn in a .wasm.v file. To the checker and to SSA it is an ordinary C extern; resolving it into a real wasm module import happens here, because this is the only layer that still sees the signature spelled in V types. A pointer parameter or result is an offset into the module's linear memory, which is the only representation wasm32 has.