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