Skip to content

Commit

Permalink
Implement parsing of tables with initializer expressions (#823)
Browse files Browse the repository at this point in the history
The function references proposal adds initializer for tables when
its type is non-nullable reference. The text format is extended
with constant expression (which can have ref.func). The binary format
adds `0x40 0x00` prefix to the table section entry to indicate expression
presence.

https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md
  • Loading branch information
yurydelendik committed Nov 17, 2022
1 parent e15e768 commit ebce499
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 12 deletions.
8 changes: 7 additions & 1 deletion crates/wast/src/core/binary.rs
Expand Up @@ -427,7 +427,13 @@ impl Encode for Table<'_> {
fn encode(&self, e: &mut Vec<u8>) {
assert!(self.exports.names.is_empty());
match &self.kind {
TableKind::Normal(t) => t.encode(e),
TableKind::Normal { ty, init_expr: None } => ty.encode(e),
TableKind::Normal { ty, init_expr: Some(init_expr) } => {
e.push(0x40);
e.push(0x00);
ty.encode(e);
init_expr.encode(e);
}
_ => panic!("TableKind should be normal during encoding"),
}
}
Expand Down
17 changes: 10 additions & 7 deletions crates/wast/src/core/resolve/deinline_import_export.rs
Expand Up @@ -120,13 +120,16 @@ pub fn run(fields: &mut Vec<ModuleField>) {
ElemPayload::Indices(v) => v.len(),
ElemPayload::Exprs { exprs, .. } => exprs.len(),
};
let kind = TableKind::Normal(TableType {
limits: Limits {
min: len as u32,
max: Some(len as u32),
let kind = TableKind::Normal {
ty: TableType {
limits: Limits {
min: len as u32,
max: Some(len as u32),
},
elem: *elem,
},
elem: *elem,
});
init_expr: None,
};
let payload = match mem::replace(&mut t.kind, kind) {
TableKind::Inline { payload, .. } => payload,
_ => unreachable!(),
Expand All @@ -146,7 +149,7 @@ pub fn run(fields: &mut Vec<ModuleField>) {
}));
}

TableKind::Normal(_) => {}
TableKind::Normal { .. } => {}
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/wast/src/core/resolve/names.rs
Expand Up @@ -262,8 +262,11 @@ impl<'a> Resolver<'a> {
}

ModuleField::Table(t) => {
if let TableKind::Normal(t) = &mut t.kind {
self.resolve_heaptype(&mut t.elem.heap)?;
if let TableKind::Normal { ty, init_expr } = &mut t.kind {
self.resolve_heaptype(&mut ty.elem.heap)?;
if let Some(init_expr) = init_expr {
self.resolve_expr(init_expr)?;
}
}
Ok(())
}
Expand Down
16 changes: 14 additions & 2 deletions crates/wast/src/core/table.rs
Expand Up @@ -30,7 +30,12 @@ pub enum TableKind<'a> {
},

/// A typical memory definition which simply says the limits of the table
Normal(TableType<'a>),
Normal {
/// Table type.
ty: TableType<'a>,
/// Optional items initializer expression.
init_expr: Option<Expression<'a>>,
},

/// The elem segments of this table, starting from 0, explicitly listed
Inline {
Expand Down Expand Up @@ -68,7 +73,14 @@ impl<'a> Parse<'a> for Table<'a> {
})?;
TableKind::Inline { elem, payload }
} else if l.peek::<u32>() {
TableKind::Normal(parser.parse()?)
TableKind::Normal {
ty: parser.parse()?,
init_expr: if parser.peek::<LParen>() {
Some(parser.parse::<Expression>()?)
} else {
None
},
}
} else if let Some(import) = parser.parse()? {
TableKind::Import {
import,
Expand Down
19 changes: 19 additions & 0 deletions tests/local/function-references/table-nonnull.wast
@@ -0,0 +1,19 @@
;; Table initializer

(module
(type $dummy (func))
(func $dummy)

(table $t1 10 funcref)
(table $t2 10 funcref (ref.func $dummy))
(table $t3 10 (ref $dummy) (ref.func $dummy))
(table $t4 10 (ref func) (ref.func $dummy))

(func (export "get1") (result funcref) (table.get $t1 (i32.const 1)))
(func (export "get2") (result funcref) (table.get $t2 (i32.const 4)))
(func (export "get3") (result funcref) (table.get $t3 (i32.const 7)))
)

(assert_return (invoke "get1") (ref.null))
(assert_return (invoke "get2") (ref.func))
(assert_return (invoke "get3") (ref.func))

0 comments on commit ebce499

Please sign in to comment.