| 1 | module main |
| 2 | |
| 3 | import wasm |
| 4 | |
| 5 | // A funcref table populated by an active element segment, dispatched through |
| 6 | // `call_indirect`. |
| 7 | fn test_call_indirect() { |
| 8 | mut m := wasm.Module{} |
| 9 | |
| 10 | mut f0 := m.new_function('f0', [], [.i32_t]) |
| 11 | { |
| 12 | f0.i32_const(10) |
| 13 | } |
| 14 | m.commit(f0, false) |
| 15 | |
| 16 | mut f1 := m.new_function('f1', [], [.i32_t]) |
| 17 | { |
| 18 | f1.i32_const(20) |
| 19 | } |
| 20 | m.commit(f1, false) |
| 21 | |
| 22 | tidx := m.assign_table('__indirect_function_table', true, .funcref_t, 2, none) |
| 23 | m.new_active_element(tidx, 0, ['f0', 'f1']) |
| 24 | |
| 25 | sig := m.new_functype(wasm.FuncType{ |
| 26 | parameters: []wasm.ValType{} |
| 27 | results: [.i32_t] |
| 28 | }) |
| 29 | |
| 30 | mut dispatch := m.new_function('dispatch', [.i32_t], [.i32_t]) |
| 31 | { |
| 32 | dispatch.local_get(0) // table index argument |
| 33 | dispatch.call_indirect(sig, tidx) |
| 34 | } |
| 35 | m.commit(dispatch, true) |
| 36 | |
| 37 | validate(m.compile()) or { panic(err) } |
| 38 | } |
| 39 | |
| 40 | // A growable externref table exercised with table.size/grow/set/get. |
| 41 | fn test_externref_table() { |
| 42 | mut m := wasm.Module{} |
| 43 | |
| 44 | tidx := m.assign_table('refs', true, .externref_t, 1, none) |
| 45 | |
| 46 | // grow by 3 (filling with null); leaves the previous size on the stack |
| 47 | mut grow := m.new_function('grow_refs', [], [.i32_t]) |
| 48 | { |
| 49 | grow.ref_null(.externref_t) // init value |
| 50 | grow.i32_const(3) // n |
| 51 | grow.table_grow(tidx) |
| 52 | } |
| 53 | m.commit(grow, true) |
| 54 | |
| 55 | mut size := m.new_function('refs_size', [], [.i32_t]) |
| 56 | { |
| 57 | size.table_size(tidx) |
| 58 | } |
| 59 | m.commit(size, true) |
| 60 | |
| 61 | // refs[0] = null, then read it back and report whether it is null |
| 62 | mut roundtrip := m.new_function('roundtrip', [], [.i32_t]) |
| 63 | { |
| 64 | roundtrip.i32_const(0) // index |
| 65 | roundtrip.ref_null(.externref_t) // value |
| 66 | roundtrip.table_set(tidx) |
| 67 | roundtrip.i32_const(0) // index |
| 68 | roundtrip.table_get(tidx) |
| 69 | roundtrip.ref_is_null(.externref_t) |
| 70 | } |
| 71 | m.commit(roundtrip, true) |
| 72 | |
| 73 | validate(m.compile()) or { panic(err) } |
| 74 | } |
| 75 | |
| 76 | // A declarative element segment makes `ref.func` to a non-exported, non-tabled |
| 77 | // function validate. Without the segment, validation would fail. |
| 78 | fn test_declarative_element() { |
| 79 | mut m := wasm.Module{} |
| 80 | |
| 81 | mut hidden := m.new_function('f_hidden', [], [.i32_t]) |
| 82 | { |
| 83 | hidden.i32_const(42) |
| 84 | } |
| 85 | m.commit(hidden, false) // NOT exported |
| 86 | |
| 87 | m.new_declarative_element(['f_hidden']) |
| 88 | |
| 89 | mut probe := m.new_function('probe', [], [.i32_t]) |
| 90 | { |
| 91 | probe.ref_func('f_hidden') |
| 92 | probe.ref_is_null(.funcref_t) |
| 93 | } |
| 94 | m.commit(probe, true) |
| 95 | |
| 96 | validate(m.compile()) or { panic(err) } |
| 97 | } |
| 98 | |