use super::*;
pub(super) struct HostImport {
pub(super) module: &'static str,
pub(super) name: &'static str,
pub(super) arity: usize,
}
pub(super) const HOST_IMPORTS: &[HostImport] = &[
HostImport {
module: "math",
name: "pow",
arity: 2,
},
HostImport {
module: "math",
name: "sin",
arity: 1,
},
HostImport {
module: "math",
name: "cos",
arity: 1,
},
HostImport {
module: "io",
name: "log_value",
arity: 1,
},
];
pub(super) fn build_wasm_module(fns: &[CompiledFn], heap_start: i32, string_data: &[u8]) -> Result<Vec<u8>, String> {
let mut module = Module::new();
let num_imports = HOST_IMPORTS.len() as u32;
let mut types = TypeSection::new();
for imp in HOST_IMPORTS {
let params: Vec<ValType> = vec![ValType::F64; imp.arity];
types.ty().function(params, vec![ValType::F64]);
}
for f in fns {
types.ty().function(f.params.clone(), f.results.clone());
}
module.section(&types);
let mut imports = wasm_encoder::ImportSection::new();
for (i, imp) in HOST_IMPORTS.iter().enumerate() {
imports.import(imp.module, imp.name, wasm_encoder::EntityType::Function(i as u32));
}
module.section(&imports);
let mut functions = FunctionSection::new();
for (i, _) in fns.iter().enumerate() {
functions.function(num_imports + i as u32);
}
module.section(&functions);
let mut memories = MemorySection::new();
memories.memory(MemoryType {
minimum: 1,
maximum: None,
memory64: false,
shared: false,
page_size_log2: None,
});
module.section(&memories);
let mut globals = GlobalSection::new();
globals.global(
GlobalType {
val_type: ValType::I32,
mutable: true,
shared: false,
},
&ConstExpr::i32_const(heap_start),
);
module.section(&globals);
let mut exports = ExportSection::new();
exports.export("memory", ExportKind::Memory, 0);
for (i, f) in fns.iter().enumerate() {
if let Some(export_name) = &f.export_name {
exports.export(export_name, ExportKind::Func, num_imports + i as u32);
}
}
module.section(&exports);
let mut codes = CodeSection::new();
for f in fns {
let locals: Vec<(u32, ValType)> = if f.locals.is_empty() {
vec![]
} else {
let mut groups = Vec::new();
let mut count = 1u32;
let mut prev = f.locals[0];
for &t in &f.locals[1..] {
if t == prev {
count += 1;
} else {
groups.push((count, prev));
prev = t;
count = 1;
}
}
groups.push((count, prev));
groups
};
let mut func = Function::new(locals);
for instr in &f.instructions {
func.instruction(instr);
}
func.instruction(&Instruction::End);
codes.function(&func);
}
module.section(&codes);
if !string_data.is_empty() {
let mut data = wasm_encoder::DataSection::new();
data.active(0, &ConstExpr::i32_const(HEAP_BASE), string_data.iter().copied());
module.section(&data);
}
Ok(module.finish())
}
pub(super) fn build_runtime_fns(base_index: u32) -> (Vec<CompiledFn>, HashMap<String, u32>) {
let mut fn_index = HashMap::new();
let mut fns = Vec::new();
let copy_name = String::from("__rt_copy_f64_slots");
fn_index.insert(copy_name.clone(), base_index + fns.len() as u32);
let i_local = 3u32;
let copy_instructions = vec![
Instruction::I32Const(0),
Instruction::LocalSet(i_local),
Instruction::Block(wasm_encoder::BlockType::Empty),
Instruction::Loop(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(i_local),
Instruction::LocalGet(2),
Instruction::I32GeU,
Instruction::BrIf(1),
Instruction::LocalGet(0),
Instruction::LocalGet(i_local),
Instruction::I32Const(8),
Instruction::I32Mul,
Instruction::I32Add,
Instruction::LocalGet(1),
Instruction::LocalGet(i_local),
Instruction::I32Const(8),
Instruction::I32Mul,
Instruction::I32Add,
Instruction::F64Load(mem_arg_f64(0)),
Instruction::F64Store(mem_arg_f64(0)),
Instruction::LocalGet(i_local),
Instruction::I32Const(1),
Instruction::I32Add,
Instruction::LocalSet(i_local),
Instruction::Br(0),
Instruction::End,
Instruction::End,
];
fns.push(CompiledFn {
export_name: None,
params: vec![ValType::I32, ValType::I32, ValType::I32],
results: vec![],
locals: vec![ValType::I32],
instructions: copy_instructions,
});
let map_flat_pairs_name = String::from("__rt_map_flat_pairs");
fn_index.insert(map_flat_pairs_name, base_index + fns.len() as u32);
let map_flat_pairs_instructions = vec![
Instruction::LocalGet(0),
Instruction::F64Load(mem_arg_f64(8)),
Instruction::I32TruncF64U,
];
fns.push(CompiledFn {
export_name: None,
params: vec![ValType::I32],
results: vec![ValType::I32],
locals: vec![],
instructions: map_flat_pairs_instructions,
});
let map_find_key_name = String::from("__rt_map_find_key");
fn_index.insert(map_find_key_name, base_index + fns.len() as u32);
let map_find_key_instructions = vec![
Instruction::LocalGet(0),
Instruction::F64Load(mem_arg_f64(8)),
Instruction::I32TruncF64U,
Instruction::LocalSet(5),
Instruction::LocalGet(5),
Instruction::F64Load(mem_arg_f64(0)),
Instruction::I32TruncF64U,
Instruction::LocalSet(2),
Instruction::I32Const(-1),
Instruction::LocalSet(4),
Instruction::I32Const(0),
Instruction::LocalSet(3),
Instruction::Block(wasm_encoder::BlockType::Empty),
Instruction::Loop(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalGet(2),
Instruction::I32GeU,
Instruction::BrIf(1),
Instruction::LocalGet(5),
Instruction::I32Const(8),
Instruction::I32Add,
Instruction::LocalGet(3),
Instruction::I32Const(16),
Instruction::I32Mul,
Instruction::I32Add,
Instruction::F64Load(mem_arg_f64(0)),
Instruction::LocalGet(1),
Instruction::F64Eq,
Instruction::If(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalSet(4),
Instruction::Br(2),
Instruction::End,
Instruction::LocalGet(3),
Instruction::I32Const(1),
Instruction::I32Add,
Instruction::LocalSet(3),
Instruction::Br(0),
Instruction::End,
Instruction::End,
Instruction::LocalGet(4),
];
fns.push(CompiledFn {
export_name: None,
params: vec![ValType::I32, ValType::F64],
results: vec![ValType::I32],
locals: vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
instructions: map_find_key_instructions,
});
let map_find_value_name = String::from("__rt_map_find_value");
fn_index.insert(map_find_value_name, base_index + fns.len() as u32);
let map_find_value_instructions = vec![
Instruction::LocalGet(0),
Instruction::F64Load(mem_arg_f64(8)),
Instruction::I32TruncF64U,
Instruction::LocalSet(5),
Instruction::LocalGet(5),
Instruction::F64Load(mem_arg_f64(0)),
Instruction::I32TruncF64U,
Instruction::LocalSet(2),
Instruction::I32Const(-1),
Instruction::LocalSet(4),
Instruction::I32Const(0),
Instruction::LocalSet(3),
Instruction::Block(wasm_encoder::BlockType::Empty),
Instruction::Loop(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalGet(2),
Instruction::I32GeU,
Instruction::BrIf(1),
Instruction::LocalGet(5),
Instruction::I32Const(16),
Instruction::I32Add,
Instruction::LocalGet(3),
Instruction::I32Const(16),
Instruction::I32Mul,
Instruction::I32Add,
Instruction::F64Load(mem_arg_f64(0)),
Instruction::LocalGet(1),
Instruction::F64Eq,
Instruction::If(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalSet(4),
Instruction::Br(2),
Instruction::End,
Instruction::LocalGet(3),
Instruction::I32Const(1),
Instruction::I32Add,
Instruction::LocalSet(3),
Instruction::Br(0),
Instruction::End,
Instruction::End,
Instruction::LocalGet(4),
];
fns.push(CompiledFn {
export_name: None,
params: vec![ValType::I32, ValType::F64],
results: vec![ValType::I32],
locals: vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
instructions: map_find_value_instructions,
});
let set_find_name = String::from("__rt_set_find_elem");
fn_index.insert(set_find_name, base_index + fns.len() as u32);
let set_find_instructions = vec![
Instruction::LocalGet(0),
Instruction::F64Load(mem_arg_f64(0)),
Instruction::I32TruncF64U,
Instruction::LocalSet(2),
Instruction::I32Const(-1),
Instruction::LocalSet(4),
Instruction::I32Const(0),
Instruction::LocalSet(3),
Instruction::Block(wasm_encoder::BlockType::Empty),
Instruction::Loop(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalGet(2),
Instruction::I32GeU,
Instruction::BrIf(1),
Instruction::LocalGet(0),
Instruction::I32Const(8),
Instruction::I32Add,
Instruction::LocalGet(3),
Instruction::I32Const(8),
Instruction::I32Mul,
Instruction::I32Add,
Instruction::F64Load(mem_arg_f64(0)),
Instruction::LocalGet(1),
Instruction::F64Eq,
Instruction::If(wasm_encoder::BlockType::Empty),
Instruction::LocalGet(3),
Instruction::LocalSet(4),
Instruction::Br(2),
Instruction::End,
Instruction::LocalGet(3),
Instruction::I32Const(1),
Instruction::I32Add,
Instruction::LocalSet(3),
Instruction::Br(0),
Instruction::End,
Instruction::End,
Instruction::LocalGet(4),
];
fns.push(CompiledFn {
export_name: None,
params: vec![ValType::I32, ValType::F64],
results: vec![ValType::I32],
locals: vec![ValType::I32, ValType::I32, ValType::I32],
instructions: set_find_instructions,
});
let hash_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_hash_f64"), hash_idx);
fns.push(build_rt_hash_f64());
let map_root_assoc_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_root_assoc"), map_root_assoc_idx);
fns.push(build_rt_map_root_assoc(*fn_index.get("__rt_copy_f64_slots").expect("copy helper")));
let map_root_lookup_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_root_lookup"), map_root_lookup_idx);
fns.push(build_rt_map_root_lookup());
let map_root_contains_value_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_root_contains_value"), map_root_contains_value_idx);
fns.push(build_rt_map_root_contains_value());
let map_root_write_pairs_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_root_write_pairs"), map_root_write_pairs_idx);
fns.push(build_rt_map_root_write_pairs());
let map_make_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_make"), map_make_idx);
fns.push(build_rt_map_make());
let map_from_flat_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_from_flat"), map_from_flat_idx);
fns.push(build_rt_map_from_flat(hash_idx, map_root_assoc_idx, map_make_idx));
let map_root_from_flat_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_root_from_flat"), map_root_from_flat_idx);
fns.push(build_rt_map_root_from_flat(hash_idx, map_root_assoc_idx));
let map_linearize_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_linearize"), map_linearize_idx);
fns.push(build_rt_map_linearize(map_root_write_pairs_idx));
let map_assoc_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_assoc"), map_assoc_idx);
fns.push(build_rt_map_assoc(hash_idx, map_root_assoc_idx, map_make_idx));
let map_get_value_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_get_value"), map_get_value_idx);
fns.push(build_rt_map_get_value(hash_idx, map_root_lookup_idx));
let map_contains_key_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_contains_key"), map_contains_key_idx);
fns.push(build_rt_map_contains_key(hash_idx, map_root_lookup_idx));
let map_contains_value_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_contains_value"), map_contains_value_idx);
fns.push(build_rt_map_contains_value(map_root_contains_value_idx));
let map_dissoc_idx = base_index + fns.len() as u32;
fn_index.insert(String::from("__rt_map_dissoc"), map_dissoc_idx);
fns.push(build_rt_map_dissoc(
*fn_index.get("__rt_copy_f64_slots").expect("copy helper"),
map_linearize_idx,
map_from_flat_idx,
));
(fns, fn_index)
}
const RT_MAP_TABLE_KIND: f64 = 0.0;
const RT_MAP_BUCKET_KIND: f64 = 1.0;
const RT_MAP_TABLE_CHILDREN: i32 = 32;
const RT_MAP_TABLE_SLOTS: i32 = 33; const RT_MAP_TABLE_BYTES: i32 = RT_MAP_TABLE_SLOTS * 8;
struct RuntimeFnBuilder {
locals: Vec<ValType>,
next_local: u32,
instructions: Vec<Instruction<'static>>,
}
impl RuntimeFnBuilder {
fn new(param_count: u32) -> Self {
Self {
locals: Vec::new(),
next_local: param_count,
instructions: Vec::new(),
}
}
fn alloc_i32(&mut self) -> u32 {
let idx = self.next_local;
self.next_local += 1;
self.locals.push(ValType::I32);
idx
}
fn alloc_f64(&mut self) -> u32 {
let idx = self.next_local;
self.next_local += 1;
self.locals.push(ValType::F64);
idx
}
fn emit(&mut self, instr: Instruction<'static>) {
self.instructions.push(instr);
}
fn finish(self, params: Vec<ValType>, results: Vec<ValType>) -> CompiledFn {
CompiledFn {
export_name: None,
params,
results,
locals: self.locals,
instructions: self.instructions,
}
}
}
fn rt_emit_alloc_const(builder: &mut RuntimeFnBuilder, byte_size: i32, dst_local: u32) {
let raw = builder.alloc_i32();
builder.emit(Instruction::GlobalGet(HEAP_PTR_GLOBAL));
builder.emit(Instruction::LocalTee(raw));
builder.emit(Instruction::I32Const(HEAP_MAGIC));
builder.emit(Instruction::I32Store(mem_arg_i32(0)));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(4));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::I32Const(0));
builder.emit(Instruction::I32Store(mem_arg_i32(0)));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalSet(dst_local));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(byte_size + 8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::GlobalSet(HEAP_PTR_GLOBAL));
}
fn rt_emit_alloc_dynamic(builder: &mut RuntimeFnBuilder, size_local: u32, dst_local: u32) {
let raw = builder.alloc_i32();
builder.emit(Instruction::GlobalGet(HEAP_PTR_GLOBAL));
builder.emit(Instruction::LocalTee(raw));
builder.emit(Instruction::I32Const(HEAP_MAGIC));
builder.emit(Instruction::I32Store(mem_arg_i32(0)));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(4));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::I32Const(0));
builder.emit(Instruction::I32Store(mem_arg_i32(0)));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalSet(dst_local));
builder.emit(Instruction::LocalGet(raw));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalGet(size_local));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::GlobalSet(HEAP_PTR_GLOBAL));
}
fn rt_emit_table_child_addr(builder: &mut RuntimeFnBuilder, table_local: u32, child_idx_local: u32, dst_local: u32) {
builder.emit(Instruction::LocalGet(table_local));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalGet(child_idx_local));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Mul);
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalSet(dst_local));
}
fn rt_emit_load_table_child(builder: &mut RuntimeFnBuilder, table_local: u32, child_idx_local: u32, dst_local: u32) {
builder.emit(Instruction::LocalGet(table_local));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalGet(child_idx_local));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Mul);
builder.emit(Instruction::I32Add);
builder.emit(Instruction::F64Load(mem_arg_f64(0)));
builder.emit(Instruction::I32TruncF64U);
builder.emit(Instruction::LocalSet(dst_local));
}
fn rt_emit_alloc_empty_table(builder: &mut RuntimeFnBuilder, dst_local: u32) {
rt_emit_alloc_const(builder, RT_MAP_TABLE_BYTES, dst_local);
builder.emit(Instruction::LocalGet(dst_local));
builder.emit(f64_const(RT_MAP_TABLE_KIND));
builder.emit(Instruction::F64Store(mem_arg_f64(0)));
let i = builder.alloc_i32();
let addr = builder.alloc_i32();
builder.emit(Instruction::I32Const(0));
builder.emit(Instruction::LocalSet(i));
builder.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
builder.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
builder.emit(Instruction::LocalGet(i));
builder.emit(Instruction::I32Const(RT_MAP_TABLE_CHILDREN));
builder.emit(Instruction::I32GeU);
builder.emit(Instruction::BrIf(1));
rt_emit_table_child_addr(builder, dst_local, i, addr);
builder.emit(Instruction::LocalGet(addr));
builder.emit(f64_const(0.0));
builder.emit(Instruction::F64Store(mem_arg_f64(0)));
builder.emit(Instruction::LocalGet(i));
builder.emit(Instruction::I32Const(1));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalSet(i));
builder.emit(Instruction::Br(0));
builder.emit(Instruction::End);
builder.emit(Instruction::End);
}
fn rt_emit_alloc_bucket(builder: &mut RuntimeFnBuilder, count_local: u32, dst_local: u32) {
let slots = builder.alloc_i32();
let size = builder.alloc_i32();
builder.emit(Instruction::LocalGet(count_local));
builder.emit(Instruction::I32Const(2));
builder.emit(Instruction::I32Mul);
builder.emit(Instruction::I32Const(2));
builder.emit(Instruction::I32Add);
builder.emit(Instruction::LocalSet(slots));
builder.emit(Instruction::LocalGet(slots));
builder.emit(Instruction::I32Const(8));
builder.emit(Instruction::I32Mul);
builder.emit(Instruction::LocalSet(size));
rt_emit_alloc_dynamic(builder, size, dst_local);
builder.emit(Instruction::LocalGet(dst_local));
builder.emit(f64_const(RT_MAP_BUCKET_KIND));
builder.emit(Instruction::F64Store(mem_arg_f64(0)));
builder.emit(Instruction::LocalGet(dst_local));
builder.emit(Instruction::LocalGet(count_local));
builder.emit(Instruction::F64ConvertI32U);
builder.emit(Instruction::F64Store(mem_arg_f64(8)));
}
fn rt_emit_copy_slots(builder: &mut RuntimeFnBuilder, copy_fn_idx: u32, dst_local: u32, src_local: u32, count_local: u32) {
builder.emit(Instruction::LocalGet(dst_local));
builder.emit(Instruction::LocalGet(src_local));
builder.emit(Instruction::LocalGet(count_local));
builder.emit(Instruction::Call(copy_fn_idx));
}
fn build_rt_hash_f64() -> CompiledFn {
let mut b = RuntimeFnBuilder::new(1);
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I64ReinterpretF64);
b.emit(Instruction::I64Const(32));
b.emit(Instruction::I64ShrU);
b.emit(Instruction::I32WrapI64);
b.emit(Instruction::I32Const(0x9e37_79b9u32 as i32));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Rotl);
b.finish(vec![ValType::F64], vec![ValType::I32])
}
fn build_rt_map_make() -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2);
let dst = b.alloc_i32();
rt_emit_alloc_const(&mut b, 16, dst);
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(8)));
b.emit(Instruction::LocalGet(dst));
b.finish(vec![ValType::I32, ValType::I32], vec![ValType::I32])
}
fn build_rt_map_root_assoc(copy_fn_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(4); let idx0 = b.alloc_i32();
let idx1 = b.alloc_i32();
let table1 = b.alloc_i32();
let bucket = b.alloc_i32();
let new_root = b.alloc_i32();
let new_table1 = b.alloc_i32();
let new_bucket = b.alloc_i32();
let bucket_count = b.alloc_i32();
let found_idx = b.alloc_i32();
let i = b.alloc_i32();
let slots = b.alloc_i32();
let addr = b.alloc_i32();
let added = b.alloc_i32();
let key_addr = b.alloc_i32();
b.emit(Instruction::LocalGet(3));
b.emit(Instruction::I32Const(31));
b.emit(Instruction::I32And);
b.emit(Instruction::LocalSet(idx0));
b.emit(Instruction::LocalGet(3));
b.emit(Instruction::I32Const(5));
b.emit(Instruction::I32ShrU);
b.emit(Instruction::I32Const(31));
b.emit(Instruction::I32And);
b.emit(Instruction::LocalSet(idx1));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
rt_emit_alloc_empty_table(&mut b, new_root);
rt_emit_alloc_empty_table(&mut b, new_table1);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(bucket_count));
rt_emit_alloc_bucket(&mut b, bucket_count, new_bucket);
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Store(mem_arg_f64(16)));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::F64Store(mem_arg_f64(24)));
rt_emit_table_child_addr(&mut b, new_table1, idx1, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
rt_emit_table_child_addr(&mut b, new_root, idx0, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_table1));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::Else);
rt_emit_load_table_child(&mut b, 0, idx0, table1);
b.emit(Instruction::LocalGet(table1));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
rt_emit_alloc_const(&mut b, RT_MAP_TABLE_BYTES, new_root);
b.emit(Instruction::I32Const(RT_MAP_TABLE_SLOTS));
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_root, 0, slots);
rt_emit_alloc_empty_table(&mut b, new_table1);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(bucket_count));
rt_emit_alloc_bucket(&mut b, bucket_count, new_bucket);
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Store(mem_arg_f64(16)));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::F64Store(mem_arg_f64(24)));
rt_emit_table_child_addr(&mut b, new_table1, idx1, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
rt_emit_table_child_addr(&mut b, new_root, idx0, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_table1));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::Else);
rt_emit_load_table_child(&mut b, table1, idx1, bucket);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
rt_emit_alloc_const(&mut b, RT_MAP_TABLE_BYTES, new_root);
b.emit(Instruction::I32Const(RT_MAP_TABLE_SLOTS));
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_root, 0, slots);
rt_emit_alloc_const(&mut b, RT_MAP_TABLE_BYTES, new_table1);
b.emit(Instruction::I32Const(RT_MAP_TABLE_SLOTS));
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_table1, table1, slots);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(bucket_count));
rt_emit_alloc_bucket(&mut b, bucket_count, new_bucket);
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Store(mem_arg_f64(16)));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::F64Store(mem_arg_f64(24)));
rt_emit_table_child_addr(&mut b, new_table1, idx1, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
rt_emit_table_child_addr(&mut b, new_root, idx0, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_table1));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(bucket_count));
b.emit(Instruction::I32Const(-1));
b.emit(Instruction::LocalSet(found_idx));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalGet(bucket_count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalTee(key_addr));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Eq);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalSet(found_idx));
b.emit(Instruction::Br(2));
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Const(-1));
b.emit(Instruction::I32Eq);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(bucket_count));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(slots));
rt_emit_alloc_bucket(&mut b, slots, new_bucket);
b.emit(Instruction::LocalGet(bucket_count));
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_bucket, bucket, slots);
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(bucket_count));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalTee(addr));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::F64Store(mem_arg_f64(8)));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::Else);
rt_emit_alloc_bucket(&mut b, bucket_count, new_bucket);
b.emit(Instruction::LocalGet(bucket_count));
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_bucket, bucket, slots);
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::I32Const(24));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::End);
rt_emit_alloc_const(&mut b, RT_MAP_TABLE_BYTES, new_root);
b.emit(Instruction::I32Const(RT_MAP_TABLE_SLOTS));
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_root, 0, slots);
rt_emit_alloc_const(&mut b, RT_MAP_TABLE_BYTES, new_table1);
b.emit(Instruction::I32Const(RT_MAP_TABLE_SLOTS));
b.emit(Instruction::LocalSet(slots));
rt_emit_copy_slots(&mut b, copy_fn_idx, new_table1, table1, slots);
rt_emit_table_child_addr(&mut b, new_table1, idx1, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_bucket));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
rt_emit_table_child_addr(&mut b, new_root, idx0, addr);
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(new_table1));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(new_root));
b.emit(Instruction::LocalGet(added));
b.finish(
vec![ValType::I32, ValType::F64, ValType::F64, ValType::I32],
vec![ValType::I32, ValType::I32],
)
}
fn build_rt_map_root_lookup() -> CompiledFn {
let mut b = RuntimeFnBuilder::new(3); let idx0 = b.alloc_i32();
let idx1 = b.alloc_i32();
let table1 = b.alloc_i32();
let bucket = b.alloc_i32();
let count = b.alloc_i32();
let i = b.alloc_i32();
let found = b.alloc_i32();
let value = b.alloc_f64();
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(found));
b.emit(f64_const(0.0));
b.emit(Instruction::LocalSet(value));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::I32Const(31));
b.emit(Instruction::I32And);
b.emit(Instruction::LocalSet(idx0));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::I32Const(5));
b.emit(Instruction::I32ShrU);
b.emit(Instruction::I32Const(31));
b.emit(Instruction::I32And);
b.emit(Instruction::LocalSet(idx1));
rt_emit_load_table_child(&mut b, 0, idx0, table1);
b.emit(Instruction::LocalGet(table1));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
rt_emit_load_table_child(&mut b, table1, idx1, bucket);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Eq);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(24));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(value));
b.emit(Instruction::Br(2));
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(found));
b.emit(Instruction::LocalGet(value));
b.finish(vec![ValType::I32, ValType::F64, ValType::I32], vec![ValType::I32, ValType::F64])
}
fn build_rt_map_root_contains_value() -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2); let i0 = b.alloc_i32();
let i1 = b.alloc_i32();
let table1 = b.alloc_i32();
let bucket = b.alloc_i32();
let count = b.alloc_i32();
let bi = b.alloc_i32();
let found = b.alloc_i32();
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i0));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i0));
b.emit(Instruction::I32Const(RT_MAP_TABLE_CHILDREN));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
rt_emit_load_table_child(&mut b, 0, i0, table1);
b.emit(Instruction::LocalGet(table1));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i1));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i1));
b.emit(Instruction::I32Const(RT_MAP_TABLE_CHILDREN));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
rt_emit_load_table_child(&mut b, table1, i1, bucket);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(bi));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(24));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Eq);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::Br(6));
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(bi));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i1));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i1));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i0));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i0));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(found));
b.finish(vec![ValType::I32, ValType::F64], vec![ValType::I32])
}
fn build_rt_map_root_write_pairs() -> CompiledFn {
let mut b = RuntimeFnBuilder::new(3); let i0 = b.alloc_i32();
let i1 = b.alloc_i32();
let table1 = b.alloc_i32();
let bucket = b.alloc_i32();
let count = b.alloc_i32();
let bi = b.alloc_i32();
let out = b.alloc_i32();
let addr = b.alloc_i32();
let tmp = b.alloc_f64();
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::LocalSet(out));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i0));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i0));
b.emit(Instruction::I32Const(RT_MAP_TABLE_CHILDREN));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
rt_emit_load_table_child(&mut b, 0, i0, table1);
b.emit(Instruction::LocalGet(table1));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i1));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i1));
b.emit(Instruction::I32Const(RT_MAP_TABLE_CHILDREN));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
rt_emit_load_table_child(&mut b, table1, i1, bucket);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(bi));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::LocalGet(out));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(addr));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(tmp));
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(tmp));
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(bucket));
b.emit(Instruction::I32Const(24));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(tmp));
b.emit(Instruction::LocalGet(addr));
b.emit(Instruction::LocalGet(tmp));
b.emit(Instruction::F64Store(mem_arg_f64(8)));
b.emit(Instruction::LocalGet(out));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(out));
b.emit(Instruction::LocalGet(bi));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(bi));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i1));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i1));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i0));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i0));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(out));
b.finish(vec![ValType::I32, ValType::I32, ValType::I32], vec![ValType::I32])
}
fn build_rt_map_from_flat(hash_idx: u32, root_assoc_idx: u32, map_make_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(1);
let count = b.alloc_i32();
let i = b.alloc_i32();
let root = b.alloc_i32();
let actual = b.alloc_i32();
let key = b.alloc_f64();
let val = b.alloc_f64();
let hash = b.alloc_i32();
let added = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(actual));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(key));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(val));
b.emit(Instruction::LocalGet(key));
b.emit(Instruction::Call(hash_idx));
b.emit(Instruction::LocalSet(hash));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(key));
b.emit(Instruction::LocalGet(val));
b.emit(Instruction::LocalGet(hash));
b.emit(Instruction::Call(root_assoc_idx));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(actual));
b.emit(Instruction::LocalGet(added));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(actual));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(actual));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::Call(map_make_idx));
b.finish(vec![ValType::I32], vec![ValType::I32])
}
fn build_rt_map_root_from_flat(hash_idx: u32, root_assoc_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(1);
let count = b.alloc_i32();
let i = b.alloc_i32();
let root = b.alloc_i32();
let key = b.alloc_f64();
let val = b.alloc_f64();
let hash = b.alloc_i32();
let added = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(key));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalSet(val));
b.emit(Instruction::LocalGet(key));
b.emit(Instruction::Call(hash_idx));
b.emit(Instruction::LocalSet(hash));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(key));
b.emit(Instruction::LocalGet(val));
b.emit(Instruction::LocalGet(hash));
b.emit(Instruction::Call(root_assoc_idx));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(root));
b.finish(vec![ValType::I32], vec![ValType::I32])
}
fn build_rt_map_linearize(root_write_pairs_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(1);
let count = b.alloc_i32();
let root = b.alloc_i32();
let slots = b.alloc_i32();
let size = b.alloc_i32();
let dst = b.alloc_i32();
let base = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(slots));
b.emit(Instruction::LocalGet(slots));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Mul);
b.emit(Instruction::LocalSet(size));
rt_emit_alloc_dynamic(&mut b, size, dst);
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(base));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(base));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::Call(root_write_pairs_idx));
b.emit(Instruction::Drop);
b.emit(Instruction::LocalGet(dst));
b.finish(vec![ValType::I32], vec![ValType::I32])
}
fn build_rt_map_assoc(hash_idx: u32, root_assoc_idx: u32, map_make_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(3);
let count = b.alloc_i32();
let root = b.alloc_i32();
let hash = b.alloc_i32();
let added = b.alloc_i32();
let new_count = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::Call(hash_idx));
b.emit(Instruction::LocalSet(hash));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::LocalGet(2));
b.emit(Instruction::LocalGet(hash));
b.emit(Instruction::Call(root_assoc_idx));
b.emit(Instruction::LocalSet(added));
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::LocalGet(added));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(new_count));
b.emit(Instruction::LocalGet(new_count));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::Call(map_make_idx));
b.finish(vec![ValType::I32, ValType::F64, ValType::F64], vec![ValType::I32])
}
fn build_rt_map_get_value(hash_idx: u32, root_lookup_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2);
let root = b.alloc_i32();
let hash = b.alloc_i32();
let found = b.alloc_i32();
let value = b.alloc_f64();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::Call(hash_idx));
b.emit(Instruction::LocalSet(hash));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::LocalGet(hash));
b.emit(Instruction::Call(root_lookup_idx));
b.emit(Instruction::LocalSet(value));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::LocalGet(value));
b.finish(vec![ValType::I32, ValType::F64], vec![ValType::F64])
}
fn build_rt_map_contains_key(hash_idx: u32, root_lookup_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2);
let root = b.alloc_i32();
let hash = b.alloc_i32();
let found = b.alloc_i32();
let value = b.alloc_f64();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::Call(hash_idx));
b.emit(Instruction::LocalSet(hash));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::LocalGet(hash));
b.emit(Instruction::Call(root_lookup_idx));
b.emit(Instruction::LocalSet(value));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::LocalGet(found));
b.finish(vec![ValType::I32, ValType::F64], vec![ValType::I32])
}
fn build_rt_map_contains_value(root_contains_value_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2);
let root = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(8)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(root));
b.emit(Instruction::LocalGet(root));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::Call(root_contains_value_idx));
b.finish(vec![ValType::I32, ValType::F64], vec![ValType::I32])
}
fn build_rt_map_dissoc(copy_fn_idx: u32, map_linearize_idx: u32, map_from_flat_idx: u32) -> CompiledFn {
let mut b = RuntimeFnBuilder::new(2);
let count = b.alloc_i32();
let flat = b.alloc_i32();
let found = b.alloc_i32();
let found_idx = b.alloc_i32();
let i = b.alloc_i32();
let new_count = b.alloc_i32();
let slots = b.alloc_i32();
let size = b.alloc_i32();
let dst = b.alloc_i32();
let before_slots = b.alloc_i32();
let after_slots = b.alloc_i32();
let dst_base = b.alloc_i32();
let src_base = b.alloc_i32();
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::I32TruncF64U);
b.emit(Instruction::LocalSet(count));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32Eqz);
b.emit(Instruction::If(wasm_encoder::BlockType::Result(ValType::I32)));
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::Call(map_linearize_idx));
b.emit(Instruction::LocalSet(flat));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::I32Const(-1));
b.emit(Instruction::LocalSet(found_idx));
b.emit(Instruction::I32Const(0));
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Block(wasm_encoder::BlockType::Empty));
b.emit(Instruction::Loop(wasm_encoder::BlockType::Empty));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32GeU);
b.emit(Instruction::BrIf(1));
b.emit(Instruction::LocalGet(flat));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::F64Load(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(1));
b.emit(Instruction::F64Eq);
b.emit(Instruction::If(wasm_encoder::BlockType::Empty));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::LocalSet(found));
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::LocalSet(found_idx));
b.emit(Instruction::Br(2));
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(i));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(i));
b.emit(Instruction::Br(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.emit(Instruction::LocalGet(found));
b.emit(Instruction::If(wasm_encoder::BlockType::Result(ValType::I32)));
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Sub);
b.emit(Instruction::LocalSet(new_count));
b.emit(Instruction::LocalGet(new_count));
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(slots));
b.emit(Instruction::LocalGet(slots));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Mul);
b.emit(Instruction::LocalSet(size));
rt_emit_alloc_dynamic(&mut b, size, dst);
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::LocalGet(new_count));
b.emit(Instruction::F64ConvertI32U);
b.emit(Instruction::F64Store(mem_arg_f64(0)));
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(before_slots));
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(dst_base));
b.emit(Instruction::LocalGet(flat));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(src_base));
rt_emit_copy_slots(&mut b, copy_fn_idx, dst_base, src_base, before_slots);
b.emit(Instruction::LocalGet(count));
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Sub);
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Sub);
b.emit(Instruction::I32Const(2));
b.emit(Instruction::I32Mul);
b.emit(Instruction::LocalSet(after_slots));
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(dst_base));
b.emit(Instruction::LocalGet(flat));
b.emit(Instruction::I32Const(8));
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalGet(found_idx));
b.emit(Instruction::I32Const(1));
b.emit(Instruction::I32Add);
b.emit(Instruction::I32Const(16));
b.emit(Instruction::I32Mul);
b.emit(Instruction::I32Add);
b.emit(Instruction::LocalSet(src_base));
rt_emit_copy_slots(&mut b, copy_fn_idx, dst_base, src_base, after_slots);
b.emit(Instruction::LocalGet(dst));
b.emit(Instruction::Call(map_from_flat_idx));
b.emit(Instruction::Else);
b.emit(Instruction::LocalGet(0));
b.emit(Instruction::End);
b.emit(Instruction::End);
b.finish(vec![ValType::I32, ValType::F64], vec![ValType::I32])
}