Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ci/generate-spec-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ fn copy_test(src: &Path, dst: &Path) {
return;
}

// FIXME(WebAssembly/custom-page-sizes#58)
if src.ends_with("proposals/custom-page-sizes/custom-page-sizes-invalid.wast") {
return;
}

let directive = match dst.file_name().and_then(|s| s.to_str()) {
// Disable tests by doing something like:
// Some("exact-func-import.wast") => "FAIL",
Expand Down
26 changes: 26 additions & 0 deletions crates/json-from-wast/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ impl<'a> JsonBuilder<'a, '_> {
file,
}
}
WastDirective::AssertMalformedCustom {
span: _,
module,
message,
} => {
let line = self.lineno(module.span());
let (_name, file) = self.emit_file(module, true)?;
crate::Command::AssertMalformedCustom {
line,
text: message.into(),
file,
}
}
WastDirective::AssertInvalid {
span: _,
module,
Expand All @@ -116,6 +129,19 @@ impl<'a> JsonBuilder<'a, '_> {
file,
}
}
WastDirective::AssertInvalidCustom {
span: _,
module,
message,
} => {
let line = self.lineno(module.span());
let (_name, file) = self.emit_file(module, false)?;
crate::Command::AssertInvalidCustom {
line,
text: message.into(),
file,
}
}
WastDirective::Register {
span: _,
module,
Expand Down
16 changes: 16 additions & 0 deletions crates/json-from-wast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,27 @@ pub enum Command<'a> {
#[serde(borrow)]
text: Cow<'a, str>,
},
AssertMalformedCustom {
line: u32,
#[serde(borrow, flatten)]
file: WasmFile<'a>,
#[serde(borrow)]
text: Cow<'a, str>,
},
AssertInvalid {
line: u32,
#[serde(borrow, flatten)]
file: WasmFile<'a>,
#[serde(borrow)]
text: Cow<'a, str>,
},
AssertInvalidCustom {
line: u32,
#[serde(borrow, flatten)]
file: WasmFile<'a>,
#[serde(borrow)]
text: Cow<'a, str>,
},
Register {
line: u32,
#[serde(borrow, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -197,7 +211,9 @@ impl Command<'_> {
| ModuleDefinition { line, .. }
| ModuleInstance { line, .. }
| AssertMalformed { line, .. }
| AssertMalformedCustom { line, .. }
| AssertInvalid { line, .. }
| AssertInvalidCustom { line, .. }
| Register { line, .. }
| AssertUnlinkable { line, .. }
| AssertUninstantiable { line, .. }
Expand Down
71 changes: 35 additions & 36 deletions crates/wasmprinter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,7 @@ struct State {
core: CoreState,
#[cfg(feature = "component-model")]
component: ComponentState,
custom_section_place: Option<(&'static str, usize)>,
// `custom_section_place` stores the text representation of the location where
// a custom section should be serialized in the binary format.
// The tuple elements are a str (e.g. "after elem") and the line number
// where the custom section place was set. `update_custom_section_place` won't
// update the custom section place unless the line number changes; this prevents
// printing a place "after xxx" where the xxx section doesn't appear in the text format
// (e.g. because it was present but empty in the binary format).
custom_section_place: Option<&'static str>,
}

impl State {
Expand Down Expand Up @@ -485,8 +478,7 @@ impl Printer<'_, '_> {
match encoding {
Encoding::Module => {
states.push(State::new(Encoding::Module));
states.last_mut().unwrap().custom_section_place =
Some(("before first", self.line));
states.last_mut().unwrap().custom_section_place = Some("before first");
if states.len() > 1 {
self.start_group("core module")?;
} else {
Expand Down Expand Up @@ -546,7 +538,6 @@ impl Printer<'_, '_> {
self.result
.print_custom_section(c.name(), c.data_offset(), c.data())?;
if printed {
self.update_custom_section_line(&mut states);
continue;
}

Expand Down Expand Up @@ -589,16 +580,19 @@ impl Printer<'_, '_> {
}
}
assert!(self.nesting == start);
self.update_custom_section_line(&mut states);
}
Payload::TypeSection(s) => {
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after type");
}
self.print_types(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after type");
}
Payload::ImportSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after import");
}
self.print_imports(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after import");
}
Payload::FunctionSection(reader) => {
Self::ensure_module(&states)?;
Expand All @@ -609,35 +603,47 @@ impl Printer<'_, '_> {
MAX_WASM_FUNCTIONS
);
}
if reader.count() > 0 {
self.update_custom_section_place(&mut states, "after func");
}
for ty in reader {
states.last_mut().unwrap().core.func_to_type.push(Some(ty?))
}
self.update_custom_section_place(&mut states, "after func");
}
Payload::TableSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after table");
}
self.print_tables(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after table");
}
Payload::MemorySection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after memory");
}
self.print_memories(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after memory");
}
Payload::TagSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after tag");
}
self.print_tags(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after tag");
}
Payload::GlobalSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after global");
}
self.print_globals(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after global");
}
Payload::ExportSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after export");
}
self.print_exports(states.last().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after export");
}
Payload::StartSection { func, range } => {
Self::ensure_module(&states)?;
Expand All @@ -649,8 +655,10 @@ impl Printer<'_, '_> {
}
Payload::ElementSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after elem");
}
self.print_elems(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after elem");
}
Payload::CodeSectionStart { .. } => {
Self::ensure_module(&states)?;
Expand All @@ -669,8 +677,10 @@ impl Printer<'_, '_> {
}
Payload::DataSection(s) => {
Self::ensure_module(&states)?;
if s.count() > 0 {
self.update_custom_section_place(&mut states, "after data");
}
self.print_data(states.last_mut().unwrap(), s)?;
self.update_custom_section_place(&mut states, "after data");
}

#[cfg(feature = "component-model")]
Expand Down Expand Up @@ -774,19 +784,8 @@ impl Printer<'_, '_> {

fn update_custom_section_place(&self, states: &mut Vec<State>, place: &'static str) {
if let Some(last) = states.last_mut() {
if let Some((prev, prev_line)) = &mut last.custom_section_place {
if *prev_line != self.line {
*prev = place;
*prev_line = self.line;
}
}
}
}

fn update_custom_section_line(&self, states: &mut Vec<State>) {
if let Some(last) = states.last_mut() {
if let Some((_, prev_line)) = &mut last.custom_section_place {
*prev_line = self.line;
if let Some(prev) = &mut last.custom_section_place {
*prev = place;
}
}
}
Expand Down Expand Up @@ -1997,7 +1996,7 @@ impl Printer<'_, '_> {
self.newline(section.range().start)?;
self.start_group("@custom ")?;
self.print_str(section.name())?;
if let Some((place, _)) = state.custom_section_place {
if let Some(place) = state.custom_section_place {
write!(self.result, " ({place})")?;
}
self.result.write_str(" ")?;
Expand Down
2 changes: 1 addition & 1 deletion crates/wast/src/core/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,10 @@ pub(crate) fn encode(

e.typed_section(&data);

e.custom_sections(AfterLast);
if !names.is_empty() {
e.wasm.section(&names.to_name_section());
}
e.custom_sections(AfterLast);
if let Some(dwarf) = &mut dwarf {
dwarf.emit(&mut e);
}
Expand Down
14 changes: 10 additions & 4 deletions crates/wast/src/core/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,16 @@ impl<'a> ExpressionParser<'a> {
_ => return Err(parser.error("invalid value for branch hint")),
};

self.branch_hints.push(BranchHint {
instr_index: self.raw_instrs.len(),
value,
});
let instr_index = self.raw_instrs.len();
if let Some(prev) = self.branch_hints.last() {
if prev.instr_index == instr_index {
return Err(
parser.error("@metadata.code.branch_hint annotation: duplicate annotation")
);
}
}

self.branch_hints.push(BranchHint { instr_index, value });
Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions crates/wast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,9 @@ pub mod kw {
custom_keyword!(assert_exception);
custom_keyword!(assert_exhaustion);
custom_keyword!(assert_invalid);
custom_keyword!(assert_invalid_custom);
custom_keyword!(assert_malformed);
custom_keyword!(assert_malformed_custom);
custom_keyword!(assert_return);
custom_keyword!(assert_trap);
custom_keyword!(assert_unlinkable);
Expand Down
30 changes: 30 additions & 0 deletions crates/wast/src/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ pub enum WastDirective<'a> {
message: &'a str,
},

/// Asserts the module has an invalid custom section.
AssertInvalidCustom {
span: Span,
module: QuoteWat<'a>,
message: &'a str,
},

/// Registers the `module` instance with the given `name` to be available
/// for importing in future module instances.
Register {
Expand Down Expand Up @@ -149,6 +156,13 @@ pub enum WastDirective<'a> {

/// Waits for the specified thread to exit.
Wait { span: Span, thread: Id<'a> },

/// Asserts that a custom section of `module` is malformed.
AssertMalformedCustom {
span: Span,
module: QuoteWat<'a>,
message: &'a str,
},
}

impl WastDirective<'_> {
Expand All @@ -163,12 +177,14 @@ impl WastDirective<'_> {
| WastDirective::ModuleDefinition(QuoteWat::QuoteComponent(span, _)) => *span,
WastDirective::ModuleInstance { span, .. }
| WastDirective::AssertMalformed { span, .. }
| WastDirective::AssertMalformedCustom { span, .. }
| WastDirective::Register { span, .. }
| WastDirective::AssertTrap { span, .. }
| WastDirective::AssertReturn { span, .. }
| WastDirective::AssertExhaustion { span, .. }
| WastDirective::AssertUnlinkable { span, .. }
| WastDirective::AssertInvalid { span, .. }
| WastDirective::AssertInvalidCustom { span, .. }
| WastDirective::AssertException { span, .. }
| WastDirective::AssertSuspension { span, .. }
| WastDirective::Wait { span, .. } => *span,
Expand All @@ -190,13 +206,27 @@ impl<'a> Parse<'a> for WastDirective<'a> {
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_malformed_custom>()? {
let span = parser.parse::<kw::assert_malformed_custom>()?.0;
Ok(WastDirective::AssertMalformedCustom {
span,
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_invalid>()? {
let span = parser.parse::<kw::assert_invalid>()?.0;
Ok(WastDirective::AssertInvalid {
span,
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::assert_invalid_custom>()? {
let span = parser.parse::<kw::assert_invalid_custom>()?.0;
Ok(WastDirective::AssertInvalidCustom {
span,
module: parser.parens(|p| p.parse())?,
message: parser.parse()?,
})
} else if l.peek::<kw::register>()? {
let span = parser.parse::<kw::register>()?.0;
Ok(WastDirective::Register {
Expand Down
Loading
Loading