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