v3.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 FrameTag.from #
fn FrameTag.from[W](input W) !FrameTag
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 WType.from #
fn WType.from[W](input W) !WType
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)
---- constants ----
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)
---- locals / globals ----
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)
---- memory ----
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()
---- control flow ----
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) 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
}
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) compile #
fn (m &Module) compile() []u8
compile serializes the whole module into a .wasm byte buffer.