diff --git a/crates/environ/src/collections/hash_map.rs b/crates/environ/src/collections/hash_map.rs index 6f3a674ef9b1..d83d67d966c8 100644 --- a/crates/environ/src/collections/hash_map.rs +++ b/crates/environ/src/collections/hash_map.rs @@ -252,3 +252,9 @@ impl IntoIterator for TryHashMap { self.inner.into_iter() } } + +impl From> for inner::HashMap { + fn from(map: TryHashMap) -> Self { + map.inner + } +} diff --git a/crates/wasmtime/src/runtime/component/func/typed.rs b/crates/wasmtime/src/runtime/component/func/typed.rs index 960c07624e28..b74f14345bf6 100644 --- a/crates/wasmtime/src/runtime/component/func/typed.rs +++ b/crates/wasmtime/src/runtime/component/func/typed.rs @@ -2,7 +2,6 @@ use crate::component::Instance; use crate::component::func::{Func, LiftContext, LowerContext}; use crate::component::matching::InstanceType; use crate::component::storage::{storage_as_slice, storage_as_slice_mut}; -#[cfg(not(feature = "std"))] use crate::hash_map::HashMap; use crate::prelude::*; use crate::{AsContextMut, StoreContext, StoreContextMut, ValRaw}; @@ -15,15 +14,12 @@ use core::mem::{self, MaybeUninit}; use core::str; use wasmtime_environ::component::{ CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, - OptionsIndex, StringEncoding, VariantInfo, + OptionsIndex, StringEncoding, TypeMap, VariantInfo, }; #[cfg(feature = "component-model-async")] use crate::component::concurrent::{self, AsAccessor, PreparedCall}; -#[cfg(feature = "std")] -use wasmtime_environ::collections::TryHashMap; - /// A statically-typed version of [`Func`] which takes `Params` as input and /// returns `Return`. /// @@ -1440,6 +1436,49 @@ unsafe impl Lift for char { } } +fn lift_pointer_pair_from_flat( + cx: &mut LiftContext<'_>, + src: &[ValRaw; 2], +) -> Result<(usize, usize)> { + // FIXME(#4311): needs memory64 treatment + let _ = cx; // this will be needed for memory64 in the future + let ptr = src[0].get_u32(); + let len = src[1].get_u32(); + Ok((usize::try_from(ptr)?, usize::try_from(len)?)) +} + +fn lift_pointer_pair_from_memory(cx: &mut LiftContext<'_>, bytes: &[u8]) -> Result<(usize, usize)> { + // FIXME(#4311): needs memory64 treatment + let _ = cx; // this will be needed for memory64 in the future + let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); + let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); + Ok((usize::try_from(ptr)?, usize::try_from(len)?)) +} + +fn lower_pointer_pair_to_flat( + cx: &mut LowerContext, + dst: &mut MaybeUninit<[ValRaw; 2]>, + ptr: usize, + len: usize, +) { + // See "WRITEPTR64" above for why this is always storing a 64-bit + // integer. + let _ = cx; // this will eventually be needed for memory64 information. + map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64)); + map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64)); +} + +fn lower_pointer_pair_to_memory( + cx: &mut LowerContext, + offset: usize, + ptr: usize, + len: usize, +) { + // FIXME(#4311): needs memory64 handling + *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); + *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); +} + // FIXME(#4311): these probably need different constants for memory64 const UTF16_TAG: usize = 1 << 31; const MAX_STRING_BYTE_LENGTH: usize = (1 << 31) - 1; @@ -1468,10 +1507,7 @@ unsafe impl Lower for str { ) -> Result<()> { debug_assert!(matches!(ty, InterfaceType::String)); let (ptr, len) = lower_string(cx, self)?; - // See "WRITEPTR64" above for why this is always storing a 64-bit - // integer. - map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64)); - map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64)); + lower_pointer_pair_to_flat(cx, dst, ptr, len); Ok(()) } @@ -1484,9 +1520,7 @@ unsafe impl Lower for str { debug_assert!(matches!(ty, InterfaceType::String)); debug_assert!(offset % (Self::ALIGN32 as usize) == 0); let (ptr, len) = lower_string(cx, self)?; - // FIXME(#4311): needs memory64 handling - *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); - *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); + lower_pointer_pair_to_memory(cx, offset, ptr, len); Ok(()) } } @@ -1768,10 +1802,7 @@ unsafe impl Lift for WasmStr { src: &Self::Lower, ) -> Result { debug_assert!(matches!(ty, InterfaceType::String)); - // FIXME(#4311): needs memory64 treatment - let ptr = src[0].get_u32(); - let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?; WasmStr::new(ptr, len, cx) } @@ -1783,10 +1814,7 @@ unsafe impl Lift for WasmStr { ) -> Result { debug_assert!(matches!(ty, InterfaceType::String)); debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0); - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?; WasmStr::new(ptr, len, cx) } } @@ -1822,10 +1850,7 @@ where _ => bad_type_info(), }; let (ptr, len) = lower_list(cx, elem, self)?; - // See "WRITEPTR64" above for why this is always storing a 64-bit - // integer. - map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64)); - map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64)); + lower_pointer_pair_to_flat(cx, dst, ptr, len); Ok(()) } @@ -1841,8 +1866,7 @@ where }; debug_assert!(offset % (Self::ALIGN32 as usize) == 0); let (ptr, len) = lower_list(cx, elem, self)?; - *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); - *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); + lower_pointer_pair_to_memory(cx, offset, ptr, len); Ok(()) } } @@ -2064,10 +2088,7 @@ unsafe impl Lift for WasmList { InterfaceType::List(i) => cx.types[i].element, _ => bad_type_info(), }; - // FIXME(#4311): needs memory64 treatment - let ptr = src[0].get_u32(); - let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?; WasmList::new(ptr, len, cx, elem) } @@ -2081,10 +2102,7 @@ unsafe impl Lift for WasmList { _ => bad_type_info(), }; debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0); - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?; WasmList::new(ptr, len, cx, elem) } } @@ -2095,48 +2113,13 @@ unsafe impl Lift for WasmList { // Maps are represented as `list>` in the canonical ABI, so the // lowered form is a (pointer, length) pair just like lists. -fn typecheck_map(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> -where - K: ComponentType, - V: ComponentType, -{ +fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap { match ty { - InterfaceType::Map(t) => { - let map_ty = &types.types[*t]; - K::typecheck(&map_ty.key, types)?; - V::typecheck(&map_ty.value, types)?; - Ok(()) - } - other => bail!("expected `map` found `{}`", desc(other)), - } -} - -#[derive(Copy, Clone)] -struct MapAbi32 { - key_ty: InterfaceType, - value_ty: InterfaceType, - tuple_size: usize, - tuple_align: u32, - value_offset: usize, -} - -fn map_abi32(ty: InterfaceType, types: &ComponentTypes) -> MapAbi32 { - match ty { - InterfaceType::Map(i) => { - let m = &types[i]; - MapAbi32 { - key_ty: m.key, - value_ty: m.value, - tuple_size: usize::try_from(m.entry_abi.size32).unwrap(), - tuple_align: m.entry_abi.align32, - value_offset: usize::try_from(m.value_offset32).unwrap(), - } - } + InterfaceType::Map(i) => &types[i], _ => bad_type_info(), } } -#[cfg(not(feature = "std"))] unsafe impl ComponentType for HashMap where K: ComponentType, @@ -2147,11 +2130,10 @@ where const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR; fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> { - typecheck_map::(ty, types) + TryHashMap::::typecheck(ty, types) } } -#[cfg(not(feature = "std"))] unsafe impl Lower for HashMap where K: Lower, @@ -2163,7 +2145,10 @@ where ty: InterfaceType, dst: &mut MaybeUninit<[ValRaw; 2]>, ) -> Result<()> { - linear_lower_map_to_flat(cx, ty, self.len(), self.iter(), dst) + let map = map_abi(ty, &cx.types); + let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?; + lower_pointer_pair_to_flat(cx, dst, ptr, len); + Ok(()) } fn linear_lower_to_memory( @@ -2172,81 +2157,14 @@ where ty: InterfaceType, offset: usize, ) -> Result<()> { - linear_lower_map_to_memory(cx, ty, self.len(), self.iter(), offset) - } -} - -fn lower_map_iter<'a, K, V, U>( - cx: &mut LowerContext<'_, U>, - map: MapAbi32, - len: usize, - iter: impl Iterator, -) -> Result<(usize, usize)> -where - K: Lower + 'a, - V: Lower + 'a, -{ - let size = len - .checked_mul(map.tuple_size) - .ok_or_else(|| format_err!("size overflow copying a map"))?; - let ptr = cx.realloc(0, 0, map.tuple_align, size)?; - - let mut entry_offset = ptr; - for (key, value) in iter { - // Keys are the first field in each entry tuple. - ::linear_lower_to_memory(key, cx, map.key_ty, entry_offset)?; - // Values start at the precomputed value offset within the tuple. - ::linear_lower_to_memory( - value, - cx, - map.value_ty, - entry_offset + map.value_offset, - )?; - entry_offset += map.tuple_size; + let map = map_abi(ty, &cx.types); + debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0); + let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?; + lower_pointer_pair_to_memory(cx, offset, ptr, len); + Ok(()) } - - Ok((ptr, len)) -} - -fn linear_lower_map_to_flat<'a, K, V, U>( - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - len: usize, - iter: impl Iterator, - dst: &mut MaybeUninit<[ValRaw; 2]>, -) -> Result<()> -where - K: Lower + 'a, - V: Lower + 'a, -{ - let map = map_abi32(ty, &cx.types); - let (ptr, len) = lower_map_iter(cx, map, len, iter)?; - // See "WRITEPTR64" above for why this is always storing a 64-bit integer. - map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64)); - map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64)); - Ok(()) -} - -fn linear_lower_map_to_memory<'a, K, V, U>( - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - len: usize, - iter: impl Iterator, - offset: usize, -) -> Result<()> -where - K: Lower + 'a, - V: Lower + 'a, -{ - let map = map_abi32(ty, &cx.types); - debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0); - let (ptr, len) = lower_map_iter(cx, map, len, iter)?; - *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); - *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); - Ok(()) } -#[cfg(not(feature = "std"))] unsafe impl Lift for HashMap where K: Lift + Eq + Hash, @@ -2257,12 +2175,7 @@ where ty: InterfaceType, src: &Self::Lower, ) -> Result { - let map = map_abi32(ty, &cx.types); - // FIXME(#4311): needs memory64 treatment - let ptr = src[0].get_u32(); - let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); - lift_map(cx, map, ptr, len) + Ok(TryHashMap::::linear_lift_from_flat(cx, ty, src)?.into()) } fn linear_lift_from_memory( @@ -2270,150 +2183,43 @@ where ty: InterfaceType, bytes: &[u8], ) -> Result { - let map = map_abi32(ty, &cx.types); - debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0); - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); - lift_map(cx, map, ptr, len) - } -} - -/// Shared helper that validates a map's memory region and lifts each -/// (key, value) pair, forwarding them to `insert`. -fn lift_map_pairs( - cx: &mut LiftContext<'_>, - map: MapAbi32, - ptr: usize, - len: usize, - mut insert: impl FnMut(K, V) -> Result<()>, -) -> Result<()> -where - K: Lift, - V: Lift, -{ - match len - .checked_mul(map.tuple_size) - .and_then(|total| ptr.checked_add(total)) - { - Some(n) if n <= cx.memory().len() => {} - _ => bail!("map pointer/length out of bounds of memory"), - } - if ptr % (map.tuple_align as usize) != 0 { - bail!("map pointer is not aligned"); + Ok(TryHashMap::::linear_lift_from_memory(cx, ty, bytes)?.into()) } - - for i in 0..len { - let entry_base = ptr + (i * map.tuple_size); - - let key_bytes = &cx.memory()[entry_base..][..K::SIZE32]; - let key = K::linear_lift_from_memory(cx, map.key_ty, key_bytes)?; - - let value_bytes = &cx.memory()[entry_base + map.value_offset..][..V::SIZE32]; - let value = V::linear_lift_from_memory(cx, map.value_ty, value_bytes)?; - - insert(key, value)?; - } - - Ok(()) } -#[cfg(not(feature = "std"))] -fn lift_map( - cx: &mut LiftContext<'_>, - map: MapAbi32, - ptr: usize, +fn lower_map_iter<'a, K, V, U>( + cx: &mut LowerContext<'_, U>, + map: &TypeMap, len: usize, -) -> Result> -where - K: Lift + Eq + Hash, - V: Lift, -{ - let mut result = HashMap::with_capacity(len); - lift_map_pairs(cx, map, ptr, len, |k, v| { - result.insert(k, v); - Ok(()) - })?; - Ok(result) -} - -// ============================================================================= -// std::collections::HashMap support for component model `map` - -#[cfg(feature = "std")] -unsafe impl ComponentType for std::collections::HashMap -where - K: ComponentType, - V: ComponentType, -{ - type Lower = [ValRaw; 2]; - - const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR; - - fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> { - typecheck_map::(ty, types) - } -} - -#[cfg(feature = "std")] -unsafe impl Lower for std::collections::HashMap + iter: impl Iterator, +) -> Result<(usize, usize)> where - K: Lower, - V: Lower, + K: Lower + 'a, + V: Lower + 'a, { - fn linear_lower_to_flat( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - dst: &mut MaybeUninit<[ValRaw; 2]>, - ) -> Result<()> { - linear_lower_map_to_flat(cx, ty, self.len(), self.iter(), dst) - } - - fn linear_lower_to_memory( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - offset: usize, - ) -> Result<()> { - linear_lower_map_to_memory(cx, ty, self.len(), self.iter(), offset) - } -} + let size = len + .checked_mul(usize::try_from(map.entry_abi.size32)?) + .ok_or_else(|| format_err!("size overflow copying a map"))?; + let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?; -#[cfg(feature = "std")] -unsafe impl Lift for std::collections::HashMap -where - K: Lift + Eq + Hash, - V: Lift, -{ - fn linear_lift_from_flat( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - src: &Self::Lower, - ) -> Result { - let try_map = - as Lift>::linear_lift_from_flat( - cx, ty, src, - )?; - Ok(try_map.into_iter().collect()) + let mut entry_offset = ptr; + for (key, value) in iter { + // Keys are the first field in each entry tuple. + ::linear_lower_to_memory(key, cx, map.key, entry_offset)?; + // Values start at the precomputed value offset within the tuple. + ::linear_lower_to_memory( + value, + cx, + map.value, + entry_offset + usize::try_from(map.value_offset32)?, + )?; + entry_offset += usize::try_from(map.entry_abi.size32)?; } - fn linear_lift_from_memory( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - bytes: &[u8], - ) -> Result { - let try_map = - as Lift>::linear_lift_from_memory( - cx, ty, bytes, - )?; - Ok(try_map.into_iter().collect()) - } + Ok((ptr, len)) } -#[cfg(feature = "std")] -unsafe impl ComponentType for wasmtime_environ::collections::TryHashMap +unsafe impl ComponentType for TryHashMap where K: ComponentType, V: ComponentType, @@ -2423,12 +2229,19 @@ where const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR; fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> { - typecheck_map::(ty, types) + match ty { + InterfaceType::Map(t) => { + let map_ty = &types.types[*t]; + K::typecheck(&map_ty.key, types)?; + V::typecheck(&map_ty.value, types)?; + Ok(()) + } + other => bail!("expected `map` found `{}`", desc(other)), + } } } -#[cfg(feature = "std")] -unsafe impl Lower for wasmtime_environ::collections::TryHashMap +unsafe impl Lower for TryHashMap where K: Lower, V: Lower, @@ -2439,7 +2252,10 @@ where ty: InterfaceType, dst: &mut MaybeUninit<[ValRaw; 2]>, ) -> Result<()> { - linear_lower_map_to_flat(cx, ty, self.len(), self.iter(), dst) + let map = map_abi(ty, &cx.types); + let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?; + lower_pointer_pair_to_flat(cx, dst, ptr, len); + Ok(()) } fn linear_lower_to_memory( @@ -2448,12 +2264,15 @@ where ty: InterfaceType, offset: usize, ) -> Result<()> { - linear_lower_map_to_memory(cx, ty, self.len(), self.iter(), offset) + let map = map_abi(ty, &cx.types); + debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0); + let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?; + lower_pointer_pair_to_memory(cx, offset, ptr, len); + Ok(()) } } -#[cfg(feature = "std")] -unsafe impl Lift for wasmtime_environ::collections::TryHashMap +unsafe impl Lift for TryHashMap where K: Lift + Eq + Hash, V: Lift, @@ -2463,11 +2282,8 @@ where ty: InterfaceType, src: &Self::Lower, ) -> Result { - let map = map_abi32(ty, &cx.types); - // FIXME(#4311): needs memory64 treatment - let ptr = src[0].get_u32(); - let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let map = map_abi(ty, &cx.types); + let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?; lift_try_map(cx, map, ptr, len) } @@ -2476,20 +2292,16 @@ where ty: InterfaceType, bytes: &[u8], ) -> Result { - let map = map_abi32(ty, &cx.types); + let map = map_abi(ty, &cx.types); debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0); - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?; lift_try_map(cx, map, ptr, len) } } -#[cfg(feature = "std")] fn lift_try_map( cx: &mut LiftContext<'_>, - map: MapAbi32, + map: &TypeMap, ptr: usize, len: usize, ) -> Result> @@ -2498,9 +2310,31 @@ where V: Lift, { let mut result = TryHashMap::with_capacity(len)?; - lift_map_pairs(cx, map, ptr, len, |k, v| { - result.insert(k, v).map(drop).map_err(Into::into) - })?; + + match len + .checked_mul(usize::try_from(map.entry_abi.size32)?) + .and_then(|total| ptr.checked_add(total)) + { + Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?, + _ => bail!("map pointer/length out of bounds of memory"), + } + if ptr % (map.entry_abi.align32 as usize) != 0 { + bail!("map pointer is not aligned"); + } + + for i in 0..len { + let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?); + + let key_bytes = &cx.memory()[entry_base..][..K::SIZE32]; + let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?; + + let value_bytes = + &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32]; + let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?; + + result.insert(key, value)?; + } + Ok(result) } diff --git a/crates/wasmtime/src/runtime/component/values.rs b/crates/wasmtime/src/runtime/component/values.rs index efab9768cd7f..cb5ebf834e74 100644 --- a/crates/wasmtime/src/runtime/component/values.rs +++ b/crates/wasmtime/src/runtime/component/values.rs @@ -124,16 +124,11 @@ impl Val { &[*next(src), *next(src)], )?), InterfaceType::List(i) => { - // FIXME(#4311): needs memory64 treatment - let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; - let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; + let (ptr, len) = lift_flat_pointer_pair(cx, src)?; load_list(cx, i, ptr, len)? } InterfaceType::Map(i) => { - // FIXME(#4311): needs memory64 treatment - // Maps are represented as list> in canonical ABI - let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; - let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; + let (ptr, len) = lift_flat_pointer_pair(cx, src)?; load_map(cx, i, ptr, len)? } InterfaceType::Record(i) => Val::Record( @@ -249,15 +244,11 @@ impl Val { Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?) } InterfaceType::List(i) => { - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize; - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize; + let (ptr, len) = load_flat_pointer_pair(bytes); load_list(cx, i, ptr, len)? } InterfaceType::Map(i) => { - // FIXME(#4311): needs memory64 treatment - let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize; - let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize; + let (ptr, len) = load_flat_pointer_pair(bytes); load_map(cx, i, ptr, len)? } @@ -945,6 +936,22 @@ impl GenericVariant<'_> { } } +fn lift_flat_pointer_pair( + cx: &mut LiftContext<'_>, + src: &mut Iter<'_, ValRaw>, +) -> Result<(usize, usize)> { + // FIXME(#4311): needs memory64 treatment + let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; + let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; + Ok((ptr, len)) +} + +fn load_flat_pointer_pair(bytes: &[u8]) -> (usize, usize) { + let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize; + let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize; + (ptr, len) +} + fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result { let elem = cx.types[ty].element; let abi = cx.types.canonical_abi(&elem); @@ -994,7 +1001,7 @@ fn load_map(cx: &mut LiftContext<'_>, ty: TypeMapIndex, ptr: usize, len: usize) .checked_mul(tuple_size) .and_then(|len| ptr.checked_add(len)) { - Some(n) if n <= cx.memory().len() => {} + Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?, _ => bail!("map pointer/length out of bounds of memory"), } if ptr % usize::try_from(tuple_alignment)? != 0 {