1 use std::fmt; 2 use wasmtime_environ::{ir, wasm, EntityIndex}; 3 4 // Type Representations 5 6 // Type attributes 7 8 /// Indicator of whether a global is mutable or not 9 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] 10 pub enum Mutability { 11 /// The global is constant and its value does not change 12 Const, 13 /// The value of the global can change over time 14 Var, 15 } 16 17 /// Limits of tables/memories where the units of the limits are defined by the 18 /// table/memory types. 19 /// 20 /// A minimum is always available but the maximum may not be present. 21 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 22 pub struct Limits { 23 min: u32, 24 max: Option<u32>, 25 } 26 27 impl Limits { 28 /// Creates a new set of limits with the minimum and maximum both specified. new(min: u32, max: Option<u32>) -> Limits29 pub fn new(min: u32, max: Option<u32>) -> Limits { 30 Limits { min, max } 31 } 32 33 /// Creates a new `Limits` with the `min` specified and no maximum specified. at_least(min: u32) -> Limits34 pub fn at_least(min: u32) -> Limits { 35 Limits::new(min, None) 36 } 37 38 /// Returns the minimum amount for these limits. min(&self) -> u3239 pub fn min(&self) -> u32 { 40 self.min 41 } 42 43 /// Returns the maximum amount for these limits, if specified. max(&self) -> Option<u32>44 pub fn max(&self) -> Option<u32> { 45 self.max 46 } 47 } 48 49 // Value Types 50 51 /// A list of all possible value types in WebAssembly. 52 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 53 pub enum ValType { 54 /// Signed 32 bit integer. 55 I32, 56 /// Signed 64 bit integer. 57 I64, 58 /// Floating point 32 bit integer. 59 F32, 60 /// Floating point 64 bit integer. 61 F64, 62 /// A 128 bit number. 63 V128, 64 /// A reference to opaque data in the Wasm instance. 65 ExternRef, /* = 128 */ 66 /// A reference to a Wasm function. 67 FuncRef, 68 } 69 70 impl fmt::Display for ValType { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 72 match self { 73 ValType::I32 => write!(f, "i32"), 74 ValType::I64 => write!(f, "i64"), 75 ValType::F32 => write!(f, "f32"), 76 ValType::F64 => write!(f, "f64"), 77 ValType::V128 => write!(f, "v128"), 78 ValType::ExternRef => write!(f, "externref"), 79 ValType::FuncRef => write!(f, "funcref"), 80 } 81 } 82 } 83 84 impl ValType { 85 /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`, 86 /// `I64`, `F32`, `F64`). is_num(&self) -> bool87 pub fn is_num(&self) -> bool { 88 match self { 89 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true, 90 _ => false, 91 } 92 } 93 94 /// Returns true if `ValType` matches either of the reference types. is_ref(&self) -> bool95 pub fn is_ref(&self) -> bool { 96 match self { 97 ValType::ExternRef | ValType::FuncRef => true, 98 _ => false, 99 } 100 } 101 get_wasmtime_type(&self) -> Option<ir::Type>102 pub(crate) fn get_wasmtime_type(&self) -> Option<ir::Type> { 103 match self { 104 ValType::I32 => Some(ir::types::I32), 105 ValType::I64 => Some(ir::types::I64), 106 ValType::F32 => Some(ir::types::F32), 107 ValType::F64 => Some(ir::types::F64), 108 ValType::V128 => Some(ir::types::I8X16), 109 _ => None, 110 } 111 } 112 from_wasmtime_type(ty: ir::Type) -> Option<ValType>113 pub(crate) fn from_wasmtime_type(ty: ir::Type) -> Option<ValType> { 114 match ty { 115 ir::types::I32 => Some(ValType::I32), 116 ir::types::I64 => Some(ValType::I64), 117 ir::types::F32 => Some(ValType::F32), 118 ir::types::F64 => Some(ValType::F64), 119 ir::types::I8X16 => Some(ValType::V128), 120 _ => None, 121 } 122 } 123 to_wasm_type(&self) -> wasm::WasmType124 pub(crate) fn to_wasm_type(&self) -> wasm::WasmType { 125 match self { 126 Self::I32 => wasm::WasmType::I32, 127 Self::I64 => wasm::WasmType::I64, 128 Self::F32 => wasm::WasmType::F32, 129 Self::F64 => wasm::WasmType::F64, 130 Self::V128 => wasm::WasmType::V128, 131 Self::FuncRef => wasm::WasmType::FuncRef, 132 Self::ExternRef => wasm::WasmType::ExternRef, 133 } 134 } 135 from_wasm_type(ty: &wasm::WasmType) -> Option<Self>136 pub(crate) fn from_wasm_type(ty: &wasm::WasmType) -> Option<Self> { 137 match ty { 138 wasm::WasmType::I32 => Some(Self::I32), 139 wasm::WasmType::I64 => Some(Self::I64), 140 wasm::WasmType::F32 => Some(Self::F32), 141 wasm::WasmType::F64 => Some(Self::F64), 142 wasm::WasmType::V128 => Some(Self::V128), 143 wasm::WasmType::FuncRef => Some(Self::FuncRef), 144 wasm::WasmType::ExternRef => Some(Self::ExternRef), 145 wasm::WasmType::Func | wasm::WasmType::EmptyBlockType => None, 146 } 147 } 148 } 149 150 // External Types 151 152 /// A list of all possible types which can be externally referenced from a 153 /// WebAssembly module. 154 /// 155 /// This list can be found in [`ImportType`] or [`ExportType`], so these types 156 /// can either be imported or exported. 157 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 158 pub enum ExternType { 159 /// This external type is the type of a WebAssembly function. 160 Func(FuncType), 161 /// This external type is the type of a WebAssembly global. 162 Global(GlobalType), 163 /// This external type is the type of a WebAssembly table. 164 Table(TableType), 165 /// This external type is the type of a WebAssembly memory. 166 Memory(MemoryType), 167 } 168 169 macro_rules! accessors { 170 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($( 171 /// Attempt to return the underlying type of this external type, 172 /// returning `None` if it is a different type. 173 pub fn $get(&self) -> Option<&$ty> { 174 if let ExternType::$variant(e) = self { 175 Some(e) 176 } else { 177 None 178 } 179 } 180 181 /// Returns the underlying descriptor of this [`ExternType`], panicking 182 /// if it is a different type. 183 /// 184 /// # Panics 185 /// 186 /// Panics if `self` is not of the right type. 187 pub fn $unwrap(&self) -> &$ty { 188 self.$get().expect(concat!("expected ", stringify!($ty))) 189 } 190 )*) 191 } 192 193 impl ExternType { 194 accessors! { 195 (Func(FuncType) func unwrap_func) 196 (Global(GlobalType) global unwrap_global) 197 (Table(TableType) table unwrap_table) 198 (Memory(MemoryType) memory unwrap_memory) 199 } 200 } 201 202 impl From<FuncType> for ExternType { from(ty: FuncType) -> ExternType203 fn from(ty: FuncType) -> ExternType { 204 ExternType::Func(ty) 205 } 206 } 207 208 impl From<GlobalType> for ExternType { from(ty: GlobalType) -> ExternType209 fn from(ty: GlobalType) -> ExternType { 210 ExternType::Global(ty) 211 } 212 } 213 214 impl From<MemoryType> for ExternType { from(ty: MemoryType) -> ExternType215 fn from(ty: MemoryType) -> ExternType { 216 ExternType::Memory(ty) 217 } 218 } 219 220 impl From<TableType> for ExternType { from(ty: TableType) -> ExternType221 fn from(ty: TableType) -> ExternType { 222 ExternType::Table(ty) 223 } 224 } 225 226 /// A descriptor for a function in a WebAssembly module. 227 /// 228 /// WebAssembly functions can have 0 or more parameters and results. 229 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 230 pub struct FuncType { 231 params: Box<[ValType]>, 232 results: Box<[ValType]>, 233 } 234 235 impl FuncType { 236 /// Creates a new function descriptor from the given parameters and results. 237 /// 238 /// The function descriptor returned will represent a function which takes 239 /// `params` as arguments and returns `results` when it is finished. new(params: Box<[ValType]>, results: Box<[ValType]>) -> FuncType240 pub fn new(params: Box<[ValType]>, results: Box<[ValType]>) -> FuncType { 241 FuncType { params, results } 242 } 243 244 /// Returns the list of parameter types for this function. params(&self) -> &[ValType]245 pub fn params(&self) -> &[ValType] { 246 &self.params 247 } 248 249 /// Returns the list of result types for this function. results(&self) -> &[ValType]250 pub fn results(&self) -> &[ValType] { 251 &self.results 252 } 253 to_wasm_func_type(&self) -> wasm::WasmFuncType254 pub(crate) fn to_wasm_func_type(&self) -> wasm::WasmFuncType { 255 wasm::WasmFuncType { 256 params: self.params.iter().map(|p| p.to_wasm_type()).collect(), 257 returns: self.results.iter().map(|r| r.to_wasm_type()).collect(), 258 } 259 } 260 261 /// Returns `Some` if this function signature was compatible with cranelift, 262 /// or `None` if one of the types/results wasn't supported or compatible 263 /// with cranelift. get_wasmtime_signature(&self, pointer_type: ir::Type) -> Option<ir::Signature>264 pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> Option<ir::Signature> { 265 use wasmtime_environ::ir::{AbiParam, ArgumentPurpose, Signature}; 266 use wasmtime_jit::native; 267 let call_conv = native::call_conv(); 268 let mut params = self 269 .params 270 .iter() 271 .map(|p| p.get_wasmtime_type().map(AbiParam::new)) 272 .collect::<Option<Vec<_>>>()?; 273 let returns = self 274 .results 275 .iter() 276 .map(|p| p.get_wasmtime_type().map(AbiParam::new)) 277 .collect::<Option<Vec<_>>>()?; 278 params.insert( 279 0, 280 AbiParam::special(pointer_type, ArgumentPurpose::VMContext), 281 ); 282 params.insert(1, AbiParam::new(pointer_type)); 283 284 Some(Signature { 285 params, 286 returns, 287 call_conv, 288 }) 289 } 290 291 /// Returns `None` if any types in the signature can't be converted to the 292 /// types in this crate, but that should very rarely happen and largely only 293 /// indicate a bug in our cranelift integration. from_wasm_func_type(signature: &wasm::WasmFuncType) -> Option<FuncType>294 pub(crate) fn from_wasm_func_type(signature: &wasm::WasmFuncType) -> Option<FuncType> { 295 let params = signature 296 .params 297 .iter() 298 .map(|p| ValType::from_wasm_type(p)) 299 .collect::<Option<Vec<_>>>()?; 300 let results = signature 301 .returns 302 .iter() 303 .map(|r| ValType::from_wasm_type(r)) 304 .collect::<Option<Vec<_>>>()?; 305 Some(FuncType { 306 params: params.into_boxed_slice(), 307 results: results.into_boxed_slice(), 308 }) 309 } 310 } 311 312 // Global Types 313 314 /// A WebAssembly global descriptor. 315 /// 316 /// This type describes an instance of a global in a WebAssembly module. Globals 317 /// are local to an [`Instance`](crate::Instance) and are either immutable or 318 /// mutable. 319 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 320 pub struct GlobalType { 321 content: ValType, 322 mutability: Mutability, 323 } 324 325 impl GlobalType { 326 /// Creates a new global descriptor of the specified `content` type and 327 /// whether or not it's mutable. new(content: ValType, mutability: Mutability) -> GlobalType328 pub fn new(content: ValType, mutability: Mutability) -> GlobalType { 329 GlobalType { 330 content, 331 mutability, 332 } 333 } 334 335 /// Returns the value type of this global descriptor. content(&self) -> &ValType336 pub fn content(&self) -> &ValType { 337 &self.content 338 } 339 340 /// Returns whether or not this global is mutable. mutability(&self) -> Mutability341 pub fn mutability(&self) -> Mutability { 342 self.mutability 343 } 344 345 /// Returns `None` if the wasmtime global has a type that we can't 346 /// represent, but that should only very rarely happen and indicate a bug. from_wasmtime_global(global: &wasm::Global) -> Option<GlobalType>347 pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> Option<GlobalType> { 348 let ty = ValType::from_wasmtime_type(global.ty)?; 349 let mutability = if global.mutability { 350 Mutability::Var 351 } else { 352 Mutability::Const 353 }; 354 Some(GlobalType::new(ty, mutability)) 355 } 356 } 357 358 // Table Types 359 360 /// A descriptor for a table in a WebAssembly module. 361 /// 362 /// Tables are contiguous chunks of a specific element, typically a `funcref` or 363 /// an `externref`. The most common use for tables is a function table through 364 /// which `call_indirect` can invoke other functions. 365 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 366 pub struct TableType { 367 element: ValType, 368 limits: Limits, 369 } 370 371 impl TableType { 372 /// Creates a new table descriptor which will contain the specified 373 /// `element` and have the `limits` applied to its length. new(element: ValType, limits: Limits) -> TableType374 pub fn new(element: ValType, limits: Limits) -> TableType { 375 TableType { element, limits } 376 } 377 378 /// Returns the element value type of this table. element(&self) -> &ValType379 pub fn element(&self) -> &ValType { 380 &self.element 381 } 382 383 /// Returns the limits, in units of elements, of this table. limits(&self) -> &Limits384 pub fn limits(&self) -> &Limits { 385 &self.limits 386 } 387 from_wasmtime_table(table: &wasm::Table) -> TableType388 pub(crate) fn from_wasmtime_table(table: &wasm::Table) -> TableType { 389 assert!(if let wasm::TableElementType::Func = table.ty { 390 true 391 } else { 392 false 393 }); 394 let ty = ValType::FuncRef; 395 let limits = Limits::new(table.minimum, table.maximum); 396 TableType::new(ty, limits) 397 } 398 } 399 400 // Memory Types 401 402 /// A descriptor for a WebAssembly memory type. 403 /// 404 /// Memories are described in units of pages (64KB) and represent contiguous 405 /// chunks of addressable memory. 406 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 407 pub struct MemoryType { 408 limits: Limits, 409 } 410 411 impl MemoryType { 412 /// Creates a new descriptor for a WebAssembly memory given the specified 413 /// limits of the memory. new(limits: Limits) -> MemoryType414 pub fn new(limits: Limits) -> MemoryType { 415 MemoryType { limits } 416 } 417 418 /// Returns the limits (in pages) that are configured for this memory. limits(&self) -> &Limits419 pub fn limits(&self) -> &Limits { 420 &self.limits 421 } 422 from_wasmtime_memory(memory: &wasm::Memory) -> MemoryType423 pub(crate) fn from_wasmtime_memory(memory: &wasm::Memory) -> MemoryType { 424 MemoryType::new(Limits::new(memory.minimum, memory.maximum)) 425 } 426 } 427 428 // Entity Types 429 430 #[derive(Clone, Hash, Eq, PartialEq)] 431 pub(crate) enum EntityType<'module> { 432 Function(&'module wasm::WasmFuncType), 433 Table(&'module wasm::Table), 434 Memory(&'module wasm::Memory), 435 Global(&'module wasm::Global), 436 } 437 438 impl<'module> EntityType<'module> { 439 /// Translate from a `EntityIndex` into an `ExternType`. new( entity_index: &EntityIndex, module: &'module wasmtime_environ::Module, ) -> EntityType<'module>440 pub(crate) fn new( 441 entity_index: &EntityIndex, 442 module: &'module wasmtime_environ::Module, 443 ) -> EntityType<'module> { 444 match entity_index { 445 EntityIndex::Function(func_index) => { 446 let sig = module.local.wasm_func_type(*func_index); 447 EntityType::Function(&sig) 448 } 449 EntityIndex::Table(table_index) => { 450 EntityType::Table(&module.local.table_plans[*table_index].table) 451 } 452 EntityIndex::Memory(memory_index) => { 453 EntityType::Memory(&module.local.memory_plans[*memory_index].memory) 454 } 455 EntityIndex::Global(global_index) => { 456 EntityType::Global(&module.local.globals[*global_index]) 457 } 458 } 459 } 460 461 /// Convert this `EntityType` to an `ExternType`. extern_type(&self) -> ExternType462 pub(crate) fn extern_type(&self) -> ExternType { 463 match self { 464 EntityType::Function(sig) => FuncType::from_wasm_func_type(sig) 465 .expect("core wasm function type should be supported") 466 .into(), 467 EntityType::Table(table) => TableType::from_wasmtime_table(table).into(), 468 EntityType::Memory(memory) => MemoryType::from_wasmtime_memory(memory).into(), 469 EntityType::Global(global) => GlobalType::from_wasmtime_global(global) 470 .expect("core wasm global type should be supported") 471 .into(), 472 } 473 } 474 } 475 476 // Import Types 477 478 /// A descriptor for an imported value into a wasm module. 479 /// 480 /// This type is primarily accessed from the 481 /// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`] 482 /// describes an import into the wasm module with the module/name that it's 483 /// imported from as well as the type of item that's being imported. 484 #[derive(Clone, Hash, Eq, PartialEq)] 485 pub struct ImportType<'module> { 486 /// The module of the import. 487 module: &'module str, 488 489 /// The field of the import. 490 name: &'module str, 491 492 /// The type of the import. 493 ty: EntityType<'module>, 494 } 495 496 impl<'module> ImportType<'module> { 497 /// Creates a new import descriptor which comes from `module` and `name` and 498 /// is of type `ty`. new( module: &'module str, name: &'module str, ty: EntityType<'module>, ) -> ImportType<'module>499 pub(crate) fn new( 500 module: &'module str, 501 name: &'module str, 502 ty: EntityType<'module>, 503 ) -> ImportType<'module> { 504 ImportType { module, name, ty } 505 } 506 507 /// Returns the module name that this import is expected to come from. module(&self) -> &'module str508 pub fn module(&self) -> &'module str { 509 self.module 510 } 511 512 /// Returns the field name of the module that this import is expected to 513 /// come from. name(&self) -> &'module str514 pub fn name(&self) -> &'module str { 515 self.name 516 } 517 518 /// Returns the expected type of this import. ty(&self) -> ExternType519 pub fn ty(&self) -> ExternType { 520 self.ty.extern_type() 521 } 522 } 523 524 impl<'module> fmt::Debug for ImportType<'module> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 526 f.debug_struct("ImportType") 527 .field("module", &self.module().to_owned()) 528 .field("name", &self.name().to_owned()) 529 .field("ty", &self.ty()) 530 .finish() 531 } 532 } 533 534 // Export Types 535 536 /// A descriptor for an exported WebAssembly value. 537 /// 538 /// This type is primarily accessed from the 539 /// [`Module::exports`](crate::Module::exports) accessor and describes what 540 /// names are exported from a wasm module and the type of the item that is 541 /// exported. 542 #[derive(Clone, Hash, Eq, PartialEq)] 543 pub struct ExportType<'module> { 544 /// The name of the export. 545 name: &'module str, 546 547 /// The type of the export. 548 ty: EntityType<'module>, 549 } 550 551 impl<'module> ExportType<'module> { 552 /// Creates a new export which is exported with the given `name` and has the 553 /// given `ty`. new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module>554 pub(crate) fn new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module> { 555 ExportType { name, ty } 556 } 557 558 /// Returns the name by which this export is known. name(&self) -> &'module str559 pub fn name(&self) -> &'module str { 560 self.name 561 } 562 563 /// Returns the type of this export. ty(&self) -> ExternType564 pub fn ty(&self) -> ExternType { 565 self.ty.extern_type() 566 } 567 } 568 569 impl<'module> fmt::Debug for ExportType<'module> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 571 f.debug_struct("ExportType") 572 .field("name", &self.name().to_owned()) 573 .field("ty", &self.ty()) 574 .finish() 575 } 576 } 577