Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ wasmtime_option_group! {
pub component_model_gc: Option<bool>,
/// Map support in the component model.
pub component_model_map: Option<bool>,
/// Component model support for `memory64`: this corresponds
/// to the 🐘 emoji in the component model specification.
pub component_model_memory64: Option<bool>,
/// Configure support for the function-references proposal.
pub function_references: Option<bool>,
/// Configure support for the stack-switching proposal.
Expand Down Expand Up @@ -1449,6 +1452,7 @@ impl CommonOptions {
),
component_model_implements: Some(features.contains(WasmFeatures::CM_IMPLEMENTS)),
component_model_map: Some(features.contains(WasmFeatures::CM_MAP)),
component_model_memory64: Some(features.contains(WasmFeatures::CM64)),
component_model_more_async_builtins: Some(
features.contains(WasmFeatures::CM_MORE_ASYNC_BUILTINS),
),
Expand Down
3 changes: 3 additions & 0 deletions crates/fuzzing/src/generators/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl Config {
component_model_error_context,
component_model_gc,
component_model_map,
component_model_memory64,
component_model_fixed_length_lists,
component_model_implements,
simd,
Expand Down Expand Up @@ -174,6 +175,7 @@ impl Config {
component_model_error_context.unwrap_or(false);
self.module_config.component_model_gc = component_model_gc.unwrap_or(false);
self.module_config.component_model_map = component_model_map.unwrap_or(false);
self.module_config.component_model_memory64 = component_model_memory64.unwrap_or(false);
self.module_config.component_model_fixed_length_lists =
component_model_fixed_length_lists.unwrap_or(false);
self.module_config.component_model_implements = component_model_implements.unwrap_or(false);
Expand Down Expand Up @@ -329,6 +331,7 @@ impl Config {
Some(self.module_config.component_model_error_context);
cfg.wasm.component_model_gc = Some(self.module_config.component_model_gc);
cfg.wasm.component_model_map = Some(self.module_config.component_model_map);
cfg.wasm.component_model_memory64 = Some(self.module_config.component_model_memory64);
cfg.wasm.component_model_fixed_length_lists =
Some(self.module_config.component_model_fixed_length_lists);
cfg.wasm.component_model_implements = Some(self.module_config.component_model_implements);
Expand Down
2 changes: 2 additions & 0 deletions crates/fuzzing/src/generators/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct ModuleConfig {
pub component_model_error_context: bool,
pub component_model_gc: bool,
pub component_model_map: bool,
pub component_model_memory64: bool,
pub component_model_fixed_length_lists: bool,
pub component_model_implements: bool,
pub legacy_exceptions: bool,
Expand Down Expand Up @@ -84,6 +85,7 @@ impl<'a> Arbitrary<'a> for ModuleConfig {
component_model_error_context: false,
component_model_gc: false,
component_model_map: false,
component_model_memory64: false,
component_model_fixed_length_lists: false,
component_model_implements: false,
legacy_exceptions: false,
Expand Down
3 changes: 3 additions & 0 deletions crates/test-util/src/wasmtime_wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub fn apply_test_config(config: &mut Config, test_config: &wast::TestConfig) {
component_model_error_context,
component_model_gc,
component_model_map,
component_model_memory64,
component_model_fixed_length_lists,
component_model_implements,
nan_canonicalization,
Expand Down Expand Up @@ -81,6 +82,7 @@ pub fn apply_test_config(config: &mut Config, test_config: &wast::TestConfig) {
let component_model_error_context = component_model_error_context.unwrap_or(false);
let component_model_gc = component_model_gc.unwrap_or(false);
let component_model_map = component_model_map.unwrap_or(false);
let component_model_memory64 = component_model_memory64.unwrap_or(false);
let component_model_fixed_length_lists = component_model_fixed_length_lists.unwrap_or(false);
let component_model_implements = component_model_implements.unwrap_or(false);
let nan_canonicalization = nan_canonicalization.unwrap_or(false);
Expand Down Expand Up @@ -125,6 +127,7 @@ pub fn apply_test_config(config: &mut Config, test_config: &wast::TestConfig) {
.wasm_component_model_error_context(component_model_error_context)
.wasm_component_model_gc(component_model_gc)
.wasm_component_model_map(component_model_map)
.wasm_component_model_memory64(component_model_memory64)
.wasm_component_model_fixed_length_lists(component_model_fixed_length_lists)
.wasm_component_model_implements(component_model_implements)
.wasm_exceptions(exceptions)
Expand Down
6 changes: 4 additions & 2 deletions crates/test-util/src/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ fn component_test_config(test: &Path) -> TestConfig {
ret.reference_types = Some(true);
ret.multi_memory = Some(true);
ret.component_model_implements = Some(true);
ret.component_model_memory64 = Some(true);

if let Some(parent) = test.parent() {
if parent.ends_with("async")
Expand Down Expand Up @@ -286,6 +287,7 @@ macro_rules! foreach_config_option {
component_model_error_context
component_model_gc
component_model_map
component_model_memory64
component_model_fixed_length_lists
component_model_implements
simd
Expand Down Expand Up @@ -471,8 +473,8 @@ impl WastTest {
}

let unsupported = [
// Wasmtime doesn't expose the component-model `cm64` feature toggle
// yet, so this parser-only test can't be enabled here.
// Can be re-enabled once the tests/component-model submodule has been bumped to a commit that includes
// https://github.com/WebAssembly/component-model/pull/676
"test/wasm-tools/memory64.wast",
];
if unsupported.iter().any(|part| self.path.ends_with(part)) {
Expand Down
13 changes: 13 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,18 @@ impl Config {
self
}

/// Configures whether the component model memory64 support is enabled
///
/// This corresponds to the 🐘 emoji in the component model specification.
///
/// Please note that Wasmtime's support for this feature is _very_
/// incomplete.
#[cfg(feature = "component-model")]
pub fn wasm_component_model_memory64(&mut self, enable: bool) -> &mut Self {
self.wasm_features(WasmFeatures::CM64, enable);
self
}

/// This corresponds to the 🔧 emoji in the component model specification.
///
/// Please note that Wasmtime's support for this feature is _very_
Expand Down Expand Up @@ -2396,6 +2408,7 @@ impl Config {
| WasmFeatures::CM_ERROR_CONTEXT
| WasmFeatures::CM_GC
| WasmFeatures::CM_MAP
| WasmFeatures::CM64
| WasmFeatures::CM_FIXED_LENGTH_LISTS
| WasmFeatures::CM_IMPLEMENTS;

Expand Down
133 changes: 133 additions & 0 deletions tests/misc_testsuite/component-model/memory64.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
;;! component_model_memory64 = true
;;! memory64 = true
;;! multi_memory = true
;;! bulk_memory = true
;;! hogs_memory = true

;; Exercise a fused adapter that passes a `string` across the boundary
;; between a 64-bit component (core memory is `i64`) and a 32-bit component
;; (core memory is `i32`).
;;
;; The top-level `roundtrip` export is lifted out of the 32-bit component. When
;; invoked, the string travels:
;;
;; host -> (lift into c32's i32 memory)
;; -> (lower out of c32's i32 memory into the canonical ABI)
;; -> (lift into c64's i64 memory) -> c64 copies the bytes
;; -> (lower back out of c64's i64 memory)
;; -> (lift back into c32's i32 memory)
;; -> host
;;
;; so the string is copied through both a 32-bit and a 64-bit linear memory in
;; both the argument and result directions.

(component
(component $c64
(core module $m
;; Just enough pages to be bigger than the max 32bit memory, and fit the data for our roundtrip
(memory (export "memory") i64 0x1_0002 0x1_0005)

;; Start the allocator past the 4GB limit of 32bit memories
(global $next (mut i64) (i64.const 4295032832)) ;; 0x1_0001 * 0x1_0000
(func $realloc (export "realloc")
(param $old i64) (param $old_sz i64) (param $align i64) (param $new_sz i64)
(result i64)
(local $ret i64)
(local.set $ret
(i64.and
(i64.add (global.get $next) (i64.const 7))
(i64.const -8)))
(global.set $next (i64.add (local.get $ret) (local.get $new_sz)))
(local.get $ret))

(func (export "roundtrip") (param $ptr i64) (param $len i64) (result i64)
(local $dst i64)
(local $ret i64)

(local.set $dst
(call $realloc (i64.const 0) (i64.const 0) (i64.const 1) (local.get $len)))
(memory.copy (local.get $dst) (local.get $ptr) (local.get $len))

(local.set $ret
(call $realloc (i64.const 0) (i64.const 0) (i64.const 8) (i64.const 16)))
(i64.store (local.get $ret) (local.get $dst))
(i64.store offset=8 (local.get $ret) (local.get $len))
(local.get $ret))
)
(core instance $m (instantiate $m))

(func (export "roundtrip") (param "a" string) (result string)
(canon lift (core func $m "roundtrip")
(memory $m "memory")
(realloc (func $m "realloc"))))
)
(instance $c64 (instantiate $c64))

(component $c32
(import "backend" (instance $i
(export "roundtrip" (func (param "a" string) (result string)))
))

(core module $libc
(memory (export "memory") 1)
(global $next (mut i32) (i32.const 0))
(func (export "realloc")
(param $old i32) (param $old_sz i32) (param $align i32) (param $new_sz i32)
(result i32)
(local $ret i32)
(local.set $ret
(i32.and
(i32.add (global.get $next) (i32.const 7))
(i32.const -8)))
(global.set $next (i32.add (local.get $ret) (local.get $new_sz)))
(local.get $ret))
)
(core instance $libc (instantiate $libc))

(core func $roundtrip
(canon lower (func $i "roundtrip")
(memory $libc "memory")
(realloc (func $libc "realloc"))))

(core module $m
(import "" "memory" (memory 1))
(import "" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(import "" "roundtrip" (func $roundtrip (param i32 i32 i32)))

(func (export "roundtrip") (param $ptr i32) (param $len i32) (result i32)
(local $ret i32)
;; Allocate space for the return value: [ptr:i32; len:i32]
(local.set $ret (call $realloc (i32.const 0) (i32.const 0) (i32.const 1) (i32.const 8)))
(call $roundtrip (local.get $ptr) (local.get $len) (local.get $ret))
(local.get $ret))
)
(core instance $m (instantiate $m
(with "" (instance
(export "memory" (memory $libc "memory"))
(export "realloc" (func $libc "realloc"))
(export "roundtrip" (func $roundtrip))
))
))

(func (export "roundtrip") (param "a" string) (result string)
(canon lift (core func $m "roundtrip")
(memory $libc "memory")
(realloc (func $libc "realloc"))))
)

(instance $c32 (instantiate $c32 (with "backend" (instance $c64))))
(export "roundtrip" (func $c32 "roundtrip"))
)

(assert_return
(invoke "roundtrip" (str.const "hello"))
(str.const "hello"))

(assert_return
(invoke "roundtrip"
(str.const "Hello, I'm a longer string asdljasdlkjasdlkjasdlkjasdljkasd0"))
(str.const "Hello, I'm a longer string asdljasdlkjasdlkjasdlkjasdljkasd0"))

(assert_return
(invoke "roundtrip" (str.const ""))
(str.const ""))
Loading