Skip to content

Commit

Permalink
Update the exception-handling validator implementation
Browse files Browse the repository at this point in the history
This commit updates the implementation of the exception-handling
proposal to the latest version of the proposal. This was already
implemented in the text format but all other crates needed updating. The
changes were:

* A new `exn` heap type is added for `exnref`. Currently this isn't a
  subtype with anything else, and this probably isn't correct but it's
  at least conservative for now.

* The `try`, `delegate`, `catch`, `catch_all`, and `rethrow`
  instructions were all removed as they're no longer present.

* New `try_table` and `throw_ref` instructions were added.

* Support for the name section subsection for tags has been added along
  with printing tag names in the text format.

* All exception-handling spec tests are now re-enabled.
  • Loading branch information
alexcrichton committed Dec 18, 2023
1 parent 6ae4441 commit 137e6f8
Show file tree
Hide file tree
Showing 50 changed files with 1,057 additions and 851 deletions.
67 changes: 44 additions & 23 deletions crates/wasm-encoder/src/core/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,6 @@ pub enum Instruction<'a> {
Loop(BlockType),
If(BlockType),
Else,
Try(BlockType),
Delegate(u32),
Catch(u32),
CatchAll,
End,
Br(u32),
BrIf(u32),
Expand All @@ -327,8 +323,9 @@ pub enum Instruction<'a> {
ReturnCallRef(u32),
ReturnCall(u32),
ReturnCallIndirect { ty: u32, table: u32 },
TryTable(BlockType, Cow<'a, [Catch]>),
Throw(u32),
Rethrow(u32),
ThrowRef,

// Parametric instructions.
Drop,
Expand Down Expand Up @@ -916,21 +913,12 @@ impl Encode for Instruction<'_> {
bt.encode(sink);
}
Instruction::Else => sink.push(0x05),
Instruction::Try(bt) => {
sink.push(0x06);
bt.encode(sink);
}
Instruction::Catch(t) => {
sink.push(0x07);
t.encode(sink);
}
Instruction::Throw(t) => {
sink.push(0x08);
t.encode(sink);
}
Instruction::Rethrow(l) => {
sink.push(0x09);
l.encode(sink);
Instruction::ThrowRef => {
sink.push(0x0A);
}
Instruction::End => sink.push(0x0B),
Instruction::Br(l) => {
Expand Down Expand Up @@ -982,13 +970,6 @@ impl Encode for Instruction<'_> {
ty.encode(sink);
table.encode(sink);
}
Instruction::Delegate(l) => {
sink.push(0x18);
l.encode(sink);
}
Instruction::CatchAll => {
sink.push(0x19);
}

// Parametric instructions.
Instruction::Drop => sink.push(0x1A),
Expand All @@ -998,6 +979,12 @@ impl Encode for Instruction<'_> {
[ty].encode(sink);
}

Instruction::TryTable(ty, ref catches) => {
sink.push(0x1f);
ty.encode(sink);
catches.encode(sink);
}

// Variable instructions.
Instruction::LocalGet(l) => {
sink.push(0x20);
Expand Down Expand Up @@ -2975,6 +2962,40 @@ impl Encode for Instruction<'_> {
}
}

#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum Catch {
One { tag: u32, label: u32 },
OneRef { tag: u32, label: u32 },
All { label: u32 },
AllRef { label: u32 },
}

impl Encode for Catch {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Catch::One { tag, label } => {
sink.push(0x00);
tag.encode(sink);
label.encode(sink);
}
Catch::OneRef { tag, label } => {
sink.push(0x01);
tag.encode(sink);
label.encode(sink);
}
Catch::All { label } => {
sink.push(0x02);
label.encode(sink);
}
Catch::AllRef { label } => {
sink.push(0x03);
label.encode(sink);
}
}
}
}

/// A constant expression.
///
/// Usable in contexts such as offsets or initializers.
Expand Down
8 changes: 8 additions & 0 deletions crates/wasm-encoder/src/core/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ impl NameSection {
names.encode(&mut self.bytes);
}

/// Appends a subsection for the names of all tags in this wasm module.
///
/// This section should come after the data name subsection (if present).
pub fn tag(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Tag, names.size());
names.encode(&mut self.bytes);
}

/// Appends a subsection for the names of fields within types in this
/// wasm module.
///
Expand Down
13 changes: 13 additions & 0 deletions crates/wasm-encoder/src/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ impl ValType {
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
/// Alias for the `externref` type in WebAssembly
pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
/// Alias for the `exnref` type in WebAssembly
pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF);
}

impl Encode for StorageType {
Expand Down Expand Up @@ -304,6 +306,12 @@ impl RefType {
nullable: true,
heap_type: HeapType::Extern,
};

/// Alias for the `exnref` type in WebAssembly
pub const EXNREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Exn,
};
}

impl Encode for RefType {
Expand Down Expand Up @@ -393,6 +401,9 @@ pub enum HeapType {
/// The unboxed `i31` heap type.
I31,

/// The abstract` exception` heap type.
Exn,

/// A concrete Wasm-defined type at the given index.
Concrete(u32),
}
Expand All @@ -410,6 +421,7 @@ impl Encode for HeapType {
HeapType::Struct => sink.push(0x6B),
HeapType::Array => sink.push(0x6A),
HeapType::I31 => sink.push(0x6C),
HeapType::Exn => sink.push(0x69),
// Note that this is encoded as a signed type rather than unsigned
// as it's decoded as an s33
HeapType::Concrete(i) => i64::from(*i).encode(sink),
Expand All @@ -434,6 +446,7 @@ impl TryFrom<wasmparser::HeapType> for HeapType {
wasmparser::HeapType::Struct => HeapType::Struct,
wasmparser::HeapType::Array => HeapType::Array,
wasmparser::HeapType::I31 => HeapType::I31,
wasmparser::HeapType::Exn => HeapType::Exn,
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/wasm-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,8 @@ impl<'a> ModuleNames<'a> {
wasmparser::Name::Memory(m) => section.memories(&name_map(&m)?),
wasmparser::Name::Global(m) => section.globals(&name_map(&m)?),
wasmparser::Name::Element(m) => section.elements(&name_map(&m)?),
wasmparser::Name::Data(m) => section.types(&name_map(&m)?),
wasmparser::Name::Data(m) => section.data(&name_map(&m)?),
wasmparser::Name::Tag(m) => section.tags(&name_map(&m)?),
wasmparser::Name::Unknown { .. } => {} // wasm-encoder doesn't support it
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/wasm-mutate/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub fn map_ref_type(ref_ty: wasmparser::RefType) -> Result<RefType> {
wasmparser::HeapType::Struct => HeapType::Struct,
wasmparser::HeapType::Array => HeapType::Array,
wasmparser::HeapType::I31 => HeapType::I31,
wasmparser::HeapType::Exn => HeapType::Exn,
wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().unwrap()),
},
})
Expand Down
7 changes: 7 additions & 0 deletions crates/wasm-mutate/src/mutators/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ pub fn heapty(t: &mut dyn Translator, ty: &wasmparser::HeapType) -> Result<HeapT
wasmparser::HeapType::Struct => Ok(HeapType::Struct),
wasmparser::HeapType::Array => Ok(HeapType::Array),
wasmparser::HeapType::I31 => Ok(HeapType::I31),
wasmparser::HeapType::Exn => Ok(HeapType::Exn),
wasmparser::HeapType::Concrete(i) => Ok(HeapType::Concrete(
t.remap(Item::Type, i.as_module_index().unwrap())?,
)),
Expand Down Expand Up @@ -362,6 +363,7 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result<Instruction<'stat
(map $arg:ident value) => ($arg);
(map $arg:ident lane) => (*$arg);
(map $arg:ident lanes) => (*$arg);
(map $arg:ident try_table) => ($arg);

// This case takes the arguments of a wasmparser instruction and creates
// a wasm-encoder instruction. There are a few special cases for where
Expand All @@ -374,6 +376,7 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result<Instruction<'stat
(build F32Const $arg:ident) => (I::F32Const(f32::from_bits($arg.bits())));
(build F64Const $arg:ident) => (I::F64Const(f64::from_bits($arg.bits())));
(build V128Const $arg:ident) => (I::V128Const($arg.i128()));
(build TryTable $table:ident) => (unimplemented_try_table());
(build $op:ident $arg:ident) => (I::$op($arg));
(build CallIndirect $ty:ident $table:ident $_:ident) => (I::CallIndirect {
ty: $ty,
Expand All @@ -391,6 +394,10 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result<Instruction<'stat
wasmparser::for_each_operator!(translate)
}

fn unimplemented_try_table() -> wasm_encoder::Instruction<'static> {
unimplemented!()
}

pub fn block_type(t: &mut dyn Translator, ty: &wasmparser::BlockType) -> Result<BlockType> {
match ty {
wasmparser::BlockType::Empty => Ok(BlockType::Empty),
Expand Down
Loading

0 comments on commit 137e6f8

Please sign in to comment.