1use super::{Adapter, ComponentEncoder, LibraryInfo, RequiredOptions};
2use crate::validation::{
3 validate_adapter_module, validate_module, Import, ImportMap, ValidatedModule,
4};
5use anyhow::{Context, Result};
6use indexmap::{IndexMap, IndexSet};
7use std::borrow::Cow;
8use std::collections::{HashMap, HashSet};
9use wit_parser::{
10 abi::{AbiVariant, WasmSignature},
11 Function, InterfaceId, LiveTypes, Resolve, TypeDefKind, TypeId, TypeOwner, WorldId, WorldItem,
12 WorldKey,
13};
14
15pub struct WorldAdapter<'a> {
16 pub wasm: Cow<'a, [u8]>,
17 pub info: ValidatedModule,
18 pub library_info: Option<&'a LibraryInfo>,
19}
20
21pub struct ComponentWorld<'a> {
27 pub encoder: &'a ComponentEncoder,
29 pub info: ValidatedModule,
32 pub adapters: IndexMap<&'a str, WorldAdapter<'a>>,
35 pub import_map: IndexMap<Option<String>, ImportedInterface>,
37 pub live_type_imports: IndexMap<InterfaceId, IndexSet<TypeId>>,
40 pub exports_used: HashMap<InterfaceId, HashSet<InterfaceId>>,
46}
47
48#[derive(Debug)]
49pub struct ImportedInterface {
50 pub lowerings: IndexMap<(String, AbiVariant), Lowering>,
51 pub interface: Option<InterfaceId>,
52}
53
54#[derive(Debug)]
55pub enum Lowering {
56 Direct,
57 Indirect {
58 sig: WasmSignature,
59 options: RequiredOptions,
60 },
61 ResourceDrop(TypeId),
62}
63
64impl<'a> ComponentWorld<'a> {
65 pub fn new(encoder: &'a ComponentEncoder) -> Result<Self> {
66 let info = validate_module(encoder, &encoder.module).context("module was not valid")?;
67
68 let mut ret = ComponentWorld {
69 encoder,
70 info,
71 adapters: IndexMap::new(),
72 import_map: IndexMap::new(),
73 live_type_imports: Default::default(),
74 exports_used: HashMap::new(),
75 };
76
77 ret.process_adapters()?;
78 ret.process_imports()?;
79 ret.process_exports_used();
80 ret.process_live_type_imports();
81
82 Ok(ret)
83 }
84
85 fn process_adapters(&mut self) -> Result<()> {
90 let resolve = &self.encoder.metadata.resolve;
91 let world = self.encoder.metadata.world;
92 for (
93 name,
94 Adapter {
95 wasm,
96 metadata: _,
97 required_exports,
98 library_info,
99 },
100 ) in self.encoder.adapters.iter()
101 {
102 let required_by_import = self.info.imports.required_from_adapter(name.as_str());
103 let no_required_by_import = || required_by_import.is_empty();
104 let no_required_exports = || {
105 required_exports
106 .iter()
107 .all(|name| match &resolve.worlds[world].exports[name] {
108 WorldItem::Function(_) => false,
109 WorldItem::Interface { id, .. } => {
110 resolve.interfaces[*id].functions.is_empty()
111 }
112 WorldItem::Type(_) => true,
113 })
114 };
115 if no_required_by_import() && no_required_exports() && library_info.is_none() {
116 continue;
117 }
118 let wasm = if library_info.is_some() {
119 Cow::Borrowed(wasm as &[u8])
120 } else {
121 let info = validate_adapter_module(
148 self.encoder,
149 &wasm,
150 &required_by_import,
151 required_exports,
152 library_info.as_ref(),
153 )
154 .with_context(|| {
155 format!("failed to validate the imports of the adapter module `{name}`")
156 })?;
157 let mut required = IndexSet::new();
158 for (name, _ty) in required_by_import.iter() {
159 required.insert(name.to_string());
160 }
161 for (name, _export) in info.exports.iter() {
162 required.insert(name.to_string());
163 }
164
165 Cow::Owned(
166 crate::gc::run(
167 wasm,
168 &required,
169 if self.encoder.realloc_via_memory_grow {
170 None
171 } else {
172 self.info.exports.realloc_to_import_into_adapter()
173 },
174 )
175 .context("failed to reduce input adapter module to its minimal size")?,
176 )
177 };
178 let info = validate_adapter_module(
179 self.encoder,
180 &wasm,
181 &required_by_import,
182 required_exports,
183 library_info.as_ref(),
184 )
185 .with_context(|| {
186 format!("failed to validate the imports of the minimized adapter module `{name}`")
187 })?;
188 self.adapters.insert(
189 name,
190 WorldAdapter {
191 info,
192 wasm,
193 library_info: library_info.as_ref(),
194 },
195 );
196 }
197 Ok(())
198 }
199
200 fn process_imports(&mut self) -> Result<()> {
204 let resolve = &self.encoder.metadata.resolve;
205 let world = self.encoder.metadata.world;
206
207 let mut required = Required::default();
211 for (_, _, import) in self
212 .adapters
213 .values()
214 .flat_map(|a| a.info.imports.imports())
215 .chain(self.info.imports.imports())
216 {
217 match import {
218 Import::WorldFunc(_, name, abi) => {
219 required
220 .interface_funcs
221 .entry(None)
222 .or_default()
223 .insert((name, *abi));
224 }
225 Import::InterfaceFunc(_, id, name, abi) => {
226 required
227 .interface_funcs
228 .entry(Some(*id))
229 .or_default()
230 .insert((name, *abi));
231 }
232 Import::ImportedResourceDrop(_, _, id) => {
233 required.resource_drops.insert(*id);
234 }
235 _ => {}
236 }
237 }
238 for (name, item) in resolve.worlds[world].imports.iter() {
239 add_item(&mut self.import_map, resolve, name, item, &required)?;
240 }
241 return Ok(());
242
243 fn add_item(
244 import_map: &mut IndexMap<Option<String>, ImportedInterface>,
245 resolve: &Resolve,
246 name: &WorldKey,
247 item: &WorldItem,
248 required: &Required<'_>,
249 ) -> Result<()> {
250 let name = resolve.name_world_key(name);
251 log::trace!("register import `{name}`");
252 let import_map_key = match item {
253 WorldItem::Function(_) | WorldItem::Type(_) => None,
254 WorldItem::Interface { .. } => Some(name),
255 };
256 let interface_id = match item {
257 WorldItem::Function(_) | WorldItem::Type(_) => None,
258 WorldItem::Interface { id, .. } => Some(*id),
259 };
260 let interface = import_map
261 .entry(import_map_key)
262 .or_insert_with(|| ImportedInterface {
263 interface: interface_id,
264 lowerings: Default::default(),
265 });
266 assert_eq!(interface.interface, interface_id);
267 match item {
268 WorldItem::Function(func) => {
269 interface.add_func(required, resolve, func);
270 }
271 WorldItem::Type(ty) => {
272 interface.add_type(required, resolve, *ty);
273 }
274 WorldItem::Interface { id, .. } => {
275 for (_name, ty) in resolve.interfaces[*id].types.iter() {
276 interface.add_type(required, resolve, *ty);
277 }
278 for (_name, func) in resolve.interfaces[*id].functions.iter() {
279 interface.add_func(required, resolve, func);
280 }
281 }
282 }
283 Ok(())
284 }
285 }
286
287 fn process_live_type_imports(&mut self) {
290 let mut live = LiveTypes::default();
291 let resolve = &self.encoder.metadata.resolve;
292 let world = self.encoder.metadata.world;
293
294 self.add_live_imports(world, &self.info.imports, &mut live);
297 for (adapter_name, adapter) in self.adapters.iter() {
298 log::trace!("processing adapter `{adapter_name}`");
299 self.add_live_imports(world, &adapter.info.imports, &mut live);
300 }
301
302 for (name, item) in resolve.worlds[world].exports.iter() {
316 log::trace!("add live world export `{}`", resolve.name_world_key(name));
317 let id = match item {
318 WorldItem::Interface { id, .. } => id,
319 WorldItem::Function(_) | WorldItem::Type(_) => {
320 live.add_world_item(resolve, item);
321 continue;
322 }
323 };
324
325 let exports_used = &self.exports_used[id];
326 let mut live_from_export = LiveTypes::default();
327 live_from_export.add_world_item(resolve, item);
328 for ty in live_from_export.iter() {
329 let owner = match resolve.types[ty].owner {
330 TypeOwner::Interface(id) => id,
331 _ => continue,
332 };
333 if owner != *id && !exports_used.contains(&owner) {
334 live.add_type_id(resolve, ty);
335 }
336 }
337 }
338
339 for live in live.iter() {
340 let owner = match resolve.types[live].owner {
341 TypeOwner::Interface(id) => id,
342 _ => continue,
343 };
344 self.live_type_imports
345 .entry(owner)
346 .or_insert(Default::default())
347 .insert(live);
348 }
349 }
350
351 fn add_live_imports(&self, world: WorldId, imports: &ImportMap, live: &mut LiveTypes) {
352 let resolve = &self.encoder.metadata.resolve;
353 let world = &resolve.worlds[world];
354
355 for (_, item) in world.imports.iter() {
361 if let WorldItem::Type(id) = item {
362 live.add_type_id(resolve, *id);
363 }
364 }
365
366 for (_, _, import) in imports.imports() {
367 match import {
368 Import::WorldFunc(key, _, _) => {
370 live.add_world_item(resolve, &world.imports[key]);
371 }
372 Import::InterfaceFunc(_, id, name, _) => {
373 live.add_func(resolve, &resolve.interfaces[*id].functions[name]);
374 }
375
376 Import::ImportedResourceDrop(.., ty)
378 | Import::ExportedResourceDrop(_, ty)
379 | Import::ExportedResourceNew(_, ty)
380 | Import::ExportedResourceRep(_, ty) => live.add_type_id(resolve, *ty),
381
382 Import::StreamNew(info)
385 | Import::StreamRead { info, async_: _ }
386 | Import::StreamWrite { info, async_: _ }
387 | Import::StreamCancelRead { info, async_: _ }
388 | Import::StreamCancelWrite { info, async_: _ }
389 | Import::StreamCloseReadable(info)
390 | Import::StreamCloseWritable(info)
391 | Import::FutureNew(info)
392 | Import::FutureRead { info, async_: _ }
393 | Import::FutureWrite { info, async_: _ }
394 | Import::FutureCancelRead { info, async_: _ }
395 | Import::FutureCancelWrite { info, async_: _ }
396 | Import::FutureCloseReadable(info)
397 | Import::FutureCloseWritable(info) => {
398 live.add_type_id(resolve, info.ty);
399 }
400
401 Import::ExportedTaskReturn(.., ty) => {
404 if let Some(ty) = ty {
405 live.add_type(resolve, ty);
406 }
407 }
408
409 Import::AdapterExport(_)
412 | Import::MainModuleMemory
413 | Import::MainModuleExport { .. }
414 | Import::Item(_)
415 | Import::ContextGet(_)
416 | Import::ContextSet(_)
417 | Import::BackpressureSet
418 | Import::WaitableSetNew
419 | Import::WaitableSetWait { .. }
420 | Import::WaitableSetPoll { .. }
421 | Import::WaitableSetDrop
422 | Import::WaitableJoin
423 | Import::Yield { .. }
424 | Import::SubtaskDrop
425 | Import::SubtaskCancel { .. }
426 | Import::ErrorContextNew { .. }
427 | Import::ErrorContextDebugMessage { .. }
428 | Import::ErrorContextDrop
429 | Import::ExportedTaskCancel => {}
430 }
431 }
432 }
433
434 fn process_exports_used(&mut self) {
435 let resolve = &self.encoder.metadata.resolve;
436 let world = self.encoder.metadata.world;
437
438 let exports = &resolve.worlds[world].exports;
439 for (_name, item) in exports.iter() {
440 let id = match item {
441 WorldItem::Function(_) => continue,
442 WorldItem::Interface { id, .. } => *id,
443 WorldItem::Type(_) => unreachable!(),
444 };
445 let mut set = HashSet::new();
446
447 for other in resolve.interface_direct_deps(id) {
448 if !exports.contains_key(&WorldKey::Interface(other)) {
451 continue;
452 }
453
454 if set.insert(other) {
458 set.extend(self.exports_used[&other].iter().copied());
459 }
460 }
461 let prev = self.exports_used.insert(id, set);
462 assert!(prev.is_none());
463 }
464 }
465}
466
467#[derive(Default)]
468struct Required<'a> {
469 interface_funcs: IndexMap<Option<InterfaceId>, IndexSet<(&'a str, AbiVariant)>>,
470 resource_drops: IndexSet<TypeId>,
471}
472
473impl ImportedInterface {
474 fn add_func(&mut self, required: &Required<'_>, resolve: &Resolve, func: &Function) {
475 let mut abis = Vec::with_capacity(2);
476 if let Some(set) = required.interface_funcs.get(&self.interface) {
477 if set.contains(&(func.name.as_str(), AbiVariant::GuestImport)) {
478 abis.push(AbiVariant::GuestImport);
479 }
480 if set.contains(&(func.name.as_str(), AbiVariant::GuestImportAsync)) {
481 abis.push(AbiVariant::GuestImportAsync);
482 }
483 }
484 for abi in abis {
485 log::trace!("add func {} {abi:?}", func.name);
486 let options = RequiredOptions::for_import(resolve, func, abi);
487 let lowering = if options.is_empty() {
488 Lowering::Direct
489 } else {
490 let sig = resolve.wasm_signature(abi, func);
491 Lowering::Indirect { sig, options }
492 };
493
494 let prev = self.lowerings.insert((func.name.clone(), abi), lowering);
495 assert!(prev.is_none());
496 }
497 }
498
499 fn add_type(&mut self, required: &Required<'_>, resolve: &Resolve, id: TypeId) {
500 let ty = &resolve.types[id];
501 match &ty.kind {
502 TypeDefKind::Resource => {}
503 _ => return,
504 }
505 let name = ty.name.as_deref().expect("resources must be named");
506
507 if required.resource_drops.contains(&id) {
508 let name = format!("{name}_drop");
509 let prev = self
510 .lowerings
511 .insert((name, AbiVariant::GuestImport), Lowering::ResourceDrop(id));
512 assert!(prev.is_none());
513 }
514 }
515}