Skip to content

Commit a28e134

Browse files
authored
Preserve element segment encoding more often (#1807)
This commit fixes a small regression in reencoding from #1794 where element segments subtly changed encoding by accident. This commit additionally ensures that there's a text format for all element encodings and updates printing to respect the same defaults. It should now be possible to represent all formats for element segments in the text format and have them round-trippable.
1 parent 7de4d1d commit a28e134

File tree

331 files changed

+714
-628
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

331 files changed

+714
-628
lines changed

crates/wasm-encoder/src/reencode.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,14 +1408,13 @@ pub mod utils {
14081408
// example which wants to track uses to know when it's ok to
14091409
// remove a table.
14101410
//
1411-
// If the table index is still zero though go ahead and pass
1412-
// `None` here since that implicitly references table 0. Note
1413-
// that this means that this does not round-trip the encoding of
1414-
// `Some(0)` since that reencodes to `None`, but that's seen as
1415-
// hopefully ok.
1416-
match reencoder.table_index(table_index.unwrap_or(0)) {
1417-
0 => None,
1418-
i => Some(i),
1411+
// If the table index started at `None` and is still zero then
1412+
// preserve this encoding and keep it at `None`. Otherwise if
1413+
// the result is nonzero or it was previously nonzero then keep
1414+
// that encoding too.
1415+
match (table_index, reencoder.table_index(table_index.unwrap_or(0))) {
1416+
(None, 0) => None,
1417+
(_, n) => Some(n),
14191418
},
14201419
&reencoder.const_expr(offset_expr)?,
14211420
elems,

crates/wasmprinter/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,8 +1531,7 @@ impl Printer<'_, '_> {
15311531
table_index,
15321532
offset_expr,
15331533
} => {
1534-
let table_index = table_index.unwrap_or(0);
1535-
if table_index != 0 {
1534+
if let Some(table_index) = *table_index {
15361535
self.result.write_str(" ")?;
15371536
self.start_group("table ")?;
15381537
self.print_idx(&state.core.table_names, table_index)?;

crates/wast/src/core/binary.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ impl Encode for Elem<'_> {
703703
match (&self.kind, &self.payload) {
704704
(
705705
ElemKind::Active {
706-
table: Index::Num(0, _),
706+
table: None,
707707
offset,
708708
},
709709
ElemPayload::Indices(_),
@@ -715,7 +715,13 @@ impl Encode for Elem<'_> {
715715
e.push(0x01); // flags
716716
e.push(0x00); // extern_kind
717717
}
718-
(ElemKind::Active { table, offset }, ElemPayload::Indices(_)) => {
718+
(
719+
ElemKind::Active {
720+
table: Some(table),
721+
offset,
722+
},
723+
ElemPayload::Indices(_),
724+
) => {
719725
e.push(0x02); // flags
720726
table.encode(e);
721727
offset.encode(e, None);
@@ -727,7 +733,7 @@ impl Encode for Elem<'_> {
727733
}
728734
(
729735
ElemKind::Active {
730-
table: Index::Num(0, _),
736+
table: None,
731737
offset,
732738
},
733739
ElemPayload::Exprs {
@@ -752,7 +758,7 @@ impl Encode for Elem<'_> {
752758
}
753759
(ElemKind::Active { table, offset }, ElemPayload::Exprs { ty, .. }) => {
754760
e.push(0x06);
755-
table.encode(e);
761+
table.map(|t| t.unwrap_u32()).unwrap_or(0).encode(e);
756762
offset.encode(e, None);
757763
ty.encode(e);
758764
}

crates/wast/src/core/resolve/deinline_import_export.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ pub fn run(fields: &mut Vec<ModuleField>) {
139139
id: None,
140140
name: None,
141141
kind: ElemKind::Active {
142-
table: Index::Id(id),
142+
table: Some(Index::Id(id)),
143143
offset: Expression::one(if is64 {
144144
Instruction::I64Const(0)
145145
} else {

crates/wast/src/core/resolve/names.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,9 @@ impl<'a> Resolver<'a> {
184184
ModuleField::Elem(e) => {
185185
match &mut e.kind {
186186
ElemKind::Active { table, offset } => {
187-
self.resolve(table, Ns::Table)?;
187+
if let Some(table) = table {
188+
self.resolve(table, Ns::Table)?;
189+
}
188190
self.resolve_expr(offset)?;
189191
}
190192
ElemKind::Passive { .. } | ElemKind::Declared { .. } => {}

crates/wast/src/core/table.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ pub enum ElemKind<'a> {
149149
/// An active segment associated with a table.
150150
Active {
151151
/// The table this `elem` is initializing.
152-
table: Index<'a>,
152+
table: Option<Index<'a>>,
153153
/// The offset within `table` that we'll initialize at.
154154
offset: Expression<'a>,
155155
},
@@ -197,15 +197,15 @@ impl<'a> Parse<'a> for Elem<'a> {
197197
// time, this probably should get removed when the threads
198198
// proposal is rebased on the current spec.
199199
table_omitted = true;
200-
Index::Num(parser.parse()?, span)
200+
Some(Index::Num(parser.parse()?, span))
201201
} else if parser.peek2::<kw::table>()? {
202-
parser.parens(|p| {
202+
Some(parser.parens(|p| {
203203
p.parse::<kw::table>()?;
204204
p.parse()
205-
})?
205+
})?)
206206
} else {
207207
table_omitted = true;
208-
Index::Num(0, span)
208+
None
209209
};
210210

211211
let offset = parse_expr_or_single_instr::<kw::offset>(parser)?;

fuzz/src/lib.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use libfuzzer_sys::arbitrary::{Result, Unstructured};
22
use std::fmt::Debug;
3+
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
34
use wasm_smith::{Component, Config, Module};
45
use wasmparser::WasmFeatures;
56

@@ -120,15 +121,25 @@ pub fn validator_for_config(config: &Config) -> wasmparser::Validator {
120121
pub fn log_wasm(wasm: &[u8], config: impl Debug) {
121122
drop(env_logger::try_init());
122123

123-
if log::log_enabled!(log::Level::Debug) {
124-
log::debug!("writing test case to `test.wasm` ...");
125-
std::fs::write("test.wasm", wasm).unwrap();
126-
std::fs::write("test.config", format!("{:#?}", config)).unwrap();
127-
if let Ok(wat) = wasmprinter::print_bytes(wasm) {
128-
log::debug!("writing text format to `test.wat` ...");
129-
std::fs::write("test.wat", wat).unwrap();
130-
} else {
131-
drop(std::fs::remove_file("test.wat"));
132-
}
124+
if !log::log_enabled!(log::Level::Debug) {
125+
return;
126+
}
127+
128+
static CNT: AtomicUsize = AtomicUsize::new(0);
129+
130+
let i = CNT.fetch_add(1, SeqCst);
131+
132+
let wasm_file = format!("test{i}.wasm");
133+
let config_file = format!("test{i}.config");
134+
let wat_file = format!("test{i}.wat");
135+
136+
log::debug!("writing test case to `{wasm_file}` ...");
137+
std::fs::write(&wasm_file, wasm).unwrap();
138+
std::fs::write(&config_file, format!("{:#?}", config)).unwrap();
139+
if let Ok(wat) = wasmprinter::print_bytes(wasm) {
140+
log::debug!("writing text format to `{wat_file}` ...");
141+
std::fs::write(&wat_file, wat).unwrap();
142+
} else {
143+
drop(std::fs::remove_file(&wat_file));
133144
}
134145
}

fuzz/src/reencode.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ use arbitrary::{Result, Unstructured};
22
use wasm_encoder::reencode::{Reencode, RoundtripReencoder};
33

44
pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
5-
let (module1, _) = super::generate_valid_module(u, |_, _| Ok(()))?;
5+
let (module1, config) = super::generate_valid_module(u, |_, _| Ok(()))?;
66

77
let mut module2 = Default::default();
88
RoundtripReencoder
99
.parse_core_module(&mut module2, wasmparser::Parser::new(0), &module1)
1010
.unwrap();
1111

1212
let module2 = module2.finish();
13+
if module1 == module2 {
14+
return Ok(());
15+
}
16+
crate::log_wasm(&module1, &config);
17+
crate::log_wasm(&module2, &config);
1318
assert_eq!(module1, module2);
1419

1520
Ok(())

tests/cli/dump-elem-segments.wat

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
;; RUN: print % | dump
2+
3+
;; test that all forms of element segments can be round-tripped from
4+
;; text-to-binary.
5+
(module
6+
(table 1 1 funcref)
7+
8+
(func $f)
9+
10+
(elem (i32.const 0) func) ;; 0x00
11+
(elem func) ;; 0x01
12+
(elem (table 0) (i32.const 0) func) ;; 0x02
13+
(elem declare func) ;; 0x03
14+
(elem (i32.const 0) funcref) ;; 0x04
15+
(elem funcref) ;; 0x05
16+
(elem (table 0) (i32.const 0) funcref) ;; 0x06
17+
(elem declare funcref) ;; 0x07
18+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
0x0 | 00 61 73 6d | version 1 (Module)
2+
| 01 00 00 00
3+
0x8 | 01 04 | type section
4+
0xa | 01 | 1 count
5+
--- rec group 0 (implicit) ---
6+
0xb | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }
7+
0xe | 03 02 | func section
8+
0x10 | 01 | 1 count
9+
0x11 | 00 | [func 0] type 0
10+
0x12 | 04 05 | table section
11+
0x14 | 01 | 1 count
12+
0x15 | 70 01 01 01 | [table 0] Table { ty: TableType { element_type: funcref, table64: false, initial: 1, maximum: Some(1), shared: false }, init: RefNull }
13+
0x19 | 09 25 | element section
14+
0x1b | 08 | 8 count
15+
0x1c | 00 | element table[None]
16+
0x1d | 41 00 | i32_const value:0
17+
0x1f | 0b | end
18+
0x20 | 00 | 0 items [indices]
19+
0x21 | 01 00 00 | element passive, 0 items [indices]
20+
0x24 | 02 00 | element table[Some(0)]
21+
0x26 | 41 00 | i32_const value:0
22+
0x28 | 0b | end
23+
0x29 | 00 00 | 0 items [indices]
24+
0x2b | 03 00 00 | element declared 0 items [indices]
25+
0x2e | 04 | element table[None]
26+
0x2f | 41 00 | i32_const value:0
27+
0x31 | 0b | end
28+
0x32 | 00 | 0 items [exprs funcref]
29+
0x33 | 05 70 00 | element passive, 0 items [exprs funcref]
30+
0x36 | 06 00 | element table[Some(0)]
31+
0x38 | 41 00 | i32_const value:0
32+
0x3a | 0b | end
33+
0x3b | 70 00 | 0 items [exprs funcref]
34+
0x3d | 07 70 00 | element declared 0 items [exprs funcref]
35+
0x40 | 0a 04 | code section
36+
0x42 | 01 | 1 count
37+
============== func 0 ====================
38+
0x43 | 02 | size of function
39+
0x44 | 00 | 0 local blocks
40+
0x45 | 0b | end
41+
0x46 | 00 0b | custom section
42+
0x48 | 04 6e 61 6d | name: "name"
43+
| 65
44+
0x4d | 01 04 | function name section
45+
0x4f | 01 | 1 count
46+
0x50 | 00 01 66 | Naming { index: 0, name: "f" }

0 commit comments

Comments
 (0)