| 1 | //! Support for encoding a core wasm module into a component. | 
| 2 | //! | 
|---|
| 3 | //! This module, at a high level, is tasked with transforming a core wasm | 
|---|
| 4 | //! module into a component. This will process the imports/exports of the core | 
|---|
| 5 | //! wasm module and translate between the `wit-parser` AST and the component | 
|---|
| 6 | //! model binary format, producing a final component which will import | 
|---|
| 7 | //! `*.wit` defined interfaces and export `*.wit` defined interfaces as well | 
|---|
| 8 | //! with everything wired up internally according to the canonical ABI and such. | 
|---|
| 9 | //! | 
|---|
| 10 | //! This doc block here is not currently 100% complete and doesn't cover the | 
|---|
| 11 | //! full functionality of this module. | 
|---|
| 12 | //! | 
|---|
| 13 | //! # Adapter Modules | 
|---|
| 14 | //! | 
|---|
| 15 | //! One feature of this encoding process which is non-obvious is the support for | 
|---|
| 16 | //! "adapter modules". The general idea here is that historical host API | 
|---|
| 17 | //! definitions have been around for quite some time, such as | 
|---|
| 18 | //! `wasi_snapshot_preview1`, but these host API definitions are not compatible | 
|---|
| 19 | //! with the canonical ABI or component model exactly. These APIs, however, can | 
|---|
| 20 | //! in most situations be roughly adapted to component-model equivalents. This | 
|---|
| 21 | //! is where adapter modules come into play, they're converting from some | 
|---|
| 22 | //! arbitrary API/ABI into a component-model using API. | 
|---|
| 23 | //! | 
|---|
| 24 | //! An adapter module is a separately compiled `*.wasm` blob which will export | 
|---|
| 25 | //! functions matching the desired ABI (e.g. exporting functions matching the | 
|---|
| 26 | //! `wasi_snapshot_preview1` ABI). The `*.wasm` blob will then import functions | 
|---|
| 27 | //! in the canonical ABI and internally adapt the exported functions to the | 
|---|
| 28 | //! imported functions. The encoding support in this module is what wires | 
|---|
| 29 | //! everything up and makes sure that everything is imported and exported to the | 
|---|
| 30 | //! right place. Adapter modules currently always use "indirect lowerings" | 
|---|
| 31 | //! meaning that a shim module is created and provided as the imports to the | 
|---|
| 32 | //! main core wasm module, and the shim module is "filled in" at a later time | 
|---|
| 33 | //! during the instantiation process. | 
|---|
| 34 | //! | 
|---|
| 35 | //! Adapter modules are not intended to be general purpose and are currently | 
|---|
| 36 | //! very restrictive, namely: | 
|---|
| 37 | //! | 
|---|
| 38 | //! * They must import a linear memory and not define their own linear memory | 
|---|
| 39 | //!   otherwise. In other words they import memory and cannot use multi-memory. | 
|---|
| 40 | //! * They cannot define any `elem` or `data` segments since otherwise there's | 
|---|
| 41 | //!   no knowledge ahead-of-time of where their data or element segments could | 
|---|
| 42 | //!   go. This means things like no panics, no indirect calls, etc. | 
|---|
| 43 | //! * If the adapter uses a shadow stack, the global that points to it must be a | 
|---|
| 44 | //!   mutable `i32` named `__stack_pointer`. This stack is automatically | 
|---|
| 45 | //!   allocated with an injected `allocate_stack` function that will either use | 
|---|
| 46 | //!   the main module's `cabi_realloc` export (if present) or `memory.grow`. It | 
|---|
| 47 | //!   allocates only 64KB of stack space, and there is no protection if that | 
|---|
| 48 | //!   overflows. | 
|---|
| 49 | //! * If the adapter has a global, mutable `i32` named `allocation_state`, it | 
|---|
| 50 | //!   will be used to keep track of stack allocation status and avoid infinite | 
|---|
| 51 | //!   recursion if the main module's `cabi_realloc` function calls back into the | 
|---|
| 52 | //!   adapter.  `allocate_stack` will check this global on entry; if it is zero, | 
|---|
| 53 | //!   it will set it to one, then allocate the stack, and finally set it to two. | 
|---|
| 54 | //!   If it is non-zero, `allocate_stack` will do nothing and return immediately | 
|---|
| 55 | //!   (because either the stack has already been allocated or is in the process | 
|---|
| 56 | //!   of being allocated).  If the adapter does not have an `allocation_state`, | 
|---|
| 57 | //!   `allocate_stack` will use `memory.grow` to allocate the stack; it will | 
|---|
| 58 | //!   _not_ use the main module's `cabi_realloc` even if it's available. | 
|---|
| 59 | //! * If the adapter imports a `cabi_realloc` function, and the main module | 
|---|
| 60 | //!   exports one, they'll be linked together via an alias. If the adapter | 
|---|
| 61 | //!   imports such a function but the main module does _not_ export one, we'll | 
|---|
| 62 | //!   synthesize one based on `memory.grow` (which will trap for any size other | 
|---|
| 63 | //!   than 64KB). Note that the main module's `cabi_realloc` function may call | 
|---|
| 64 | //!   back into the adapter before the shadow stack has been allocated. In this | 
|---|
| 65 | //!   case (when `allocation_state` is zero or one), the adapter should return | 
|---|
| 66 | //!   whatever dummy value(s) it can immediately without touching the stack. | 
|---|
| 67 | //! | 
|---|
| 68 | //! This means that adapter modules are not meant to be written by everyone. | 
|---|
| 69 | //! It's assumed that these will be relatively few and far between yet still a | 
|---|
| 70 | //! crucial part of the transition process from to the component model since | 
|---|
| 71 | //! otherwise there's no way to run a `wasi_snapshot_preview1` module within the | 
|---|
| 72 | //! component model. | 
|---|
| 73 |  | 
|---|
| 74 | use crate::metadata::{self, Bindgen, ModuleMetadata}; | 
|---|
| 75 | use crate::validation::{Export, ExportMap, Import, ImportInstance, ImportMap, PayloadInfo}; | 
|---|
| 76 | use crate::StringEncoding; | 
|---|
| 77 | use anyhow::{anyhow, bail, Context, Result}; | 
|---|
| 78 | use indexmap::{IndexMap, IndexSet}; | 
|---|
| 79 | use std::borrow::Cow; | 
|---|
| 80 | use std::collections::HashMap; | 
|---|
| 81 | use std::hash::Hash; | 
|---|
| 82 | use std::mem; | 
|---|
| 83 | use wasm_encoder::*; | 
|---|
| 84 | use wasmparser::Validator; | 
|---|
| 85 | use wit_parser::{ | 
|---|
| 86 | abi::{AbiVariant, WasmSignature, WasmType}, | 
|---|
| 87 | Docs, Function, FunctionKind, InterfaceId, LiveTypes, Resolve, Results, Stability, Type, | 
|---|
| 88 | TypeDefKind, TypeId, TypeOwner, WorldItem, WorldKey, | 
|---|
| 89 | }; | 
|---|
| 90 |  | 
|---|
| 91 | const INDIRECT_TABLE_NAME: &str = "$imports"; | 
|---|
| 92 |  | 
|---|
| 93 | mod wit; | 
|---|
| 94 | pub use wit::{encode, encode_world}; | 
|---|
| 95 |  | 
|---|
| 96 | mod types; | 
|---|
| 97 | use types::{InstanceTypeEncoder, RootTypeEncoder, ValtypeEncoder}; | 
|---|
| 98 | mod world; | 
|---|
| 99 | use world::{ComponentWorld, ImportedInterface, Lowering}; | 
|---|
| 100 |  | 
|---|
| 101 | fn to_val_type(ty: &WasmType) -> ValType { | 
|---|
| 102 | match ty { | 
|---|
| 103 | WasmType::I32 => ValType::I32, | 
|---|
| 104 | WasmType::I64 => ValType::I64, | 
|---|
| 105 | WasmType::F32 => ValType::F32, | 
|---|
| 106 | WasmType::F64 => ValType::F64, | 
|---|
| 107 | WasmType::Pointer => ValType::I32, | 
|---|
| 108 | WasmType::PointerOrI64 => ValType::I64, | 
|---|
| 109 | WasmType::Length => ValType::I32, | 
|---|
| 110 | } | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 | bitflags::bitflags! { | 
|---|
| 114 | /// Options in the `canon lower` or `canon lift` required for a particular | 
|---|
| 115 | /// function. | 
|---|
| 116 | #[ derive(Copy, Clone, Debug)] | 
|---|
| 117 | pub struct RequiredOptions: u8 { | 
|---|
| 118 | /// A memory must be specified, typically the "main module"'s memory | 
|---|
| 119 | /// export. | 
|---|
| 120 | const MEMORY = 1 << 0; | 
|---|
| 121 | /// A `realloc` function must be specified, typically named | 
|---|
| 122 | /// `cabi_realloc`. | 
|---|
| 123 | const REALLOC = 1 << 1; | 
|---|
| 124 | /// A string encoding must be specified, which is always utf-8 for now | 
|---|
| 125 | /// today. | 
|---|
| 126 | const STRING_ENCODING = 1 << 2; | 
|---|
| 127 | const ASYNC = 1 << 3; | 
|---|
| 128 | } | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | impl RequiredOptions { | 
|---|
| 132 | fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions { | 
|---|
| 133 | let sig = resolve.wasm_signature(abi, func); | 
|---|
| 134 | let mut ret = RequiredOptions::empty(); | 
|---|
| 135 | // Lift the params and lower the results for imports | 
|---|
| 136 | ret.add_lift(TypeContents::for_types( | 
|---|
| 137 | resolve, | 
|---|
| 138 | func.params.iter().map(|(_, t)| t), | 
|---|
| 139 | )); | 
|---|
| 140 | ret.add_lower(TypeContents::for_types(resolve, func.results.iter_types())); | 
|---|
| 141 |  | 
|---|
| 142 | // If anything is indirect then `memory` will be required to read the | 
|---|
| 143 | // indirect values. | 
|---|
| 144 | if sig.retptr || sig.indirect_params { | 
|---|
| 145 | ret |= RequiredOptions::MEMORY; | 
|---|
| 146 | } | 
|---|
| 147 | if abi == AbiVariant::GuestImportAsync { | 
|---|
| 148 | ret |= RequiredOptions::ASYNC; | 
|---|
| 149 | } | 
|---|
| 150 | ret | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions { | 
|---|
| 154 | let sig = resolve.wasm_signature(abi, func); | 
|---|
| 155 | let mut ret = RequiredOptions::empty(); | 
|---|
| 156 | // Lower the params and lift the results for exports | 
|---|
| 157 | ret.add_lower(TypeContents::for_types( | 
|---|
| 158 | resolve, | 
|---|
| 159 | func.params.iter().map(|(_, t)| t), | 
|---|
| 160 | )); | 
|---|
| 161 | ret.add_lift(TypeContents::for_types(resolve, func.results.iter_types())); | 
|---|
| 162 |  | 
|---|
| 163 | // If anything is indirect then `memory` will be required to read the | 
|---|
| 164 | // indirect values, but if the arguments are indirect then `realloc` is | 
|---|
| 165 | // additionally required to allocate space for the parameters. | 
|---|
| 166 | if sig.retptr || sig.indirect_params { | 
|---|
| 167 | ret |= RequiredOptions::MEMORY; | 
|---|
| 168 | if sig.indirect_params { | 
|---|
| 169 | ret |= RequiredOptions::REALLOC; | 
|---|
| 170 | } | 
|---|
| 171 | } | 
|---|
| 172 | if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi { | 
|---|
| 173 | ret |= RequiredOptions::ASYNC; | 
|---|
| 174 | } | 
|---|
| 175 | ret | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | fn add_lower(&mut self, types: TypeContents) { | 
|---|
| 179 | // If lists/strings are lowered into wasm then memory is required as | 
|---|
| 180 | // usual but `realloc` is also required to allow the external caller to | 
|---|
| 181 | // allocate space in the destination for the list/string. | 
|---|
| 182 | if types.contains(TypeContents::LIST) { | 
|---|
| 183 | *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC; | 
|---|
| 184 | } | 
|---|
| 185 | if types.contains(TypeContents::STRING) { | 
|---|
| 186 | *self |= RequiredOptions::MEMORY | 
|---|
| 187 | | RequiredOptions::STRING_ENCODING | 
|---|
| 188 | | RequiredOptions::REALLOC; | 
|---|
| 189 | } | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | fn add_lift(&mut self, types: TypeContents) { | 
|---|
| 193 | // Unlike for `lower` when lifting a string/list all that's needed is | 
|---|
| 194 | // memory, since the string/list already resides in memory `realloc` | 
|---|
| 195 | // isn't needed. | 
|---|
| 196 | if types.contains(TypeContents::LIST) { | 
|---|
| 197 | *self |= RequiredOptions::MEMORY; | 
|---|
| 198 | } | 
|---|
| 199 | if types.contains(TypeContents::STRING) { | 
|---|
| 200 | *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING; | 
|---|
| 201 | } | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | fn into_iter( | 
|---|
| 205 | self, | 
|---|
| 206 | encoding: StringEncoding, | 
|---|
| 207 | memory_index: Option<u32>, | 
|---|
| 208 | realloc_index: Option<u32>, | 
|---|
| 209 | ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> { | 
|---|
| 210 | #[ derive(Default)] | 
|---|
| 211 | struct Iter { | 
|---|
| 212 | options: [Option<CanonicalOption>; 5], | 
|---|
| 213 | current: usize, | 
|---|
| 214 | count: usize, | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | impl Iter { | 
|---|
| 218 | fn push(&mut self, option: CanonicalOption) { | 
|---|
| 219 | assert!(self.count < self.options.len()); | 
|---|
| 220 | self.options[self.count] = Some(option); | 
|---|
| 221 | self.count += 1; | 
|---|
| 222 | } | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 | impl Iterator for Iter { | 
|---|
| 226 | type Item = CanonicalOption; | 
|---|
| 227 |  | 
|---|
| 228 | fn next(&mut self) -> Option<Self::Item> { | 
|---|
| 229 | if self.current == self.count { | 
|---|
| 230 | return None; | 
|---|
| 231 | } | 
|---|
| 232 | let option = self.options[self.current]; | 
|---|
| 233 | self.current += 1; | 
|---|
| 234 | option | 
|---|
| 235 | } | 
|---|
| 236 |  | 
|---|
| 237 | fn size_hint(&self) -> (usize, Option<usize>) { | 
|---|
| 238 | (self.count - self.current, Some(self.count - self.current)) | 
|---|
| 239 | } | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | impl ExactSizeIterator for Iter {} | 
|---|
| 243 |  | 
|---|
| 244 | let mut iter = Iter::default(); | 
|---|
| 245 |  | 
|---|
| 246 | if self.contains(RequiredOptions::MEMORY) { | 
|---|
| 247 | iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| { | 
|---|
| 248 | anyhow!( "module does not export a memory named `memory`") | 
|---|
| 249 | })?)); | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | if self.contains(RequiredOptions::REALLOC) { | 
|---|
| 253 | iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else( | 
|---|
| 254 | || anyhow!( "module does not export a function named `cabi_realloc`"), | 
|---|
| 255 | )?)); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 | if self.contains(RequiredOptions::STRING_ENCODING) { | 
|---|
| 259 | iter.push(encoding.into()); | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 | if self.contains(RequiredOptions::ASYNC) { | 
|---|
| 263 | iter.push(CanonicalOption::Async); | 
|---|
| 264 | } | 
|---|
| 265 |  | 
|---|
| 266 | Ok(iter) | 
|---|
| 267 | } | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 | bitflags::bitflags! { | 
|---|
| 271 | /// Flags about what kinds of types are present within the recursive | 
|---|
| 272 | /// structure of a type. | 
|---|
| 273 | struct TypeContents: u8 { | 
|---|
| 274 | const STRING = 1 << 0; | 
|---|
| 275 | const LIST = 1 << 1; | 
|---|
| 276 | } | 
|---|
| 277 | } | 
|---|
| 278 |  | 
|---|
| 279 | impl TypeContents { | 
|---|
| 280 | fn for_types<'a>(resolve: &Resolve, types: impl Iterator<Item = &'a Type>) -> Self { | 
|---|
| 281 | let mut cur = TypeContents::empty(); | 
|---|
| 282 | for ty in types { | 
|---|
| 283 | cur |= Self::for_type(resolve, ty); | 
|---|
| 284 | } | 
|---|
| 285 | cur | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | fn for_optional_types<'a>( | 
|---|
| 289 | resolve: &Resolve, | 
|---|
| 290 | types: impl Iterator<Item = Option<&'a Type>>, | 
|---|
| 291 | ) -> Self { | 
|---|
| 292 | Self::for_types(resolve, types.flatten()) | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 | fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self { | 
|---|
| 296 | match ty { | 
|---|
| 297 | Some(ty) => Self::for_type(resolve, ty), | 
|---|
| 298 | None => Self::empty(), | 
|---|
| 299 | } | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 | fn for_type(resolve: &Resolve, ty: &Type) -> Self { | 
|---|
| 303 | match ty { | 
|---|
| 304 | Type::Id(id) => match &resolve.types[*id].kind { | 
|---|
| 305 | TypeDefKind::Handle(h) => match h { | 
|---|
| 306 | wit_parser::Handle::Own(_) => Self::empty(), | 
|---|
| 307 | wit_parser::Handle::Borrow(_) => Self::empty(), | 
|---|
| 308 | }, | 
|---|
| 309 | TypeDefKind::Resource => Self::empty(), | 
|---|
| 310 | TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)), | 
|---|
| 311 | TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()), | 
|---|
| 312 | TypeDefKind::Flags(_) => Self::empty(), | 
|---|
| 313 | TypeDefKind::Option(t) => Self::for_type(resolve, t), | 
|---|
| 314 | TypeDefKind::Result(r) => { | 
|---|
| 315 | Self::for_optional_type(resolve, r.ok.as_ref()) | 
|---|
| 316 | | Self::for_optional_type(resolve, r.err.as_ref()) | 
|---|
| 317 | } | 
|---|
| 318 | TypeDefKind::Variant(v) => { | 
|---|
| 319 | Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref())) | 
|---|
| 320 | } | 
|---|
| 321 | TypeDefKind::Enum(_) => Self::empty(), | 
|---|
| 322 | TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST, | 
|---|
| 323 | TypeDefKind::Type(t) => Self::for_type(resolve, t), | 
|---|
| 324 | TypeDefKind::Future(_) => Self::empty(), | 
|---|
| 325 | TypeDefKind::Stream(_) => Self::empty(), | 
|---|
| 326 | TypeDefKind::ErrorContext => Self::empty(), | 
|---|
| 327 | TypeDefKind::Unknown => unreachable!(), | 
|---|
| 328 | }, | 
|---|
| 329 | Type::String => Self::STRING, | 
|---|
| 330 | _ => Self::empty(), | 
|---|
| 331 | } | 
|---|
| 332 | } | 
|---|
| 333 | } | 
|---|
| 334 |  | 
|---|
| 335 | /// State relating to encoding a component. | 
|---|
| 336 | pub struct EncodingState<'a> { | 
|---|
| 337 | /// The component being encoded. | 
|---|
| 338 | component: ComponentBuilder, | 
|---|
| 339 | /// The index into the core module index space for the inner core module. | 
|---|
| 340 | /// | 
|---|
| 341 | /// If `None`, the core module has not been encoded. | 
|---|
| 342 | module_index: Option<u32>, | 
|---|
| 343 | /// The index into the core instance index space for the inner core module. | 
|---|
| 344 | /// | 
|---|
| 345 | /// If `None`, the core module has not been instantiated. | 
|---|
| 346 | instance_index: Option<u32>, | 
|---|
| 347 | /// The index in the core memory index space for the exported memory. | 
|---|
| 348 | /// | 
|---|
| 349 | /// If `None`, then the memory has not yet been aliased. | 
|---|
| 350 | memory_index: Option<u32>, | 
|---|
| 351 | /// The index of the shim instance used for lowering imports into the core instance. | 
|---|
| 352 | /// | 
|---|
| 353 | /// If `None`, then the shim instance how not yet been encoded. | 
|---|
| 354 | shim_instance_index: Option<u32>, | 
|---|
| 355 | /// The index of the fixups module to instantiate to fill in the lowered imports. | 
|---|
| 356 | /// | 
|---|
| 357 | /// If `None`, then a fixup module has not yet been encoded. | 
|---|
| 358 | fixups_module_index: Option<u32>, | 
|---|
| 359 |  | 
|---|
| 360 | /// A map of named adapter modules and the index that the module was defined | 
|---|
| 361 | /// at. | 
|---|
| 362 | adapter_modules: IndexMap<&'a str, u32>, | 
|---|
| 363 | /// A map of adapter module instances and the index of their instance. | 
|---|
| 364 | adapter_instances: IndexMap<&'a str, u32>, | 
|---|
| 365 |  | 
|---|
| 366 | /// Imported instances and what index they were imported as. | 
|---|
| 367 | imported_instances: IndexMap<InterfaceId, u32>, | 
|---|
| 368 | imported_funcs: IndexMap<String, u32>, | 
|---|
| 369 | exported_instances: IndexMap<InterfaceId, u32>, | 
|---|
| 370 |  | 
|---|
| 371 | /// Maps used when translating types to the component model binary format. | 
|---|
| 372 | /// Note that imports and exports are stored in separate maps since they | 
|---|
| 373 | /// need fresh hierarchies of types in case the same interface is both | 
|---|
| 374 | /// imported and exported. | 
|---|
| 375 | import_type_map: HashMap<TypeId, u32>, | 
|---|
| 376 | import_func_type_map: HashMap<types::FunctionKey<'a>, u32>, | 
|---|
| 377 | export_type_map: HashMap<TypeId, u32>, | 
|---|
| 378 | export_func_type_map: HashMap<types::FunctionKey<'a>, u32>, | 
|---|
| 379 |  | 
|---|
| 380 | /// Cache of items that have been aliased from core instances. | 
|---|
| 381 | /// | 
|---|
| 382 | /// This is a helper to reduce the number of aliases created by ensuring | 
|---|
| 383 | /// that repeated requests for the same item return the same index of an | 
|---|
| 384 | /// original `core alias` item. | 
|---|
| 385 | aliased_core_items: HashMap<(u32, String), u32>, | 
|---|
| 386 |  | 
|---|
| 387 | /// Metadata about the world inferred from the input to `ComponentEncoder`. | 
|---|
| 388 | info: &'a ComponentWorld<'a>, | 
|---|
| 389 | } | 
|---|
| 390 |  | 
|---|
| 391 | impl<'a> EncodingState<'a> { | 
|---|
| 392 | fn encode_core_modules(&mut self) { | 
|---|
| 393 | assert!(self.module_index.is_none()); | 
|---|
| 394 | let idx = self.component.core_module_raw(&self.info.encoder.module); | 
|---|
| 395 | self.module_index = Some(idx); | 
|---|
| 396 |  | 
|---|
| 397 | for (name, adapter) in self.info.adapters.iter() { | 
|---|
| 398 | let add_meta = wasm_metadata::AddMetadata { | 
|---|
| 399 | name: Some(if adapter.library_info.is_some() { | 
|---|
| 400 | name.to_string() | 
|---|
| 401 | } else { | 
|---|
| 402 | format!( "wit-component:adapter:{name} ") | 
|---|
| 403 | }), | 
|---|
| 404 | ..Default::default() | 
|---|
| 405 | }; | 
|---|
| 406 | let wasm = add_meta | 
|---|
| 407 | .to_wasm(&adapter.wasm) | 
|---|
| 408 | .expect( "core wasm can get name added"); | 
|---|
| 409 | let idx = self.component.core_module_raw(&wasm); | 
|---|
| 410 | let prev = self.adapter_modules.insert(name, idx); | 
|---|
| 411 | assert!(prev.is_none()); | 
|---|
| 412 | } | 
|---|
| 413 | } | 
|---|
| 414 |  | 
|---|
| 415 | fn root_import_type_encoder( | 
|---|
| 416 | &mut self, | 
|---|
| 417 | interface: Option<InterfaceId>, | 
|---|
| 418 | ) -> RootTypeEncoder<'_, 'a> { | 
|---|
| 419 | RootTypeEncoder { | 
|---|
| 420 | state: self, | 
|---|
| 421 | interface, | 
|---|
| 422 | import_types: true, | 
|---|
| 423 | } | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | fn root_export_type_encoder( | 
|---|
| 427 | &mut self, | 
|---|
| 428 | interface: Option<InterfaceId>, | 
|---|
| 429 | ) -> RootTypeEncoder<'_, 'a> { | 
|---|
| 430 | RootTypeEncoder { | 
|---|
| 431 | state: self, | 
|---|
| 432 | interface, | 
|---|
| 433 | import_types: false, | 
|---|
| 434 | } | 
|---|
| 435 | } | 
|---|
| 436 |  | 
|---|
| 437 | fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> { | 
|---|
| 438 | InstanceTypeEncoder { | 
|---|
| 439 | state: self, | 
|---|
| 440 | interface, | 
|---|
| 441 | type_map: Default::default(), | 
|---|
| 442 | func_type_map: Default::default(), | 
|---|
| 443 | ty: Default::default(), | 
|---|
| 444 | } | 
|---|
| 445 | } | 
|---|
| 446 |  | 
|---|
| 447 | fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> { | 
|---|
| 448 | let mut has_funcs = false; | 
|---|
| 449 | for (name, info) in self.info.import_map.iter() { | 
|---|
| 450 | match name { | 
|---|
| 451 | Some(name) => { | 
|---|
| 452 | self.encode_interface_import(name_map.get(name).unwrap_or(name), info)? | 
|---|
| 453 | } | 
|---|
| 454 | None => has_funcs = true, | 
|---|
| 455 | } | 
|---|
| 456 | } | 
|---|
| 457 |  | 
|---|
| 458 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 459 | let world = &resolve.worlds[self.info.encoder.metadata.world]; | 
|---|
| 460 | for (_name, item) in world.imports.iter() { | 
|---|
| 461 | if let WorldItem::Type(ty) = item { | 
|---|
| 462 | self.root_import_type_encoder(None) | 
|---|
| 463 | .encode_valtype(resolve, &Type::Id(*ty))?; | 
|---|
| 464 | } | 
|---|
| 465 | } | 
|---|
| 466 |  | 
|---|
| 467 | if has_funcs { | 
|---|
| 468 | let info = &self.info.import_map[&None]; | 
|---|
| 469 | self.encode_root_import_funcs(info)?; | 
|---|
| 470 | } | 
|---|
| 471 | Ok(()) | 
|---|
| 472 | } | 
|---|
| 473 |  | 
|---|
| 474 | fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> { | 
|---|
| 475 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 476 | let interface_id = info.interface.as_ref().unwrap(); | 
|---|
| 477 | let interface_id = *interface_id; | 
|---|
| 478 | let interface = &resolve.interfaces[interface_id]; | 
|---|
| 479 | log::trace!( "encoding imports for `{name} ` as {:?} ", interface_id); | 
|---|
| 480 | let mut encoder = self.instance_type_encoder(interface_id); | 
|---|
| 481 |  | 
|---|
| 482 | // First encode all type information | 
|---|
| 483 | if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) { | 
|---|
| 484 | for ty in live { | 
|---|
| 485 | log::trace!( | 
|---|
| 486 | "encoding extra type {ty:?}  name={:?} ", | 
|---|
| 487 | resolve.types[*ty].name | 
|---|
| 488 | ); | 
|---|
| 489 | encoder.encode_valtype(resolve, &Type::Id(*ty))?; | 
|---|
| 490 | } | 
|---|
| 491 | } | 
|---|
| 492 |  | 
|---|
| 493 | // Next encode all required functions from this imported interface | 
|---|
| 494 | // into the instance type. | 
|---|
| 495 | for (_, func) in interface.functions.iter() { | 
|---|
| 496 | if !(info | 
|---|
| 497 | .lowerings | 
|---|
| 498 | .contains_key(&(func.name.clone(), AbiVariant::GuestImport)) | 
|---|
| 499 | || info | 
|---|
| 500 | .lowerings | 
|---|
| 501 | .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync))) | 
|---|
| 502 | { | 
|---|
| 503 | continue; | 
|---|
| 504 | } | 
|---|
| 505 | log::trace!( "encoding function type for `{} `", func.name); | 
|---|
| 506 | let idx = encoder.encode_func_type(resolve, func)?; | 
|---|
| 507 |  | 
|---|
| 508 | encoder.ty.export(&func.name, ComponentTypeRef::Func(idx)); | 
|---|
| 509 | } | 
|---|
| 510 |  | 
|---|
| 511 | let ty = encoder.ty; | 
|---|
| 512 | // Don't encode empty instance types since they're not | 
|---|
| 513 | // meaningful to the runtime of the component anyway. | 
|---|
| 514 | if ty.is_empty() { | 
|---|
| 515 | return Ok(()); | 
|---|
| 516 | } | 
|---|
| 517 | let instance_type_idx = self.component.type_instance(&ty); | 
|---|
| 518 | let instance_idx = self | 
|---|
| 519 | .component | 
|---|
| 520 | .import(name, ComponentTypeRef::Instance(instance_type_idx)); | 
|---|
| 521 | let prev = self.imported_instances.insert(interface_id, instance_idx); | 
|---|
| 522 | assert!(prev.is_none()); | 
|---|
| 523 | Ok(()) | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 | fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> { | 
|---|
| 527 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 528 | let world = self.info.encoder.metadata.world; | 
|---|
| 529 | for (name, item) in resolve.worlds[world].imports.iter() { | 
|---|
| 530 | let func = match item { | 
|---|
| 531 | WorldItem::Function(f) => f, | 
|---|
| 532 | WorldItem::Interface { .. } | WorldItem::Type(_) => continue, | 
|---|
| 533 | }; | 
|---|
| 534 | let name = resolve.name_world_key(name); | 
|---|
| 535 | if !(info | 
|---|
| 536 | .lowerings | 
|---|
| 537 | .contains_key(&(name.clone(), AbiVariant::GuestImport)) | 
|---|
| 538 | || info | 
|---|
| 539 | .lowerings | 
|---|
| 540 | .contains_key(&(name.clone(), AbiVariant::GuestImportAsync))) | 
|---|
| 541 | { | 
|---|
| 542 | continue; | 
|---|
| 543 | } | 
|---|
| 544 | log::trace!( "encoding function type for `{} `", func.name); | 
|---|
| 545 | let idx = self | 
|---|
| 546 | .root_import_type_encoder(None) | 
|---|
| 547 | .encode_func_type(resolve, func)?; | 
|---|
| 548 | let func_idx = self.component.import(&name, ComponentTypeRef::Func(idx)); | 
|---|
| 549 | let prev = self.imported_funcs.insert(name, func_idx); | 
|---|
| 550 | assert!(prev.is_none()); | 
|---|
| 551 | } | 
|---|
| 552 | Ok(()) | 
|---|
| 553 | } | 
|---|
| 554 |  | 
|---|
| 555 | fn alias_imported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { | 
|---|
| 556 | let ty = &self.info.encoder.metadata.resolve.types[id]; | 
|---|
| 557 | let name = ty.name.as_ref().expect( "type must have a name"); | 
|---|
| 558 | let instance = self.imported_instances[&interface]; | 
|---|
| 559 | self.component | 
|---|
| 560 | .alias_export(instance, name, ComponentExportKind::Type) | 
|---|
| 561 | } | 
|---|
| 562 |  | 
|---|
| 563 | fn alias_exported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { | 
|---|
| 564 | let ty = &self.info.encoder.metadata.resolve.types[id]; | 
|---|
| 565 | let name = ty.name.as_ref().expect( "type must have a name"); | 
|---|
| 566 | let instance = self.exported_instances[&interface]; | 
|---|
| 567 | self.component | 
|---|
| 568 | .alias_export(instance, name, ComponentExportKind::Type) | 
|---|
| 569 | } | 
|---|
| 570 |  | 
|---|
| 571 | fn encode_core_instantiation(&mut self) -> Result<()> { | 
|---|
| 572 | // Encode a shim instantiation if needed | 
|---|
| 573 | let shims = self.encode_shim_instantiation()?; | 
|---|
| 574 |  | 
|---|
| 575 | // Next declare all exported resource types. This populates | 
|---|
| 576 | // `export_type_map` and will additionally be used for imports to | 
|---|
| 577 | // modules instantiated below. | 
|---|
| 578 | self.declare_exported_resources(&shims); | 
|---|
| 579 |  | 
|---|
| 580 | // Next instantiate the main module. This provides the linear memory to | 
|---|
| 581 | // use for all future adapters and enables creating indirect lowerings | 
|---|
| 582 | // at the end. | 
|---|
| 583 | self.instantiate_main_module(&shims)?; | 
|---|
| 584 |  | 
|---|
| 585 | // Separate the adapters according which should be instantiated before | 
|---|
| 586 | // and after indirect lowerings are encoded. | 
|---|
| 587 | let (before, after) = self | 
|---|
| 588 | .info | 
|---|
| 589 | .adapters | 
|---|
| 590 | .iter() | 
|---|
| 591 | .partition::<Vec<_>, _>(|(_, adapter)| { | 
|---|
| 592 | !matches!( | 
|---|
| 593 | adapter.library_info, | 
|---|
| 594 | Some(LibraryInfo { | 
|---|
| 595 | instantiate_after_shims: true, | 
|---|
| 596 | .. | 
|---|
| 597 | }) | 
|---|
| 598 | ) | 
|---|
| 599 | }); | 
|---|
| 600 |  | 
|---|
| 601 | for (name, _adapter) in before { | 
|---|
| 602 | self.instantiate_adapter_module(&shims, name)?; | 
|---|
| 603 | } | 
|---|
| 604 |  | 
|---|
| 605 | // With all the relevant core wasm instances in play now the original shim | 
|---|
| 606 | // module, if present, can be filled in with lowerings/adapters/etc. | 
|---|
| 607 | self.encode_indirect_lowerings(&shims)?; | 
|---|
| 608 |  | 
|---|
| 609 | for (name, _adapter) in after { | 
|---|
| 610 | self.instantiate_adapter_module(&shims, name)?; | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 | self.encode_initialize_with_start()?; | 
|---|
| 614 |  | 
|---|
| 615 | Ok(()) | 
|---|
| 616 | } | 
|---|
| 617 |  | 
|---|
| 618 | fn lookup_resource_index(&mut self, id: TypeId) -> u32 { | 
|---|
| 619 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 620 | let ty = &resolve.types[id]; | 
|---|
| 621 | match ty.owner { | 
|---|
| 622 | // If this resource is owned by a world then it's a top-level | 
|---|
| 623 | // resource which means it must have already been translated so | 
|---|
| 624 | // it's available for lookup in `import_type_map`. | 
|---|
| 625 | TypeOwner::World(_) => self.import_type_map[&id], | 
|---|
| 626 | TypeOwner::Interface(i) => { | 
|---|
| 627 | let instance = self.imported_instances[&i]; | 
|---|
| 628 | let name = ty.name.as_ref().expect( "resources must be named"); | 
|---|
| 629 | self.component | 
|---|
| 630 | .alias_export(instance, name, ComponentExportKind::Type) | 
|---|
| 631 | } | 
|---|
| 632 | TypeOwner::None => panic!( "resources must have an owner"), | 
|---|
| 633 | } | 
|---|
| 634 | } | 
|---|
| 635 |  | 
|---|
| 636 | fn encode_exports(&mut self, module: CustomModule) -> Result<()> { | 
|---|
| 637 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 638 | let exports = match module { | 
|---|
| 639 | CustomModule::Main => &self.info.encoder.main_module_exports, | 
|---|
| 640 | CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports, | 
|---|
| 641 | }; | 
|---|
| 642 |  | 
|---|
| 643 | if exports.is_empty() { | 
|---|
| 644 | return Ok(()); | 
|---|
| 645 | } | 
|---|
| 646 |  | 
|---|
| 647 | let mut interface_func_core_names = IndexMap::new(); | 
|---|
| 648 | let mut world_func_core_names = IndexMap::new(); | 
|---|
| 649 | for (core_name, export) in self.info.exports_for(module).iter() { | 
|---|
| 650 | match export { | 
|---|
| 651 | Export::WorldFunc(_, name, _) => { | 
|---|
| 652 | let prev = world_func_core_names.insert(name, core_name); | 
|---|
| 653 | assert!(prev.is_none()); | 
|---|
| 654 | } | 
|---|
| 655 | Export::InterfaceFunc(_, id, name, _) => { | 
|---|
| 656 | let prev = interface_func_core_names | 
|---|
| 657 | .entry(id) | 
|---|
| 658 | .or_insert(IndexMap::new()) | 
|---|
| 659 | .insert(name.as_str(), core_name); | 
|---|
| 660 | assert!(prev.is_none()); | 
|---|
| 661 | } | 
|---|
| 662 | Export::WorldFuncCallback(..) | 
|---|
| 663 | | Export::InterfaceFuncCallback(..) | 
|---|
| 664 | | Export::WorldFuncPostReturn(..) | 
|---|
| 665 | | Export::InterfaceFuncPostReturn(..) | 
|---|
| 666 | | Export::ResourceDtor(..) | 
|---|
| 667 | | Export::Memory | 
|---|
| 668 | | Export::GeneralPurposeRealloc | 
|---|
| 669 | | Export::GeneralPurposeExportRealloc | 
|---|
| 670 | | Export::GeneralPurposeImportRealloc | 
|---|
| 671 | | Export::Initialize | 
|---|
| 672 | | Export::ReallocForAdapter => continue, | 
|---|
| 673 | } | 
|---|
| 674 | } | 
|---|
| 675 |  | 
|---|
| 676 | let world = &resolve.worlds[self.info.encoder.metadata.world]; | 
|---|
| 677 |  | 
|---|
| 678 | for export_name in exports { | 
|---|
| 679 | let export_string = resolve.name_world_key(export_name); | 
|---|
| 680 | match &world.exports[export_name] { | 
|---|
| 681 | WorldItem::Function(func) => { | 
|---|
| 682 | let ty = self | 
|---|
| 683 | .root_import_type_encoder(None) | 
|---|
| 684 | .encode_func_type(resolve, func)?; | 
|---|
| 685 | let core_name = world_func_core_names[&func.name]; | 
|---|
| 686 | let idx = self.encode_lift(module, &core_name, export_name, func, ty)?; | 
|---|
| 687 | self.component | 
|---|
| 688 | .export(&export_string, ComponentExportKind::Func, idx, None); | 
|---|
| 689 | } | 
|---|
| 690 | WorldItem::Interface { id, .. } => { | 
|---|
| 691 | let core_names = interface_func_core_names.get(id); | 
|---|
| 692 | self.encode_interface_export( | 
|---|
| 693 | &export_string, | 
|---|
| 694 | module, | 
|---|
| 695 | export_name, | 
|---|
| 696 | *id, | 
|---|
| 697 | core_names, | 
|---|
| 698 | )?; | 
|---|
| 699 | } | 
|---|
| 700 | WorldItem::Type(_) => unreachable!(), | 
|---|
| 701 | } | 
|---|
| 702 | } | 
|---|
| 703 |  | 
|---|
| 704 | Ok(()) | 
|---|
| 705 | } | 
|---|
| 706 |  | 
|---|
| 707 | fn encode_interface_export( | 
|---|
| 708 | &mut self, | 
|---|
| 709 | export_name: &str, | 
|---|
| 710 | module: CustomModule<'_>, | 
|---|
| 711 | key: &WorldKey, | 
|---|
| 712 | export: InterfaceId, | 
|---|
| 713 | interface_func_core_names: Option<&IndexMap<&str, &str>>, | 
|---|
| 714 | ) -> Result<()> { | 
|---|
| 715 | log::trace!( "encode interface export `{export_name} `"); | 
|---|
| 716 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 717 |  | 
|---|
| 718 | // First execute a `canon lift` for all the functions in this interface | 
|---|
| 719 | // from the core wasm export. This requires type information but notably | 
|---|
| 720 | // not exported type information since we don't want to export this | 
|---|
| 721 | // interface's types from the root of the component. Each lifted | 
|---|
| 722 | // function is saved off into an `imports` array to get imported into | 
|---|
| 723 | // the nested component synthesized below. | 
|---|
| 724 | let mut imports = Vec::new(); | 
|---|
| 725 | let mut root = self.root_export_type_encoder(Some(export)); | 
|---|
| 726 | for (_, func) in &resolve.interfaces[export].functions { | 
|---|
| 727 | let core_name = interface_func_core_names.unwrap()[func.name.as_str()]; | 
|---|
| 728 | let ty = root.encode_func_type(resolve, func)?; | 
|---|
| 729 | let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?; | 
|---|
| 730 | imports.push(( | 
|---|
| 731 | import_func_name(func), | 
|---|
| 732 | ComponentExportKind::Func, | 
|---|
| 733 | func_index, | 
|---|
| 734 | )); | 
|---|
| 735 | } | 
|---|
| 736 |  | 
|---|
| 737 | // Next a nested component is created which will import the functions | 
|---|
| 738 | // above and then reexport them. The purpose of them is to "re-type" the | 
|---|
| 739 | // functions through type ascription on each `func` item. | 
|---|
| 740 | let mut nested = NestedComponentTypeEncoder { | 
|---|
| 741 | component: ComponentBuilder::default(), | 
|---|
| 742 | type_map: Default::default(), | 
|---|
| 743 | func_type_map: Default::default(), | 
|---|
| 744 | export_types: false, | 
|---|
| 745 | interface: export, | 
|---|
| 746 | state: self, | 
|---|
| 747 | imports: IndexMap::new(), | 
|---|
| 748 | }; | 
|---|
| 749 |  | 
|---|
| 750 | // Import all transitively-referenced types from other interfaces into | 
|---|
| 751 | // this component. This temporarily switches the `interface` listed to | 
|---|
| 752 | // the interface of the referred-to-type to generate the import. After | 
|---|
| 753 | // this loop `interface` is rewritten to `export`. | 
|---|
| 754 | // | 
|---|
| 755 | // Each component is a standalone "island" so the necessary type | 
|---|
| 756 | // information needs to be rebuilt within this component. This ensures | 
|---|
| 757 | // that we're able to build a valid component and additionally connect | 
|---|
| 758 | // all the type information to the outer context. | 
|---|
| 759 | let mut types_to_import = LiveTypes::default(); | 
|---|
| 760 | types_to_import.add_interface(resolve, export); | 
|---|
| 761 | let exports_used = &nested.state.info.exports_used[&export]; | 
|---|
| 762 | for ty in types_to_import.iter() { | 
|---|
| 763 | if let TypeOwner::Interface(owner) = resolve.types[ty].owner { | 
|---|
| 764 | if owner == export { | 
|---|
| 765 | // Here this deals with the current exported interface which | 
|---|
| 766 | // is handled below. | 
|---|
| 767 | continue; | 
|---|
| 768 | } | 
|---|
| 769 |  | 
|---|
| 770 | // Ensure that `self` has encoded this type before. If so this | 
|---|
| 771 | // is a noop but otherwise it generates the type here. | 
|---|
| 772 | let mut encoder = if exports_used.contains(&owner) { | 
|---|
| 773 | nested.state.root_export_type_encoder(Some(export)) | 
|---|
| 774 | } else { | 
|---|
| 775 | nested.state.root_import_type_encoder(Some(export)) | 
|---|
| 776 | }; | 
|---|
| 777 | encoder.encode_valtype(resolve, &Type::Id(ty))?; | 
|---|
| 778 |  | 
|---|
| 779 | // Next generate the same type but this time within the | 
|---|
| 780 | // component itself. The type generated above (or prior) will be | 
|---|
| 781 | // used to satisfy this type import. | 
|---|
| 782 | nested.interface = owner; | 
|---|
| 783 | nested.encode_valtype(resolve, &Type::Id(ty))?; | 
|---|
| 784 | } | 
|---|
| 785 | } | 
|---|
| 786 | nested.interface = export; | 
|---|
| 787 |  | 
|---|
| 788 | // Record the map of types imported to their index at where they were | 
|---|
| 789 | // imported. This is used after imports are encoded as exported types | 
|---|
| 790 | // will refer to these. | 
|---|
| 791 | let imported_types = nested.type_map.clone(); | 
|---|
| 792 |  | 
|---|
| 793 | // Handle resource types for this instance specially, namely importing | 
|---|
| 794 | // them into the nested component. This models how the resource is | 
|---|
| 795 | // imported from its definition in the outer component to get reexported | 
|---|
| 796 | // internally. This chiefly avoids creating a second resource which is | 
|---|
| 797 | // not desired in this situation. | 
|---|
| 798 | let mut resources = HashMap::new(); | 
|---|
| 799 | for (_name, ty) in resolve.interfaces[export].types.iter() { | 
|---|
| 800 | if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) { | 
|---|
| 801 | continue; | 
|---|
| 802 | } | 
|---|
| 803 | let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? { | 
|---|
| 804 | ComponentValType::Type(idx) => idx, | 
|---|
| 805 | _ => unreachable!(), | 
|---|
| 806 | }; | 
|---|
| 807 | resources.insert(*ty, idx); | 
|---|
| 808 | } | 
|---|
| 809 |  | 
|---|
| 810 | // Next import each function of this interface. This will end up | 
|---|
| 811 | // defining local types as necessary or using the types as imported | 
|---|
| 812 | // above. | 
|---|
| 813 | for (_, func) in resolve.interfaces[export].functions.iter() { | 
|---|
| 814 | let ty = nested.encode_func_type(resolve, func)?; | 
|---|
| 815 | nested | 
|---|
| 816 | .component | 
|---|
| 817 | .import(&import_func_name(func), ComponentTypeRef::Func(ty)); | 
|---|
| 818 | } | 
|---|
| 819 |  | 
|---|
| 820 | // Swap the `nested.type_map` which was previously from `TypeId` to | 
|---|
| 821 | // `u32` to instead being from `u32` to `TypeId`. This reverse map is | 
|---|
| 822 | // then used in conjunction with `self.type_map` to satisfy all type | 
|---|
| 823 | // imports of the nested component generated. The type import's index in | 
|---|
| 824 | // the inner component is translated to a `TypeId` via `reverse_map` | 
|---|
| 825 | // which is then translated back to our own index space via `type_map`. | 
|---|
| 826 | let reverse_map = nested | 
|---|
| 827 | .type_map | 
|---|
| 828 | .drain() | 
|---|
| 829 | .map(|p| (p.1, p.0)) | 
|---|
| 830 | .collect::<HashMap<_, _>>(); | 
|---|
| 831 | for (name, idx) in nested.imports.drain(..) { | 
|---|
| 832 | let id = reverse_map[&idx]; | 
|---|
| 833 | let owner = match resolve.types[id].owner { | 
|---|
| 834 | TypeOwner::Interface(id) => id, | 
|---|
| 835 | _ => unreachable!(), | 
|---|
| 836 | }; | 
|---|
| 837 | let idx = if owner == export || exports_used.contains(&owner) { | 
|---|
| 838 | log::trace!( "consulting exports for {id:?} "); | 
|---|
| 839 | nested.state.export_type_map[&id] | 
|---|
| 840 | } else { | 
|---|
| 841 | log::trace!( "consulting imports for {id:?} "); | 
|---|
| 842 | nested.state.import_type_map[&id] | 
|---|
| 843 | }; | 
|---|
| 844 | imports.push((name, ComponentExportKind::Type, idx)) | 
|---|
| 845 | } | 
|---|
| 846 |  | 
|---|
| 847 | // Before encoding exports reset the type map to what all was imported | 
|---|
| 848 | // from foreign interfaces. This will enable any encoded types below to | 
|---|
| 849 | // refer to imports which, after type substitution, will point to the | 
|---|
| 850 | // correct type in the outer component context. | 
|---|
| 851 | nested.type_map = imported_types; | 
|---|
| 852 |  | 
|---|
| 853 | // Next the component reexports all of its imports, but notably uses the | 
|---|
| 854 | // type ascription feature to change the type of the function. Note that | 
|---|
| 855 | // no structural change is happening to the types here but instead types | 
|---|
| 856 | // are getting proper names and such now that this nested component is a | 
|---|
| 857 | // new type index space. Hence the `export_types = true` flag here which | 
|---|
| 858 | // flows through the type encoding and when types are emitted. | 
|---|
| 859 | nested.export_types = true; | 
|---|
| 860 | nested.func_type_map.clear(); | 
|---|
| 861 |  | 
|---|
| 862 | // To start off all type information is encoded. This will be used by | 
|---|
| 863 | // functions below but notably this also has special handling for | 
|---|
| 864 | // resources. Resources reexport their imported resource type under | 
|---|
| 865 | // the final name which achieves the desired goal of threading through | 
|---|
| 866 | // the original resource without creating a new one. | 
|---|
| 867 | for (_, id) in resolve.interfaces[export].types.iter() { | 
|---|
| 868 | let ty = &resolve.types[*id]; | 
|---|
| 869 | match ty.kind { | 
|---|
| 870 | TypeDefKind::Resource => { | 
|---|
| 871 | let idx = nested.component.export( | 
|---|
| 872 | ty.name.as_ref().expect( "resources must be named"), | 
|---|
| 873 | ComponentExportKind::Type, | 
|---|
| 874 | resources[id], | 
|---|
| 875 | None, | 
|---|
| 876 | ); | 
|---|
| 877 | nested.type_map.insert(*id, idx); | 
|---|
| 878 | } | 
|---|
| 879 | _ => { | 
|---|
| 880 | nested.encode_valtype(resolve, &Type::Id(*id))?; | 
|---|
| 881 | } | 
|---|
| 882 | } | 
|---|
| 883 | } | 
|---|
| 884 |  | 
|---|
| 885 | for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() { | 
|---|
| 886 | let ty = nested.encode_func_type(resolve, func)?; | 
|---|
| 887 | nested.component.export( | 
|---|
| 888 | &func.name, | 
|---|
| 889 | ComponentExportKind::Func, | 
|---|
| 890 | i as u32, | 
|---|
| 891 | Some(ComponentTypeRef::Func(ty)), | 
|---|
| 892 | ); | 
|---|
| 893 | } | 
|---|
| 894 |  | 
|---|
| 895 | // Embed the component within our component and then instantiate it with | 
|---|
| 896 | // the lifted functions. That final instance is then exported under the | 
|---|
| 897 | // appropriate name as the final typed export of this component. | 
|---|
| 898 | let component = nested.component; | 
|---|
| 899 | let component_index = self.component.component(component); | 
|---|
| 900 | let instance_index = self.component.instantiate(component_index, imports); | 
|---|
| 901 | let idx = self.component.export( | 
|---|
| 902 | export_name, | 
|---|
| 903 | ComponentExportKind::Instance, | 
|---|
| 904 | instance_index, | 
|---|
| 905 | None, | 
|---|
| 906 | ); | 
|---|
| 907 | let prev = self.exported_instances.insert(export, idx); | 
|---|
| 908 | assert!(prev.is_none()); | 
|---|
| 909 |  | 
|---|
| 910 | // After everything is all said and done remove all the type information | 
|---|
| 911 | // about type exports of this interface. Any entries in the map | 
|---|
| 912 | // currently were used to create the instance above but aren't the | 
|---|
| 913 | // actual copy of the exported type since that comes from the exported | 
|---|
| 914 | // instance itself. Entries will be re-inserted into this map as | 
|---|
| 915 | // necessary via aliases from the exported instance which is the new | 
|---|
| 916 | // source of truth for all these types. | 
|---|
| 917 | for (_name, id) in resolve.interfaces[export].types.iter() { | 
|---|
| 918 | self.export_type_map.remove(id); | 
|---|
| 919 | } | 
|---|
| 920 |  | 
|---|
| 921 | return Ok(()); | 
|---|
| 922 |  | 
|---|
| 923 | struct NestedComponentTypeEncoder<'state, 'a> { | 
|---|
| 924 | component: ComponentBuilder, | 
|---|
| 925 | type_map: HashMap<TypeId, u32>, | 
|---|
| 926 | func_type_map: HashMap<types::FunctionKey<'a>, u32>, | 
|---|
| 927 | export_types: bool, | 
|---|
| 928 | interface: InterfaceId, | 
|---|
| 929 | state: &'state mut EncodingState<'a>, | 
|---|
| 930 | imports: IndexMap<String, u32>, | 
|---|
| 931 | } | 
|---|
| 932 |  | 
|---|
| 933 | impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> { | 
|---|
| 934 | fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { | 
|---|
| 935 | self.component.type_defined() | 
|---|
| 936 | } | 
|---|
| 937 | fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { | 
|---|
| 938 | self.component.type_function() | 
|---|
| 939 | } | 
|---|
| 940 | fn export_type(&mut self, idx: u32, name: &'a str) -> Option<u32> { | 
|---|
| 941 | if self.export_types { | 
|---|
| 942 | Some( | 
|---|
| 943 | self.component | 
|---|
| 944 | .export(name, ComponentExportKind::Type, idx, None), | 
|---|
| 945 | ) | 
|---|
| 946 | } else { | 
|---|
| 947 | let name = self.unique_import_name(name); | 
|---|
| 948 | let ret = self | 
|---|
| 949 | .component | 
|---|
| 950 | .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx))); | 
|---|
| 951 | self.imports.insert(name, ret); | 
|---|
| 952 | Some(ret) | 
|---|
| 953 | } | 
|---|
| 954 | } | 
|---|
| 955 | fn export_resource(&mut self, name: &'a str) -> u32 { | 
|---|
| 956 | if self.export_types { | 
|---|
| 957 | panic!( "resources should already be exported") | 
|---|
| 958 | } else { | 
|---|
| 959 | let name = self.unique_import_name(name); | 
|---|
| 960 | let ret = self | 
|---|
| 961 | .component | 
|---|
| 962 | .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource)); | 
|---|
| 963 | self.imports.insert(name, ret); | 
|---|
| 964 | ret | 
|---|
| 965 | } | 
|---|
| 966 | } | 
|---|
| 967 | fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 { | 
|---|
| 968 | unreachable!() | 
|---|
| 969 | } | 
|---|
| 970 | fn type_map(&mut self) -> &mut HashMap<TypeId, u32> { | 
|---|
| 971 | &mut self.type_map | 
|---|
| 972 | } | 
|---|
| 973 | fn func_type_map(&mut self) -> &mut HashMap<types::FunctionKey<'a>, u32> { | 
|---|
| 974 | &mut self.func_type_map | 
|---|
| 975 | } | 
|---|
| 976 | fn interface(&self) -> Option<InterfaceId> { | 
|---|
| 977 | Some(self.interface) | 
|---|
| 978 | } | 
|---|
| 979 | } | 
|---|
| 980 |  | 
|---|
| 981 | impl NestedComponentTypeEncoder<'_, '_> { | 
|---|
| 982 | fn unique_import_name(&mut self, name: &str) -> String { | 
|---|
| 983 | let mut name = format!( "import-type-{name} "); | 
|---|
| 984 | let mut n = 0; | 
|---|
| 985 | while self.imports.contains_key(&name) { | 
|---|
| 986 | name = format!( "{name}{n} "); | 
|---|
| 987 | n += 1; | 
|---|
| 988 | } | 
|---|
| 989 | name | 
|---|
| 990 | } | 
|---|
| 991 | } | 
|---|
| 992 |  | 
|---|
| 993 | fn import_func_name(f: &Function) -> String { | 
|---|
| 994 | match f.kind { | 
|---|
| 995 | FunctionKind::Freestanding => { | 
|---|
| 996 | format!( "import-func-{} ", f.name) | 
|---|
| 997 | } | 
|---|
| 998 |  | 
|---|
| 999 | // transform `[method]foo.bar` into `import-method-foo-bar` to | 
|---|
| 1000 | // have it be a valid kebab-name which can't conflict with | 
|---|
| 1001 | // anything else. | 
|---|
| 1002 | // | 
|---|
| 1003 | // There's probably a better and more "formal" way to do this | 
|---|
| 1004 | // but quick-and-dirty string manipulation should work well | 
|---|
| 1005 | // enough for now hopefully. | 
|---|
| 1006 | FunctionKind::Method(_) | 
|---|
| 1007 | | FunctionKind::Static(_) | 
|---|
| 1008 | | FunctionKind::Constructor(_) => { | 
|---|
| 1009 | format!( | 
|---|
| 1010 | "import-{} ", | 
|---|
| 1011 | f.name.replace( '[', "").replace([ ']', '.'], "-") | 
|---|
| 1012 | ) | 
|---|
| 1013 | } | 
|---|
| 1014 | } | 
|---|
| 1015 | } | 
|---|
| 1016 | } | 
|---|
| 1017 |  | 
|---|
| 1018 | fn encode_lift( | 
|---|
| 1019 | &mut self, | 
|---|
| 1020 | module: CustomModule<'_>, | 
|---|
| 1021 | core_name: &str, | 
|---|
| 1022 | key: &WorldKey, | 
|---|
| 1023 | func: &Function, | 
|---|
| 1024 | ty: u32, | 
|---|
| 1025 | ) -> Result<u32> { | 
|---|
| 1026 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 1027 | let metadata = self.info.module_metadata_for(module); | 
|---|
| 1028 | let instance_index = self.instance_for(module); | 
|---|
| 1029 | let core_func_index = self.core_alias_export(instance_index, core_name, ExportKind::Func); | 
|---|
| 1030 | let exports = self.info.exports_for(module); | 
|---|
| 1031 |  | 
|---|
| 1032 | let options = RequiredOptions::for_export( | 
|---|
| 1033 | resolve, | 
|---|
| 1034 | func, | 
|---|
| 1035 | exports | 
|---|
| 1036 | .abi(key, func) | 
|---|
| 1037 | .ok_or_else(|| anyhow!( "no ABI found for {} ", func.name))?, | 
|---|
| 1038 | ); | 
|---|
| 1039 |  | 
|---|
| 1040 | let encoding = metadata | 
|---|
| 1041 | .export_encodings | 
|---|
| 1042 | .get(resolve, key, &func.name) | 
|---|
| 1043 | .unwrap(); | 
|---|
| 1044 | let exports = self.info.exports_for(module); | 
|---|
| 1045 | let realloc_index = exports | 
|---|
| 1046 | .export_realloc_for(key, func) | 
|---|
| 1047 | .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func)); | 
|---|
| 1048 | let mut options = options | 
|---|
| 1049 | .into_iter(encoding, self.memory_index, realloc_index)? | 
|---|
| 1050 | .collect::<Vec<_>>(); | 
|---|
| 1051 |  | 
|---|
| 1052 | if let Some(post_return) = exports.post_return(key, func) { | 
|---|
| 1053 | let post_return = self.core_alias_export(instance_index, post_return, ExportKind::Func); | 
|---|
| 1054 | options.push(CanonicalOption::PostReturn(post_return)); | 
|---|
| 1055 | } | 
|---|
| 1056 | if let Some(callback) = exports.callback(key, func) { | 
|---|
| 1057 | let callback = self.core_alias_export(instance_index, callback, ExportKind::Func); | 
|---|
| 1058 | options.push(CanonicalOption::Callback(callback)); | 
|---|
| 1059 | } | 
|---|
| 1060 | let func_index = self.component.lift_func(core_func_index, ty, options); | 
|---|
| 1061 | Ok(func_index) | 
|---|
| 1062 | } | 
|---|
| 1063 |  | 
|---|
| 1064 | fn encode_shim_instantiation(&mut self) -> Result<Shims<'a>> { | 
|---|
| 1065 | let mut ret = Shims::default(); | 
|---|
| 1066 |  | 
|---|
| 1067 | ret.append_indirect(self.info, CustomModule::Main) | 
|---|
| 1068 | .context( "failed to register indirect shims for main module")?; | 
|---|
| 1069 |  | 
|---|
| 1070 | // For all required adapter modules a shim is created for each required | 
|---|
| 1071 | // function and additionally a set of shims are created for the | 
|---|
| 1072 | // interface imported into the shim module itself. | 
|---|
| 1073 | for (adapter_name, _adapter) in self.info.adapters.iter() { | 
|---|
| 1074 | ret.append_indirect(self.info, CustomModule::Adapter(adapter_name)) | 
|---|
| 1075 | .with_context(|| { | 
|---|
| 1076 | format!( "failed to register indirect shims for adapter {adapter_name} ") | 
|---|
| 1077 | })?; | 
|---|
| 1078 | } | 
|---|
| 1079 |  | 
|---|
| 1080 | if ret.shims.is_empty() { | 
|---|
| 1081 | return Ok(ret); | 
|---|
| 1082 | } | 
|---|
| 1083 |  | 
|---|
| 1084 | assert!(self.shim_instance_index.is_none()); | 
|---|
| 1085 | assert!(self.fixups_module_index.is_none()); | 
|---|
| 1086 |  | 
|---|
| 1087 | // This function encodes two modules: | 
|---|
| 1088 | // - A shim module that defines a table and exports functions | 
|---|
| 1089 | //   that indirectly call through the table. | 
|---|
| 1090 | // - A fixup module that imports that table and a set of functions | 
|---|
| 1091 | //   and populates the imported table via active element segments. The | 
|---|
| 1092 | //   fixup module is used to populate the shim's table once the | 
|---|
| 1093 | //   imported functions have been lowered. | 
|---|
| 1094 |  | 
|---|
| 1095 | let mut types = TypeSection::new(); | 
|---|
| 1096 | let mut tables = TableSection::new(); | 
|---|
| 1097 | let mut functions = FunctionSection::new(); | 
|---|
| 1098 | let mut exports = ExportSection::new(); | 
|---|
| 1099 | let mut code = CodeSection::new(); | 
|---|
| 1100 | let mut sigs = IndexMap::new(); | 
|---|
| 1101 | let mut imports_section = ImportSection::new(); | 
|---|
| 1102 | let mut elements = ElementSection::new(); | 
|---|
| 1103 | let mut func_indexes = Vec::new(); | 
|---|
| 1104 | let mut func_names = NameMap::new(); | 
|---|
| 1105 |  | 
|---|
| 1106 | for (i, shim) in ret.shims.values().enumerate() { | 
|---|
| 1107 | let i = i as u32; | 
|---|
| 1108 | let type_index = *sigs.entry(&shim.sig).or_insert_with(|| { | 
|---|
| 1109 | let index = types.len(); | 
|---|
| 1110 | types.ty().function( | 
|---|
| 1111 | shim.sig.params.iter().map(to_val_type), | 
|---|
| 1112 | shim.sig.results.iter().map(to_val_type), | 
|---|
| 1113 | ); | 
|---|
| 1114 | index | 
|---|
| 1115 | }); | 
|---|
| 1116 |  | 
|---|
| 1117 | functions.function(type_index); | 
|---|
| 1118 | Self::encode_shim_function(type_index, i, &mut code, shim.sig.params.len() as u32); | 
|---|
| 1119 | exports.export(&shim.name, ExportKind::Func, i); | 
|---|
| 1120 |  | 
|---|
| 1121 | imports_section.import( "", &shim.name, EntityType::Function(type_index)); | 
|---|
| 1122 | func_indexes.push(i); | 
|---|
| 1123 | func_names.append(i, &shim.debug_name); | 
|---|
| 1124 | } | 
|---|
| 1125 | let mut names = NameSection::new(); | 
|---|
| 1126 | names.module( "wit-component:shim"); | 
|---|
| 1127 | names.functions(&func_names); | 
|---|
| 1128 |  | 
|---|
| 1129 | let table_type = TableType { | 
|---|
| 1130 | element_type: RefType::FUNCREF, | 
|---|
| 1131 | minimum: ret.shims.len() as u64, | 
|---|
| 1132 | maximum: Some(ret.shims.len() as u64), | 
|---|
| 1133 | table64: false, | 
|---|
| 1134 | shared: false, | 
|---|
| 1135 | }; | 
|---|
| 1136 |  | 
|---|
| 1137 | tables.table(table_type); | 
|---|
| 1138 |  | 
|---|
| 1139 | exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0); | 
|---|
| 1140 | imports_section.import( "", INDIRECT_TABLE_NAME, table_type); | 
|---|
| 1141 |  | 
|---|
| 1142 | elements.active( | 
|---|
| 1143 | None, | 
|---|
| 1144 | &ConstExpr::i32_const(0), | 
|---|
| 1145 | Elements::Functions(func_indexes.into()), | 
|---|
| 1146 | ); | 
|---|
| 1147 |  | 
|---|
| 1148 | let mut shim = Module::new(); | 
|---|
| 1149 | shim.section(&types); | 
|---|
| 1150 | shim.section(&functions); | 
|---|
| 1151 | shim.section(&tables); | 
|---|
| 1152 | shim.section(&exports); | 
|---|
| 1153 | shim.section(&code); | 
|---|
| 1154 | shim.section(&RawCustomSection( | 
|---|
| 1155 | &crate::base_producers().raw_custom_section(), | 
|---|
| 1156 | )); | 
|---|
| 1157 | shim.section(&names); | 
|---|
| 1158 |  | 
|---|
| 1159 | let mut fixups = Module::default(); | 
|---|
| 1160 | fixups.section(&types); | 
|---|
| 1161 | fixups.section(&imports_section); | 
|---|
| 1162 | fixups.section(&elements); | 
|---|
| 1163 | fixups.section(&RawCustomSection( | 
|---|
| 1164 | &crate::base_producers().raw_custom_section(), | 
|---|
| 1165 | )); | 
|---|
| 1166 |  | 
|---|
| 1167 | let mut names = NameSection::new(); | 
|---|
| 1168 | names.module( "wit-component:fixups"); | 
|---|
| 1169 | fixups.section(&names); | 
|---|
| 1170 |  | 
|---|
| 1171 | let shim_module_index = self.component.core_module(&shim); | 
|---|
| 1172 | self.fixups_module_index = Some(self.component.core_module(&fixups)); | 
|---|
| 1173 | self.shim_instance_index = Some(self.component.core_instantiate(shim_module_index, [])); | 
|---|
| 1174 |  | 
|---|
| 1175 | return Ok(ret); | 
|---|
| 1176 | } | 
|---|
| 1177 |  | 
|---|
| 1178 | fn encode_shim_function( | 
|---|
| 1179 | type_index: u32, | 
|---|
| 1180 | func_index: u32, | 
|---|
| 1181 | code: &mut CodeSection, | 
|---|
| 1182 | param_count: u32, | 
|---|
| 1183 | ) { | 
|---|
| 1184 | let mut func = wasm_encoder::Function::new(std::iter::empty()); | 
|---|
| 1185 | for i in 0..param_count { | 
|---|
| 1186 | func.instruction(&Instruction::LocalGet(i)); | 
|---|
| 1187 | } | 
|---|
| 1188 | func.instruction(&Instruction::I32Const(func_index as i32)); | 
|---|
| 1189 | func.instruction(&Instruction::CallIndirect { | 
|---|
| 1190 | type_index, | 
|---|
| 1191 | table_index: 0, | 
|---|
| 1192 | }); | 
|---|
| 1193 | func.instruction(&Instruction::End); | 
|---|
| 1194 | code.function(&func); | 
|---|
| 1195 | } | 
|---|
| 1196 |  | 
|---|
| 1197 | fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> { | 
|---|
| 1198 | if shims.shims.is_empty() { | 
|---|
| 1199 | return Ok(()); | 
|---|
| 1200 | } | 
|---|
| 1201 |  | 
|---|
| 1202 | let shim_instance_index = self | 
|---|
| 1203 | .shim_instance_index | 
|---|
| 1204 | .expect( "must have an instantiated shim"); | 
|---|
| 1205 |  | 
|---|
| 1206 | let table_index = | 
|---|
| 1207 | self.core_alias_export(shim_instance_index, INDIRECT_TABLE_NAME, ExportKind::Table); | 
|---|
| 1208 |  | 
|---|
| 1209 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 1210 |  | 
|---|
| 1211 | let mut exports = Vec::new(); | 
|---|
| 1212 | exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index)); | 
|---|
| 1213 |  | 
|---|
| 1214 | for shim in shims.shims.values() { | 
|---|
| 1215 | let core_func_index = match &shim.kind { | 
|---|
| 1216 | // Indirect lowerings are a `canon lower`'d function with | 
|---|
| 1217 | // options specified from a previously instantiated instance. | 
|---|
| 1218 | // This previous instance could either be the main module or an | 
|---|
| 1219 | // adapter module, which affects the `realloc` option here. | 
|---|
| 1220 | // Currently only one linear memory is supported so the linear | 
|---|
| 1221 | // memory always comes from the main module. | 
|---|
| 1222 | ShimKind::IndirectLowering { | 
|---|
| 1223 | interface, | 
|---|
| 1224 | index, | 
|---|
| 1225 | realloc, | 
|---|
| 1226 | encoding, | 
|---|
| 1227 | } => { | 
|---|
| 1228 | let interface = &self.info.import_map[interface]; | 
|---|
| 1229 | let ((name, _), _) = interface.lowerings.get_index(*index).unwrap(); | 
|---|
| 1230 | let func_index = match &interface.interface { | 
|---|
| 1231 | Some(interface_id) => { | 
|---|
| 1232 | let instance_index = self.imported_instances[interface_id]; | 
|---|
| 1233 | self.component.alias_export( | 
|---|
| 1234 | instance_index, | 
|---|
| 1235 | name, | 
|---|
| 1236 | ComponentExportKind::Func, | 
|---|
| 1237 | ) | 
|---|
| 1238 | } | 
|---|
| 1239 | None => self.imported_funcs[name], | 
|---|
| 1240 | }; | 
|---|
| 1241 |  | 
|---|
| 1242 | let realloc = self | 
|---|
| 1243 | .info | 
|---|
| 1244 | .exports_for(*realloc) | 
|---|
| 1245 | .import_realloc_for(interface.interface, name) | 
|---|
| 1246 | .map(|name| { | 
|---|
| 1247 | let instance = self.instance_for(*realloc); | 
|---|
| 1248 | self.core_alias_export(instance, name, ExportKind::Func) | 
|---|
| 1249 | }); | 
|---|
| 1250 |  | 
|---|
| 1251 | self.component.lower_func( | 
|---|
| 1252 | func_index, | 
|---|
| 1253 | shim.options | 
|---|
| 1254 | .into_iter(*encoding, self.memory_index, realloc)?, | 
|---|
| 1255 | ) | 
|---|
| 1256 | } | 
|---|
| 1257 |  | 
|---|
| 1258 | // Adapter shims are defined by an export from an adapter | 
|---|
| 1259 | // instance, so use the specified name here and the previously | 
|---|
| 1260 | // created instances to get the core item that represents the | 
|---|
| 1261 | // shim. | 
|---|
| 1262 | ShimKind::Adapter { adapter, func } => { | 
|---|
| 1263 | self.core_alias_export(self.adapter_instances[adapter], func, ExportKind::Func) | 
|---|
| 1264 | } | 
|---|
| 1265 |  | 
|---|
| 1266 | // Resources are required for a module to be instantiated | 
|---|
| 1267 | // meaning that any destructor for the resource must be called | 
|---|
| 1268 | // indirectly due to the otherwise circular dependency between | 
|---|
| 1269 | // the module and the resource itself. | 
|---|
| 1270 | ShimKind::ResourceDtor { module, export } => { | 
|---|
| 1271 | self.core_alias_export(self.instance_for(*module), export, ExportKind::Func) | 
|---|
| 1272 | } | 
|---|
| 1273 |  | 
|---|
| 1274 | ShimKind::PayloadFunc { | 
|---|
| 1275 | for_module, | 
|---|
| 1276 | async_, | 
|---|
| 1277 | info, | 
|---|
| 1278 | kind, | 
|---|
| 1279 | } => { | 
|---|
| 1280 | let metadata = self.info.module_metadata_for(*for_module); | 
|---|
| 1281 | let exports = self.info.exports_for(*for_module); | 
|---|
| 1282 | let instance_index = self.instance_for(*for_module); | 
|---|
| 1283 | let (encoding, realloc) = if info.imported { | 
|---|
| 1284 | ( | 
|---|
| 1285 | metadata | 
|---|
| 1286 | .import_encodings | 
|---|
| 1287 | .get(resolve, &info.key, &info.function.name), | 
|---|
| 1288 | exports.import_realloc_for(info.interface, &info.function.name), | 
|---|
| 1289 | ) | 
|---|
| 1290 | } else { | 
|---|
| 1291 | ( | 
|---|
| 1292 | metadata | 
|---|
| 1293 | .export_encodings | 
|---|
| 1294 | .get(resolve, &info.key, &info.function.name), | 
|---|
| 1295 | exports.export_realloc_for(&info.key, &info.function), | 
|---|
| 1296 | ) | 
|---|
| 1297 | }; | 
|---|
| 1298 | let encoding = encoding.unwrap_or(StringEncoding::UTF8); | 
|---|
| 1299 | let realloc_index = realloc | 
|---|
| 1300 | .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func)); | 
|---|
| 1301 | let options = |me: &mut Self, params: Vec<Type>, results: Vec<Type>| { | 
|---|
| 1302 | Ok::<_, anyhow::Error>( | 
|---|
| 1303 | (RequiredOptions::for_import( | 
|---|
| 1304 | resolve, | 
|---|
| 1305 | &Function { | 
|---|
| 1306 | name: String::new(), | 
|---|
| 1307 | kind: FunctionKind::Freestanding, | 
|---|
| 1308 | params: params | 
|---|
| 1309 | .into_iter() | 
|---|
| 1310 | .enumerate() | 
|---|
| 1311 | .map(|(i, v)| (format!( "a{i} "), v)) | 
|---|
| 1312 | .collect(), | 
|---|
| 1313 | results: match &results[..] { | 
|---|
| 1314 | [] => Results::Named(Vec::new()), | 
|---|
| 1315 | [ty] => Results::Anon(*ty), | 
|---|
| 1316 | _ => unreachable!(), | 
|---|
| 1317 | }, | 
|---|
| 1318 | docs: Default::default(), | 
|---|
| 1319 | stability: Stability::Unknown, | 
|---|
| 1320 | }, | 
|---|
| 1321 | if *async_ { | 
|---|
| 1322 | AbiVariant::GuestImportAsync | 
|---|
| 1323 | } else { | 
|---|
| 1324 | AbiVariant::GuestImport | 
|---|
| 1325 | }, | 
|---|
| 1326 | ) | RequiredOptions::MEMORY) | 
|---|
| 1327 | .into_iter(encoding, me.memory_index, realloc_index)? | 
|---|
| 1328 | .collect::<Vec<_>>(), | 
|---|
| 1329 | ) | 
|---|
| 1330 | }; | 
|---|
| 1331 | let type_index = self.payload_type_index(info.ty, info.imported)?; | 
|---|
| 1332 |  | 
|---|
| 1333 | match kind { | 
|---|
| 1334 | PayloadFuncKind::FutureWrite => { | 
|---|
| 1335 | let TypeDefKind::Future(payload_type) = &resolve.types[info.ty].kind | 
|---|
| 1336 | else { | 
|---|
| 1337 | unreachable!() | 
|---|
| 1338 | }; | 
|---|
| 1339 | let options = options( | 
|---|
| 1340 | self, | 
|---|
| 1341 | if let Some(payload_type) = payload_type { | 
|---|
| 1342 | vec![*payload_type] | 
|---|
| 1343 | } else { | 
|---|
| 1344 | vec![] | 
|---|
| 1345 | }, | 
|---|
| 1346 | vec![], | 
|---|
| 1347 | )?; | 
|---|
| 1348 | self.component.future_write(type_index, options) | 
|---|
| 1349 | } | 
|---|
| 1350 | PayloadFuncKind::FutureRead => { | 
|---|
| 1351 | let TypeDefKind::Future(payload_type) = &resolve.types[info.ty].kind | 
|---|
| 1352 | else { | 
|---|
| 1353 | unreachable!() | 
|---|
| 1354 | }; | 
|---|
| 1355 | let options = options( | 
|---|
| 1356 | self, | 
|---|
| 1357 | vec![], | 
|---|
| 1358 | if let Some(payload_type) = payload_type { | 
|---|
| 1359 | vec![*payload_type] | 
|---|
| 1360 | } else { | 
|---|
| 1361 | vec![] | 
|---|
| 1362 | }, | 
|---|
| 1363 | )?; | 
|---|
| 1364 | self.component.future_read(type_index, options) | 
|---|
| 1365 | } | 
|---|
| 1366 | PayloadFuncKind::StreamWrite => { | 
|---|
| 1367 | let TypeDefKind::Stream(payload_type) = &resolve.types[info.ty].kind | 
|---|
| 1368 | else { | 
|---|
| 1369 | unreachable!() | 
|---|
| 1370 | }; | 
|---|
| 1371 | let options = options(self, vec![*payload_type], vec![])?; | 
|---|
| 1372 | self.component.stream_write(type_index, options) | 
|---|
| 1373 | } | 
|---|
| 1374 | PayloadFuncKind::StreamRead => { | 
|---|
| 1375 | let TypeDefKind::Stream(payload_type) = &resolve.types[info.ty].kind | 
|---|
| 1376 | else { | 
|---|
| 1377 | unreachable!() | 
|---|
| 1378 | }; | 
|---|
| 1379 | let options = options(self, vec![], vec![*payload_type])?; | 
|---|
| 1380 | self.component.stream_read(type_index, options) | 
|---|
| 1381 | } | 
|---|
| 1382 | } | 
|---|
| 1383 | } | 
|---|
| 1384 |  | 
|---|
| 1385 | ShimKind::TaskWait { async_ } => self | 
|---|
| 1386 | .component | 
|---|
| 1387 | .task_wait(*async_, self.memory_index.unwrap()), | 
|---|
| 1388 | ShimKind::TaskPoll { async_ } => self | 
|---|
| 1389 | .component | 
|---|
| 1390 | .task_poll(*async_, self.memory_index.unwrap()), | 
|---|
| 1391 | ShimKind::ErrorContextNew { encoding } | 
|---|
| 1392 | | ShimKind::ErrorContextDebugMessage { encoding, .. } => match &shim.kind { | 
|---|
| 1393 | ShimKind::ErrorContextNew { .. } => self.component.error_context_new( | 
|---|
| 1394 | (RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING) | 
|---|
| 1395 | .into_iter(*encoding, self.memory_index, None)? | 
|---|
| 1396 | .collect::<Vec<_>>(), | 
|---|
| 1397 | ), | 
|---|
| 1398 | ShimKind::ErrorContextDebugMessage { | 
|---|
| 1399 | for_module, | 
|---|
| 1400 | realloc, | 
|---|
| 1401 | .. | 
|---|
| 1402 | } => { | 
|---|
| 1403 | let instance_index = self.instance_for(*for_module); | 
|---|
| 1404 | let realloc_index = | 
|---|
| 1405 | Some(self.core_alias_export(instance_index, realloc, ExportKind::Func)); | 
|---|
| 1406 |  | 
|---|
| 1407 | self.component.error_context_debug_message( | 
|---|
| 1408 | (RequiredOptions::MEMORY | 
|---|
| 1409 | | RequiredOptions::STRING_ENCODING | 
|---|
| 1410 | | RequiredOptions::REALLOC) | 
|---|
| 1411 | .into_iter(*encoding, self.memory_index, realloc_index)? | 
|---|
| 1412 | .collect::<Vec<_>>(), | 
|---|
| 1413 | ) | 
|---|
| 1414 | } | 
|---|
| 1415 | _ => unreachable!(), | 
|---|
| 1416 | }, | 
|---|
| 1417 | }; | 
|---|
| 1418 |  | 
|---|
| 1419 | exports.push((shim.name.as_str(), ExportKind::Func, core_func_index)); | 
|---|
| 1420 | } | 
|---|
| 1421 |  | 
|---|
| 1422 | let instance_index = self.component.core_instantiate_exports(exports); | 
|---|
| 1423 | self.component.core_instantiate( | 
|---|
| 1424 | self.fixups_module_index.expect( "must have fixup module"), | 
|---|
| 1425 | [( "", ModuleArg::Instance(instance_index))], | 
|---|
| 1426 | ); | 
|---|
| 1427 | Ok(()) | 
|---|
| 1428 | } | 
|---|
| 1429 |  | 
|---|
| 1430 | /// Encode the specified `stream` or `future` type in the component using | 
|---|
| 1431 | /// either the `root_import_type_encoder` or the `root_export_type_encoder` | 
|---|
| 1432 | /// depending on the value of `imported`. | 
|---|
| 1433 | /// | 
|---|
| 1434 | /// Note that the payload type `T` of `stream<T>` or `future<T>` may be an | 
|---|
| 1435 | /// imported or exported type, and that determines the appropriate type | 
|---|
| 1436 | /// encoder to use. | 
|---|
| 1437 | fn payload_type_index(&mut self, ty: TypeId, imported: bool) -> Result<u32> { | 
|---|
| 1438 | // `stream` and `future` types don't have owners, but their payload | 
|---|
| 1439 | // types (or the payload type of the payload type, etc. in the case of | 
|---|
| 1440 | // nesting) might have an owner, in which case we need to find that in | 
|---|
| 1441 | // order to make the types match up e.g. when we're exporting a resource | 
|---|
| 1442 | // that's used as a payload type. | 
|---|
| 1443 | fn owner(resolve: &Resolve, ty: TypeId) -> Option<InterfaceId> { | 
|---|
| 1444 | let def = &resolve.types[ty]; | 
|---|
| 1445 | match &def.kind { | 
|---|
| 1446 | TypeDefKind::Future(Some(Type::Id(ty))) => owner(resolve, *ty), | 
|---|
| 1447 | TypeDefKind::Stream(Type::Id(ty)) => owner(resolve, *ty), | 
|---|
| 1448 | _ => match &def.owner { | 
|---|
| 1449 | TypeOwner::World(_) | TypeOwner::None => None, | 
|---|
| 1450 | TypeOwner::Interface(id) => Some(*id), | 
|---|
| 1451 | }, | 
|---|
| 1452 | } | 
|---|
| 1453 | } | 
|---|
| 1454 |  | 
|---|
| 1455 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 1456 | let ComponentValType::Type(type_index) = if imported { | 
|---|
| 1457 | self.root_import_type_encoder(None) | 
|---|
| 1458 | } else { | 
|---|
| 1459 | let owner = owner(resolve, ty); | 
|---|
| 1460 | self.root_export_type_encoder(owner) | 
|---|
| 1461 | } | 
|---|
| 1462 | .encode_valtype(resolve, &Type::Id(ty))? | 
|---|
| 1463 | else { | 
|---|
| 1464 | unreachable!() | 
|---|
| 1465 | }; | 
|---|
| 1466 | Ok(type_index) | 
|---|
| 1467 | } | 
|---|
| 1468 |  | 
|---|
| 1469 | /// This is a helper function that will declare, in the component itself, | 
|---|
| 1470 | /// all exported resources. | 
|---|
| 1471 | /// | 
|---|
| 1472 | /// These resources later on get packaged up into instances and such. The | 
|---|
| 1473 | /// main thing that this handles is that it registers the right destructor | 
|---|
| 1474 | /// from `shims`, if needed, for each resource. | 
|---|
| 1475 | fn declare_exported_resources(&mut self, shims: &Shims<'_>) { | 
|---|
| 1476 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 1477 | let world = &resolve.worlds[self.info.encoder.metadata.world]; | 
|---|
| 1478 |  | 
|---|
| 1479 | // Iterate over the main module's exports and the exports of all | 
|---|
| 1480 | // adapters. Look for exported interfaces that themselves have | 
|---|
| 1481 | // resources. | 
|---|
| 1482 | let main_module_keys = self.info.encoder.main_module_exports.iter(); | 
|---|
| 1483 | let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key)); | 
|---|
| 1484 | let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| { | 
|---|
| 1485 | info.required_exports | 
|---|
| 1486 | .iter() | 
|---|
| 1487 | .map(move |key| (CustomModule::Adapter(name), key)) | 
|---|
| 1488 | }); | 
|---|
| 1489 | for (for_module, key) in main_module_keys.chain(adapter_keys) { | 
|---|
| 1490 | let id = match &world.exports[key] { | 
|---|
| 1491 | WorldItem::Interface { id, .. } => *id, | 
|---|
| 1492 | WorldItem::Type { .. } => unreachable!(), | 
|---|
| 1493 | WorldItem::Function(_) => continue, | 
|---|
| 1494 | }; | 
|---|
| 1495 |  | 
|---|
| 1496 | for ty in resolve.interfaces[id].types.values() { | 
|---|
| 1497 | match resolve.types[*ty].kind { | 
|---|
| 1498 | TypeDefKind::Resource => {} | 
|---|
| 1499 | _ => continue, | 
|---|
| 1500 | } | 
|---|
| 1501 |  | 
|---|
| 1502 | // Load the destructor, previously detected in module | 
|---|
| 1503 | // validation, if one is present. | 
|---|
| 1504 | let exports = self.info.exports_for(for_module); | 
|---|
| 1505 | let dtor = exports.resource_dtor(*ty).map(|name| { | 
|---|
| 1506 | let name = &shims.shims[&ShimKind::ResourceDtor { | 
|---|
| 1507 | module: for_module, | 
|---|
| 1508 | export: name, | 
|---|
| 1509 | }] | 
|---|
| 1510 | .name; | 
|---|
| 1511 | let shim = self.shim_instance_index.unwrap(); | 
|---|
| 1512 | self.core_alias_export(shim, name, ExportKind::Func) | 
|---|
| 1513 | }); | 
|---|
| 1514 |  | 
|---|
| 1515 | // Declare the resource with this destructor and register it in | 
|---|
| 1516 | // our internal map. This should be the first and only time this | 
|---|
| 1517 | // type is inserted into this map. | 
|---|
| 1518 | let resource_idx = self.component.type_resource(ValType::I32, dtor); | 
|---|
| 1519 | let prev = self.export_type_map.insert(*ty, resource_idx); | 
|---|
| 1520 | assert!(prev.is_none()); | 
|---|
| 1521 | } | 
|---|
| 1522 | } | 
|---|
| 1523 | } | 
|---|
| 1524 |  | 
|---|
| 1525 | /// Helper to instantiate the main module and record various results of its | 
|---|
| 1526 | /// instantiation within `self`. | 
|---|
| 1527 | fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> { | 
|---|
| 1528 | assert!(self.instance_index.is_none()); | 
|---|
| 1529 |  | 
|---|
| 1530 | let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?; | 
|---|
| 1531 |  | 
|---|
| 1532 | if let Some(memory) = self.info.info.exports.memory() { | 
|---|
| 1533 | self.memory_index = | 
|---|
| 1534 | Some(self.core_alias_export(instance_index, memory, ExportKind::Memory)); | 
|---|
| 1535 | } | 
|---|
| 1536 |  | 
|---|
| 1537 | self.instance_index = Some(instance_index); | 
|---|
| 1538 | Ok(()) | 
|---|
| 1539 | } | 
|---|
| 1540 |  | 
|---|
| 1541 | /// This function will instantiate the specified adapter module, which may | 
|---|
| 1542 | /// depend on previously-instantiated modules. | 
|---|
| 1543 | fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> { | 
|---|
| 1544 | let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?; | 
|---|
| 1545 | self.adapter_instances.insert(name, instance); | 
|---|
| 1546 | Ok(()) | 
|---|
| 1547 | } | 
|---|
| 1548 |  | 
|---|
| 1549 | /// Generic helper to instantiate a module. | 
|---|
| 1550 | /// | 
|---|
| 1551 | /// The `for_module` provided will have all of its imports satisfied from | 
|---|
| 1552 | /// either previous instantiations or the `shims` module present. This | 
|---|
| 1553 | /// iterates over the metadata produced during validation to determine what | 
|---|
| 1554 | /// hooks up to what import. | 
|---|
| 1555 | fn instantiate_core_module( | 
|---|
| 1556 | &mut self, | 
|---|
| 1557 | shims: &Shims, | 
|---|
| 1558 | for_module: CustomModule<'_>, | 
|---|
| 1559 | ) -> Result<u32> { | 
|---|
| 1560 | let module = self.module_for(for_module); | 
|---|
| 1561 |  | 
|---|
| 1562 | let mut args = Vec::new(); | 
|---|
| 1563 | for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() { | 
|---|
| 1564 | match instance { | 
|---|
| 1565 | // For import modules that are a "bag of names" iterate over | 
|---|
| 1566 | // each name and materialize it into this component with the | 
|---|
| 1567 | // `materialize_import` helper. This is then all bottled up into | 
|---|
| 1568 | // a bag-of-exports instances which is then used for | 
|---|
| 1569 | // instantiation. | 
|---|
| 1570 | ImportInstance::Names(names) => { | 
|---|
| 1571 | let mut exports = Vec::new(); | 
|---|
| 1572 | for (name, import) in names { | 
|---|
| 1573 | let (kind, index) = self | 
|---|
| 1574 | .materialize_import(&shims, for_module, core_wasm_name, name, import) | 
|---|
| 1575 | .with_context(|| { | 
|---|
| 1576 | format!( "failed to satisfy import `{core_wasm_name} ::{name} `") | 
|---|
| 1577 | })?; | 
|---|
| 1578 | exports.push((name.as_str(), kind, index)); | 
|---|
| 1579 | } | 
|---|
| 1580 | let index = self.component.core_instantiate_exports(exports); | 
|---|
| 1581 | args.push((core_wasm_name.as_str(), ModuleArg::Instance(index))); | 
|---|
| 1582 | } | 
|---|
| 1583 |  | 
|---|
| 1584 | // Some imports are entire instances, so use the instance for | 
|---|
| 1585 | // the module identifier as the import. | 
|---|
| 1586 | ImportInstance::Whole(which) => { | 
|---|
| 1587 | let instance = self.instance_for(which.to_custom_module()); | 
|---|
| 1588 | args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance))); | 
|---|
| 1589 | } | 
|---|
| 1590 | } | 
|---|
| 1591 | } | 
|---|
| 1592 |  | 
|---|
| 1593 | // And with all arguments prepared now, instantiate the module. | 
|---|
| 1594 | Ok(self.component.core_instantiate(module, args)) | 
|---|
| 1595 | } | 
|---|
| 1596 |  | 
|---|
| 1597 | /// Helper function to materialize an import into a core module within the | 
|---|
| 1598 | /// component being built. | 
|---|
| 1599 | /// | 
|---|
| 1600 | /// This function is called for individual imports and uses the results of | 
|---|
| 1601 | /// validation, notably the `Import` type, to determine what WIT-level or | 
|---|
| 1602 | /// component-level construct is being hooked up. | 
|---|
| 1603 | fn materialize_import( | 
|---|
| 1604 | &mut self, | 
|---|
| 1605 | shims: &Shims<'_>, | 
|---|
| 1606 | for_module: CustomModule<'_>, | 
|---|
| 1607 | module: &str, | 
|---|
| 1608 | field: &str, | 
|---|
| 1609 | import: &'a Import, | 
|---|
| 1610 | ) -> Result<(ExportKind, u32)> { | 
|---|
| 1611 | log::trace!( "attempting to materialize import of `{module} ::{field} ` for {for_module:?} "); | 
|---|
| 1612 | let resolve = &self.info.encoder.metadata.resolve; | 
|---|
| 1613 | let payload_indirect = |me: &mut Self, async_, info, kind| { | 
|---|
| 1614 | me.component.core_alias_export( | 
|---|
| 1615 | me.shim_instance_index.expect( "shim should be instantiated"), | 
|---|
| 1616 | &shims.shims[&ShimKind::PayloadFunc { | 
|---|
| 1617 | for_module, | 
|---|
| 1618 | async_, | 
|---|
| 1619 | info, | 
|---|
| 1620 | kind, | 
|---|
| 1621 | }] | 
|---|
| 1622 | .name, | 
|---|
| 1623 | ExportKind::Func, | 
|---|
| 1624 | ) | 
|---|
| 1625 | }; | 
|---|
| 1626 | let name_tmp; | 
|---|
| 1627 | let (key, name, interface_key, abi) = match import { | 
|---|
| 1628 | // Main module dependencies on an adapter in use are done with an | 
|---|
| 1629 | // indirection here, so load the shim function and use that. | 
|---|
| 1630 | Import::AdapterExport(_) => { | 
|---|
| 1631 | assert!(self.info.encoder.adapters.contains_key(module)); | 
|---|
| 1632 | let shim_instance = self | 
|---|
| 1633 | .shim_instance_index | 
|---|
| 1634 | .expect( "shim should be instantiated"); | 
|---|
| 1635 | let index = self.core_alias_export( | 
|---|
| 1636 | shim_instance, | 
|---|
| 1637 | &shims.shims[&ShimKind::Adapter { | 
|---|
| 1638 | adapter: module, | 
|---|
| 1639 | func: field, | 
|---|
| 1640 | }] | 
|---|
| 1641 | .name, | 
|---|
| 1642 | ExportKind::Func, | 
|---|
| 1643 | ); | 
|---|
| 1644 | return Ok((ExportKind::Func, index)); | 
|---|
| 1645 | } | 
|---|
| 1646 |  | 
|---|
| 1647 | // Adapters might uset he main module's memory, in which case it | 
|---|
| 1648 | // should have been previously instantiated. | 
|---|
| 1649 | Import::MainModuleMemory => { | 
|---|
| 1650 | let index = self | 
|---|
| 1651 | .memory_index | 
|---|
| 1652 | .ok_or_else(|| anyhow!( "main module cannot import memory"))?; | 
|---|
| 1653 | return Ok((ExportKind::Memory, index)); | 
|---|
| 1654 | } | 
|---|
| 1655 |  | 
|---|
| 1656 | // Grab-bag of "this adapter wants this thing from the main module". | 
|---|
| 1657 | Import::MainModuleExport { name, kind } => { | 
|---|
| 1658 | let instance = self.instance_index.unwrap(); | 
|---|
| 1659 | let index = self.core_alias_export(instance, name, *kind); | 
|---|
| 1660 | return Ok((*kind, index)); | 
|---|
| 1661 | } | 
|---|
| 1662 |  | 
|---|
| 1663 | // A similar grab-bag to above but with a slightly different | 
|---|
| 1664 | // structure. Should probably refactor to make these two the same in | 
|---|
| 1665 | // the future. | 
|---|
| 1666 | Import::Item(item) => { | 
|---|
| 1667 | let instance = self.instance_for(item.which.to_custom_module()); | 
|---|
| 1668 | let index = self.core_alias_export(instance, &item.name, item.kind); | 
|---|
| 1669 | return Ok((item.kind, index)); | 
|---|
| 1670 | } | 
|---|
| 1671 |  | 
|---|
| 1672 | // Resource intrinsics related to exported resources. Despite being | 
|---|
| 1673 | // an exported resource the component still provides necessary | 
|---|
| 1674 | // intrinsics for manipulating resource state. These are all | 
|---|
| 1675 | // handled here using the resource types created during | 
|---|
| 1676 | // `declare_exported_resources` above. | 
|---|
| 1677 | Import::ExportedResourceDrop(_key, id) => { | 
|---|
| 1678 | let index = self.component.resource_drop(self.export_type_map[id]); | 
|---|
| 1679 | return Ok((ExportKind::Func, index)); | 
|---|
| 1680 | } | 
|---|
| 1681 | Import::ExportedResourceRep(_key, id) => { | 
|---|
| 1682 | let index = self.component.resource_rep(self.export_type_map[id]); | 
|---|
| 1683 | return Ok((ExportKind::Func, index)); | 
|---|
| 1684 | } | 
|---|
| 1685 | Import::ExportedResourceNew(_key, id) => { | 
|---|
| 1686 | let index = self.component.resource_new(self.export_type_map[id]); | 
|---|
| 1687 | return Ok((ExportKind::Func, index)); | 
|---|
| 1688 | } | 
|---|
| 1689 |  | 
|---|
| 1690 | // And finally here at the end these cases are going to all fall | 
|---|
| 1691 | // through to the code below. This is where these are connected to a | 
|---|
| 1692 | // WIT `ImportedInterface` one way or another with the name that was | 
|---|
| 1693 | // detected during validation. | 
|---|
| 1694 | Import::ImportedResourceDrop(key, iface, id) => { | 
|---|
| 1695 | let ty = &resolve.types[*id]; | 
|---|
| 1696 | let name = ty.name.as_ref().unwrap(); | 
|---|
| 1697 | name_tmp = format!( "{name} _drop"); | 
|---|
| 1698 | ( | 
|---|
| 1699 | key, | 
|---|
| 1700 | &name_tmp, | 
|---|
| 1701 | iface.map(|_| resolve.name_world_key(key)), | 
|---|
| 1702 | AbiVariant::GuestImport, | 
|---|
| 1703 | ) | 
|---|
| 1704 | } | 
|---|
| 1705 | Import::ExportedTaskReturn(function) => { | 
|---|
| 1706 | let signature = resolve.wasm_signature( | 
|---|
| 1707 | AbiVariant::GuestImport, | 
|---|
| 1708 | &Function { | 
|---|
| 1709 | name: String::new(), | 
|---|
| 1710 | kind: FunctionKind::Freestanding, | 
|---|
| 1711 | params: match &function.results { | 
|---|
| 1712 | Results::Named(params) => params.clone(), | 
|---|
| 1713 | Results::Anon(ty) => vec![( "v".to_string(), *ty)], | 
|---|
| 1714 | }, | 
|---|
| 1715 | results: Results::Named(Vec::new()), | 
|---|
| 1716 | docs: Docs::default(), | 
|---|
| 1717 | stability: Stability::Unknown, | 
|---|
| 1718 | }, | 
|---|
| 1719 | ); | 
|---|
| 1720 | let (type_index, encoder) = self.component.core_type(); | 
|---|
| 1721 | encoder.core().function( | 
|---|
| 1722 | signature.params.into_iter().map(into_val_type), | 
|---|
| 1723 | signature.results.into_iter().map(into_val_type), | 
|---|
| 1724 | ); | 
|---|
| 1725 |  | 
|---|
| 1726 | let index = self.component.task_return(type_index); | 
|---|
| 1727 | return Ok((ExportKind::Func, index)); | 
|---|
| 1728 |  | 
|---|
| 1729 | fn into_val_type(ty: WasmType) -> ValType { | 
|---|
| 1730 | match ty { | 
|---|
| 1731 | WasmType::I32 | WasmType::Pointer | WasmType::Length => ValType::I32, | 
|---|
| 1732 | WasmType::I64 | WasmType::PointerOrI64 => ValType::I64, | 
|---|
| 1733 | WasmType::F32 => ValType::F32, | 
|---|
| 1734 | WasmType::F64 => ValType::F64, | 
|---|
| 1735 | } | 
|---|
| 1736 | } | 
|---|
| 1737 | } | 
|---|
| 1738 | Import::TaskBackpressure => { | 
|---|
| 1739 | let index = self.component.task_backpressure(); | 
|---|
| 1740 | return Ok((ExportKind::Func, index)); | 
|---|
| 1741 | } | 
|---|
| 1742 | Import::TaskWait { async_ } => { | 
|---|
| 1743 | let index = self.component.core_alias_export( | 
|---|
| 1744 | self.shim_instance_index | 
|---|
| 1745 | .expect( "shim should be instantiated"), | 
|---|
| 1746 | &shims.shims[&ShimKind::TaskWait { async_: *async_ }].name, | 
|---|
| 1747 | ExportKind::Func, | 
|---|
| 1748 | ); | 
|---|
| 1749 | return Ok((ExportKind::Func, index)); | 
|---|
| 1750 | } | 
|---|
| 1751 | Import::TaskPoll { async_ } => { | 
|---|
| 1752 | let index = self.component.core_alias_export( | 
|---|
| 1753 | self.shim_instance_index | 
|---|
| 1754 | .expect( "shim should be instantiated"), | 
|---|
| 1755 | &shims.shims[&ShimKind::TaskPoll { async_: *async_ }].name, | 
|---|
| 1756 | ExportKind::Func, | 
|---|
| 1757 | ); | 
|---|
| 1758 | return Ok((ExportKind::Func, index)); | 
|---|
| 1759 | } | 
|---|
| 1760 | Import::TaskYield { async_ } => { | 
|---|
| 1761 | let index = self.component.task_yield(*async_); | 
|---|
| 1762 | return Ok((ExportKind::Func, index)); | 
|---|
| 1763 | } | 
|---|
| 1764 | Import::SubtaskDrop => { | 
|---|
| 1765 | let index = self.component.subtask_drop(); | 
|---|
| 1766 | return Ok((ExportKind::Func, index)); | 
|---|
| 1767 | } | 
|---|
| 1768 | Import::StreamNew(info) => { | 
|---|
| 1769 | let ty = self.payload_type_index(info.ty, info.imported)?; | 
|---|
| 1770 | let index = self.component.stream_new(ty); | 
|---|
| 1771 | return Ok((ExportKind::Func, index)); | 
|---|
| 1772 | } | 
|---|
| 1773 | Import::StreamRead { async_, info } => { | 
|---|
| 1774 | return Ok(( | 
|---|
| 1775 | ExportKind::Func, | 
|---|
| 1776 | payload_indirect(self, *async_, info, PayloadFuncKind::StreamRead), | 
|---|
| 1777 | )); | 
|---|
| 1778 | } | 
|---|
| 1779 | Import::StreamWrite { async_, info } => { | 
|---|
| 1780 | return Ok(( | 
|---|
| 1781 | ExportKind::Func, | 
|---|
| 1782 | payload_indirect(self, *async_, info, PayloadFuncKind::StreamWrite), | 
|---|
| 1783 | )); | 
|---|
| 1784 | } | 
|---|
| 1785 | Import::StreamCancelRead { | 
|---|
| 1786 | ty, | 
|---|
| 1787 | imported, | 
|---|
| 1788 | async_, | 
|---|
| 1789 | } => { | 
|---|
| 1790 | let ty = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1791 | let index = self.component.stream_cancel_read(ty, *async_); | 
|---|
| 1792 | return Ok((ExportKind::Func, index)); | 
|---|
| 1793 | } | 
|---|
| 1794 | Import::StreamCancelWrite { | 
|---|
| 1795 | ty, | 
|---|
| 1796 | imported, | 
|---|
| 1797 | async_, | 
|---|
| 1798 | } => { | 
|---|
| 1799 | let ty = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1800 | let index = self.component.stream_cancel_write(ty, *async_); | 
|---|
| 1801 | return Ok((ExportKind::Func, index)); | 
|---|
| 1802 | } | 
|---|
| 1803 | Import::StreamCloseReadable { ty, imported } => { | 
|---|
| 1804 | let type_index = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1805 | let index = self.component.stream_close_readable(type_index); | 
|---|
| 1806 | return Ok((ExportKind::Func, index)); | 
|---|
| 1807 | } | 
|---|
| 1808 | Import::StreamCloseWritable { ty, imported } => { | 
|---|
| 1809 | let type_index = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1810 | let index = self.component.stream_close_writable(type_index); | 
|---|
| 1811 | return Ok((ExportKind::Func, index)); | 
|---|
| 1812 | } | 
|---|
| 1813 | Import::FutureNew(info) => { | 
|---|
| 1814 | let ty = self.payload_type_index(info.ty, info.imported)?; | 
|---|
| 1815 | let index = self.component.future_new(ty); | 
|---|
| 1816 | return Ok((ExportKind::Func, index)); | 
|---|
| 1817 | } | 
|---|
| 1818 | Import::FutureRead { async_, info } => { | 
|---|
| 1819 | return Ok(( | 
|---|
| 1820 | ExportKind::Func, | 
|---|
| 1821 | payload_indirect(self, *async_, info, PayloadFuncKind::FutureRead), | 
|---|
| 1822 | )); | 
|---|
| 1823 | } | 
|---|
| 1824 | Import::FutureWrite { async_, info } => { | 
|---|
| 1825 | return Ok(( | 
|---|
| 1826 | ExportKind::Func, | 
|---|
| 1827 | payload_indirect(self, *async_, info, PayloadFuncKind::FutureWrite), | 
|---|
| 1828 | )); | 
|---|
| 1829 | } | 
|---|
| 1830 | Import::FutureCancelRead { | 
|---|
| 1831 | ty, | 
|---|
| 1832 | imported, | 
|---|
| 1833 | async_, | 
|---|
| 1834 | } => { | 
|---|
| 1835 | let ty = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1836 | let index = self.component.future_cancel_read(ty, *async_); | 
|---|
| 1837 | return Ok((ExportKind::Func, index)); | 
|---|
| 1838 | } | 
|---|
| 1839 | Import::FutureCancelWrite { | 
|---|
| 1840 | ty, | 
|---|
| 1841 | imported, | 
|---|
| 1842 | async_, | 
|---|
| 1843 | } => { | 
|---|
| 1844 | let ty = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1845 | let index = self.component.future_cancel_write(ty, *async_); | 
|---|
| 1846 | return Ok((ExportKind::Func, index)); | 
|---|
| 1847 | } | 
|---|
| 1848 | Import::FutureCloseReadable { ty, imported } => { | 
|---|
| 1849 | let type_index = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1850 | let index = self.component.future_close_readable(type_index); | 
|---|
| 1851 | return Ok((ExportKind::Func, index)); | 
|---|
| 1852 | } | 
|---|
| 1853 | Import::FutureCloseWritable { ty, imported } => { | 
|---|
| 1854 | let type_index = self.payload_type_index(*ty, *imported)?; | 
|---|
| 1855 | let index = self.component.future_close_writable(type_index); | 
|---|
| 1856 | return Ok((ExportKind::Func, index)); | 
|---|
| 1857 | } | 
|---|
| 1858 | Import::ErrorContextNew { encoding } => { | 
|---|
| 1859 | let index = self.component.core_alias_export( | 
|---|
| 1860 | self.shim_instance_index | 
|---|
| 1861 | .expect( "shim should be instantiated"), | 
|---|
| 1862 | &shims.shims[&ShimKind::ErrorContextNew { | 
|---|
| 1863 | encoding: *encoding, | 
|---|
| 1864 | }] | 
|---|
| 1865 | .name, | 
|---|
| 1866 | ExportKind::Func, | 
|---|
| 1867 | ); | 
|---|
| 1868 | return Ok((ExportKind::Func, index)); | 
|---|
| 1869 | } | 
|---|
| 1870 | Import::ErrorContextDebugMessage { encoding, realloc } => { | 
|---|
| 1871 | let index = self.component.core_alias_export( | 
|---|
| 1872 | self.shim_instance_index | 
|---|
| 1873 | .expect( "shim should be instantiated"), | 
|---|
| 1874 | &shims.shims[&ShimKind::ErrorContextDebugMessage { | 
|---|
| 1875 | for_module, | 
|---|
| 1876 | encoding: *encoding, | 
|---|
| 1877 | realloc, | 
|---|
| 1878 | }] | 
|---|
| 1879 | .name, | 
|---|
| 1880 | ExportKind::Func, | 
|---|
| 1881 | ); | 
|---|
| 1882 | return Ok((ExportKind::Func, index)); | 
|---|
| 1883 | } | 
|---|
| 1884 | Import::ErrorContextDrop => { | 
|---|
| 1885 | let index = self.component.error_context_drop(); | 
|---|
| 1886 | return Ok((ExportKind::Func, index)); | 
|---|
| 1887 | } | 
|---|
| 1888 | Import::WorldFunc(key, name, abi) => (key, name, None, *abi), | 
|---|
| 1889 | Import::InterfaceFunc(key, _, name, abi) => { | 
|---|
| 1890 | (key, name, Some(resolve.name_world_key(key)), *abi) | 
|---|
| 1891 | } | 
|---|
| 1892 | }; | 
|---|
| 1893 |  | 
|---|
| 1894 | let import = &self.info.import_map[&interface_key]; | 
|---|
| 1895 | let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap(); | 
|---|
| 1896 | let metadata = self.info.module_metadata_for(for_module); | 
|---|
| 1897 |  | 
|---|
| 1898 | let index = match lowering { | 
|---|
| 1899 | // All direct lowerings can be `canon lower`'d here immediately | 
|---|
| 1900 | // and passed as arguments. | 
|---|
| 1901 | Lowering::Direct => { | 
|---|
| 1902 | let func_index = match &import.interface { | 
|---|
| 1903 | Some(interface) => { | 
|---|
| 1904 | let instance_index = self.imported_instances[interface]; | 
|---|
| 1905 | self.component | 
|---|
| 1906 | .alias_export(instance_index, name, ComponentExportKind::Func) | 
|---|
| 1907 | } | 
|---|
| 1908 | None => self.imported_funcs[name], | 
|---|
| 1909 | }; | 
|---|
| 1910 | self.component.lower_func( | 
|---|
| 1911 | func_index, | 
|---|
| 1912 | if let AbiVariant::GuestImportAsync = abi { | 
|---|
| 1913 | vec![CanonicalOption::Async] | 
|---|
| 1914 | } else { | 
|---|
| 1915 | Vec::new() | 
|---|
| 1916 | }, | 
|---|
| 1917 | ) | 
|---|
| 1918 | } | 
|---|
| 1919 |  | 
|---|
| 1920 | // Indirect lowerings come from the shim that was previously | 
|---|
| 1921 | // created, so the specific export is loaded here and used as an | 
|---|
| 1922 | // import. | 
|---|
| 1923 | Lowering::Indirect { .. } => { | 
|---|
| 1924 | let encoding = metadata.import_encodings.get(resolve, key, name).unwrap(); | 
|---|
| 1925 | self.core_alias_export( | 
|---|
| 1926 | self.shim_instance_index | 
|---|
| 1927 | .expect( "shim should be instantiated"), | 
|---|
| 1928 | &shims.shims[&ShimKind::IndirectLowering { | 
|---|
| 1929 | interface: interface_key, | 
|---|
| 1930 | index, | 
|---|
| 1931 | realloc: for_module, | 
|---|
| 1932 | encoding, | 
|---|
| 1933 | }] | 
|---|
| 1934 | .name, | 
|---|
| 1935 | ExportKind::Func, | 
|---|
| 1936 | ) | 
|---|
| 1937 | } | 
|---|
| 1938 |  | 
|---|
| 1939 | // A "resource drop" intrinsic only needs to find the index of the | 
|---|
| 1940 | // resource type itself and then the intrinsic is declared. | 
|---|
| 1941 | Lowering::ResourceDrop(id) => { | 
|---|
| 1942 | let resource_idx = self.lookup_resource_index(*id); | 
|---|
| 1943 | self.component.resource_drop(resource_idx) | 
|---|
| 1944 | } | 
|---|
| 1945 | }; | 
|---|
| 1946 | Ok((ExportKind::Func, index)) | 
|---|
| 1947 | } | 
|---|
| 1948 |  | 
|---|
| 1949 | /// Generates component bits that are responsible for executing | 
|---|
| 1950 | /// `_initialize`, if found, in the original component. | 
|---|
| 1951 | /// | 
|---|
| 1952 | /// The `_initialize` function was a part of WASIp1 where it generally is | 
|---|
| 1953 | /// intended to run after imports and memory and such are all "hooked up" | 
|---|
| 1954 | /// and performs other various initialization tasks. This is additionally | 
|---|
| 1955 | /// specified in https://github.com/WebAssembly/component-model/pull/378 | 
|---|
| 1956 | /// to be part of the component model lowerings as well. | 
|---|
| 1957 | /// | 
|---|
| 1958 | /// This implements this functionality by encoding a core module that | 
|---|
| 1959 | /// imports a function and then registers a `start` section with that | 
|---|
| 1960 | /// imported function. This is all encoded after the | 
|---|
| 1961 | /// imports/lowerings/tables/etc are all filled in above meaning that this | 
|---|
| 1962 | /// is the last piece to run. That means that when this is running | 
|---|
| 1963 | /// everything should be hooked up for all imported functions to work. | 
|---|
| 1964 | /// | 
|---|
| 1965 | /// Note that at this time `_initialize` is only detected in the "main | 
|---|
| 1966 | /// module", not adapters/libraries. | 
|---|
| 1967 | fn encode_initialize_with_start(&mut self) -> Result<()> { | 
|---|
| 1968 | let initialize = match self.info.info.exports.initialize() { | 
|---|
| 1969 | Some(name) => name, | 
|---|
| 1970 | // If this core module didn't have `_initialize` or similar, then | 
|---|
| 1971 | // there's nothing to do here. | 
|---|
| 1972 | None => return Ok(()), | 
|---|
| 1973 | }; | 
|---|
| 1974 | let initialize_index = | 
|---|
| 1975 | self.core_alias_export(self.instance_index.unwrap(), initialize, ExportKind::Func); | 
|---|
| 1976 | let mut shim = Module::default(); | 
|---|
| 1977 | let mut section = TypeSection::new(); | 
|---|
| 1978 | section.ty().function([], []); | 
|---|
| 1979 | shim.section(§ion); | 
|---|
| 1980 | let mut section = ImportSection::new(); | 
|---|
| 1981 | section.import( "", "", EntityType::Function(0)); | 
|---|
| 1982 | shim.section(§ion); | 
|---|
| 1983 | shim.section(&StartSection { function_index: 0 }); | 
|---|
| 1984 |  | 
|---|
| 1985 | // Declare the core module within the component, create a dummy core | 
|---|
| 1986 | // instance with one export of our `_initialize` function, and then use | 
|---|
| 1987 | // that to instantiate the module we emit to run the `start` function in | 
|---|
| 1988 | // core wasm to run `_initialize`. | 
|---|
| 1989 | let shim_module_index = self.component.core_module(&shim); | 
|---|
| 1990 | let shim_args_instance_index = | 
|---|
| 1991 | self.component | 
|---|
| 1992 | .core_instantiate_exports([( "", ExportKind::Func, initialize_index)]); | 
|---|
| 1993 | self.component.core_instantiate( | 
|---|
| 1994 | shim_module_index, | 
|---|
| 1995 | [( "", ModuleArg::Instance(shim_args_instance_index))], | 
|---|
| 1996 | ); | 
|---|
| 1997 | Ok(()) | 
|---|
| 1998 | } | 
|---|
| 1999 |  | 
|---|
| 2000 | /// Convenience function to go from `CustomModule` to the instance index | 
|---|
| 2001 | /// corresponding to what that points to. | 
|---|
| 2002 | fn instance_for(&self, module: CustomModule) -> u32 { | 
|---|
| 2003 | match module { | 
|---|
| 2004 | CustomModule::Main => self.instance_index.expect( "instantiated by now"), | 
|---|
| 2005 | CustomModule::Adapter(name) => self.adapter_instances[name], | 
|---|
| 2006 | } | 
|---|
| 2007 | } | 
|---|
| 2008 |  | 
|---|
| 2009 | /// Convenience function to go from `CustomModule` to the module index | 
|---|
| 2010 | /// corresponding to what that points to. | 
|---|
| 2011 | fn module_for(&self, module: CustomModule) -> u32 { | 
|---|
| 2012 | match module { | 
|---|
| 2013 | CustomModule::Main => self.module_index.unwrap(), | 
|---|
| 2014 | CustomModule::Adapter(name) => self.adapter_modules[name], | 
|---|
| 2015 | } | 
|---|
| 2016 | } | 
|---|
| 2017 |  | 
|---|
| 2018 | /// Convenience function which caches aliases created so repeated calls to | 
|---|
| 2019 | /// this function will all return the same index. | 
|---|
| 2020 | fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { | 
|---|
| 2021 | *self | 
|---|
| 2022 | .aliased_core_items | 
|---|
| 2023 | .entry((instance, name.to_string())) | 
|---|
| 2024 | .or_insert_with(|| self.component.core_alias_export(instance, name, kind)) | 
|---|
| 2025 | } | 
|---|
| 2026 | } | 
|---|
| 2027 |  | 
|---|
| 2028 | /// A list of "shims" which start out during the component instantiation process | 
|---|
| 2029 | /// as functions which immediately trap due to a `call_indirect`-to-`null` but | 
|---|
| 2030 | /// will get filled in by the time the component instantiation process | 
|---|
| 2031 | /// completes. | 
|---|
| 2032 | /// | 
|---|
| 2033 | /// Shims currently include: | 
|---|
| 2034 | /// | 
|---|
| 2035 | /// * "Indirect functions" lowered from imported instances where the lowering | 
|---|
| 2036 | ///   requires an item exported from the main module. These are indirect due to | 
|---|
| 2037 | ///   the circular dependency between the module needing an import and the | 
|---|
| 2038 | ///   import needing the module. | 
|---|
| 2039 | /// | 
|---|
| 2040 | /// * Adapter modules which convert from a historical ABI to the component | 
|---|
| 2041 | ///   model's ABI (e.g. wasi preview1 to preview2) get a shim since the adapters | 
|---|
| 2042 | ///   are currently indicated as always requiring the memory of the main module. | 
|---|
| 2043 | /// | 
|---|
| 2044 | /// This structure is created by `encode_shim_instantiation`. | 
|---|
| 2045 | #[ derive(Default)] | 
|---|
| 2046 | struct Shims<'a> { | 
|---|
| 2047 | /// The list of all shims that a module will require. | 
|---|
| 2048 | shims: IndexMap<ShimKind<'a>, Shim<'a>>, | 
|---|
| 2049 | } | 
|---|
| 2050 |  | 
|---|
| 2051 | struct Shim<'a> { | 
|---|
| 2052 | /// Canonical ABI options required by this shim, used during `canon lower` | 
|---|
| 2053 | /// operations. | 
|---|
| 2054 | options: RequiredOptions, | 
|---|
| 2055 |  | 
|---|
| 2056 | /// The name, in the shim instance, of this shim. | 
|---|
| 2057 | /// | 
|---|
| 2058 | /// Currently this is `"0"`, `"1"`, ... | 
|---|
| 2059 | name: String, | 
|---|
| 2060 |  | 
|---|
| 2061 | /// A human-readable debugging name for this shim, used in a core wasm | 
|---|
| 2062 | /// `name` section. | 
|---|
| 2063 | debug_name: String, | 
|---|
| 2064 |  | 
|---|
| 2065 | /// Precise information about what this shim is a lowering of. | 
|---|
| 2066 | kind: ShimKind<'a>, | 
|---|
| 2067 |  | 
|---|
| 2068 | /// Wasm type of this shim. | 
|---|
| 2069 | sig: WasmSignature, | 
|---|
| 2070 | } | 
|---|
| 2071 |  | 
|---|
| 2072 | /// Which variation of `{stream|future}.{read|write}` we're emitting for a | 
|---|
| 2073 | /// `ShimKind::PayloadFunc`. | 
|---|
| 2074 | #[ derive(Debug, Clone, Hash, Eq, PartialEq)] | 
|---|
| 2075 | enum PayloadFuncKind { | 
|---|
| 2076 | FutureWrite, | 
|---|
| 2077 | FutureRead, | 
|---|
| 2078 | StreamWrite, | 
|---|
| 2079 | StreamRead, | 
|---|
| 2080 | } | 
|---|
| 2081 |  | 
|---|
| 2082 | #[ derive(Debug, Clone, Hash, Eq, PartialEq)] | 
|---|
| 2083 | enum ShimKind<'a> { | 
|---|
| 2084 | /// This shim is a late indirect lowering of an imported function in a | 
|---|
| 2085 | /// component which is only possible after prior core wasm modules are | 
|---|
| 2086 | /// instantiated so their memories and functions are available. | 
|---|
| 2087 | IndirectLowering { | 
|---|
| 2088 | /// The name of the interface that's being lowered. | 
|---|
| 2089 | interface: Option<String>, | 
|---|
| 2090 | /// The index within the `lowerings` array of the function being lowered. | 
|---|
| 2091 | index: usize, | 
|---|
| 2092 | /// Which instance to pull the `realloc` function from, if necessary. | 
|---|
| 2093 | realloc: CustomModule<'a>, | 
|---|
| 2094 | /// The string encoding that this lowering is going to use. | 
|---|
| 2095 | encoding: StringEncoding, | 
|---|
| 2096 | }, | 
|---|
| 2097 | /// This shim is a core wasm function defined in an adapter module but isn't | 
|---|
| 2098 | /// available until the adapter module is itself instantiated. | 
|---|
| 2099 | Adapter { | 
|---|
| 2100 | /// The name of the adapter module this shim comes from. | 
|---|
| 2101 | adapter: &'a str, | 
|---|
| 2102 | /// The name of the export in the adapter module this shim points to. | 
|---|
| 2103 | func: &'a str, | 
|---|
| 2104 | }, | 
|---|
| 2105 | /// A shim used as the destructor for a resource which allows defining the | 
|---|
| 2106 | /// resource before the core module being instantiated. | 
|---|
| 2107 | ResourceDtor { | 
|---|
| 2108 | /// Which instance to pull the destructor function from. | 
|---|
| 2109 | module: CustomModule<'a>, | 
|---|
| 2110 | /// The exported function name of this destructor in the core module. | 
|---|
| 2111 | export: &'a str, | 
|---|
| 2112 | }, | 
|---|
| 2113 | /// A shim used for a `{stream|future}.{read|write}` built-in function, | 
|---|
| 2114 | /// which must refer to the core module instance's memory from/to which | 
|---|
| 2115 | /// payload values must be lifted/lowered. | 
|---|
| 2116 | PayloadFunc { | 
|---|
| 2117 | /// Which instance to pull the `realloc` function and string encoding | 
|---|
| 2118 | /// from, if necessary. | 
|---|
| 2119 | for_module: CustomModule<'a>, | 
|---|
| 2120 | /// Whether this read/write call is using the `async` option. | 
|---|
| 2121 | async_: bool, | 
|---|
| 2122 | /// Additional information regarding the function where this `stream` or | 
|---|
| 2123 | /// `future` type appeared, which we use in combination with | 
|---|
| 2124 | /// `for_module` to determine which `realloc` and string encoding to | 
|---|
| 2125 | /// use, as well as which type to specify when emitting the built-in. | 
|---|
| 2126 | info: &'a PayloadInfo, | 
|---|
| 2127 | /// Which variation of `{stream|future}.{read|write}` we're emitting. | 
|---|
| 2128 | kind: PayloadFuncKind, | 
|---|
| 2129 | }, | 
|---|
| 2130 | /// A shim used for the `task.wait` built-in function, which must refer to | 
|---|
| 2131 | /// the core module instance's memory to which results will be written. | 
|---|
| 2132 | TaskWait { async_: bool }, | 
|---|
| 2133 | /// A shim used for the `task.poll` built-in function, which must refer to | 
|---|
| 2134 | /// the core module instance's memory to which results will be written. | 
|---|
| 2135 | TaskPoll { async_: bool }, | 
|---|
| 2136 | /// A shim used for the `error-context.new` built-in function, which must | 
|---|
| 2137 | /// refer to the core module instance's memory from which the debug message | 
|---|
| 2138 | /// will be read. | 
|---|
| 2139 | ErrorContextNew { | 
|---|
| 2140 | /// String encoding to use when lifting the debug message. | 
|---|
| 2141 | encoding: StringEncoding, | 
|---|
| 2142 | }, | 
|---|
| 2143 | /// A shim used for the `error-context.debug-message` built-in function, | 
|---|
| 2144 | /// which must refer to the core module instance's memory to which results | 
|---|
| 2145 | /// will be written. | 
|---|
| 2146 | ErrorContextDebugMessage { | 
|---|
| 2147 | /// Which instance to pull the `realloc` function from, if necessary. | 
|---|
| 2148 | for_module: CustomModule<'a>, | 
|---|
| 2149 | /// The string encoding to use when lowering the debug message. | 
|---|
| 2150 | encoding: StringEncoding, | 
|---|
| 2151 | /// The realloc function to use when allocating linear memory for the | 
|---|
| 2152 | /// debug message. | 
|---|
| 2153 | realloc: &'a str, | 
|---|
| 2154 | }, | 
|---|
| 2155 | } | 
|---|
| 2156 |  | 
|---|
| 2157 | /// Indicator for which module is being used for a lowering or where options | 
|---|
| 2158 | /// like `realloc` are drawn from. | 
|---|
| 2159 | /// | 
|---|
| 2160 | /// This is necessary for situations such as an imported function being lowered | 
|---|
| 2161 | /// into the main module and additionally into an adapter module. For example an | 
|---|
| 2162 | /// adapter might adapt from preview1 to preview2 for the standard library of a | 
|---|
| 2163 | /// programming language but the main module's custom application code may also | 
|---|
| 2164 | /// explicitly import from preview2. These two different lowerings of a preview2 | 
|---|
| 2165 | /// function are parameterized by this enumeration. | 
|---|
| 2166 | #[ derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] | 
|---|
| 2167 | enum CustomModule<'a> { | 
|---|
| 2168 | /// This points to the "main module" which is generally the "output of LLVM" | 
|---|
| 2169 | /// or what a user wrote. | 
|---|
| 2170 | Main, | 
|---|
| 2171 | /// This is selecting an adapter module, identified by name here, where | 
|---|
| 2172 | /// something is being lowered into. | 
|---|
| 2173 | Adapter(&'a str), | 
|---|
| 2174 | } | 
|---|
| 2175 |  | 
|---|
| 2176 | impl<'a> Shims<'a> { | 
|---|
| 2177 | /// Adds all shims necessary for the instantiation of `for_module`. | 
|---|
| 2178 | /// | 
|---|
| 2179 | /// This function will iterate over all the imports required by this module | 
|---|
| 2180 | /// and for those that require a shim they're registered here. | 
|---|
| 2181 | fn append_indirect( | 
|---|
| 2182 | &mut self, | 
|---|
| 2183 | world: &'a ComponentWorld<'a>, | 
|---|
| 2184 | for_module: CustomModule<'a>, | 
|---|
| 2185 | ) -> Result<()> { | 
|---|
| 2186 | let module_imports = world.imports_for(for_module); | 
|---|
| 2187 | let module_exports = world.exports_for(for_module); | 
|---|
| 2188 | let metadata = world.module_metadata_for(for_module); | 
|---|
| 2189 | let resolve = &world.encoder.metadata.resolve; | 
|---|
| 2190 |  | 
|---|
| 2191 | let payload_push = | 
|---|
| 2192 | |me: &mut Self, module, async_, info: &'a PayloadInfo, kind, params, results| { | 
|---|
| 2193 | let debug_name = format!( "{module} -{} ", info.name); | 
|---|
| 2194 | let name = me.shims.len().to_string(); | 
|---|
| 2195 | me.push(Shim { | 
|---|
| 2196 | name, | 
|---|
| 2197 | debug_name, | 
|---|
| 2198 | options: RequiredOptions::empty(), | 
|---|
| 2199 | kind: ShimKind::PayloadFunc { | 
|---|
| 2200 | for_module, | 
|---|
| 2201 | async_, | 
|---|
| 2202 | info, | 
|---|
| 2203 | kind, | 
|---|
| 2204 | }, | 
|---|
| 2205 | sig: WasmSignature { | 
|---|
| 2206 | params, | 
|---|
| 2207 | results, | 
|---|
| 2208 | indirect_params: false, | 
|---|
| 2209 | retptr: false, | 
|---|
| 2210 | }, | 
|---|
| 2211 | }); | 
|---|
| 2212 | }; | 
|---|
| 2213 |  | 
|---|
| 2214 | for (module, field, import) in module_imports.imports() { | 
|---|
| 2215 | let (key, name, interface_key, abi) = match import { | 
|---|
| 2216 | // These imports don't require shims, they can be satisfied | 
|---|
| 2217 | // as-needed when required. | 
|---|
| 2218 | Import::ImportedResourceDrop(..) | 
|---|
| 2219 | | Import::MainModuleMemory | 
|---|
| 2220 | | Import::MainModuleExport { .. } | 
|---|
| 2221 | | Import::Item(_) | 
|---|
| 2222 | | Import::ExportedResourceDrop(..) | 
|---|
| 2223 | | Import::ExportedResourceRep(..) | 
|---|
| 2224 | | Import::ExportedResourceNew(..) | 
|---|
| 2225 | | Import::ErrorContextDrop | 
|---|
| 2226 | | Import::TaskBackpressure | 
|---|
| 2227 | | Import::TaskYield { .. } | 
|---|
| 2228 | | Import::SubtaskDrop | 
|---|
| 2229 | | Import::ExportedTaskReturn(..) | 
|---|
| 2230 | | Import::FutureNew(..) | 
|---|
| 2231 | | Import::StreamNew(..) | 
|---|
| 2232 | | Import::FutureCancelRead { .. } | 
|---|
| 2233 | | Import::FutureCancelWrite { .. } | 
|---|
| 2234 | | Import::FutureCloseWritable { .. } | 
|---|
| 2235 | | Import::FutureCloseReadable { .. } | 
|---|
| 2236 | | Import::StreamCancelRead { .. } | 
|---|
| 2237 | | Import::StreamCancelWrite { .. } | 
|---|
| 2238 | | Import::StreamCloseWritable { .. } | 
|---|
| 2239 | | Import::StreamCloseReadable { .. } => continue, | 
|---|
| 2240 |  | 
|---|
| 2241 | Import::FutureWrite { async_, info } => { | 
|---|
| 2242 | payload_push( | 
|---|
| 2243 | self, | 
|---|
| 2244 | module, | 
|---|
| 2245 | *async_, | 
|---|
| 2246 | info, | 
|---|
| 2247 | PayloadFuncKind::FutureWrite, | 
|---|
| 2248 | vec![WasmType::I32; 2], | 
|---|
| 2249 | vec![WasmType::I32], | 
|---|
| 2250 | ); | 
|---|
| 2251 | continue; | 
|---|
| 2252 | } | 
|---|
| 2253 | Import::FutureRead { async_, info } => { | 
|---|
| 2254 | payload_push( | 
|---|
| 2255 | self, | 
|---|
| 2256 | module, | 
|---|
| 2257 | *async_, | 
|---|
| 2258 | info, | 
|---|
| 2259 | PayloadFuncKind::FutureRead, | 
|---|
| 2260 | vec![WasmType::I32; 2], | 
|---|
| 2261 | vec![WasmType::I32], | 
|---|
| 2262 | ); | 
|---|
| 2263 | continue; | 
|---|
| 2264 | } | 
|---|
| 2265 | Import::StreamWrite { async_, info } => { | 
|---|
| 2266 | payload_push( | 
|---|
| 2267 | self, | 
|---|
| 2268 | module, | 
|---|
| 2269 | *async_, | 
|---|
| 2270 | info, | 
|---|
| 2271 | PayloadFuncKind::StreamWrite, | 
|---|
| 2272 | vec![WasmType::I32; 3], | 
|---|
| 2273 | vec![WasmType::I32], | 
|---|
| 2274 | ); | 
|---|
| 2275 | continue; | 
|---|
| 2276 | } | 
|---|
| 2277 | Import::StreamRead { async_, info } => { | 
|---|
| 2278 | payload_push( | 
|---|
| 2279 | self, | 
|---|
| 2280 | module, | 
|---|
| 2281 | *async_, | 
|---|
| 2282 | info, | 
|---|
| 2283 | PayloadFuncKind::StreamRead, | 
|---|
| 2284 | vec![WasmType::I32; 3], | 
|---|
| 2285 | vec![WasmType::I32], | 
|---|
| 2286 | ); | 
|---|
| 2287 | continue; | 
|---|
| 2288 | } | 
|---|
| 2289 |  | 
|---|
| 2290 | Import::TaskWait { async_ } => { | 
|---|
| 2291 | let name = self.shims.len().to_string(); | 
|---|
| 2292 | self.push(Shim { | 
|---|
| 2293 | name, | 
|---|
| 2294 | debug_name: "task-wait".to_string(), | 
|---|
| 2295 | options: RequiredOptions::empty(), | 
|---|
| 2296 | kind: ShimKind::TaskWait { async_: *async_ }, | 
|---|
| 2297 | sig: WasmSignature { | 
|---|
| 2298 | params: vec![WasmType::I32], | 
|---|
| 2299 | results: vec![WasmType::I32], | 
|---|
| 2300 | indirect_params: false, | 
|---|
| 2301 | retptr: false, | 
|---|
| 2302 | }, | 
|---|
| 2303 | }); | 
|---|
| 2304 | continue; | 
|---|
| 2305 | } | 
|---|
| 2306 |  | 
|---|
| 2307 | Import::TaskPoll { async_ } => { | 
|---|
| 2308 | let name = self.shims.len().to_string(); | 
|---|
| 2309 | self.push(Shim { | 
|---|
| 2310 | name, | 
|---|
| 2311 | debug_name: "task-poll".to_string(), | 
|---|
| 2312 | options: RequiredOptions::empty(), | 
|---|
| 2313 | kind: ShimKind::TaskPoll { async_: *async_ }, | 
|---|
| 2314 | sig: WasmSignature { | 
|---|
| 2315 | params: vec![WasmType::I32], | 
|---|
| 2316 | results: vec![WasmType::I32], | 
|---|
| 2317 | indirect_params: false, | 
|---|
| 2318 | retptr: false, | 
|---|
| 2319 | }, | 
|---|
| 2320 | }); | 
|---|
| 2321 | continue; | 
|---|
| 2322 | } | 
|---|
| 2323 |  | 
|---|
| 2324 | Import::ErrorContextNew { encoding } => { | 
|---|
| 2325 | let name = self.shims.len().to_string(); | 
|---|
| 2326 | self.push(Shim { | 
|---|
| 2327 | name, | 
|---|
| 2328 | debug_name: "error-new".to_string(), | 
|---|
| 2329 | options: RequiredOptions::empty(), | 
|---|
| 2330 | kind: ShimKind::ErrorContextNew { | 
|---|
| 2331 | encoding: *encoding, | 
|---|
| 2332 | }, | 
|---|
| 2333 | sig: WasmSignature { | 
|---|
| 2334 | params: vec![WasmType::I32; 2], | 
|---|
| 2335 | results: vec![WasmType::I32], | 
|---|
| 2336 | indirect_params: false, | 
|---|
| 2337 | retptr: false, | 
|---|
| 2338 | }, | 
|---|
| 2339 | }); | 
|---|
| 2340 | continue; | 
|---|
| 2341 | } | 
|---|
| 2342 |  | 
|---|
| 2343 | Import::ErrorContextDebugMessage { encoding, realloc } => { | 
|---|
| 2344 | let name = self.shims.len().to_string(); | 
|---|
| 2345 | self.push(Shim { | 
|---|
| 2346 | name, | 
|---|
| 2347 | debug_name: "error-debug-message".to_string(), | 
|---|
| 2348 | options: RequiredOptions::empty(), | 
|---|
| 2349 | kind: ShimKind::ErrorContextDebugMessage { | 
|---|
| 2350 | for_module, | 
|---|
| 2351 | encoding: *encoding, | 
|---|
| 2352 | realloc, | 
|---|
| 2353 | }, | 
|---|
| 2354 | sig: WasmSignature { | 
|---|
| 2355 | params: vec![WasmType::I32; 2], | 
|---|
| 2356 | results: vec![], | 
|---|
| 2357 | indirect_params: false, | 
|---|
| 2358 | retptr: false, | 
|---|
| 2359 | }, | 
|---|
| 2360 | }); | 
|---|
| 2361 | continue; | 
|---|
| 2362 | } | 
|---|
| 2363 |  | 
|---|
| 2364 | // Adapter imports into the main module must got through an | 
|---|
| 2365 | // indirection, so that's registered here. | 
|---|
| 2366 | Import::AdapterExport(ty) => { | 
|---|
| 2367 | let name = self.shims.len().to_string(); | 
|---|
| 2368 | log::debug!( "shim {name}  is adapter `{module} ::{field} `"); | 
|---|
| 2369 | self.push(Shim { | 
|---|
| 2370 | name, | 
|---|
| 2371 | debug_name: format!( "adapt-{module} -{field} "), | 
|---|
| 2372 | // Pessimistically assume that all adapters require | 
|---|
| 2373 | // memory in one form or another. While this isn't | 
|---|
| 2374 | // technically true it's true enough for WASI. | 
|---|
| 2375 | options: RequiredOptions::MEMORY, | 
|---|
| 2376 | kind: ShimKind::Adapter { | 
|---|
| 2377 | adapter: module, | 
|---|
| 2378 | func: field, | 
|---|
| 2379 | }, | 
|---|
| 2380 | sig: WasmSignature { | 
|---|
| 2381 | params: ty.params().iter().map(to_wasm_type).collect(), | 
|---|
| 2382 | results: ty.results().iter().map(to_wasm_type).collect(), | 
|---|
| 2383 | indirect_params: false, | 
|---|
| 2384 | retptr: false, | 
|---|
| 2385 | }, | 
|---|
| 2386 | }); | 
|---|
| 2387 | continue; | 
|---|
| 2388 |  | 
|---|
| 2389 | fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType { | 
|---|
| 2390 | match ty { | 
|---|
| 2391 | wasmparser::ValType::I32 => WasmType::I32, | 
|---|
| 2392 | wasmparser::ValType::I64 => WasmType::I64, | 
|---|
| 2393 | wasmparser::ValType::F32 => WasmType::F32, | 
|---|
| 2394 | wasmparser::ValType::F64 => WasmType::F64, | 
|---|
| 2395 | _ => unreachable!(), | 
|---|
| 2396 | } | 
|---|
| 2397 | } | 
|---|
| 2398 | } | 
|---|
| 2399 |  | 
|---|
| 2400 | // WIT-level functions may require an indirection, so yield some | 
|---|
| 2401 | // metadata out of this `match` to the loop below to figure that | 
|---|
| 2402 | // out. | 
|---|
| 2403 | Import::InterfaceFunc(key, _, name, abi) => { | 
|---|
| 2404 | (key, name, Some(resolve.name_world_key(key)), *abi) | 
|---|
| 2405 | } | 
|---|
| 2406 | Import::WorldFunc(key, name, abi) => (key, name, None, *abi), | 
|---|
| 2407 | }; | 
|---|
| 2408 | let interface = &world.import_map[&interface_key]; | 
|---|
| 2409 | let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap(); | 
|---|
| 2410 | let shim_name = self.shims.len().to_string(); | 
|---|
| 2411 | match lowering { | 
|---|
| 2412 | Lowering::Direct | Lowering::ResourceDrop(_) => {} | 
|---|
| 2413 |  | 
|---|
| 2414 | Lowering::Indirect { sig, options } => { | 
|---|
| 2415 | log::debug!( | 
|---|
| 2416 | "shim {shim_name}  is import `{module} ::{field} ` lowering {index}  `{name} `", | 
|---|
| 2417 | ); | 
|---|
| 2418 | let encoding = metadata | 
|---|
| 2419 | .import_encodings | 
|---|
| 2420 | .get(resolve, key, name) | 
|---|
| 2421 | .ok_or_else(|| { | 
|---|
| 2422 | anyhow::anyhow!( | 
|---|
| 2423 | "missing component metadata for import of \ | 
|---|
| 2424 |                                 `{module} ::{field} `" | 
|---|
| 2425 | ) | 
|---|
| 2426 | })?; | 
|---|
| 2427 | self.push(Shim { | 
|---|
| 2428 | name: shim_name, | 
|---|
| 2429 | debug_name: format!( "indirect-{module} -{field} "), | 
|---|
| 2430 | options: *options, | 
|---|
| 2431 | kind: ShimKind::IndirectLowering { | 
|---|
| 2432 | interface: interface_key, | 
|---|
| 2433 | index, | 
|---|
| 2434 | realloc: for_module, | 
|---|
| 2435 | encoding, | 
|---|
| 2436 | }, | 
|---|
| 2437 | sig: sig.clone(), | 
|---|
| 2438 | }); | 
|---|
| 2439 | } | 
|---|
| 2440 | } | 
|---|
| 2441 | } | 
|---|
| 2442 |  | 
|---|
| 2443 | // In addition to all the shims added for imports above this module also | 
|---|
| 2444 | // requires shims for resource destructors that it exports. Resource | 
|---|
| 2445 | // types are declared before the module is instantiated so the actual | 
|---|
| 2446 | // destructor is registered as a shim (defined here) and it's then | 
|---|
| 2447 | // filled in with the module's exports later. | 
|---|
| 2448 | for (export_name, export) in module_exports.iter() { | 
|---|
| 2449 | let id = match export { | 
|---|
| 2450 | Export::ResourceDtor(id) => id, | 
|---|
| 2451 | _ => continue, | 
|---|
| 2452 | }; | 
|---|
| 2453 | let resource = resolve.types[*id].name.as_ref().unwrap(); | 
|---|
| 2454 | let name = self.shims.len().to_string(); | 
|---|
| 2455 | self.push(Shim { | 
|---|
| 2456 | name, | 
|---|
| 2457 | debug_name: format!( "dtor-{resource} "), | 
|---|
| 2458 | options: RequiredOptions::empty(), | 
|---|
| 2459 | kind: ShimKind::ResourceDtor { | 
|---|
| 2460 | module: for_module, | 
|---|
| 2461 | export: export_name, | 
|---|
| 2462 | }, | 
|---|
| 2463 | sig: WasmSignature { | 
|---|
| 2464 | params: vec![WasmType::I32], | 
|---|
| 2465 | results: Vec::new(), | 
|---|
| 2466 | indirect_params: false, | 
|---|
| 2467 | retptr: false, | 
|---|
| 2468 | }, | 
|---|
| 2469 | }); | 
|---|
| 2470 | } | 
|---|
| 2471 |  | 
|---|
| 2472 | Ok(()) | 
|---|
| 2473 | } | 
|---|
| 2474 |  | 
|---|
| 2475 | fn push(&mut self, shim: Shim<'a>) { | 
|---|
| 2476 | // Only one shim per `ShimKind` is retained, so if it's already present | 
|---|
| 2477 | // don't overwrite it. If it's not present though go ahead and insert | 
|---|
| 2478 | // it. | 
|---|
| 2479 | if !self.shims.contains_key(&shim.kind) { | 
|---|
| 2480 | self.shims.insert(shim.kind.clone(), shim); | 
|---|
| 2481 | } | 
|---|
| 2482 | } | 
|---|
| 2483 | } | 
|---|
| 2484 |  | 
|---|
| 2485 | /// Alias argument to an instantiation | 
|---|
| 2486 | #[ derive(Clone, Debug)] | 
|---|
| 2487 | pub struct Item { | 
|---|
| 2488 | pub alias: String, | 
|---|
| 2489 | pub kind: ExportKind, | 
|---|
| 2490 | pub which: MainOrAdapter, | 
|---|
| 2491 | pub name: String, | 
|---|
| 2492 | } | 
|---|
| 2493 |  | 
|---|
| 2494 | /// Module argument to an instantiation | 
|---|
| 2495 | #[ derive(Debug, PartialEq, Clone)] | 
|---|
| 2496 | pub enum MainOrAdapter { | 
|---|
| 2497 | Main, | 
|---|
| 2498 | Adapter(String), | 
|---|
| 2499 | } | 
|---|
| 2500 |  | 
|---|
| 2501 | impl MainOrAdapter { | 
|---|
| 2502 | fn to_custom_module(&self) -> CustomModule<'_> { | 
|---|
| 2503 | match self { | 
|---|
| 2504 | MainOrAdapter::Main => CustomModule::Main, | 
|---|
| 2505 | MainOrAdapter::Adapter(s: &String) => CustomModule::Adapter(s), | 
|---|
| 2506 | } | 
|---|
| 2507 | } | 
|---|
| 2508 | } | 
|---|
| 2509 |  | 
|---|
| 2510 | /// Module instantiation argument | 
|---|
| 2511 | #[ derive(Clone)] | 
|---|
| 2512 | pub enum Instance { | 
|---|
| 2513 | /// Module argument | 
|---|
| 2514 | MainOrAdapter(MainOrAdapter), | 
|---|
| 2515 |  | 
|---|
| 2516 | /// Alias argument | 
|---|
| 2517 | Items(Vec<Item>), | 
|---|
| 2518 | } | 
|---|
| 2519 |  | 
|---|
| 2520 | /// Provides fine-grained control of how a library module is instantiated | 
|---|
| 2521 | /// relative to other module instances | 
|---|
| 2522 | #[ derive(Clone)] | 
|---|
| 2523 | pub struct LibraryInfo { | 
|---|
| 2524 | /// If true, instantiate any shims prior to this module | 
|---|
| 2525 | pub instantiate_after_shims: bool, | 
|---|
| 2526 |  | 
|---|
| 2527 | /// Instantiation arguments | 
|---|
| 2528 | pub arguments: Vec<(String, Instance)>, | 
|---|
| 2529 | } | 
|---|
| 2530 |  | 
|---|
| 2531 | /// Represents an adapter or library to be instantiated as part of the component | 
|---|
| 2532 | pub(super) struct Adapter { | 
|---|
| 2533 | /// The wasm of the module itself, with `component-type` sections stripped | 
|---|
| 2534 | wasm: Vec<u8>, | 
|---|
| 2535 |  | 
|---|
| 2536 | /// The metadata for the adapter | 
|---|
| 2537 | metadata: ModuleMetadata, | 
|---|
| 2538 |  | 
|---|
| 2539 | /// The set of exports from the final world which are defined by this | 
|---|
| 2540 | /// adapter or library | 
|---|
| 2541 | required_exports: IndexSet<WorldKey>, | 
|---|
| 2542 |  | 
|---|
| 2543 | /// If present, treat this module as a library rather than a "minimal" adapter | 
|---|
| 2544 | /// | 
|---|
| 2545 | /// TODO: We should refactor how various flavors of module are represented | 
|---|
| 2546 | /// and differentiated to avoid mistaking one for another. | 
|---|
| 2547 | library_info: Option<LibraryInfo>, | 
|---|
| 2548 | } | 
|---|
| 2549 |  | 
|---|
| 2550 | /// An encoder of components based on `wit` interface definitions. | 
|---|
| 2551 | #[ derive(Default)] | 
|---|
| 2552 | pub struct ComponentEncoder { | 
|---|
| 2553 | module: Vec<u8>, | 
|---|
| 2554 | pub(super) metadata: Bindgen, | 
|---|
| 2555 | validate: bool, | 
|---|
| 2556 | pub(super) main_module_exports: IndexSet<WorldKey>, | 
|---|
| 2557 | pub(super) adapters: IndexMap<String, Adapter>, | 
|---|
| 2558 | import_name_map: HashMap<String, String>, | 
|---|
| 2559 | realloc_via_memory_grow: bool, | 
|---|
| 2560 | merge_imports_based_on_semver: Option<bool>, | 
|---|
| 2561 | pub(super) reject_legacy_names: bool, | 
|---|
| 2562 | } | 
|---|
| 2563 |  | 
|---|
| 2564 | impl ComponentEncoder { | 
|---|
| 2565 | /// Set the core module to encode as a component. | 
|---|
| 2566 | /// This method will also parse any component type information stored in custom sections | 
|---|
| 2567 | /// inside the module, and add them as the interface, imports, and exports. | 
|---|
| 2568 | /// It will also add any producers information inside the component type information to the | 
|---|
| 2569 | /// core module. | 
|---|
| 2570 | pub fn module(mut self, module: &[u8]) -> Result<Self> { | 
|---|
| 2571 | let (wasm, metadata) = self.decode(module)?; | 
|---|
| 2572 | let exports = self | 
|---|
| 2573 | .merge_metadata(metadata) | 
|---|
| 2574 | .context( "failed merge WIT metadata for module with previous metadata")?; | 
|---|
| 2575 | self.main_module_exports.extend(exports); | 
|---|
| 2576 | self.module = if let Some(producers) = &self.metadata.producers { | 
|---|
| 2577 | producers.add_to_wasm(&wasm)? | 
|---|
| 2578 | } else { | 
|---|
| 2579 | wasm.to_vec() | 
|---|
| 2580 | }; | 
|---|
| 2581 | Ok(self) | 
|---|
| 2582 | } | 
|---|
| 2583 |  | 
|---|
| 2584 | fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> { | 
|---|
| 2585 | let (bytes, metadata) = metadata::decode(wasm)?; | 
|---|
| 2586 | match bytes { | 
|---|
| 2587 | Some(wasm) => Ok((Cow::Owned(wasm), metadata)), | 
|---|
| 2588 | None => Ok((Cow::Borrowed(wasm), metadata)), | 
|---|
| 2589 | } | 
|---|
| 2590 | } | 
|---|
| 2591 |  | 
|---|
| 2592 | fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> { | 
|---|
| 2593 | self.metadata.merge(metadata) | 
|---|
| 2594 | } | 
|---|
| 2595 |  | 
|---|
| 2596 | /// Sets whether or not the encoder will validate its output. | 
|---|
| 2597 | pub fn validate(mut self, validate: bool) -> Self { | 
|---|
| 2598 | self.validate = validate; | 
|---|
| 2599 | self | 
|---|
| 2600 | } | 
|---|
| 2601 |  | 
|---|
| 2602 | /// Sets whether to merge imports based on semver to the specified value. | 
|---|
| 2603 | /// | 
|---|
| 2604 | /// This affects how when to WIT worlds are merged together, for example | 
|---|
| 2605 | /// from two different libraries, whether their imports are unified when the | 
|---|
| 2606 | /// semver version ranges for interface allow it. | 
|---|
| 2607 | /// | 
|---|
| 2608 | /// This is enabled by default. | 
|---|
| 2609 | pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self { | 
|---|
| 2610 | self.merge_imports_based_on_semver = Some(merge); | 
|---|
| 2611 | self | 
|---|
| 2612 | } | 
|---|
| 2613 |  | 
|---|
| 2614 | /// Sets whether to reject the historical mangling/name scheme for core wasm | 
|---|
| 2615 | /// imports/exports as they map to the component model. | 
|---|
| 2616 | /// | 
|---|
| 2617 | /// The `wit-component` crate supported a different set of names prior to | 
|---|
| 2618 | /// WebAssembly/component-model#378 and this can be used to disable this | 
|---|
| 2619 | /// support. | 
|---|
| 2620 | /// | 
|---|
| 2621 | /// This is disabled by default. | 
|---|
| 2622 | pub fn reject_legacy_names(mut self, reject: bool) -> Self { | 
|---|
| 2623 | self.reject_legacy_names = reject; | 
|---|
| 2624 | self | 
|---|
| 2625 | } | 
|---|
| 2626 |  | 
|---|
| 2627 | /// Specifies a new adapter which is used to translate from a historical | 
|---|
| 2628 | /// wasm ABI to the canonical ABI and the `interface` provided. | 
|---|
| 2629 | /// | 
|---|
| 2630 | /// This is primarily used to polyfill, for example, | 
|---|
| 2631 | /// `wasi_snapshot_preview1` with a component-model using interface. The | 
|---|
| 2632 | /// `name` provided is the module name of the adapter that is being | 
|---|
| 2633 | /// polyfilled, for example `"wasi_snapshot_preview1"`. | 
|---|
| 2634 | /// | 
|---|
| 2635 | /// The `bytes` provided is a core wasm module which implements the `name` | 
|---|
| 2636 | /// interface in terms of the `interface` interface. This core wasm module | 
|---|
| 2637 | /// is severely restricted in its shape, for example it cannot have any data | 
|---|
| 2638 | /// segments or element segments. | 
|---|
| 2639 | /// | 
|---|
| 2640 | /// The `interface` provided is the component-model-using-interface that the | 
|---|
| 2641 | /// wasm module specified by `bytes` imports. The `bytes` will then import | 
|---|
| 2642 | /// `interface` and export functions to get imported from the module `name` | 
|---|
| 2643 | /// in the core wasm that's being wrapped. | 
|---|
| 2644 | pub fn adapter(self, name: &str, bytes: &[u8]) -> Result<Self> { | 
|---|
| 2645 | self.library_or_adapter(name, bytes, None) | 
|---|
| 2646 | } | 
|---|
| 2647 |  | 
|---|
| 2648 | /// Specifies a shared-everything library to link into the component. | 
|---|
| 2649 | /// | 
|---|
| 2650 | /// Unlike adapters, libraries _may_ have data and/or element segments, but | 
|---|
| 2651 | /// they must operate on an imported memory and table, respectively.  In | 
|---|
| 2652 | /// this case, the correct amount of space is presumed to have been | 
|---|
| 2653 | /// statically allocated in the main module's memory and table at the | 
|---|
| 2654 | /// offsets which the segments target, e.g. as arranged by | 
|---|
| 2655 | /// [super::linking::Linker]. | 
|---|
| 2656 | /// | 
|---|
| 2657 | /// Libraries are treated similarly to adapters, except that they are not | 
|---|
| 2658 | /// "minified" the way adapters are, and instantiation is controlled | 
|---|
| 2659 | /// declaratively via the `library_info` parameter. | 
|---|
| 2660 | pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result<Self> { | 
|---|
| 2661 | self.library_or_adapter(name, bytes, Some(library_info)) | 
|---|
| 2662 | } | 
|---|
| 2663 |  | 
|---|
| 2664 | fn library_or_adapter( | 
|---|
| 2665 | mut self, | 
|---|
| 2666 | name: &str, | 
|---|
| 2667 | bytes: &[u8], | 
|---|
| 2668 | library_info: Option<LibraryInfo>, | 
|---|
| 2669 | ) -> Result<Self> { | 
|---|
| 2670 | let (wasm, mut metadata) = self.decode(bytes)?; | 
|---|
| 2671 | // Merge the adapter's document into our own document to have one large | 
|---|
| 2672 | // document, and then afterwards merge worlds as well. | 
|---|
| 2673 | // | 
|---|
| 2674 | // Note that the `metadata` tracking import/export encodings is removed | 
|---|
| 2675 | // since this adapter can get different lowerings and is allowed to | 
|---|
| 2676 | // differ from the main module. This is then tracked within the | 
|---|
| 2677 | // `Adapter` structure produced below. | 
|---|
| 2678 | let adapter_metadata = mem::take(&mut metadata.metadata); | 
|---|
| 2679 | let exports = self.merge_metadata(metadata).with_context(|| { | 
|---|
| 2680 | format!( "failed to merge WIT packages of adapter `{name} ` into main packages") | 
|---|
| 2681 | })?; | 
|---|
| 2682 | if let Some(library_info) = &library_info { | 
|---|
| 2683 | // Validate that all referenced modules can be resolved. | 
|---|
| 2684 | for (_, instance) in &library_info.arguments { | 
|---|
| 2685 | let resolve = |which: &_| match which { | 
|---|
| 2686 | MainOrAdapter::Main => Ok(()), | 
|---|
| 2687 | MainOrAdapter::Adapter(name) => { | 
|---|
| 2688 | if self.adapters.contains_key(name.as_str()) { | 
|---|
| 2689 | Ok(()) | 
|---|
| 2690 | } else { | 
|---|
| 2691 | Err(anyhow!( "instance refers to unknown adapter `{name} `")) | 
|---|
| 2692 | } | 
|---|
| 2693 | } | 
|---|
| 2694 | }; | 
|---|
| 2695 |  | 
|---|
| 2696 | match instance { | 
|---|
| 2697 | Instance::MainOrAdapter(which) => resolve(which)?, | 
|---|
| 2698 | Instance::Items(items) => { | 
|---|
| 2699 | for item in items { | 
|---|
| 2700 | resolve(&item.which)?; | 
|---|
| 2701 | } | 
|---|
| 2702 | } | 
|---|
| 2703 | } | 
|---|
| 2704 | } | 
|---|
| 2705 | } | 
|---|
| 2706 | self.adapters.insert( | 
|---|
| 2707 | name.to_string(), | 
|---|
| 2708 | Adapter { | 
|---|
| 2709 | wasm: wasm.to_vec(), | 
|---|
| 2710 | metadata: adapter_metadata, | 
|---|
| 2711 | required_exports: exports, | 
|---|
| 2712 | library_info, | 
|---|
| 2713 | }, | 
|---|
| 2714 | ); | 
|---|
| 2715 | Ok(self) | 
|---|
| 2716 | } | 
|---|
| 2717 |  | 
|---|
| 2718 | /// True if the realloc and stack allocation should use memory.grow | 
|---|
| 2719 | /// The default is to use the main module realloc | 
|---|
| 2720 | /// Can be useful if cabi_realloc cannot be called before the host | 
|---|
| 2721 | /// runtime is initialized. | 
|---|
| 2722 | pub fn realloc_via_memory_grow(mut self, value: bool) -> Self { | 
|---|
| 2723 | self.realloc_via_memory_grow = value; | 
|---|
| 2724 | self | 
|---|
| 2725 | } | 
|---|
| 2726 |  | 
|---|
| 2727 | /// The instance import name map to use. | 
|---|
| 2728 | /// | 
|---|
| 2729 | /// This is used to rename instance imports in the final component. | 
|---|
| 2730 | /// | 
|---|
| 2731 | /// For example, if there is an instance import `foo:bar/baz` and it is | 
|---|
| 2732 | /// desired that the import actually be an `unlocked-dep` name, then | 
|---|
| 2733 | /// `foo:bar/baz` can be mapped to `unlocked-dep=<a:b/c@{>=x.y.z}>`. | 
|---|
| 2734 | /// | 
|---|
| 2735 | /// Note: the replacement names are not validated during encoding unless | 
|---|
| 2736 | /// the `validate` option is set to true. | 
|---|
| 2737 | pub fn import_name_map(mut self, map: HashMap<String, String>) -> Self { | 
|---|
| 2738 | self.import_name_map = map; | 
|---|
| 2739 | self | 
|---|
| 2740 | } | 
|---|
| 2741 |  | 
|---|
| 2742 | /// Encode the component and return the bytes. | 
|---|
| 2743 | pub fn encode(&mut self) -> Result<Vec<u8>> { | 
|---|
| 2744 | if self.module.is_empty() { | 
|---|
| 2745 | bail!( "a module is required when encoding a component"); | 
|---|
| 2746 | } | 
|---|
| 2747 |  | 
|---|
| 2748 | if self.merge_imports_based_on_semver.unwrap_or(true) { | 
|---|
| 2749 | self.metadata | 
|---|
| 2750 | .resolve | 
|---|
| 2751 | .merge_world_imports_based_on_semver(self.metadata.world)?; | 
|---|
| 2752 | } | 
|---|
| 2753 |  | 
|---|
| 2754 | let world = ComponentWorld::new(self).context( "failed to decode world from module")?; | 
|---|
| 2755 | let mut state = EncodingState { | 
|---|
| 2756 | component: ComponentBuilder::default(), | 
|---|
| 2757 | module_index: None, | 
|---|
| 2758 | instance_index: None, | 
|---|
| 2759 | memory_index: None, | 
|---|
| 2760 | shim_instance_index: None, | 
|---|
| 2761 | fixups_module_index: None, | 
|---|
| 2762 | adapter_modules: IndexMap::new(), | 
|---|
| 2763 | adapter_instances: IndexMap::new(), | 
|---|
| 2764 | import_type_map: HashMap::new(), | 
|---|
| 2765 | import_func_type_map: HashMap::new(), | 
|---|
| 2766 | export_type_map: HashMap::new(), | 
|---|
| 2767 | export_func_type_map: HashMap::new(), | 
|---|
| 2768 | imported_instances: Default::default(), | 
|---|
| 2769 | imported_funcs: Default::default(), | 
|---|
| 2770 | exported_instances: Default::default(), | 
|---|
| 2771 | aliased_core_items: Default::default(), | 
|---|
| 2772 | info: &world, | 
|---|
| 2773 | }; | 
|---|
| 2774 | state.encode_imports(&self.import_name_map)?; | 
|---|
| 2775 | state.encode_core_modules(); | 
|---|
| 2776 | state.encode_core_instantiation()?; | 
|---|
| 2777 | state.encode_exports(CustomModule::Main)?; | 
|---|
| 2778 | for name in self.adapters.keys() { | 
|---|
| 2779 | state.encode_exports(CustomModule::Adapter(name))?; | 
|---|
| 2780 | } | 
|---|
| 2781 | state | 
|---|
| 2782 | .component | 
|---|
| 2783 | .raw_custom_section(&crate::base_producers().raw_custom_section()); | 
|---|
| 2784 | let bytes = state.component.finish(); | 
|---|
| 2785 |  | 
|---|
| 2786 | if self.validate { | 
|---|
| 2787 | Validator::new() | 
|---|
| 2788 | .validate_all(&bytes) | 
|---|
| 2789 | .context( "failed to validate component output")?; | 
|---|
| 2790 | } | 
|---|
| 2791 |  | 
|---|
| 2792 | Ok(bytes) | 
|---|
| 2793 | } | 
|---|
| 2794 | } | 
|---|
| 2795 |  | 
|---|
| 2796 | impl ComponentWorld<'_> { | 
|---|
| 2797 | /// Convenience function to lookup a module's import map. | 
|---|
| 2798 | fn imports_for(&self, module: CustomModule) -> &ImportMap { | 
|---|
| 2799 | match module { | 
|---|
| 2800 | CustomModule::Main => &self.info.imports, | 
|---|
| 2801 | CustomModule::Adapter(name) => &self.adapters[name].info.imports, | 
|---|
| 2802 | } | 
|---|
| 2803 | } | 
|---|
| 2804 |  | 
|---|
| 2805 | /// Convenience function to lookup a module's export map. | 
|---|
| 2806 | fn exports_for(&self, module: CustomModule) -> &ExportMap { | 
|---|
| 2807 | match module { | 
|---|
| 2808 | CustomModule::Main => &self.info.exports, | 
|---|
| 2809 | CustomModule::Adapter(name) => &self.adapters[name].info.exports, | 
|---|
| 2810 | } | 
|---|
| 2811 | } | 
|---|
| 2812 |  | 
|---|
| 2813 | /// Convenience function to lookup a module's metadata. | 
|---|
| 2814 | fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata { | 
|---|
| 2815 | match module { | 
|---|
| 2816 | CustomModule::Main => &self.encoder.metadata.metadata, | 
|---|
| 2817 | CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata, | 
|---|
| 2818 | } | 
|---|
| 2819 | } | 
|---|
| 2820 | } | 
|---|
| 2821 |  | 
|---|
| 2822 | #[ cfg(all(test, feature = "dummy-module"))] | 
|---|
| 2823 | mod test { | 
|---|
| 2824 | use super::*; | 
|---|
| 2825 | use crate::{dummy_module, embed_component_metadata}; | 
|---|
| 2826 | use wit_parser::ManglingAndAbi; | 
|---|
| 2827 |  | 
|---|
| 2828 | #[ test] | 
|---|
| 2829 | fn it_renames_imports() { | 
|---|
| 2830 | let mut resolve = Resolve::new(); | 
|---|
| 2831 | let pkg = resolve | 
|---|
| 2832 | .push_str( | 
|---|
| 2833 | "test.wit", | 
|---|
| 2834 | r#" | 
|---|
| 2835 | package test:wit; | 
|---|
| 2836 |  | 
|---|
| 2837 | interface i { | 
|---|
| 2838 |     f: func(); | 
|---|
| 2839 | } | 
|---|
| 2840 |  | 
|---|
| 2841 | world test { | 
|---|
| 2842 |     import i; | 
|---|
| 2843 |     import foo: interface { | 
|---|
| 2844 |         f: func(); | 
|---|
| 2845 |     } | 
|---|
| 2846 | } | 
|---|
| 2847 | "#, | 
|---|
| 2848 | ) | 
|---|
| 2849 | .unwrap(); | 
|---|
| 2850 | let world = resolve.select_world(pkg, None).unwrap(); | 
|---|
| 2851 |  | 
|---|
| 2852 | let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32); | 
|---|
| 2853 |  | 
|---|
| 2854 | embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap(); | 
|---|
| 2855 |  | 
|---|
| 2856 | let encoded = ComponentEncoder::default() | 
|---|
| 2857 | .import_name_map(HashMap::from([ | 
|---|
| 2858 | ( | 
|---|
| 2859 | "foo".to_string(), | 
|---|
| 2860 | "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(), | 
|---|
| 2861 | ), | 
|---|
| 2862 | ( | 
|---|
| 2863 | "test:wit/i".to_string(), | 
|---|
| 2864 | "locked-dep=<foo:bar/i@1.2.3>".to_string(), | 
|---|
| 2865 | ), | 
|---|
| 2866 | ])) | 
|---|
| 2867 | .module(&module) | 
|---|
| 2868 | .unwrap() | 
|---|
| 2869 | .validate(true) | 
|---|
| 2870 | .encode() | 
|---|
| 2871 | .unwrap(); | 
|---|
| 2872 |  | 
|---|
| 2873 | let wat = wasmprinter::print_bytes(encoded).unwrap(); | 
|---|
| 2874 | assert!(wat.contains( "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>")); | 
|---|
| 2875 | assert!(wat.contains( "locked-dep=<foo:bar/i@1.2.3>")); | 
|---|
| 2876 | } | 
|---|
| 2877 | } | 
|---|
| 2878 |  | 
|---|