summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rw-r--r--README.md23
-rw-r--r--crates/parser/src/conversion.rs11
-rw-r--r--crates/parser/src/lib.rs2
-rw-r--r--crates/tinywasm/Cargo.toml6
-rw-r--r--crates/tinywasm/benches/argon2id.rs2
-rw-r--r--crates/tinywasm/benches/fibonacci.rs2
-rw-r--r--crates/tinywasm/benches/tinywasm.rs2
-rw-r--r--crates/tinywasm/src/imports.rs16
-rw-r--r--crates/tinywasm/src/store/memory.rs49
-rw-r--r--crates/tinywasm/src/store/mod.rs4
-rw-r--r--crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv1
-rw-r--r--crates/tinywasm/tests/test-wasm-custom-page-sizes.rs20
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs7
-rw-r--r--crates/types/src/lib.rs43
-rw-r--r--crates/wasm-testsuite/lib.rs19
-rw-r--r--crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes-invalid.wast112
-rw-r--r--crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes.wast110
18 files changed, 378 insertions, 63 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e429505..c8bc86c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -242,9 +242,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "cpufeatures"
-version = "0.2.13"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
@@ -754,18 +754,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
-version = "1.0.209"
+version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.209"
+version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
diff --git a/README.md b/README.md
index 2d897ee..a963ea7 100644
--- a/README.md
+++ b/README.md
@@ -27,17 +27,18 @@ TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite](
🚧 -- in development / partialy supported\
🟢 -- fully supported
-| Proposal | Status | TinyWasm Version |
-| -------------------------------------------------------------------------------------------------------------------------- | ------ | ---------------- |
-| [**Mutable Globals**](https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md) | 🟢 | 0.2.0 |
-| [**Non-trapping float-to-int Conversion**](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) | 🟢 | 0.2.0 |
-| [**Sign-extension operators**](https://github.com/WebAssembly/sign-extension-ops) | 🟢 | 0.2.0 |
-| [**Multi-value**](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md) | 🟢 | 0.2.0 |
-| [**Bulk Memory Operations**](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md) | 🟢 | 0.4.0 |
-| [**Reference Types**](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) | 🟢 | 0.7.0 |
-| [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) | 🟢 | 0.8.0 |
-| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🚧 | N/A |
-| [**Fixed-Width SIMD**](https://github.com/webassembly/simd) | 🌑 | N/A |
+| Proposal | Status | TinyWasm Version |
+| --------------------------------------------------------------------------------------------------------------------------- | ------ | ---------------- |
+| [**Mutable Globals**](https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md) | 🟢 | 0.2.0 |
+| [**Non-trapping float-to-int Conversion**](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) | 🟢 | 0.2.0 |
+| [**Sign-extension operators**](https://github.com/WebAssembly/sign-extension-ops) | 🟢 | 0.2.0 |
+| [**Multi-value**](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md) | 🟢 | 0.2.0 |
+| [**Bulk Memory Operations**](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md) | 🟢 | 0.4.0 |
+| [**Reference Types**](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) | 🟢 | 0.7.0 |
+| [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) | 🟢 | 0.8.0 |
+| [**Custom Page Sizes**](https://github.com/WebAssembly/custom-page-sizes/blob/main/proposals/custom-page-sizes/Overview.md) | 🟢 | `next` |
+| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🚧 | N/A |
+| [**Fixed-Width SIMD**](https://github.com/webassembly/simd) | 🌑 | N/A |
## Usage
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
index 10607a1..76099ca 100644
--- a/crates/parser/src/conversion.rs
+++ b/crates/parser/src/conversion.rs
@@ -105,11 +105,12 @@ pub(crate) fn convert_module_memories<T: IntoIterator<Item = wasmparser::Result<
}
pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> MemoryType {
- MemoryType {
- arch: if memory.memory64 { MemoryArch::I64 } else { MemoryArch::I32 },
- page_count_initial: memory.initial,
- page_count_max: memory.maximum,
- }
+ MemoryType::new(
+ if memory.memory64 { MemoryArch::I64 } else { MemoryArch::I32 },
+ memory.initial,
+ memory.maximum,
+ memory.page_size_log2.map(|x| 1 << x),
+ )
}
pub(crate) fn convert_module_tables<'a, T: IntoIterator<Item = wasmparser::Result<wasmparser::Table<'a>>>>(
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 5e8f9e0..8c68c64 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -63,6 +63,7 @@ impl Parser {
multi_memory: true,
memory64: false,
simd: true,
+ custom_page_sizes: true,
gc_types: true,
component_model: false,
@@ -75,7 +76,6 @@ impl Parser {
memory_control: false,
relaxed_simd: false,
threads: false,
- custom_page_sizes: false,
shared_everything_threads: false,
component_model_multiple_returns: false,
legacy_exceptions: false,
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index 98f88f1..ebe7ffd 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -73,6 +73,12 @@ name="test-wasm-simd"
harness=false
test=false
+
+[[test]]
+name="test-wasm-custom-page-sizes"
+harness=false
+test=false
+
[[test]]
name="test-wast"
harness=false
diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs
index 0a8f033..6dd5ae4 100644
--- a/crates/tinywasm/benches/argon2id.rs
+++ b/crates/tinywasm/benches/argon2id.rs
@@ -1,6 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use eyre::Result;
-use tinywasm::{ModuleInstance, Store, types};
+use tinywasm::{types, ModuleInstance, Store};
use types::{archive::AlignedVec, TinyWasmModule};
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.opt.wasm");
diff --git a/crates/tinywasm/benches/fibonacci.rs b/crates/tinywasm/benches/fibonacci.rs
index 557d787..9c994ca 100644
--- a/crates/tinywasm/benches/fibonacci.rs
+++ b/crates/tinywasm/benches/fibonacci.rs
@@ -1,6 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use eyre::Result;
-use tinywasm::{ModuleInstance, Store, types};
+use tinywasm::{types, ModuleInstance, Store};
use types::{archive::AlignedVec, TinyWasmModule};
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.opt.wasm");
diff --git a/crates/tinywasm/benches/tinywasm.rs b/crates/tinywasm/benches/tinywasm.rs
index cfc9cb8..da16eb8 100644
--- a/crates/tinywasm/benches/tinywasm.rs
+++ b/crates/tinywasm/benches/tinywasm.rs
@@ -1,6 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use eyre::Result;
-use tinywasm::{Extern, FuncContext, Imports, ModuleInstance, Store, types};
+use tinywasm::{types, Extern, FuncContext, Imports, ModuleInstance, Store};
use types::{archive::AlignedVec, TinyWasmModule};
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.opt.wasm");
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index 3a226f4..36ca4e3 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -208,7 +208,7 @@ impl From<&Import> for ExternName {
/// imports
/// .define("my_module", "print_i32", print_i32)?
/// .define("my_module", "table", Extern::table(table_type, table_init))?
-/// .define("my_module", "memory", Extern::memory(MemoryType::new_32(1, Some(2))))?
+/// .define("my_module", "memory", Extern::memory(MemoryType::new_32(1, Some(2), None)))?
/// .define("my_module", "global_i32", Extern::global(WasmValue::I32(666), false))?
/// .link_module("my_other_module", 0)?;
/// # Ok(())
@@ -317,22 +317,20 @@ impl Imports {
actual: &MemoryType,
real_size: Option<usize>,
) -> Result<()> {
- Self::compare_types(import, &expected.arch, &actual.arch)?;
+ Self::compare_types(import, &expected.arch(), &actual.arch())?;
- if actual.page_count_initial > expected.page_count_initial
- && real_size.map_or(true, |size| actual.page_count_initial > size as u64)
+ if actual.page_count_initial() > expected.page_count_initial()
+ && real_size.map_or(true, |size| actual.page_count_initial() > size as u64)
{
return Err(LinkingError::incompatible_import_type(import).into());
}
- if expected.page_count_max.is_none() && actual.page_count_max.is_some() {
+ if expected.page_size() != actual.page_size() {
return Err(LinkingError::incompatible_import_type(import).into());
}
- if let (Some(expected_max), Some(actual_max)) = (expected.page_count_max, actual.page_count_max) {
- if actual_max < expected_max {
- return Err(LinkingError::incompatible_import_type(import).into());
- }
+ if expected.page_count_max() > actual.page_count_max() {
+ return Err(LinkingError::incompatible_import_type(import).into());
}
Ok(())
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index b86435d..1e5ff7c 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -4,10 +4,6 @@ use tinywasm_types::{MemoryType, ModuleInstanceAddr};
use crate::{cold, log, Error, Result};
-const PAGE_SIZE: usize = 65536;
-const MAX_PAGES: usize = 65536;
-const MAX_SIZE: u64 = PAGE_SIZE as u64 * MAX_PAGES as u64;
-
/// A WebAssembly Memory Instance
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
@@ -21,13 +17,13 @@ pub(crate) struct MemoryInstance {
impl MemoryInstance {
pub(crate) fn new(kind: MemoryType, owner: ModuleInstanceAddr) -> Self {
- assert!(kind.page_count_initial <= kind.page_count_max.unwrap_or(MAX_PAGES as u64));
- log::debug!("initializing memory with {} pages", kind.page_count_initial);
+ assert!(kind.page_count_initial() <= kind.page_count_max());
+ log::debug!("initializing memory with {} pages of {} bytes", kind.page_count_initial(), kind.page_size());
Self {
kind,
- data: vec![0; PAGE_SIZE * kind.page_count_initial as usize],
- page_count: kind.page_count_initial as usize,
+ data: vec![0; kind.initial_size() as usize],
+ page_count: kind.page_count_initial() as usize,
_owner: owner,
}
}
@@ -58,7 +54,7 @@ impl MemoryInstance {
}
pub(crate) fn max_pages(&self) -> usize {
- self.kind.page_count_max.unwrap_or(MAX_PAGES as u64) as usize
+ self.kind.page_count_max() as usize
}
pub(crate) fn load(&self, addr: usize, len: usize) -> Result<&[u8]> {
@@ -133,12 +129,12 @@ impl MemoryInstance {
let new_pages = current_pages as i64 + pages_delta as i64;
debug_assert!(new_pages <= i32::MAX as i64, "page count should never be greater than i32::MAX");
- if new_pages < 0 || new_pages > MAX_PAGES as i64 || new_pages as usize > self.max_pages() {
+ if new_pages < 0 || new_pages as usize > self.max_pages() {
return None;
}
- let new_size = new_pages as usize * PAGE_SIZE;
- if new_size as u64 > MAX_SIZE {
+ let new_size = (new_pages as u64 * self.kind.page_size()) as usize;
+ if new_size as u64 > self.kind.max_size() {
return None;
}
@@ -190,7 +186,7 @@ mod memory_instance_tests {
use tinywasm_types::MemoryArch;
fn create_test_memory() -> MemoryInstance {
- let kind = MemoryType { arch: MemoryArch::I32, page_count_initial: 1, page_count_max: Some(2) };
+ let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
let owner = ModuleInstanceAddr::default();
MemoryInstance::new(kind, owner)
}
@@ -249,7 +245,7 @@ mod memory_instance_tests {
#[test]
fn test_memory_grow_out_of_bounds() {
let mut memory = create_test_memory();
- assert!(memory.grow(MAX_PAGES as i32 + 1).is_none());
+ assert!(memory.grow(memory.kind.max_size() as i32 + 1).is_none());
}
#[test]
@@ -258,4 +254,29 @@ mod memory_instance_tests {
assert_eq!(memory.grow(1), Some(1));
assert_eq!(memory.grow(1), None);
}
+
+ #[test]
+ fn test_memory_custom_page_size_out_of_bounds() {
+ let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), Some(1));
+ let owner = ModuleInstanceAddr::default();
+ let mut memory = MemoryInstance::new(kind, owner);
+
+ let data_to_store = [1, 2];
+ assert!(memory.store(0, data_to_store.len(), &data_to_store).is_err());
+ }
+
+ #[test]
+ fn test_memory_custom_page_size_grow() {
+ let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), Some(1));
+ let owner = ModuleInstanceAddr::default();
+ let mut memory = MemoryInstance::new(kind, owner);
+
+ assert_eq!(memory.grow(1), Some(1));
+
+ let data_to_store = [1, 2];
+ assert!(memory.store(0, data_to_store.len(), &data_to_store).is_ok());
+
+ let loaded_data = memory.load(0, data_to_store.len()).unwrap();
+ assert_eq!(loaded_data, &data_to_store);
+ }
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 124b7dc..d4bbf33 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -243,7 +243,7 @@ impl Store {
let mem_count = self.data.memories.len();
let mut mem_addrs = Vec::with_capacity(mem_count);
for (i, mem) in memories.into_iter().enumerate() {
- if let MemoryArch::I64 = mem.arch {
+ if let MemoryArch::I64 = mem.arch() {
return Err(Error::UnsupportedFeature("64-bit memories".to_string()));
}
self.data.memories.push(MemoryInstance::new(mem, idx));
@@ -405,7 +405,7 @@ impl Store {
}
pub(crate) fn add_mem(&mut self, mem: MemoryType, idx: ModuleInstanceAddr) -> Result<MemAddr> {
- if let MemoryArch::I64 = mem.arch {
+ if let MemoryArch::I64 = mem.arch() {
return Err(Error::UnsupportedFeature("64-bit memories".to_string()));
}
self.data.memories.push(MemoryInstance::new(mem, idx));
diff --git a/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv b/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv
new file mode 100644
index 0000000..f9a7914
--- /dev/null
+++ b/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv
@@ -0,0 +1 @@
+0.8.0,57,0,[{"name":"custom-page-sizes-invalid.wast","passed":22,"failed":0},{"name":"custom-page-sizes.wast","passed":35,"failed":0}]
diff --git a/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs b/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs
new file mode 100644
index 0000000..ab8d36e
--- /dev/null
+++ b/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs
@@ -0,0 +1,20 @@
+mod testsuite;
+use eyre::{eyre, Result};
+use owo_colors::OwoColorize;
+use testsuite::TestSuite;
+
+fn main() -> Result<()> {
+ let mut test_suite = TestSuite::new();
+
+ TestSuite::set_log_level(log::LevelFilter::Off);
+ test_suite.run_spec_group(wasm_testsuite::get_proposal_tests("custom-page-sizes"))?;
+ test_suite.save_csv("./tests/generated/wasm-custom-page-sizes.csv", env!("CARGO_PKG_VERSION"))?;
+
+ if test_suite.failed() {
+ println!();
+ Err(eyre!(format!("{}:\n{:#?}", "failed one or more tests".red().bold(), test_suite,)))
+ } else {
+ println!("\n\npassed all tests:\n{test_suite:#?}");
+ Ok(())
+ }
+}
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index ca788fb..a179956 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -121,7 +121,11 @@ impl TestSuite {
});
imports
- .define("spectest", "memory", Extern::memory(MemoryType::new_32(1, Some(2))))?
+ .define(
+ "spectest",
+ "memory",
+ Extern::memory(MemoryType::new(tinywasm_types::MemoryArch::I32, 1, Some(2), None)),
+ )?
.define("spectest", "table", table)?
.define("spectest", "global_i32", Extern::global(WasmValue::I32(666), false))?
.define("spectest", "global_i64", Extern::global(WasmValue::I64(666), false))?
@@ -145,6 +149,7 @@ impl TestSuite {
pub fn run_spec_group<T: AsRef<str>>(&mut self, tests: impl IntoIterator<Item = T>) -> Result<()> {
tests.into_iter().for_each(|group| {
+ println!("running group: {}", group.as_ref());
let group = group.as_ref();
let group_wast = wasm_testsuite::get_test_wast(group).expect("failed to get test wast");
if self.1.contains(&(*group).to_string()) {
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 94dc94d..ce0d4ac 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -12,6 +12,14 @@ extern crate alloc;
use alloc::boxed::Box;
use core::{fmt::Debug, ops::Range};
+// Memory defaults
+const MEM_PAGE_SIZE: u64 = 65536;
+const MAX_MEMORY_SIZE: u64 = 4294967296;
+
+const fn max_page_count(page_size: u64) -> u64 {
+ MAX_MEMORY_SIZE / page_size
+}
+
// log for logging (optional).
#[cfg(feature = "logging")]
#[allow(clippy::single_component_path_imports, unused_imports)]
@@ -252,14 +260,39 @@ impl TableType {
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
pub struct MemoryType {
- pub arch: MemoryArch,
- pub page_count_initial: u64,
- pub page_count_max: Option<u64>,
+ arch: MemoryArch,
+ page_count_initial: u64,
+ page_count_max: Option<u64>,
+ page_size: Option<u64>,
}
impl MemoryType {
- pub fn new_32(page_count_initial: u64, page_count_max: Option<u64>) -> Self {
- Self { arch: MemoryArch::I32, page_count_initial, page_count_max }
+ pub fn new(arch: MemoryArch, page_count_initial: u64, page_count_max: Option<u64>, page_size: Option<u64>) -> Self {
+ Self { arch, page_count_initial, page_count_max, page_size }
+ }
+
+ pub fn arch(&self) -> MemoryArch {
+ self.arch
+ }
+
+ pub fn page_count_initial(&self) -> u64 {
+ self.page_count_initial
+ }
+
+ pub fn page_count_max(&self) -> u64 {
+ self.page_count_max.unwrap_or_else(|| max_page_count(self.page_size()))
+ }
+
+ pub fn page_size(&self) -> u64 {
+ self.page_size.unwrap_or(MEM_PAGE_SIZE)
+ }
+
+ pub fn initial_size(&self) -> u64 {
+ self.page_count_initial * self.page_size()
+ }
+
+ pub fn max_size(&self) -> u64 {
+ self.page_count_max() * self.page_size()
}
}
diff --git a/crates/wasm-testsuite/lib.rs b/crates/wasm-testsuite/lib.rs
index 1f42664..12bf459 100644
--- a/crates/wasm-testsuite/lib.rs
+++ b/crates/wasm-testsuite/lib.rs
@@ -12,13 +12,18 @@ use std::borrow::Cow;
#[derive(RustEmbed)]
#[folder = "data/"]
#[include = "*.wast"]
-struct Asset;
+struct OfficialTests;
+
+#[derive(RustEmbed)]
+#[folder = "tests/"]
+#[include = "*.wast"]
+struct CustomTests;
/// List of all supported proposals. Can be used to filter tests.
///
/// Includes all proposals from <https://github.com/WebAssembly/testsuite/tree/master/proposals>
#[rustfmt::skip]
-pub const PROPOSALS: &[&str] = &["annotations", "exception-handling", "extended-const", "function-references", "gc", "memory64", "multi-memory", "relaxed-simd", "tail-call", "threads"];
+pub const PROPOSALS: &[&str] = &["annotations", "exception-handling", "extended-const", "function-references", "gc", "memory64", "multi-memory", "relaxed-simd", "tail-call", "threads", "custom-page-sizes"];
/// List of all tests that apply to the MVP (V1) spec
/// Note that the tests are still for the latest spec, so the latest version of Wast is used.
@@ -35,7 +40,7 @@ pub const SIMD_TESTS: &[&str] = &["simd_address.wast", "simd_align.wast", "simd_
/// List of all tests that apply to a specific proposal.
pub fn get_proposal_tests(proposal: &str) -> impl Iterator<Item = String> + '_ {
- Asset::iter().filter_map(move |x| {
+ OfficialTests::iter().chain(CustomTests::iter()).filter_map(move |x| {
let mut parts = x.split('/');
if parts.next() == Some("proposals") && parts.next() == Some(proposal) {
Some(format!("{}/{}", proposal, parts.next().unwrap_or_default()))
@@ -50,8 +55,10 @@ pub fn get_test_wast(name: &str) -> Option<Cow<'static, [u8]>> {
assert!(name.ends_with(".wast"), "Expected .wast file. Got: {name}");
match name.contains('/') {
- true => Asset::get(&format!("proposals/{name}")).map(|x| x.data),
- false => Asset::get(name).map(|x| x.data),
+ true => OfficialTests::get(&format!("proposals/{name}"))
+ .or_else(|| CustomTests::get(&format!("proposals/{name}")))
+ .map(|x| x.data),
+ false => OfficialTests::get(name).or_else(|| CustomTests::get(name)).map(|x| x.data),
}
}
@@ -66,7 +73,7 @@ mod tests {
let mut unique_proposals = HashSet::new();
// check that all proposals are present
- for proposal in Asset::iter() {
+ for proposal in OfficialTests::iter() {
if !proposal.starts_with("proposals/") {
continue;
}
diff --git a/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes-invalid.wast b/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes-invalid.wast
new file mode 100644
index 0000000..150f58b
--- /dev/null
+++ b/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes-invalid.wast
@@ -0,0 +1,112 @@
+;; from https://github.com/WebAssembly/custom-page-sizes/blob/main/test/core/custom-page-sizes/custom-page-sizes-invalid.wast
+
+;; Page size that is not a power of two.
+(assert_malformed
+ (module quote "(memory 0 (pagesize 3))")
+ "invalid custom page size"
+)
+
+;; Power-of-two page sizes that are not 1 or 64KiB.
+(assert_invalid
+ (module (memory 0 (pagesize 2)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 4)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 8)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 16)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 32)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 64)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 128)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 256)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 512)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 1024)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 2048)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 4096)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 8192)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 16384)))
+ "invalid custom page size"
+)
+(assert_invalid
+ (module (memory 0 (pagesize 32768)))
+ "invalid custom page size"
+)
+
+;; Power-of-two page size that is larger than 64KiB.
+(assert_invalid
+ (module (memory 0 (pagesize 0x20000)))
+ "invalid custom page size"
+)
+
+;; Power of two page size that cannot fit in a u64 to exercise checks against
+;; shift overflow.
+(assert_malformed
+ (module binary
+ "\00asm" "\01\00\00\00"
+ "\05\04\01" ;; Memory section
+
+ ;; memory 0
+ "\08" ;; flags w/ custom page size
+ "\00" ;; minimum = 0
+ "\41" ;; pagesize = 2**65
+ )
+ "invalid custom page size"
+)
+
+;; Importing a memory with the wrong page size.
+
+(module $m
+ (memory (export "small-pages-memory") 0 (pagesize 1))
+ (memory (export "large-pages-memory") 0 (pagesize 65536))
+)
+(register "m" $m)
+
+(assert_unlinkable
+ (module
+ (memory (import "m" "small-pages-memory") 0 (pagesize 65536))
+ )
+ "incompatible import type"
+)
+
+(assert_unlinkable
+ (module
+ (memory (import "m" "large-pages-memory") 0 (pagesize 1))
+ )
+ "incompatible import type"
+)
diff --git a/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes.wast b/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes.wast
new file mode 100644
index 0000000..f59d52b
--- /dev/null
+++ b/crates/wasm-testsuite/tests/proposals/custom-page-sizes/custom-page-sizes.wast
@@ -0,0 +1,110 @@
+;; from https://github.com/WebAssembly/custom-page-sizes/blob/main/test/core/custom-page-sizes/custom-page-sizes.wast
+
+;; Check all the valid custom page sizes.
+(module (memory 1 (pagesize 1)))
+(module (memory 1 (pagesize 65536)))
+
+;; Check them all again with maximums specified.
+(module (memory 1 2 (pagesize 1)))
+(module (memory 1 2 (pagesize 65536)))
+
+;; Check the behavior of memories with page size 1.
+(module
+ (memory 0 (pagesize 1))
+ (func (export "size") (result i32)
+ memory.size
+ )
+ (func (export "grow") (param i32) (result i32)
+ (memory.grow (local.get 0))
+ )
+ (func (export "load") (param i32) (result i32)
+ (i32.load8_u (local.get 0))
+ )
+ (func (export "store") (param i32 i32)
+ (i32.store8 (local.get 0) (local.get 1))
+ )
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access")
+
+(assert_return (invoke "grow" (i32.const 65536)) (i32.const 0))
+(assert_return (invoke "size") (i32.const 65536))
+(assert_return (invoke "load" (i32.const 65535)) (i32.const 0))
+(assert_return (invoke "store" (i32.const 65535) (i32.const 1)))
+(assert_return (invoke "load" (i32.const 65535)) (i32.const 1))
+(assert_trap (invoke "load" (i32.const 65536)) "out of bounds memory access")
+
+(assert_return (invoke "grow" (i32.const 65536)) (i32.const 65536))
+(assert_return (invoke "size") (i32.const 131072))
+(assert_return (invoke "load" (i32.const 131071)) (i32.const 0))
+(assert_return (invoke "store" (i32.const 131071) (i32.const 1)))
+(assert_return (invoke "load" (i32.const 131071)) (i32.const 1))
+(assert_trap (invoke "load" (i32.const 131072)) "out of bounds memory access")
+
+;; Although smaller page sizes let us get to memories larger than 2**16 pages,
+;; we can't do that with the default page size, even if we explicitly state it
+;; as a custom page size.
+(module
+ (memory 0 (pagesize 65536))
+ (func (export "size") (result i32)
+ memory.size
+ )
+ (func (export "grow") (param i32) (result i32)
+ (memory.grow (local.get 0))
+ )
+)
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 65537)) (i32.const -1))
+(assert_return (invoke "size") (i32.const 0))
+
+;; Can copy between memories of different page sizes.
+(module
+ (memory $small 10 (pagesize 1))
+ (memory $large 1 (pagesize 65536))
+
+ (data (memory $small) (i32.const 0) "\11\22\33\44")
+ (data (memory $large) (i32.const 0) "\55\66\77\88")
+
+ (func (export "copy-small-to-large") (param i32 i32 i32)
+ (memory.copy $large $small (local.get 0) (local.get 1) (local.get 2))
+ )
+
+ (func (export "copy-large-to-small") (param i32 i32 i32)
+ (memory.copy $small $large (local.get 0) (local.get 1) (local.get 2))
+ )
+
+ (func (export "load8-small") (param i32) (result i32)
+ (i32.load8_u $small (local.get 0))
+ )
+
+ (func (export "load8-large") (param i32) (result i32)
+ (i32.load8_u $large (local.get 0))
+ )
+)
+
+(assert_return (invoke "copy-small-to-large" (i32.const 6) (i32.const 0) (i32.const 2)))
+(assert_return (invoke "load8-large" (i32.const 6)) (i32.const 0x11))
+(assert_return (invoke "load8-large" (i32.const 7)) (i32.const 0x22))
+
+(assert_return (invoke "copy-large-to-small" (i32.const 4) (i32.const 1) (i32.const 3)))
+(assert_return (invoke "load8-small" (i32.const 4)) (i32.const 0x66))
+(assert_return (invoke "load8-small" (i32.const 5)) (i32.const 0x77))
+(assert_return (invoke "load8-small" (i32.const 6)) (i32.const 0x88))
+
+;; Can link together modules that export and import memories with custom page
+;; sizes.
+
+(module $m
+ (memory (export "small-pages-memory") 0 (pagesize 1))
+ (memory (export "large-pages-memory") 0 (pagesize 65536))
+)
+(register "m" $m)
+
+(module
+ (memory (import "m" "small-pages-memory") 0 (pagesize 1))
+)
+
+(module
+ (memory (import "m" "large-pages-memory") 0 (pagesize 65536))
+)