diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 0b12d4792f..6c033f94f6 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -255,10 +255,25 @@ impl Concurrency { } } +#[derive(Clone, Copy)] +pub(crate) enum PtrSize { + Ptr32, + Ptr64, +} + +impl PtrSize { + pub(crate) fn core_type(&self) -> ValType { + match self { + PtrSize::Ptr32 => ValType::I32, + PtrSize::Ptr64 => ValType::I64, + } + } +} + #[derive(Clone, Copy)] pub(crate) struct CanonicalOptions { pub(crate) string_encoding: StringEncoding, - pub(crate) memory: Option, + pub(crate) memory: Option<(u32, PtrSize)>, pub(crate) realloc: Option, pub(crate) post_return: Option, pub(crate) concurrency: Concurrency, @@ -2716,8 +2731,8 @@ impl ComponentState { CanonicalOption::Memory(idx) => { memory = match memory { None => { - self.cabi_memory_at(*idx, offset)?; - Some(*idx) + let ptr_size = self.cabi_memory_at(*idx, offset)?; + Some((*idx, ptr_size)) } Some(_) => { return Err(BinaryReaderError::new( @@ -2858,8 +2873,8 @@ impl ComponentState { // Validate `realloc` if let Some(realloc_idx) = realloc { - let mty = match memory { - Some(i) => self.memory_at(i, offset)?, + let addr_type = match memory { + Some((_, ptr_size)) => ptr_size.core_type(), None => { return Err(BinaryReaderError::new( "canonical option `realloc` requires `memory` to also be specified", @@ -2867,10 +2882,6 @@ impl ComponentState { )); } }; - let addr_type = match mty.memory64 { - true => ValType::I64, - false => ValType::I32, - }; let ty_id = self.core_function_at(realloc_idx, offset)?; let func_ty = types[ty_id].unwrap_func(); if func_ty.params() != [addr_type, addr_type, addr_type, addr_type] @@ -4481,7 +4492,7 @@ impl ComponentState { /// /// At this time this requires that the memory is a plain 32-bit or 64-bit linear /// memory. Notably this disallows shared memory. - fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result<()> { + fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result { let ty = self.memory_at(idx, offset)?; let valid_memory_type = MemoryType { initial: 0, @@ -4496,7 +4507,12 @@ impl ComponentState { "64-bit memories require the `cm64` feature to be enabled" ); } - SubtypeCx::memory_type(ty, &valid_memory_type, offset) + SubtypeCx::memory_type(ty, &valid_memory_type, offset)?; + Ok(if ty.memory64 { + PtrSize::Ptr64 + } else { + PtrSize::Ptr32 + }) } /// Completes the translation of this component, performing final diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index 32deb68c2a..3c5a2c0fd4 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -3,6 +3,7 @@ use super::component::ExternKind; use super::{CanonicalOptions, Concurrency}; use crate::validator::StringEncoding; +use crate::validator::component::PtrSize; use crate::validator::names::KebabString; use crate::validator::types::{ CoreTypeId, EntityType, SnapshotList, TypeAlloc, TypeData, TypeIdentifier, TypeInfo, TypeList, @@ -302,7 +303,11 @@ impl PrimitiveValType { } } -fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredTypes) -> bool { +fn push_primitive_wasm_types( + ptr_size: PtrSize, + ty: &PrimitiveValType, + lowered_types: &mut LoweredTypes, +) -> bool { match ty { PrimitiveValType::Bool | PrimitiveValType::S8 @@ -317,7 +322,8 @@ fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredT PrimitiveValType::F32 => lowered_types.try_push(ValType::F32), PrimitiveValType::F64 => lowered_types.try_push(ValType::F64), PrimitiveValType::String => { - lowered_types.try_push(ValType::I32) && lowered_types.try_push(ValType::I32) + lowered_types.try_push(ptr_size.core_type()) + && lowered_types.try_push(ptr_size.core_type()) } } } @@ -731,10 +737,15 @@ impl ComponentValType { } } - fn push_wasm_types(&self, types: &TypeList, lowered_types: &mut LoweredTypes) -> bool { + fn push_wasm_types( + &self, + ptr_size: PtrSize, + types: &TypeList, + lowered_types: &mut LoweredTypes, + ) -> bool { match self { - Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), - Self::Type(id) => types[*id].push_wasm_types(types, lowered_types), + Self::Primitive(ty) => push_primitive_wasm_types(ptr_size, ty, lowered_types), + Self::Type(id) => types[*id].push_wasm_types(ptr_size, types, lowered_types), } } @@ -1211,6 +1222,11 @@ impl ComponentFuncType { return self.lower_gc(types, abi, options, offset); } + let ptr_size = match options.memory { + None => PtrSize::Ptr32, + Some((_, ptr_size)) => ptr_size, + }; + if abi == Abi::Lower && options.concurrency.is_async() { sig.params.max = MAX_FLAT_ASYNC_PARAMS; } @@ -1231,7 +1247,7 @@ impl ComponentFuncType { } } - if !ty.push_wasm_types(types, &mut sig.params) { + if !ty.push_wasm_types(ptr_size, types, &mut sig.params) { // Too many parameters to pass directly // Function will have a single pointer parameter to pass the arguments // via linear memory @@ -1258,7 +1274,7 @@ impl ComponentFuncType { abi == Abi::Lower && ty.contains_ptr(types) })?; - if !ty.push_wasm_types(types, &mut sig.results) { + if !ty.push_wasm_types(ptr_size, types, &mut sig.results) { // Too many results to return directly, either a retptr // parameter will be used (import) or a single pointer // will be returned (export). @@ -1295,8 +1311,11 @@ impl ComponentFuncType { // Note that the return type itself has no effect on the // expected core signature of the lifted function. - let overflow = - !ty.push_wasm_types(types, &mut LoweredTypes::new(MAX_FLAT_FUNC_PARAMS)); + let overflow = !ty.push_wasm_types( + ptr_size, + types, + &mut LoweredTypes::new(MAX_FLAT_FUNC_PARAMS), + ); options.require_memory_if(offset, || overflow || ty.contains_ptr(types))?; } @@ -1562,28 +1581,35 @@ impl ComponentDefinedType { } } - fn push_wasm_types(&self, types: &TypeList, lowered_types: &mut LoweredTypes) -> bool { + fn push_wasm_types( + &self, + ptr_size: PtrSize, + types: &TypeList, + lowered_types: &mut LoweredTypes, + ) -> bool { match self { - Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), + Self::Primitive(ty) => push_primitive_wasm_types(ptr_size, ty, lowered_types), Self::Record(r) => r .fields .iter() - .all(|(_, ty)| ty.push_wasm_types(types, lowered_types)), + .all(|(_, ty)| ty.push_wasm_types(ptr_size, types, lowered_types)), Self::Variant(v) => Self::push_variant_wasm_types( v.cases.iter().filter_map(|(_, case)| case.ty.as_ref()), + ptr_size, types, lowered_types, ), Self::List(_) | Self::Map(_, _) => { - lowered_types.try_push(ValType::I32) && lowered_types.try_push(ValType::I32) + lowered_types.try_push(ptr_size.core_type()) + && lowered_types.try_push(ptr_size.core_type()) } Self::FixedLengthList(ty, length) => { - (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) + (0..*length).all(|_n| ty.push_wasm_types(ptr_size, types, lowered_types)) } Self::Tuple(t) => t .types .iter() - .all(|ty| ty.push_wasm_types(types, lowered_types)), + .all(|ty| ty.push_wasm_types(ptr_size, types, lowered_types)), Self::Flags(names) => { (0..(names.len() + 31) / 32).all(|_| lowered_types.try_push(ValType::I32)) } @@ -1591,16 +1617,20 @@ impl ComponentDefinedType { lowered_types.try_push(ValType::I32) } Self::Option(ty) => { - Self::push_variant_wasm_types([ty].into_iter(), types, lowered_types) - } - Self::Result { ok, err } => { - Self::push_variant_wasm_types(ok.iter().chain(err.iter()), types, lowered_types) + Self::push_variant_wasm_types([ty].into_iter(), ptr_size, types, lowered_types) } + Self::Result { ok, err } => Self::push_variant_wasm_types( + ok.iter().chain(err.iter()), + ptr_size, + types, + lowered_types, + ), } } fn push_variant_wasm_types<'a>( cases: impl Iterator, + ptr_size: PtrSize, types: &TypeList, lowered_types: &mut LoweredTypes, ) -> bool { @@ -1614,7 +1644,7 @@ impl ComponentDefinedType { for ty in cases { let mut temp = LoweredTypes::new(lowered_types.max); - if !ty.push_wasm_types(types, &mut temp) { + if !ty.push_wasm_types(ptr_size, types, &mut temp) { return false; } diff --git a/tests/cli/component-model/memory64/list.wast b/tests/cli/component-model/memory64/list.wast new file mode 100644 index 0000000000..31e82e7371 --- /dev/null +++ b/tests/cli/component-model/memory64/list.wast @@ -0,0 +1,13 @@ +;; RUN: wast --assert default --snapshot tests/snapshots -f cm64 % + +(component + (core module $m + (func (export "f") (param i64 i64)) + (func (export "realloc") (param i64 i64 i64 i64) (result i64) i64.const 0) + (memory (export "memory") i64 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" (list u8)) + (canon lift (core func $m "f") (realloc (func $m "realloc")) (memory $m "memory")) + ) +) diff --git a/tests/cli/component-model/memory64/string.wast b/tests/cli/component-model/memory64/string.wast new file mode 100644 index 0000000000..c15071ed4f --- /dev/null +++ b/tests/cli/component-model/memory64/string.wast @@ -0,0 +1,13 @@ +;; RUN: wast --assert default --snapshot tests/snapshots -f cm64 % + +(component + (core module $m + (func (export "f") (param i64 i64)) + (func (export "realloc") (param i64 i64 i64 i64) (result i64) i64.const 0) + (memory (export "memory") i64 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "f") (realloc (func $m "realloc")) (memory $m "memory")) + ) +) diff --git a/tests/snapshots/cli/component-model/memory64/list.wast.json b/tests/snapshots/cli/component-model/memory64/list.wast.json new file mode 100644 index 0000000000..0fc25db864 --- /dev/null +++ b/tests/snapshots/cli/component-model/memory64/list.wast.json @@ -0,0 +1,11 @@ +{ + "source_filename": "tests/cli/component-model/memory64/list.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "list.0.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/component-model/memory64/list.wast/0.print b/tests/snapshots/cli/component-model/memory64/list.wast/0.print new file mode 100644 index 0000000000..109d46d167 --- /dev/null +++ b/tests/snapshots/cli/component-model/memory64/list.wast/0.print @@ -0,0 +1,22 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i64 i64))) + (type (;1;) (func (param i64 i64 i64 i64) (result i64))) + (memory (;0;) i64 1) + (export "f" (func 0)) + (export "realloc" (func 1)) + (export "memory" (memory 0)) + (func (;0;) (type 0) (param i64 i64)) + (func (;1;) (type 1) (param i64 i64 i64 i64) (result i64) + i64.const 0 + ) + ) + (core instance $m (;0;) (instantiate $m)) + (type (;0;) (list u8)) + (type (;1;) (func (param "a" 0))) + (alias core export $m "f" (core func (;0;))) + (alias core export $m "realloc" (core func (;1;))) + (alias core export $m "memory" (core memory (;0;))) + (func (;0;) (type 1) (canon lift (core func 0) (realloc 1) (memory 0))) + (export (;1;) "a" (func 0)) +) diff --git a/tests/snapshots/cli/component-model/memory64/string.wast.json b/tests/snapshots/cli/component-model/memory64/string.wast.json new file mode 100644 index 0000000000..7a9504d454 --- /dev/null +++ b/tests/snapshots/cli/component-model/memory64/string.wast.json @@ -0,0 +1,11 @@ +{ + "source_filename": "tests/cli/component-model/memory64/string.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "string.0.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/component-model/memory64/string.wast/0.print b/tests/snapshots/cli/component-model/memory64/string.wast/0.print new file mode 100644 index 0000000000..b0b211c567 --- /dev/null +++ b/tests/snapshots/cli/component-model/memory64/string.wast/0.print @@ -0,0 +1,21 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i64 i64))) + (type (;1;) (func (param i64 i64 i64 i64) (result i64))) + (memory (;0;) i64 1) + (export "f" (func 0)) + (export "realloc" (func 1)) + (export "memory" (memory 0)) + (func (;0;) (type 0) (param i64 i64)) + (func (;1;) (type 1) (param i64 i64 i64 i64) (result i64) + i64.const 0 + ) + ) + (core instance $m (;0;) (instantiate $m)) + (type (;0;) (func (param "a" string))) + (alias core export $m "f" (core func (;0;))) + (alias core export $m "realloc" (core func (;1;))) + (alias core export $m "memory" (core memory (;0;))) + (func (;0;) (type 0) (canon lift (core func 0) (realloc 1) (memory 0))) + (export (;1;) "a" (func 0)) +)