Skip to content

Commit e987f94

Browse files
authored
Fix the codegen of the TableGrow intrinsic (#2450)
It's not safe for us to arbitrarily modify the instruction stream since wasm isn't guaranteed to be an AST! Instead we resort to a few extra instructions with locals to achieve what we want here. Closes #2446
1 parent 5442f26 commit e987f94

File tree

3 files changed

+72
-11
lines changed

3 files changed

+72
-11
lines changed

crates/externref-xform/src/lib.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -681,11 +681,13 @@ impl Transform<'_> {
681681
continue;
682682
}
683683
let entry = func.entry_block();
684+
let scratch_i32 = module.locals.add(ValType::I32);
684685
dfs_pre_order_mut(
685686
&mut Rewrite {
686687
clone_ref: self.clone_ref()?,
687688
heap_dealloc: self.heap_dealloc()?,
688689
xform: self,
690+
scratch_i32,
689691
},
690692
func,
691693
entry,
@@ -698,6 +700,7 @@ impl Transform<'_> {
698700
xform: &'a Transform<'b>,
699701
clone_ref: FunctionId,
700702
heap_dealloc: FunctionId,
703+
scratch_i32: LocalId,
701704
}
702705

703706
impl VisitorMut for Rewrite<'_, '_> {
@@ -723,16 +726,28 @@ impl Transform<'_> {
723726
let ty = ValType::Externref;
724727
match intrinsic {
725728
Intrinsic::TableGrow => {
726-
// Switch this to a `table.grow` instruction...
729+
// Change something that looks like:
730+
//
731+
// call $table_grow
732+
//
733+
// into:
734+
//
735+
// local.set $scratch
736+
// ref.null extern
737+
// local.get $scratch
738+
// table.grow $table
739+
//
740+
// Note that things happen backwards here due to the
741+
// order of insertion.
727742
seq.instrs[i].0 = TableGrow {
728743
table: self.xform.table,
729744
}
730745
.into();
731-
// ... and then insert a `ref.null` before the
732-
// preceding instruction as the value to grow the
733-
// table with.
734-
seq.instrs
735-
.insert(i - 1, (RefNull { ty }.into(), InstrLocId::default()));
746+
let loc = seq.instrs[i].1;
747+
let local = self.scratch_i32;
748+
seq.instrs.insert(i, (LocalGet { local }.into(), loc));
749+
seq.instrs.insert(i, (RefNull { ty }.into(), loc));
750+
seq.instrs.insert(i, (LocalSet { local }.into(), loc));
736751
}
737752
Intrinsic::TableSetNull => {
738753
// Switch this to a `table.set` instruction...

crates/externref-xform/tests/table-grow-intrinsic.wat

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
(type (;0;) (func (result i32)))
1818
(type (;1;) (func (param i32)))
1919
(type (;2;) (func (param externref)))
20+
(func $foo (type 1) (param i32)
21+
(local i32)
22+
i32.const 0
23+
local.set 1
24+
ref.null extern
25+
local.get 1
26+
table.grow 0
27+
drop)
2028
(func $foo_externref_shim (@name "foo externref shim") (type 2) (param externref)
2129
(local i32)
2230
call $alloc
@@ -25,11 +33,6 @@
2533
table.set 0
2634
local.get 1
2735
call $foo)
28-
(func $foo (type 1) (param i32)
29-
ref.null extern
30-
i32.const 0
31-
table.grow 0
32-
drop)
3336
(func $alloc (type 0) (result i32)
3437
i32.const 0)
3538
(table (;0;) 32 externref)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
;; @xform export "foo" (externref_owned)
2+
3+
(module
4+
(import "__wbindgen_externref_xform__" "__wbindgen_externref_table_grow"
5+
(func $grow (param i32) (result i32)))
6+
(func $foo (export "foo") (param i32)
7+
(local i32)
8+
i32.const 0
9+
local.tee 0
10+
call $grow
11+
drop)
12+
(func $alloc (export "__externref_table_alloc") (result i32)
13+
i32.const 0)
14+
(func $dealloc (export "__externref_table_dealloc") (param i32))
15+
)
16+
17+
(; CHECK-ALL:
18+
(module
19+
(type (;0;) (func (result i32)))
20+
(type (;1;) (func (param i32)))
21+
(type (;2;) (func (param externref)))
22+
(func $foo (type 1) (param i32)
23+
(local i32)
24+
i32.const 0
25+
local.tee 0
26+
local.set 1
27+
ref.null extern
28+
local.get 1
29+
table.grow 0
30+
drop)
31+
(func $foo_externref_shim (@name "foo externref shim") (type 2) (param externref)
32+
(local i32)
33+
call $alloc
34+
local.tee 1
35+
local.get 0
36+
table.set 0
37+
local.get 1
38+
call $foo)
39+
(func $alloc (type 0) (result i32)
40+
i32.const 0)
41+
(table (;0;) 32 externref)
42+
(export "foo" (func $foo_externref_shim)))
43+
;)

0 commit comments

Comments
 (0)