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