1 use crate::ValRaw; 2 use crate::component::ResourceAny; 3 use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc}; 4 use crate::prelude::*; 5 use core::mem::MaybeUninit; 6 use core::slice::{Iter, IterMut}; 7 use wasmtime_component_util::{DiscriminantSize, FlagsSize}; 8 use wasmtime_environ::component::{ 9 CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeOption, TypeResult, 10 TypeVariant, VariantInfo, 11 }; 12 13 /// Represents possible runtime values which a component function can either 14 /// consume or produce 15 /// 16 /// This is a dynamic representation of possible values in the component model. 17 /// Note that this is not an efficient representation but is instead intended to 18 /// be a flexible and somewhat convenient representation. The most efficient 19 /// representation of component model types is to use the `bindgen!` macro to 20 /// generate native Rust types with specialized liftings and lowerings. 21 /// 22 /// This type is used in conjunction with [`Func::call`] for example if the 23 /// signature of a component is not statically known ahead of time. 24 /// 25 /// # Equality and `Val` 26 /// 27 /// This type implements both the Rust `PartialEq` and `Eq` traits. This type 28 /// additionally contains values which are not necessarily easily equated, 29 /// however, such as floats (`Float32` and `Float64`) and resources. Equality 30 /// does require that two values have the same type, and then these cases are 31 /// handled as: 32 /// 33 /// * Floats are tested if they are "semantically the same" meaning all NaN 34 /// values are equal to all other NaN values. Additionally zero values must be 35 /// exactly the same, so positive zero is not equal to negative zero. The 36 /// primary use case at this time is fuzzing-related equality which this is 37 /// sufficient for. 38 /// 39 /// * Resources are tested if their types and indices into the host table are 40 /// equal. This does not compare the underlying representation so borrows of 41 /// the same guest resource are not considered equal. This additionally 42 /// doesn't go further and test for equality in the guest itself (for example 43 /// two different heap allocations of `Box<u32>` can be equal in normal Rust 44 /// if they contain the same value, but will never be considered equal when 45 /// compared as `Val::Resource`s). 46 /// 47 /// In general if a strict guarantee about equality is required here it's 48 /// recommended to "build your own" as this equality intended for fuzzing 49 /// Wasmtime may not be suitable for you. 50 /// 51 /// # Component model types and `Val` 52 /// 53 /// The `Val` type here does not contain enough information to say what the 54 /// component model type of a `Val` is. This is instead more of an AST of sorts. 55 /// For example the `Val::Enum` only carries information about a single 56 /// discriminant, not the entire enumeration or what it's a discriminant of. 57 /// 58 /// This means that when a `Val` is passed to Wasmtime, for example as a 59 /// function parameter when calling a function or as a return value from an 60 /// host-defined imported function, then it must pass a type-check. Instances of 61 /// `Val` are type-checked against what's required by the component itself. 62 /// 63 /// [`Func::call`]: crate::component::Func::call 64 #[derive(Debug, Clone)] 65 #[allow(missing_docs)] 66 pub enum Val { 67 Bool(bool), 68 S8(i8), 69 U8(u8), 70 S16(i16), 71 U16(u16), 72 S32(i32), 73 U32(u32), 74 S64(i64), 75 U64(u64), 76 Float32(f32), 77 Float64(f64), 78 Char(char), 79 String(String), 80 List(Vec<Val>), 81 Record(Vec<(String, Val)>), 82 Tuple(Vec<Val>), 83 Variant(String, Option<Box<Val>>), 84 Enum(String), 85 Option(Option<Box<Val>>), 86 Result(Result<Option<Box<Val>>, Option<Box<Val>>>), 87 Flags(Vec<String>), 88 Resource(ResourceAny), 89 } 90 91 impl Val { 92 /// Deserialize a value of this type from core Wasm stack values. 93 pub(crate) fn lift( 94 cx: &mut LiftContext<'_>, 95 ty: InterfaceType, 96 src: &mut Iter<'_, ValRaw>, 97 ) -> Result<Val> { 98 Ok(match ty { 99 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_flat(cx, ty, next(src))?), 100 InterfaceType::S8 => Val::S8(i8::linear_lift_from_flat(cx, ty, next(src))?), 101 InterfaceType::U8 => Val::U8(u8::linear_lift_from_flat(cx, ty, next(src))?), 102 InterfaceType::S16 => Val::S16(i16::linear_lift_from_flat(cx, ty, next(src))?), 103 InterfaceType::U16 => Val::U16(u16::linear_lift_from_flat(cx, ty, next(src))?), 104 InterfaceType::S32 => Val::S32(i32::linear_lift_from_flat(cx, ty, next(src))?), 105 InterfaceType::U32 => Val::U32(u32::linear_lift_from_flat(cx, ty, next(src))?), 106 InterfaceType::S64 => Val::S64(i64::linear_lift_from_flat(cx, ty, next(src))?), 107 InterfaceType::U64 => Val::U64(u64::linear_lift_from_flat(cx, ty, next(src))?), 108 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_flat(cx, ty, next(src))?), 109 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_flat(cx, ty, next(src))?), 110 InterfaceType::Char => Val::Char(char::linear_lift_from_flat(cx, ty, next(src))?), 111 InterfaceType::Own(_) | InterfaceType::Borrow(_) => { 112 Val::Resource(ResourceAny::linear_lift_from_flat(cx, ty, next(src))?) 113 } 114 InterfaceType::String => Val::String(<_>::linear_lift_from_flat( 115 cx, 116 ty, 117 &[*next(src), *next(src)], 118 )?), 119 InterfaceType::List(i) => { 120 // FIXME(#4311): needs memory64 treatment 121 let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; 122 let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; 123 load_list(cx, i, ptr, len)? 124 } 125 InterfaceType::Record(i) => Val::Record( 126 cx.types[i] 127 .fields 128 .iter() 129 .map(|field| { 130 let val = Self::lift(cx, field.ty, src)?; 131 Ok((field.name.to_string(), val)) 132 }) 133 .collect::<Result<_>>()?, 134 ), 135 InterfaceType::Tuple(i) => Val::Tuple( 136 cx.types[i] 137 .types 138 .iter() 139 .map(|ty| Self::lift(cx, *ty, src)) 140 .collect::<Result<_>>()?, 141 ), 142 InterfaceType::Variant(i) => { 143 let vty = &cx.types[i]; 144 let (discriminant, value) = lift_variant( 145 cx, 146 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 147 vty.cases.values().copied(), 148 src, 149 )?; 150 151 let (k, _) = vty.cases.get_index(discriminant as usize).unwrap(); 152 Val::Variant(k.clone(), value) 153 } 154 InterfaceType::Enum(i) => { 155 let ety = &cx.types[i]; 156 let (discriminant, _) = lift_variant( 157 cx, 158 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 159 ety.names.iter().map(|_| None), 160 src, 161 )?; 162 163 Val::Enum(ety.names[discriminant as usize].clone()) 164 } 165 InterfaceType::Option(i) => { 166 let (_discriminant, value) = lift_variant( 167 cx, 168 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 169 [None, Some(cx.types[i].ty)].into_iter(), 170 src, 171 )?; 172 173 Val::Option(value) 174 } 175 InterfaceType::Result(i) => { 176 let result_ty = &cx.types[i]; 177 let (discriminant, value) = lift_variant( 178 cx, 179 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 180 [result_ty.ok, result_ty.err].into_iter(), 181 src, 182 )?; 183 184 Val::Result(if discriminant == 0 { 185 Ok(value) 186 } else { 187 Err(value) 188 }) 189 } 190 InterfaceType::Flags(i) => { 191 let u32_count = cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(); 192 let ty = &cx.types[i]; 193 let mut flags = Vec::new(); 194 for i in 0..u32::try_from(u32_count).unwrap() { 195 push_flags( 196 ty, 197 &mut flags, 198 i * 32, 199 u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))?, 200 ); 201 } 202 203 Val::Flags(flags) 204 } 205 InterfaceType::Future(_) 206 | InterfaceType::Stream(_) 207 | InterfaceType::ErrorContext(_) => todo!(), 208 }) 209 } 210 211 /// Deserialize a value of this type from the heap. 212 pub(crate) fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Val> { 213 Ok(match ty { 214 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_memory(cx, ty, bytes)?), 215 InterfaceType::S8 => Val::S8(i8::linear_lift_from_memory(cx, ty, bytes)?), 216 InterfaceType::U8 => Val::U8(u8::linear_lift_from_memory(cx, ty, bytes)?), 217 InterfaceType::S16 => Val::S16(i16::linear_lift_from_memory(cx, ty, bytes)?), 218 InterfaceType::U16 => Val::U16(u16::linear_lift_from_memory(cx, ty, bytes)?), 219 InterfaceType::S32 => Val::S32(i32::linear_lift_from_memory(cx, ty, bytes)?), 220 InterfaceType::U32 => Val::U32(u32::linear_lift_from_memory(cx, ty, bytes)?), 221 InterfaceType::S64 => Val::S64(i64::linear_lift_from_memory(cx, ty, bytes)?), 222 InterfaceType::U64 => Val::U64(u64::linear_lift_from_memory(cx, ty, bytes)?), 223 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_memory(cx, ty, bytes)?), 224 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_memory(cx, ty, bytes)?), 225 InterfaceType::Char => Val::Char(char::linear_lift_from_memory(cx, ty, bytes)?), 226 InterfaceType::String => Val::String(<_>::linear_lift_from_memory(cx, ty, bytes)?), 227 InterfaceType::Own(_) | InterfaceType::Borrow(_) => { 228 Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?) 229 } 230 InterfaceType::List(i) => { 231 // FIXME(#4311): needs memory64 treatment 232 let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize; 233 let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize; 234 load_list(cx, i, ptr, len)? 235 } 236 237 InterfaceType::Record(i) => { 238 let mut offset = 0; 239 let fields = cx.types[i].fields.iter(); 240 Val::Record( 241 fields 242 .map(|field| -> Result<(String, Val)> { 243 let abi = cx.types.canonical_abi(&field.ty); 244 let offset = abi.next_field32(&mut offset); 245 let offset = usize::try_from(offset).unwrap(); 246 let size = usize::try_from(abi.size32).unwrap(); 247 Ok(( 248 field.name.to_string(), 249 Val::load(cx, field.ty, &bytes[offset..][..size])?, 250 )) 251 }) 252 .collect::<Result<_>>()?, 253 ) 254 } 255 InterfaceType::Tuple(i) => { 256 let types = cx.types[i].types.iter().copied(); 257 let mut offset = 0; 258 Val::Tuple( 259 types 260 .map(|ty| { 261 let abi = cx.types.canonical_abi(&ty); 262 let offset = abi.next_field32(&mut offset); 263 let offset = usize::try_from(offset).unwrap(); 264 let size = usize::try_from(abi.size32).unwrap(); 265 Val::load(cx, ty, &bytes[offset..][..size]) 266 }) 267 .collect::<Result<_>>()?, 268 ) 269 } 270 InterfaceType::Variant(i) => { 271 let ty = &cx.types[i]; 272 let (discriminant, value) = 273 load_variant(cx, &ty.info, ty.cases.values().copied(), bytes)?; 274 275 let (k, _) = ty.cases.get_index(discriminant as usize).unwrap(); 276 Val::Variant(k.clone(), value) 277 } 278 InterfaceType::Enum(i) => { 279 let ty = &cx.types[i]; 280 let (discriminant, _) = 281 load_variant(cx, &ty.info, ty.names.iter().map(|_| None), bytes)?; 282 283 Val::Enum(ty.names[discriminant as usize].clone()) 284 } 285 InterfaceType::Option(i) => { 286 let ty = &cx.types[i]; 287 let (_discriminant, value) = 288 load_variant(cx, &ty.info, [None, Some(ty.ty)].into_iter(), bytes)?; 289 290 Val::Option(value) 291 } 292 InterfaceType::Result(i) => { 293 let ty = &cx.types[i]; 294 let (discriminant, value) = 295 load_variant(cx, &ty.info, [ty.ok, ty.err].into_iter(), bytes)?; 296 297 Val::Result(if discriminant == 0 { 298 Ok(value) 299 } else { 300 Err(value) 301 }) 302 } 303 InterfaceType::Flags(i) => { 304 let ty = &cx.types[i]; 305 let mut flags = Vec::new(); 306 match FlagsSize::from_count(ty.names.len()) { 307 FlagsSize::Size0 => {} 308 FlagsSize::Size1 => { 309 let bits = u8::linear_lift_from_memory(cx, InterfaceType::U8, bytes)?; 310 push_flags(ty, &mut flags, 0, u32::from(bits)); 311 } 312 FlagsSize::Size2 => { 313 let bits = u16::linear_lift_from_memory(cx, InterfaceType::U16, bytes)?; 314 push_flags(ty, &mut flags, 0, u32::from(bits)); 315 } 316 FlagsSize::Size4Plus(n) => { 317 for i in 0..n { 318 let bits = u32::linear_lift_from_memory( 319 cx, 320 InterfaceType::U32, 321 &bytes[usize::from(i) * 4..][..4], 322 )?; 323 push_flags(ty, &mut flags, u32::from(i) * 32, bits); 324 } 325 } 326 } 327 Val::Flags(flags) 328 } 329 InterfaceType::Future(_) 330 | InterfaceType::Stream(_) 331 | InterfaceType::ErrorContext(_) => todo!(), 332 }) 333 } 334 335 /// Serialize this value as core Wasm stack values. 336 pub(crate) fn lower<T>( 337 &self, 338 cx: &mut LowerContext<'_, T>, 339 ty: InterfaceType, 340 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>, 341 ) -> Result<()> { 342 match (ty, self) { 343 (InterfaceType::Bool, Val::Bool(value)) => { 344 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 345 } 346 (InterfaceType::Bool, _) => unexpected(ty, self), 347 (InterfaceType::S8, Val::S8(value)) => { 348 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 349 } 350 (InterfaceType::S8, _) => unexpected(ty, self), 351 (InterfaceType::U8, Val::U8(value)) => { 352 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 353 } 354 (InterfaceType::U8, _) => unexpected(ty, self), 355 (InterfaceType::S16, Val::S16(value)) => { 356 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 357 } 358 (InterfaceType::S16, _) => unexpected(ty, self), 359 (InterfaceType::U16, Val::U16(value)) => { 360 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 361 } 362 (InterfaceType::U16, _) => unexpected(ty, self), 363 (InterfaceType::S32, Val::S32(value)) => { 364 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 365 } 366 (InterfaceType::S32, _) => unexpected(ty, self), 367 (InterfaceType::U32, Val::U32(value)) => { 368 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 369 } 370 (InterfaceType::U32, _) => unexpected(ty, self), 371 (InterfaceType::S64, Val::S64(value)) => { 372 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 373 } 374 (InterfaceType::S64, _) => unexpected(ty, self), 375 (InterfaceType::U64, Val::U64(value)) => { 376 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 377 } 378 (InterfaceType::U64, _) => unexpected(ty, self), 379 (InterfaceType::Float32, Val::Float32(value)) => { 380 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 381 } 382 (InterfaceType::Float32, _) => unexpected(ty, self), 383 (InterfaceType::Float64, Val::Float64(value)) => { 384 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 385 } 386 (InterfaceType::Float64, _) => unexpected(ty, self), 387 (InterfaceType::Char, Val::Char(value)) => { 388 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 389 } 390 (InterfaceType::Char, _) => unexpected(ty, self), 391 // NB: `lower` on `ResourceAny` does its own type-checking, so skip 392 // looking at it here. 393 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => { 394 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 395 } 396 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self), 397 (InterfaceType::String, Val::String(value)) => { 398 let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit(); 399 value.linear_lower_to_flat(cx, ty, my_dst)?; 400 let my_dst = unsafe { my_dst.assume_init() }; 401 next_mut(dst).write(my_dst[0]); 402 next_mut(dst).write(my_dst[1]); 403 Ok(()) 404 } 405 (InterfaceType::String, _) => unexpected(ty, self), 406 (InterfaceType::List(ty), Val::List(values)) => { 407 let ty = &cx.types[ty]; 408 let (ptr, len) = lower_list(cx, ty.element, values)?; 409 next_mut(dst).write(ValRaw::i64(ptr as i64)); 410 next_mut(dst).write(ValRaw::i64(len as i64)); 411 Ok(()) 412 } 413 (InterfaceType::List(_), _) => unexpected(ty, self), 414 (InterfaceType::Record(ty), Val::Record(values)) => { 415 let ty = &cx.types[ty]; 416 if ty.fields.len() != values.len() { 417 bail!("expected {} fields, got {}", ty.fields.len(), values.len()); 418 } 419 for ((name, value), field) in values.iter().zip(ty.fields.iter()) { 420 if *name != field.name { 421 bail!("expected field `{}`, got `{name}`", field.name); 422 } 423 value.lower(cx, field.ty, dst)?; 424 } 425 Ok(()) 426 } 427 (InterfaceType::Record(_), _) => unexpected(ty, self), 428 (InterfaceType::Tuple(ty), Val::Tuple(values)) => { 429 let ty = &cx.types[ty]; 430 if ty.types.len() != values.len() { 431 bail!("expected {} types, got {}", ty.types.len(), values.len()); 432 } 433 for (value, ty) in values.iter().zip(ty.types.iter()) { 434 value.lower(cx, *ty, dst)?; 435 } 436 Ok(()) 437 } 438 (InterfaceType::Tuple(_), _) => unexpected(ty, self), 439 (InterfaceType::Variant(ty), Val::Variant(n, v)) => { 440 GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst) 441 } 442 (InterfaceType::Variant(_), _) => unexpected(ty, self), 443 (InterfaceType::Option(ty), Val::Option(v)) => { 444 GenericVariant::option(&cx.types[ty], v).lower(cx, dst) 445 } 446 (InterfaceType::Option(_), _) => unexpected(ty, self), 447 (InterfaceType::Result(ty), Val::Result(v)) => { 448 GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst) 449 } 450 (InterfaceType::Result(_), _) => unexpected(ty, self), 451 (InterfaceType::Enum(ty), Val::Enum(discriminant)) => { 452 let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?; 453 next_mut(dst).write(ValRaw::u32(discriminant)); 454 Ok(()) 455 } 456 (InterfaceType::Enum(_), _) => unexpected(ty, self), 457 (InterfaceType::Flags(ty), Val::Flags(value)) => { 458 let ty = &cx.types[ty]; 459 let storage = flags_to_storage(ty, value)?; 460 for value in storage { 461 next_mut(dst).write(ValRaw::u32(value)); 462 } 463 Ok(()) 464 } 465 (InterfaceType::Flags(_), _) => unexpected(ty, self), 466 (InterfaceType::Future(_), _) 467 | (InterfaceType::Stream(_), _) 468 | (InterfaceType::ErrorContext(_), _) => todo!(), 469 } 470 } 471 472 /// Serialize this value to the heap at the specified memory location. 473 pub(crate) fn store<T>( 474 &self, 475 cx: &mut LowerContext<'_, T>, 476 ty: InterfaceType, 477 offset: usize, 478 ) -> Result<()> { 479 debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0); 480 481 match (ty, self) { 482 (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset), 483 (InterfaceType::Bool, _) => unexpected(ty, self), 484 (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset), 485 (InterfaceType::U8, _) => unexpected(ty, self), 486 (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset), 487 (InterfaceType::S8, _) => unexpected(ty, self), 488 (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset), 489 (InterfaceType::U16, _) => unexpected(ty, self), 490 (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset), 491 (InterfaceType::S16, _) => unexpected(ty, self), 492 (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset), 493 (InterfaceType::U32, _) => unexpected(ty, self), 494 (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset), 495 (InterfaceType::S32, _) => unexpected(ty, self), 496 (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset), 497 (InterfaceType::U64, _) => unexpected(ty, self), 498 (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset), 499 (InterfaceType::S64, _) => unexpected(ty, self), 500 (InterfaceType::Float32, Val::Float32(value)) => { 501 value.linear_lower_to_memory(cx, ty, offset) 502 } 503 (InterfaceType::Float32, _) => unexpected(ty, self), 504 (InterfaceType::Float64, Val::Float64(value)) => { 505 value.linear_lower_to_memory(cx, ty, offset) 506 } 507 (InterfaceType::Float64, _) => unexpected(ty, self), 508 (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset), 509 (InterfaceType::Char, _) => unexpected(ty, self), 510 (InterfaceType::String, Val::String(value)) => { 511 value.linear_lower_to_memory(cx, ty, offset) 512 } 513 (InterfaceType::String, _) => unexpected(ty, self), 514 515 // NB: resources do type-checking when they lower. 516 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => { 517 value.linear_lower_to_memory(cx, ty, offset) 518 } 519 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self), 520 (InterfaceType::List(ty), Val::List(values)) => { 521 let ty = &cx.types[ty]; 522 let (ptr, len) = lower_list(cx, ty.element, values)?; 523 // FIXME(#4311): needs memory64 handling 524 *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); 525 *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); 526 Ok(()) 527 } 528 (InterfaceType::List(_), _) => unexpected(ty, self), 529 (InterfaceType::Record(ty), Val::Record(values)) => { 530 let ty = &cx.types[ty]; 531 if ty.fields.len() != values.len() { 532 bail!("expected {} fields, got {}", ty.fields.len(), values.len()); 533 } 534 let mut offset = offset; 535 for ((name, value), field) in values.iter().zip(ty.fields.iter()) { 536 if *name != field.name { 537 bail!("expected field `{}`, got `{name}`", field.name); 538 } 539 value.store( 540 cx, 541 field.ty, 542 cx.types 543 .canonical_abi(&field.ty) 544 .next_field32_size(&mut offset), 545 )?; 546 } 547 Ok(()) 548 } 549 (InterfaceType::Record(_), _) => unexpected(ty, self), 550 (InterfaceType::Tuple(ty), Val::Tuple(values)) => { 551 let ty = &cx.types[ty]; 552 if ty.types.len() != values.len() { 553 bail!("expected {} types, got {}", ty.types.len(), values.len()); 554 } 555 let mut offset = offset; 556 for (value, ty) in values.iter().zip(ty.types.iter()) { 557 value.store( 558 cx, 559 *ty, 560 cx.types.canonical_abi(ty).next_field32_size(&mut offset), 561 )?; 562 } 563 Ok(()) 564 } 565 (InterfaceType::Tuple(_), _) => unexpected(ty, self), 566 567 (InterfaceType::Variant(ty), Val::Variant(n, v)) => { 568 GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset) 569 } 570 (InterfaceType::Variant(_), _) => unexpected(ty, self), 571 (InterfaceType::Enum(ty), Val::Enum(v)) => { 572 GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset) 573 } 574 (InterfaceType::Enum(_), _) => unexpected(ty, self), 575 (InterfaceType::Option(ty), Val::Option(v)) => { 576 GenericVariant::option(&cx.types[ty], v).store(cx, offset) 577 } 578 (InterfaceType::Option(_), _) => unexpected(ty, self), 579 (InterfaceType::Result(ty), Val::Result(v)) => { 580 GenericVariant::result(&cx.types[ty], v)?.store(cx, offset) 581 } 582 (InterfaceType::Result(_), _) => unexpected(ty, self), 583 584 (InterfaceType::Flags(ty), Val::Flags(flags)) => { 585 let ty = &cx.types[ty]; 586 let storage = flags_to_storage(ty, flags)?; 587 match FlagsSize::from_count(ty.names.len()) { 588 FlagsSize::Size0 => {} 589 FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory( 590 cx, 591 InterfaceType::U8, 592 offset, 593 )?, 594 FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory( 595 cx, 596 InterfaceType::U16, 597 offset, 598 )?, 599 FlagsSize::Size4Plus(_) => { 600 let mut offset = offset; 601 for value in storage { 602 value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?; 603 offset += 4; 604 } 605 } 606 } 607 Ok(()) 608 } 609 (InterfaceType::Flags(_), _) => unexpected(ty, self), 610 (InterfaceType::Future(_), _) 611 | (InterfaceType::Stream(_), _) 612 | (InterfaceType::ErrorContext(_), _) => todo!(), 613 } 614 } 615 616 fn desc(&self) -> &'static str { 617 match self { 618 Val::Bool(_) => "bool", 619 Val::U8(_) => "u8", 620 Val::S8(_) => "s8", 621 Val::U16(_) => "u16", 622 Val::S16(_) => "s16", 623 Val::U32(_) => "u32", 624 Val::S32(_) => "s32", 625 Val::U64(_) => "u64", 626 Val::S64(_) => "s64", 627 Val::Float32(_) => "f32", 628 Val::Float64(_) => "f64", 629 Val::Char(_) => "char", 630 Val::List(_) => "list", 631 Val::String(_) => "string", 632 Val::Record(_) => "record", 633 Val::Enum(_) => "enum", 634 Val::Variant(..) => "variant", 635 Val::Tuple(_) => "tuple", 636 Val::Option(_) => "option", 637 Val::Result(_) => "result", 638 Val::Resource(_) => "resource", 639 Val::Flags(_) => "flags", 640 } 641 } 642 643 /// Deserialize a [`Val`] from its [`crate::component::wasm_wave`] encoding. Deserialization 644 /// requires a target [`crate::component::Type`]. 645 #[cfg(feature = "wave")] 646 pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> { 647 Ok(wasm_wave::from_str(ty, s)?) 648 } 649 650 /// Serialize a [`Val`] to its [`crate::component::wasm_wave`] encoding. 651 #[cfg(feature = "wave")] 652 pub fn to_wave(&self) -> Result<String> { 653 Ok(wasm_wave::to_string(self)?) 654 } 655 } 656 657 impl PartialEq for Val { 658 fn eq(&self, other: &Self) -> bool { 659 match (self, other) { 660 // IEEE 754 equality considers NaN inequal to NaN and negative zero 661 // equal to positive zero, however we do the opposite here, because 662 // this logic is used by testing and fuzzing, which want to know 663 // whether two values are semantically the same, rather than 664 // numerically equal. 665 (Self::Float32(l), Self::Float32(r)) => { 666 (*l != 0.0 && l == r) 667 || (*l == 0.0 && l.to_bits() == r.to_bits()) 668 || (l.is_nan() && r.is_nan()) 669 } 670 (Self::Float32(_), _) => false, 671 (Self::Float64(l), Self::Float64(r)) => { 672 (*l != 0.0 && l == r) 673 || (*l == 0.0 && l.to_bits() == r.to_bits()) 674 || (l.is_nan() && r.is_nan()) 675 } 676 (Self::Float64(_), _) => false, 677 678 (Self::Bool(l), Self::Bool(r)) => l == r, 679 (Self::Bool(_), _) => false, 680 (Self::S8(l), Self::S8(r)) => l == r, 681 (Self::S8(_), _) => false, 682 (Self::U8(l), Self::U8(r)) => l == r, 683 (Self::U8(_), _) => false, 684 (Self::S16(l), Self::S16(r)) => l == r, 685 (Self::S16(_), _) => false, 686 (Self::U16(l), Self::U16(r)) => l == r, 687 (Self::U16(_), _) => false, 688 (Self::S32(l), Self::S32(r)) => l == r, 689 (Self::S32(_), _) => false, 690 (Self::U32(l), Self::U32(r)) => l == r, 691 (Self::U32(_), _) => false, 692 (Self::S64(l), Self::S64(r)) => l == r, 693 (Self::S64(_), _) => false, 694 (Self::U64(l), Self::U64(r)) => l == r, 695 (Self::U64(_), _) => false, 696 (Self::Char(l), Self::Char(r)) => l == r, 697 (Self::Char(_), _) => false, 698 (Self::String(l), Self::String(r)) => l == r, 699 (Self::String(_), _) => false, 700 (Self::List(l), Self::List(r)) => l == r, 701 (Self::List(_), _) => false, 702 (Self::Record(l), Self::Record(r)) => l == r, 703 (Self::Record(_), _) => false, 704 (Self::Tuple(l), Self::Tuple(r)) => l == r, 705 (Self::Tuple(_), _) => false, 706 (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv, 707 (Self::Variant(..), _) => false, 708 (Self::Enum(l), Self::Enum(r)) => l == r, 709 (Self::Enum(_), _) => false, 710 (Self::Option(l), Self::Option(r)) => l == r, 711 (Self::Option(_), _) => false, 712 (Self::Result(l), Self::Result(r)) => l == r, 713 (Self::Result(_), _) => false, 714 (Self::Flags(l), Self::Flags(r)) => l == r, 715 (Self::Flags(_), _) => false, 716 (Self::Resource(l), Self::Resource(r)) => l == r, 717 (Self::Resource(_), _) => false, 718 } 719 } 720 } 721 722 impl Eq for Val {} 723 724 struct GenericVariant<'a> { 725 discriminant: u32, 726 payload: Option<(&'a Val, InterfaceType)>, 727 abi: &'a CanonicalAbiInfo, 728 info: &'a VariantInfo, 729 } 730 731 impl GenericVariant<'_> { 732 fn result<'a>( 733 ty: &'a TypeResult, 734 r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>, 735 ) -> Result<GenericVariant<'a>> { 736 let (discriminant, payload) = match r { 737 Ok(val) => { 738 let payload = match (val, ty.ok) { 739 (Some(val), Some(ty)) => Some((&**val, ty)), 740 (None, None) => None, 741 (Some(_), None) => { 742 bail!("payload provided to `ok` but not expected"); 743 } 744 (None, Some(_)) => { 745 bail!("payload expected to `ok` but not provided"); 746 } 747 }; 748 (0, payload) 749 } 750 Err(val) => { 751 let payload = match (val, ty.err) { 752 (Some(val), Some(ty)) => Some((&**val, ty)), 753 (None, None) => None, 754 (Some(_), None) => { 755 bail!("payload provided to `err` but not expected"); 756 } 757 (None, Some(_)) => { 758 bail!("payload expected to `err` but not provided"); 759 } 760 }; 761 (1, payload) 762 } 763 }; 764 Ok(GenericVariant { 765 discriminant, 766 payload, 767 abi: &ty.abi, 768 info: &ty.info, 769 }) 770 } 771 772 fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> { 773 let (discriminant, payload) = match r { 774 None => (0, None), 775 Some(val) => (1, Some((&**val, ty.ty))), 776 }; 777 GenericVariant { 778 discriminant, 779 payload, 780 abi: &ty.abi, 781 info: &ty.info, 782 } 783 } 784 785 fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> { 786 let discriminant = get_enum_discriminant(ty, discriminant)?; 787 788 Ok(GenericVariant { 789 discriminant, 790 payload: None, 791 abi: &ty.abi, 792 info: &ty.info, 793 }) 794 } 795 796 fn variant<'a>( 797 ty: &'a TypeVariant, 798 discriminant_name: &str, 799 payload: &'a Option<Box<Val>>, 800 ) -> Result<GenericVariant<'a>> { 801 let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?; 802 803 let payload = match (payload, payload_ty) { 804 (Some(val), Some(ty)) => Some((&**val, *ty)), 805 (None, None) => None, 806 (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"), 807 (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"), 808 }; 809 810 Ok(GenericVariant { 811 discriminant, 812 payload, 813 abi: &ty.abi, 814 info: &ty.info, 815 }) 816 } 817 818 fn lower<T>( 819 &self, 820 cx: &mut LowerContext<'_, T>, 821 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>, 822 ) -> Result<()> { 823 next_mut(dst).write(ValRaw::u32(self.discriminant)); 824 825 // For the remaining lowered representation of this variant that 826 // the payload didn't write we write out zeros here to ensure 827 // the entire variant is written. 828 let value_flat = match self.payload { 829 Some((value, ty)) => { 830 value.lower(cx, ty, dst)?; 831 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap() 832 } 833 None => 0, 834 }; 835 let variant_flat = self.abi.flat_count(usize::MAX).unwrap(); 836 for _ in (1 + value_flat)..variant_flat { 837 next_mut(dst).write(ValRaw::u64(0)); 838 } 839 Ok(()) 840 } 841 842 fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> { 843 match self.info.size { 844 DiscriminantSize::Size1 => u8::try_from(self.discriminant) 845 .unwrap() 846 .linear_lower_to_memory(cx, InterfaceType::U8, offset)?, 847 DiscriminantSize::Size2 => u16::try_from(self.discriminant) 848 .unwrap() 849 .linear_lower_to_memory(cx, InterfaceType::U16, offset)?, 850 DiscriminantSize::Size4 => { 851 self.discriminant 852 .linear_lower_to_memory(cx, InterfaceType::U32, offset)? 853 } 854 } 855 856 if let Some((value, ty)) = self.payload { 857 let offset = offset + usize::try_from(self.info.payload_offset32).unwrap(); 858 value.store(cx, ty, offset)?; 859 } 860 861 Ok(()) 862 } 863 } 864 865 fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> { 866 let elem = cx.types[ty].element; 867 let abi = cx.types.canonical_abi(&elem); 868 let element_size = usize::try_from(abi.size32).unwrap(); 869 let element_alignment = abi.align32; 870 871 match len 872 .checked_mul(element_size) 873 .and_then(|len| ptr.checked_add(len)) 874 { 875 Some(n) if n <= cx.memory().len() => {} 876 _ => bail!("list pointer/length out of bounds of memory"), 877 } 878 if ptr % usize::try_from(element_alignment)? != 0 { 879 bail!("list pointer is not aligned") 880 } 881 882 Ok(Val::List( 883 (0..len) 884 .map(|index| { 885 Val::load( 886 cx, 887 elem, 888 &cx.memory()[ptr + (index * element_size)..][..element_size], 889 ) 890 }) 891 .collect::<Result<_>>()?, 892 )) 893 } 894 895 fn load_variant( 896 cx: &mut LiftContext<'_>, 897 info: &VariantInfo, 898 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>, 899 bytes: &[u8], 900 ) -> Result<(u32, Option<Box<Val>>)> { 901 let discriminant = match info.size { 902 DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory( 903 cx, 904 InterfaceType::U8, 905 &bytes[..1], 906 )?), 907 DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory( 908 cx, 909 InterfaceType::U16, 910 &bytes[..2], 911 )?), 912 DiscriminantSize::Size4 => { 913 u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])? 914 } 915 }; 916 let case_ty = types.nth(discriminant as usize).ok_or_else(|| { 917 anyhow!( 918 "discriminant {} out of range [0..{})", 919 discriminant, 920 types.len() 921 ) 922 })?; 923 let value = match case_ty { 924 Some(case_ty) => { 925 let payload_offset = usize::try_from(info.payload_offset32).unwrap(); 926 let case_abi = cx.types.canonical_abi(&case_ty); 927 let case_size = usize::try_from(case_abi.size32).unwrap(); 928 Some(Box::new(Val::load( 929 cx, 930 case_ty, 931 &bytes[payload_offset..][..case_size], 932 )?)) 933 } 934 None => None, 935 }; 936 Ok((discriminant, value)) 937 } 938 939 fn lift_variant( 940 cx: &mut LiftContext<'_>, 941 flatten_count: usize, 942 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>, 943 src: &mut Iter<'_, ValRaw>, 944 ) -> Result<(u32, Option<Box<Val>>)> { 945 let len = types.len(); 946 let discriminant = next(src).get_u32(); 947 let ty = types 948 .nth(discriminant as usize) 949 .ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?; 950 let (value, value_flat) = match ty { 951 Some(ty) => ( 952 Some(Box::new(Val::lift(cx, ty, src)?)), 953 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 954 ), 955 None => (None, 0), 956 }; 957 for _ in (1 + value_flat)..flatten_count { 958 next(src); 959 } 960 Ok((discriminant, value)) 961 } 962 963 /// Lower a list with the specified element type and values. 964 fn lower_list<T>( 965 cx: &mut LowerContext<'_, T>, 966 element_type: InterfaceType, 967 items: &[Val], 968 ) -> Result<(usize, usize)> { 969 let abi = cx.types.canonical_abi(&element_type); 970 let elt_size = usize::try_from(abi.size32)?; 971 let elt_align = abi.align32; 972 let size = items 973 .len() 974 .checked_mul(elt_size) 975 .ok_or_else(|| anyhow::anyhow!("size overflow copying a list"))?; 976 let ptr = cx.realloc(0, 0, elt_align, size)?; 977 let mut element_ptr = ptr; 978 for item in items { 979 item.store(cx, element_type, element_ptr)?; 980 element_ptr += elt_size; 981 } 982 Ok((ptr, items.len())) 983 } 984 985 fn push_flags(ty: &TypeFlags, flags: &mut Vec<String>, mut offset: u32, mut bits: u32) { 986 while bits > 0 { 987 if bits & 1 != 0 { 988 flags.push(ty.names[offset as usize].clone()); 989 } 990 bits >>= 1; 991 offset += 1; 992 } 993 } 994 995 fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> { 996 let mut storage = match FlagsSize::from_count(ty.names.len()) { 997 FlagsSize::Size0 => Vec::new(), 998 FlagsSize::Size1 | FlagsSize::Size2 => vec![0], 999 FlagsSize::Size4Plus(n) => vec![0; n.into()], 1000 }; 1001 1002 for flag in flags { 1003 let bit = ty 1004 .names 1005 .get_index_of(flag) 1006 .ok_or_else(|| anyhow::anyhow!("unknown flag: `{flag}`"))?; 1007 storage[bit / 32] |= 1 << (bit % 32); 1008 } 1009 Ok(storage) 1010 } 1011 1012 fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> { 1013 ty.names 1014 .get_index_of(n) 1015 .ok_or_else(|| anyhow::anyhow!("enum variant name `{n}` is not valid")) 1016 .map(|i| i.try_into().unwrap()) 1017 } 1018 1019 fn get_variant_discriminant<'a>( 1020 ty: &'a TypeVariant, 1021 name: &str, 1022 ) -> Result<(u32, &'a Option<InterfaceType>)> { 1023 let (i, _, ty) = ty 1024 .cases 1025 .get_full(name) 1026 .ok_or_else(|| anyhow::anyhow!("unknown variant case: `{name}`"))?; 1027 Ok((i.try_into().unwrap(), ty)) 1028 } 1029 1030 fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw { 1031 src.next().unwrap() 1032 } 1033 1034 fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> { 1035 dst.next().unwrap() 1036 } 1037 1038 #[cold] 1039 fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> { 1040 bail!( 1041 "type mismatch: expected {}, found {}", 1042 desc(&ty), 1043 val.desc() 1044 ) 1045 } 1046