1 use crate::component::func::{LiftContext, LowerContext, bad_type_info, desc};
2 use crate::component::matching::InstanceType;
3 use crate::component::{ComponentType, Lift, Lower};
4 use crate::prelude::*;
5 use crate::runtime::vm::component::{
6     ComponentInstance, InstanceFlags, ResourceTables, TypedResource, TypedResourceIndex,
7 };
8 use crate::runtime::vm::{SendSyncPtr, VMFuncRef, ValRaw};
9 use crate::store::{StoreId, StoreOpaque};
10 use crate::{AsContextMut, StoreContextMut, Trap};
11 use core::any::TypeId;
12 use core::fmt;
13 use core::marker;
14 use core::mem::MaybeUninit;
15 use core::ptr::NonNull;
16 use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
17 use wasmtime_environ::component::{
18     CanonicalAbiInfo, ComponentTypes, DefinedResourceIndex, InterfaceType, ResourceIndex,
19     TypeResourceTableIndex,
20 };
21 
22 /// Representation of a resource type in the component model.
23 ///
24 /// Resources are currently always represented as 32-bit integers but they have
25 /// unique types across instantiations and the host. For example instantiating
26 /// the same component twice means that defined resource types in the component
27 /// will all be different. Values of this type can be compared to see if
28 /// resources have the same type.
29 ///
30 /// Resource types can also be defined on the host in addition to guests. On the
31 /// host resource types are tied to a `T`, an arbitrary Rust type. Two host
32 /// resource types are the same if they point to the same `T`.
33 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
34 pub struct ResourceType {
35     kind: ResourceTypeKind,
36 }
37 
38 impl ResourceType {
39     /// Creates a new host resource type corresponding to `T`.
40     ///
41     /// Note that `T` is a mostly a phantom type parameter here. It does not
42     /// need to reflect the actual storage of the resource `T`. For example this
43     /// is valid:
44     ///
45     /// ```rust
46     /// use wasmtime::component::ResourceType;
47     ///
48     /// struct Foo;
49     ///
50     /// let ty = ResourceType::host::<Foo>();
51     /// ```
52     ///
53     /// A resource type of type `ResourceType::host::<T>()` will match the type
54     /// of the value produced by `Resource::<T>::new_{own,borrow}`.
55     pub fn host<T: 'static>() -> ResourceType {
56         ResourceType {
57             kind: ResourceTypeKind::Host(TypeId::of::<T>()),
58         }
59     }
60 
61     pub(crate) fn guest(
62         store: StoreId,
63         instance: &ComponentInstance,
64         id: DefinedResourceIndex,
65     ) -> ResourceType {
66         ResourceType {
67             kind: ResourceTypeKind::Guest {
68                 store,
69                 instance: instance as *const _ as usize,
70                 id,
71             },
72         }
73     }
74 
75     pub(crate) fn uninstantiated(types: &ComponentTypes, index: ResourceIndex) -> ResourceType {
76         ResourceType {
77             kind: ResourceTypeKind::Uninstantiated {
78                 component: types as *const _ as usize,
79                 index,
80             },
81         }
82     }
83 }
84 
85 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
86 enum ResourceTypeKind {
87     Host(TypeId),
88     Guest {
89         store: StoreId,
90         // For now this is the `*mut ComponentInstance` pointer within the store
91         // that this guest corresponds to. It's used to distinguish different
92         // instantiations of the same component within the store.
93         instance: usize,
94         id: DefinedResourceIndex,
95     },
96     Uninstantiated {
97         // Like `instance` in `Guest` above this is a pointer and is used to
98         // distinguish between two components. Technically susceptible to ABA
99         // issues but the consequence is a nonexistent resource would be equal
100         // to a new resource so there's not really any issue with that.
101         component: usize,
102         index: ResourceIndex,
103     },
104 }
105 
106 /// A host-defined resource in the component model.
107 ///
108 /// This type can be thought of as roughly a newtype wrapper around `u32` for
109 /// use as a resource with the component model. The main guarantee that the
110 /// component model provides is that the `u32` is not forgeable by guests and
111 /// there are guaranteed semantics about when a `u32` may be in use by the guest
112 /// and when it's guaranteed no longer needed. This means that it is safe for
113 /// embedders to consider the internal `u32` representation "trusted" and use it
114 /// for things like table indices with infallible accessors that panic on
115 /// out-of-bounds. This should only panic for embedder bugs, not because of any
116 /// possible behavior in the guest.
117 ///
118 /// A `Resource<T>` value dynamically represents both an `(own $t)` in the
119 /// component model as well as a `(borrow $t)`. It can be inspected via
120 /// [`Resource::owned`] to test whether it is an owned handle. An owned handle
121 /// which is not actively borrowed can be destroyed at any time as it's
122 /// guaranteed that the guest does not have access to it. A borrowed handle, on
123 /// the other hand, may be accessed by the guest so it's not necessarily
124 /// guaranteed to be able to be destroyed.
125 ///
126 /// Note that the "own" and "borrow" here refer to the component model, not
127 /// Rust. The semantics of Rust ownership and borrowing are slightly different
128 /// than the component model's (but spiritually the same) in that more dynamic
129 /// tracking is employed as part of the component model. This means that it's
130 /// possible to get runtime errors when using a `Resource<T>`. For example it is
131 /// an error to call [`Resource::new_borrow`] and pass that to a component
132 /// function expecting `(own $t)` and this is not statically disallowed.
133 ///
134 /// The [`Resource`] type implements both the [`Lift`] and [`Lower`] trait to be
135 /// used with typed functions in the component model or as part of aggregate
136 /// structures and datatypes.
137 ///
138 /// # Destruction of a resource
139 ///
140 /// Resources in the component model are optionally defined with a destructor,
141 /// but this host resource type does not specify a destructor. It is left up to
142 /// the embedder to be able to determine how best to a destroy a resource when
143 /// it is owned.
144 ///
145 /// Note, though, that while [`Resource`] itself does not specify destructors
146 /// it's still possible to do so via the [`Linker::resource`] definition. When a
147 /// resource type is defined for a guest component a destructor can be specified
148 /// which can be used to hook into resource destruction triggered by the guest.
149 ///
150 /// This means that there are two ways that resource destruction is handled:
151 ///
152 /// * Host resources destroyed by the guest can hook into the
153 ///   [`Linker::resource`] destructor closure to handle resource destruction.
154 ///   This could, for example, remove table entries.
155 ///
156 /// * Host resources owned by the host itself have no automatic means of
157 ///   destruction. The host can make its own determination that its own resource
158 ///   is not lent out to the guest and at that time choose to destroy or
159 ///   deallocate it.
160 ///
161 /// # Dynamic behavior of a resource
162 ///
163 /// A host-defined [`Resource`] does not necessarily represent a static value.
164 /// Its internals may change throughout its usage to track the state associated
165 /// with the resource. The internal 32-bit host-defined representation never
166 /// changes, however.
167 ///
168 /// For example if there's a component model function of the form:
169 ///
170 /// ```wasm
171 /// (func (param "a" (borrow $t)) (param "b" (own $t)))
172 /// ```
173 ///
174 /// Then that can be extracted in Rust with:
175 ///
176 /// ```rust,ignore
177 /// let func = instance.get_typed_func::<(&Resource<T>, &Resource<T>), ()>(&mut store, "name")?;
178 /// ```
179 ///
180 /// Here the exact same resource can be provided as both arguments but that is
181 /// not valid to do so because the same resource cannot be actively borrowed and
182 /// passed by-value as the second parameter at the same time. The internal state
183 /// in `Resource<T>` will track this information and provide a dynamic runtime
184 /// error in this situation.
185 ///
186 /// Mostly it's important to be aware that there is dynamic state associated
187 /// with a [`Resource<T>`] to provide errors in situations that cannot be
188 /// statically ruled out.
189 ///
190 /// # Borrows and host responsibilities
191 ///
192 /// Borrows to resources in the component model are guaranteed to be transient
193 /// such that if a borrow is passed as part of a function call then when the
194 /// function returns it's guaranteed that the guest no longer has access to the
195 /// resource. This guarantee, however, must be manually upheld by the host when
196 /// it receives its own borrow.
197 ///
198 /// As mentioned above the [`Resource<T>`] type can represent a borrowed value
199 /// in addition to an owned value. This means a guest can provide the host with
200 /// a borrow, such as an argument to an imported function:
201 ///
202 /// ```rust,ignore
203 /// linker.root().func_wrap("name", |_cx, (r,): (Resource<MyType>,)| {
204 ///     assert!(!r.owned());
205 ///     // .. here `r` is a borrowed value provided by the guest and the host
206 ///     // shouldn't continue to access it beyond the scope of this call
207 /// })?;
208 /// ```
209 ///
210 /// In this situation the host should take care to not attempt to persist the
211 /// resource beyond the scope of the call. It's the host's resource so it
212 /// technically can do what it wants with it but nothing is statically
213 /// preventing `r` to stay pinned to the lifetime of the closure invocation.
214 /// It's considered a mistake that the host performed if `r` is persisted too
215 /// long and accessed at the wrong time.
216 ///
217 /// [`Linker::resource`]: crate::component::LinkerInstance::resource
218 pub struct Resource<T> {
219     /// The host-defined 32-bit representation of this resource.
220     rep: u32,
221 
222     /// Dear rust please consider `T` used even though it's not actually used.
223     _marker: marker::PhantomData<fn() -> T>,
224 
225     state: AtomicResourceState,
226 }
227 
228 /// Internal dynamic state tracking for this resource. This can be one of
229 /// four different states:
230 ///
231 /// * `BORROW` / `u64::MAX` - this indicates that this is a borrowed
232 ///   resource. The `rep` doesn't live in the host table and this `Resource`
233 ///   instance is transiently available. It's the host's responsibility to
234 ///   discard this resource when the borrow duration has finished.
235 ///
236 /// * `NOT_IN_TABLE` / `u64::MAX - 1` - this indicates that this is an owned
237 ///   resource not present in any store's table. This resource is not lent
238 ///   out. It can be passed as an `(own $t)` directly into a guest's table
239 ///   or it can be passed as a borrow to a guest which will insert it into
240 ///   a host store's table for dynamic borrow tracking.
241 ///
242 /// * `TAKEN` / `u64::MAX - 2` - while the `rep` is available the resource
243 ///   has been dynamically moved into a guest and cannot be moved in again.
244 ///   This is used for example to prevent the same resource from being
245 ///   passed twice to a guest.
246 ///
247 /// * All other values - any other value indicates that the value is an
248 ///   index into a store's table of host resources. It's guaranteed that the
249 ///   table entry represents a host resource and the resource may have
250 ///   borrow tracking associated with it. The low 32-bits of the value are
251 ///   the table index and the upper 32-bits are the generation.
252 ///
253 /// Note that this is two `AtomicU32` fields but it's not intended to actually
254 /// be used in conjunction with threads as generally a `Store<T>` lives on one
255 /// thread at a time. The pair of `AtomicU32` here is used to ensure that this
256 /// type is `Send + Sync` when captured as a reference to make async
257 /// programming more ergonomic.
258 ///
259 /// Also note that two `AtomicU32` here are used instead of `AtomicU64` to be
260 /// more portable to platforms without 64-bit atomics.
261 struct AtomicResourceState {
262     index: AtomicU32,
263     generation: AtomicU32,
264 }
265 
266 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
267 enum ResourceState {
268     Borrow,
269     NotInTable,
270     Taken,
271     Index(HostResourceIndex),
272 }
273 
274 impl AtomicResourceState {
275     const BORROW: Self = AtomicResourceState::new(ResourceState::Borrow);
276     const NOT_IN_TABLE: Self = AtomicResourceState::new(ResourceState::NotInTable);
277 
278     const fn new(state: ResourceState) -> AtomicResourceState {
279         let (index, generation) = state.encode();
280         Self {
281             index: AtomicU32::new(index),
282             generation: AtomicU32::new(generation),
283         }
284     }
285 
286     fn get(&self) -> ResourceState {
287         ResourceState::decode(self.index.load(Relaxed), self.generation.load(Relaxed))
288     }
289 
290     fn swap(&self, state: ResourceState) -> ResourceState {
291         let (index, generation) = state.encode();
292         let index_prev = self.index.load(Relaxed);
293         self.index.store(index, Relaxed);
294         let generation_prev = self.generation.load(Relaxed);
295         self.generation.store(generation, Relaxed);
296         ResourceState::decode(index_prev, generation_prev)
297     }
298 }
299 
300 impl ResourceState {
301     // See comments on `state` above for info about these values.
302     const BORROW: u32 = u32::MAX;
303     const NOT_IN_TABLE: u32 = u32::MAX - 1;
304     const TAKEN: u32 = u32::MAX - 2;
305 
306     fn decode(idx: u32, generation: u32) -> ResourceState {
307         match generation {
308             Self::BORROW => Self::Borrow,
309             Self::NOT_IN_TABLE => Self::NotInTable,
310             Self::TAKEN => Self::Taken,
311             _ => Self::Index(HostResourceIndex::new(idx, generation)),
312         }
313     }
314 
315     const fn encode(&self) -> (u32, u32) {
316         match self {
317             Self::Borrow => (0, Self::BORROW),
318             Self::NotInTable => (0, Self::NOT_IN_TABLE),
319             Self::Taken => (0, Self::TAKEN),
320             Self::Index(index) => (index.index(), index.generation()),
321         }
322     }
323 }
324 
325 /// Metadata tracking the state of resources within a `Store`.
326 ///
327 /// This is a borrowed structure created from a `Store` piecemeal from below.
328 /// The `ResourceTables` type holds most of the raw information and this
329 /// structure tacks on a reference to `HostResourceData` to track generation
330 /// numbers of host indices.
331 pub struct HostResourceTables<'a> {
332     tables: ResourceTables<'a>,
333     host_resource_data: &'a mut HostResourceData,
334 }
335 
336 /// Metadata for host-owned resources owned within a `Store`.
337 ///
338 /// This metadata is used to prevent the ABA problem with indices handed out as
339 /// part of `Resource` and `ResourceAny`. Those structures are `Copy` meaning
340 /// that it's easy to reuse them, possibly accidentally. To prevent issues in
341 /// the host Wasmtime attaches both an index (within `ResourceTables`) as well
342 /// as a 32-bit generation counter onto each `HostResourceIndex` which the host
343 /// actually holds in `Resource` and `ResourceAny`.
344 ///
345 /// This structure holds a list which is a parallel list to the "list of reps"
346 /// that's stored within `ResourceTables` elsewhere in the `Store`. This
347 /// parallel list holds the last known generation of each element in the table.
348 /// The generation is then compared on access to make sure it's the same.
349 ///
350 /// Whenever a slot in the table is allocated the `cur_generation` field is
351 /// pushed at the corresponding index of `generation_of_table_slot`. Whenever
352 /// a field is accessed the current value of `generation_of_table_slot` is
353 /// checked against the generation of the index. Whenever a slot is deallocated
354 /// the generation is incremented. Put together this means that any access of a
355 /// deallocated slot should deterministically provide an error.
356 #[derive(Default)]
357 pub struct HostResourceData {
358     cur_generation: u32,
359     table_slot_metadata: Vec<TableSlot>,
360 }
361 
362 #[derive(Copy, Clone)]
363 struct TableSlot {
364     generation: u32,
365     flags: Option<InstanceFlags>,
366     dtor: Option<SendSyncPtr<VMFuncRef>>,
367 }
368 
369 /// Host representation of an index into a table slot.
370 ///
371 /// This is morally (u32, u32) but is encoded as a 64-bit integer. The low
372 /// 32-bits are the table index and the upper 32-bits are the generation
373 /// counter.
374 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
375 #[repr(transparent)]
376 pub struct HostResourceIndex(u64);
377 
378 impl HostResourceIndex {
379     fn new(idx: u32, generation: u32) -> HostResourceIndex {
380         HostResourceIndex(u64::from(idx) | (u64::from(generation) << 32))
381     }
382 
383     const fn index(&self) -> u32 {
384         (self.0 & 0xffffffff) as u32
385     }
386 
387     const fn generation(&self) -> u32 {
388         (self.0 >> 32) as u32
389     }
390 }
391 
392 impl<'a> HostResourceTables<'a> {
393     pub fn new_host(store: &'a mut StoreOpaque) -> HostResourceTables<'a> {
394         let (calls, host_table, host_resource_data) = store.component_resource_state();
395         HostResourceTables::from_parts(
396             ResourceTables {
397                 host_table: Some(host_table),
398                 calls,
399                 guest: None,
400             },
401             host_resource_data,
402         )
403     }
404 
405     pub fn from_parts(
406         tables: ResourceTables<'a>,
407         host_resource_data: &'a mut HostResourceData,
408     ) -> Self {
409         HostResourceTables {
410             tables,
411             host_resource_data,
412         }
413     }
414 
415     /// Lifts an `own` resource that resides in the host's tables at the `idx`
416     /// specified into its `rep`.
417     ///
418     /// # Errors
419     ///
420     /// Returns an error if `idx` doesn't point to a valid owned resource, or
421     /// if `idx` can't be lifted as an `own` (e.g. it has active borrows).
422     pub fn host_resource_lift_own(&mut self, idx: HostResourceIndex) -> Result<u32> {
423         let (idx, _) = self.validate_host_index(idx, true)?;
424         self.tables.resource_lift_own(TypedResourceIndex::Host(idx))
425     }
426 
427     /// See [`HostResourceTables::host_resource_lift_own`].
428     pub fn host_resource_lift_borrow(&mut self, idx: HostResourceIndex) -> Result<u32> {
429         let (idx, _) = self.validate_host_index(idx, false)?;
430         self.tables
431             .resource_lift_borrow(TypedResourceIndex::Host(idx))
432     }
433 
434     /// Lowers an `own` resource to be owned by the host.
435     ///
436     /// This returns a new index into the host's set of resource tables which
437     /// will point to the `rep` specified. The returned index is suitable for
438     /// conversion into either [`Resource`] or [`ResourceAny`].
439     ///
440     /// The `dtor` and instance `flags` are specified as well to know what
441     /// destructor to run when this resource is destroyed.
442     pub fn host_resource_lower_own(
443         &mut self,
444         rep: u32,
445         dtor: Option<NonNull<VMFuncRef>>,
446         flags: Option<InstanceFlags>,
447     ) -> Result<HostResourceIndex> {
448         let idx = self.tables.resource_lower_own(TypedResource::Host(rep))?;
449         Ok(self.new_host_index(idx, dtor, flags))
450     }
451 
452     /// See [`HostResourceTables::host_resource_lower_own`].
453     pub fn host_resource_lower_borrow(&mut self, rep: u32) -> Result<HostResourceIndex> {
454         let idx = self
455             .tables
456             .resource_lower_borrow(TypedResource::Host(rep))?;
457         Ok(self.new_host_index(idx, None, None))
458     }
459 
460     /// Validates that `idx` is still valid for the host tables, notably
461     /// ensuring that the generation listed in `idx` is the same as the
462     /// last recorded generation of the slot itself.
463     ///
464     /// The `is_removal` option indicates whether or not this table access will
465     /// end up removing the element from the host table. In such a situation the
466     /// current generation number is incremented.
467     fn validate_host_index(
468         &mut self,
469         idx: HostResourceIndex,
470         is_removal: bool,
471     ) -> Result<(u32, Option<TableSlot>)> {
472         let actual = usize::try_from(idx.index())
473             .ok()
474             .and_then(|i| self.host_resource_data.table_slot_metadata.get(i).copied());
475 
476         // If `idx` is out-of-bounds then skip returning an error. In such a
477         // situation the operation that this is guarding will return a more
478         // precise error, such as a lift operation.
479         if let Some(actual) = actual {
480             if actual.generation != idx.generation() {
481                 bail!("host-owned resource is being used with the wrong type");
482             }
483         }
484 
485         // Bump the current generation of this is a removal to ensure any
486         // future item placed in this slot can't be pointed to by the `idx`
487         // provided above.
488         if is_removal {
489             self.host_resource_data.cur_generation += 1;
490         }
491 
492         Ok((idx.index(), actual))
493     }
494 
495     /// Creates a new `HostResourceIndex` which will point to the raw table
496     /// slot provided by `idx`.
497     ///
498     /// This will register metadata necessary to track the current generation
499     /// in the returned `HostResourceIndex` as well.
500     fn new_host_index(
501         &mut self,
502         idx: u32,
503         dtor: Option<NonNull<VMFuncRef>>,
504         flags: Option<InstanceFlags>,
505     ) -> HostResourceIndex {
506         let list = &mut self.host_resource_data.table_slot_metadata;
507         let info = TableSlot {
508             generation: self.host_resource_data.cur_generation,
509             flags,
510             dtor: dtor.map(SendSyncPtr::new),
511         };
512         match list.get_mut(idx as usize) {
513             Some(slot) => *slot = info,
514             None => {
515                 // Resource handles start at 1, not zero, so push two elements
516                 // for the first resource handle.
517                 if list.is_empty() {
518                     assert_eq!(idx, 1);
519                     list.push(TableSlot {
520                         generation: 0,
521                         flags: None,
522                         dtor: None,
523                     });
524                 }
525                 assert_eq!(idx as usize, list.len());
526                 list.push(info);
527             }
528         }
529 
530         HostResourceIndex::new(idx, info.generation)
531     }
532 
533     /// Drops a host-owned resource from host tables.
534     ///
535     /// This method will attempt to interpret `idx` as pointing to either a
536     /// `borrow` or `own` resource with the `expected` type specified. This
537     /// method will then return the underlying `rep` if it points to an `own`
538     /// resource which can then be further processed for destruction.
539     ///
540     /// # Errors
541     ///
542     /// Returns an error if `idx` doesn't point to a valid resource, points to
543     /// an `own` with active borrows, or if it doesn't have the type `expected`
544     /// in the host tables.
545     fn host_resource_drop(&mut self, idx: HostResourceIndex) -> Result<Option<(u32, TableSlot)>> {
546         let (idx, slot) = self.validate_host_index(idx, true)?;
547         match self.tables.resource_drop(TypedResourceIndex::Host(idx))? {
548             Some(rep) => Ok(Some((rep, slot.unwrap()))),
549             None => Ok(None),
550         }
551     }
552 
553     /// Lowers an `own` resource into the guest, converting the `rep` specified
554     /// into a guest-local index.
555     ///
556     /// The `ty` provided is which table to put this into.
557     pub fn guest_resource_lower_own(
558         &mut self,
559         rep: u32,
560         ty: TypeResourceTableIndex,
561     ) -> Result<u32> {
562         self.tables
563             .resource_lower_own(TypedResource::Component { ty, rep })
564     }
565 
566     /// Lowers a `borrow` resource into the guest, converting the `rep`
567     /// specified into a guest-local index.
568     ///
569     /// The `ty` provided is which table to put this into.
570     ///
571     /// Note that this cannot be used in isolation because lowering a borrow
572     /// into a guest has a special case where `rep` is returned directly if `ty`
573     /// belongs to the component being lowered into. That property must be
574     /// handled by the caller of this function.
575     pub fn guest_resource_lower_borrow(
576         &mut self,
577         rep: u32,
578         ty: TypeResourceTableIndex,
579     ) -> Result<u32> {
580         self.tables
581             .resource_lower_borrow(TypedResource::Component { ty, rep })
582     }
583 
584     /// Lifts an `own` resource from the `idx` specified from the table `ty`.
585     ///
586     /// This will lookup the appropriate table in the guest and return the `rep`
587     /// corresponding to `idx` if it's valid.
588     pub fn guest_resource_lift_own(
589         &mut self,
590         index: u32,
591         ty: TypeResourceTableIndex,
592     ) -> Result<u32> {
593         self.tables
594             .resource_lift_own(TypedResourceIndex::Component { ty, index })
595     }
596 
597     /// Lifts a `borrow` resource from the `idx` specified from the table `ty`.
598     ///
599     /// This will lookup the appropriate table in the guest and return the `rep`
600     /// corresponding to `idx` if it's valid.
601     pub fn guest_resource_lift_borrow(
602         &mut self,
603         index: u32,
604         ty: TypeResourceTableIndex,
605     ) -> Result<u32> {
606         self.tables
607             .resource_lift_borrow(TypedResourceIndex::Component { ty, index })
608     }
609 
610     /// Begins a call into the component instance, starting recording of
611     /// metadata related to resource borrowing.
612     #[inline]
613     pub fn enter_call(&mut self) {
614         self.tables.enter_call()
615     }
616 
617     /// Completes a call into the component instance, validating that it's ok to
618     /// complete by ensuring the are no remaining active borrows.
619     #[inline]
620     pub fn exit_call(&mut self) -> Result<()> {
621         self.tables.exit_call()
622     }
623 }
624 
625 impl<T> Resource<T>
626 where
627     T: 'static,
628 {
629     /// Creates a new owned resource with the `rep` specified.
630     ///
631     /// The returned value is suitable for passing to a guest as either a
632     /// `(borrow $t)` or `(own $t)`.
633     pub fn new_own(rep: u32) -> Resource<T> {
634         Resource {
635             state: AtomicResourceState::NOT_IN_TABLE,
636             rep,
637             _marker: marker::PhantomData,
638         }
639     }
640 
641     /// Creates a new borrowed resource which isn't actually rooted in any
642     /// ownership.
643     ///
644     /// This can be used to pass to a guest as a borrowed resource and the
645     /// embedder will know that the `rep` won't be in use by the guest
646     /// afterwards. Exactly how the lifetime of `rep` works is up to the
647     /// embedder.
648     pub fn new_borrow(rep: u32) -> Resource<T> {
649         Resource {
650             state: AtomicResourceState::BORROW,
651             rep,
652             _marker: marker::PhantomData,
653         }
654     }
655 
656     /// Returns the underlying 32-bit representation used to originally create
657     /// this resource.
658     pub fn rep(&self) -> u32 {
659         self.rep
660     }
661 
662     /// Returns whether this is an owned resource or not.
663     ///
664     /// Owned resources can be safely destroyed by the embedder at any time, and
665     /// borrowed resources have an owner somewhere else on the stack so can only
666     /// be accessed, not destroyed.
667     pub fn owned(&self) -> bool {
668         match self.state.get() {
669             ResourceState::Borrow => false,
670             ResourceState::Taken | ResourceState::NotInTable | ResourceState::Index(_) => true,
671         }
672     }
673 
674     fn lower_to_index<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result<u32> {
675         match ty {
676             InterfaceType::Own(t) => {
677                 let rep = match self.state.get() {
678                     // If this is a borrow resource then this is a dynamic
679                     // error on behalf of the embedder.
680                     ResourceState::Borrow => {
681                         bail!("cannot lower a `borrow` resource into an `own`")
682                     }
683 
684                     // If this resource does not yet live in a table then we're
685                     // dynamically transferring ownership to wasm. Record that
686                     // it's no longer present and then pass through the
687                     // representation.
688                     ResourceState::NotInTable => {
689                         let prev = self.state.swap(ResourceState::Taken);
690                         assert_eq!(prev, ResourceState::NotInTable);
691                         self.rep
692                     }
693 
694                     // This resource has already been moved into wasm so this is
695                     // a dynamic error on behalf of the embedder.
696                     ResourceState::Taken => bail!("host resource already consumed"),
697 
698                     // If this resource lives in a host table then try to take
699                     // it out of the table, which may fail, and on success we
700                     // can move the rep into the guest table.
701                     ResourceState::Index(idx) => cx.host_resource_lift_own(idx)?,
702                 };
703                 cx.guest_resource_lower_own(t, rep)
704             }
705             InterfaceType::Borrow(t) => {
706                 let rep = match self.state.get() {
707                     // If this is already a borrowed resource, nothing else to
708                     // do and the rep is passed through.
709                     ResourceState::Borrow => self.rep,
710 
711                     // If this resource is already gone, that's a dynamic error
712                     // for the embedder.
713                     ResourceState::Taken => bail!("host resource already consumed"),
714 
715                     // If this resource is not currently in a table then it
716                     // needs to move into a table to participate in state
717                     // related to borrow tracking. Execute the
718                     // `host_resource_lower_own` operation here and update our
719                     // state.
720                     //
721                     // Afterwards this is the same as the `idx` case below.
722                     //
723                     // Note that flags/dtor are passed as `None` here since
724                     // `Resource<T>` doesn't offer destruction support.
725                     ResourceState::NotInTable => {
726                         let idx = cx.host_resource_lower_own(self.rep, None, None)?;
727                         let prev = self.state.swap(ResourceState::Index(idx));
728                         assert_eq!(prev, ResourceState::NotInTable);
729                         cx.host_resource_lift_borrow(idx)?
730                     }
731 
732                     // If this resource lives in a table then it needs to come
733                     // out of the table with borrow-tracking employed.
734                     ResourceState::Index(idx) => cx.host_resource_lift_borrow(idx)?,
735                 };
736                 cx.guest_resource_lower_borrow(t, rep)
737             }
738             _ => bad_type_info(),
739         }
740     }
741 
742     fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
743         let (state, rep) = match ty {
744             // Ownership is being transferred from a guest to the host, so move
745             // it from the guest table into a new `Resource`. Note that this
746             // isn't immediately inserted into the host table and that's left
747             // for the future if it's necessary to take a borrow from this owned
748             // resource.
749             InterfaceType::Own(t) => {
750                 debug_assert!(cx.resource_type(t) == ResourceType::host::<T>());
751                 let (rep, dtor, flags) = cx.guest_resource_lift_own(t, index)?;
752                 assert!(dtor.is_some());
753                 assert!(flags.is_none());
754                 (AtomicResourceState::NOT_IN_TABLE, rep)
755             }
756 
757             // The borrow here is lifted from the guest, but note the lack of
758             // `host_resource_lower_borrow` as it's intentional. Lowering
759             // a borrow has a special case in the canonical ABI where if the
760             // receiving module is the owner of the resource then it directly
761             // receives the `rep` and no other dynamic tracking is employed.
762             // This effectively mirrors that even though the canonical ABI
763             // isn't really all that applicable in host context here.
764             InterfaceType::Borrow(t) => {
765                 debug_assert!(cx.resource_type(t) == ResourceType::host::<T>());
766                 let rep = cx.guest_resource_lift_borrow(t, index)?;
767                 (AtomicResourceState::BORROW, rep)
768             }
769             _ => bad_type_info(),
770         };
771         Ok(Resource {
772             state,
773             rep,
774             _marker: marker::PhantomData,
775         })
776     }
777 
778     /// Attempts to convert a [`ResourceAny`] into [`Resource`].
779     ///
780     /// This method will check that `resource` has type
781     /// `ResourceType::host::<T>()` and then convert it into a typed version of
782     /// the resource.
783     ///
784     /// # Errors
785     ///
786     /// This function will return an error if `resource` does not have type
787     /// `ResourceType::host::<T>()`. This function may also return an error if
788     /// `resource` is no longer valid, for example it was previously converted.
789     ///
790     /// # Panics
791     ///
792     /// This function will panic if `resource` does not belong to the `store`
793     /// specified.
794     pub fn try_from_resource_any(
795         resource: ResourceAny,
796         mut store: impl AsContextMut,
797     ) -> Result<Self> {
798         let store = store.as_context_mut();
799         let mut tables = HostResourceTables::new_host(store.0);
800         let ResourceAny { idx, ty, owned } = resource;
801         ensure!(ty == ResourceType::host::<T>(), "resource type mismatch");
802         let (state, rep) = if owned {
803             let rep = tables.host_resource_lift_own(idx)?;
804             (AtomicResourceState::NOT_IN_TABLE, rep)
805         } else {
806             // For borrowed handles, first acquire the `rep` via lifting the
807             // borrow. Afterwards though remove any dynamic state associated
808             // with this borrow. `Resource<T>` doesn't participate in dynamic
809             // state tracking and it's assumed embedders know what they're
810             // doing, so the drop call will clear out that a borrow is active
811             //
812             // Note that the result of `drop` should always be `None` as it's a
813             // borrowed handle, so assert so.
814             let rep = tables.host_resource_lift_borrow(idx)?;
815             let res = tables.host_resource_drop(idx)?;
816             assert!(res.is_none());
817             (AtomicResourceState::BORROW, rep)
818         };
819         Ok(Resource {
820             state,
821             rep,
822             _marker: marker::PhantomData,
823         })
824     }
825 
826     /// See [`ResourceAny::try_from_resource`]
827     pub fn try_into_resource_any(self, store: impl AsContextMut) -> Result<ResourceAny> {
828         ResourceAny::try_from_resource(self, store)
829     }
830 }
831 
832 unsafe impl<T: 'static> ComponentType for Resource<T> {
833     const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
834 
835     type Lower = <u32 as ComponentType>::Lower;
836 
837     fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
838         let resource = match ty {
839             InterfaceType::Own(t) | InterfaceType::Borrow(t) => *t,
840             other => bail!("expected `own` or `borrow`, found `{}`", desc(other)),
841         };
842         match types.resource_type(resource).kind {
843             ResourceTypeKind::Host(id) if TypeId::of::<T>() == id => {}
844             _ => bail!("resource type mismatch"),
845         }
846 
847         Ok(())
848     }
849 }
850 
851 unsafe impl<T: 'static> Lower for Resource<T> {
852     fn linear_lower_to_flat<U>(
853         &self,
854         cx: &mut LowerContext<'_, U>,
855         ty: InterfaceType,
856         dst: &mut MaybeUninit<Self::Lower>,
857     ) -> Result<()> {
858         self.lower_to_index(cx, ty)?
859             .linear_lower_to_flat(cx, InterfaceType::U32, dst)
860     }
861 
862     fn linear_lower_to_memory<U>(
863         &self,
864         cx: &mut LowerContext<'_, U>,
865         ty: InterfaceType,
866         offset: usize,
867     ) -> Result<()> {
868         self.lower_to_index(cx, ty)?
869             .linear_lower_to_memory(cx, InterfaceType::U32, offset)
870     }
871 }
872 
873 unsafe impl<T: 'static> Lift for Resource<T> {
874     fn linear_lift_from_flat(
875         cx: &mut LiftContext<'_>,
876         ty: InterfaceType,
877         src: &Self::Lower,
878     ) -> Result<Self> {
879         let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
880         Resource::lift_from_index(cx, ty, index)
881     }
882 
883     fn linear_lift_from_memory(
884         cx: &mut LiftContext<'_>,
885         ty: InterfaceType,
886         bytes: &[u8],
887     ) -> Result<Self> {
888         let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
889         Resource::lift_from_index(cx, ty, index)
890     }
891 }
892 
893 impl<T> fmt::Debug for Resource<T> {
894     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895         let state = match self.state.get() {
896             ResourceState::Borrow => "borrow",
897             ResourceState::NotInTable => "own (not in table)",
898             ResourceState::Taken => "taken",
899             ResourceState::Index(_) => "own",
900         };
901         f.debug_struct("Resource")
902             .field("rep", &self.rep)
903             .field("state", &state)
904             .finish()
905     }
906 }
907 
908 /// Representation of a resource in the component model, either a guest-defined
909 /// or a host-defined resource.
910 ///
911 /// This type is similar to [`Resource`] except that it can be used to represent
912 /// any resource, either host or guest. This type cannot be directly constructed
913 /// and is only available if the guest returns it to the host (e.g. a function
914 /// returning a guest-defined resource) or by a conversion from [`Resource`] via
915 /// [`ResourceAny::try_from_resource`].
916 /// This type also does not carry a static type parameter `T` for example and
917 /// does not have as much information about its type.
918 /// This means that it's possible to get runtime type-errors when
919 /// using this type because it cannot statically prevent mismatching resource
920 /// types.
921 ///
922 /// Like [`Resource`] this type represents either an `own` or a `borrow`
923 /// resource internally. Unlike [`Resource`], however, a [`ResourceAny`] must
924 /// always be explicitly destroyed with the [`ResourceAny::resource_drop`]
925 /// method. This will update internal dynamic state tracking and invoke the
926 /// WebAssembly-defined destructor for a resource, if any.
927 ///
928 /// Note that it is required to call `resource_drop` for all instances of
929 /// [`ResourceAny`]: even borrows. Both borrows and own handles have state
930 /// associated with them that must be discarded by the time they're done being
931 /// used.
932 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
933 pub struct ResourceAny {
934     idx: HostResourceIndex,
935     ty: ResourceType,
936     owned: bool,
937 }
938 
939 impl ResourceAny {
940     /// Attempts to convert an imported [`Resource`] into [`ResourceAny`].
941     ///
942     /// * `resource` is the resource to convert.
943     /// * `store` is the store to place the returned resource into.
944     ///
945     /// The returned `ResourceAny` will not have a destructor attached to it
946     /// meaning that if `resource_drop` is called then it will not invoked a
947     /// host-defined destructor. This is similar to how `Resource<T>` does not
948     /// have a destructor associated with it.
949     ///
950     /// # Errors
951     ///
952     /// This method will return an error if `resource` has already been "taken"
953     /// and has ownership transferred elsewhere which can happen in situations
954     /// such as when it's already lowered into a component.
955     pub fn try_from_resource<T: 'static>(
956         resource: Resource<T>,
957         mut store: impl AsContextMut,
958     ) -> Result<Self> {
959         let Resource { rep, state, .. } = resource;
960         let store = store.as_context_mut();
961 
962         let mut tables = HostResourceTables::new_host(store.0);
963         let (idx, owned) = match state.get() {
964             ResourceState::Borrow => (tables.host_resource_lower_borrow(rep)?, false),
965             ResourceState::NotInTable => {
966                 let idx = tables.host_resource_lower_own(rep, None, None)?;
967                 (idx, true)
968             }
969             ResourceState::Taken => bail!("host resource already consumed"),
970             ResourceState::Index(idx) => (idx, true),
971         };
972         Ok(Self {
973             idx,
974             ty: ResourceType::host::<T>(),
975             owned,
976         })
977     }
978 
979     /// See [`Resource::try_from_resource_any`]
980     pub fn try_into_resource<T: 'static>(self, store: impl AsContextMut) -> Result<Resource<T>> {
981         Resource::try_from_resource_any(self, store)
982     }
983 
984     /// Returns the corresponding type associated with this resource, either a
985     /// host-defined type or a guest-defined type.
986     ///
987     /// This can be compared against [`ResourceType::host`] for example to see
988     /// if it's a host-resource or against a type extracted with
989     /// [`Instance::get_resource`] to see if it's a guest-defined resource.
990     ///
991     /// [`Instance::get_resource`]: crate::component::Instance::get_resource
992     pub fn ty(&self) -> ResourceType {
993         self.ty
994     }
995 
996     /// Returns whether this is an owned resource, and if not it's a borrowed
997     /// resource.
998     pub fn owned(&self) -> bool {
999         self.owned
1000     }
1001 
1002     /// Destroy this resource and release any state associated with it.
1003     ///
1004     /// This is required to be called (or the async version) for all instances
1005     /// of [`ResourceAny`] to ensure that state associated with this resource is
1006     /// properly cleaned up. For owned resources this may execute the
1007     /// guest-defined destructor if applicable (or the host-defined destructor
1008     /// if one was specified).
1009     pub fn resource_drop(self, mut store: impl AsContextMut) -> Result<()> {
1010         let mut store = store.as_context_mut();
1011         assert!(
1012             !store.0.async_support(),
1013             "must use `resource_drop_async` when async support is enabled on the config"
1014         );
1015         self.resource_drop_impl(&mut store.as_context_mut())
1016     }
1017 
1018     /// Same as [`ResourceAny::resource_drop`] except for use with async stores
1019     /// to execute the destructor asynchronously.
1020     #[cfg(feature = "async")]
1021     pub async fn resource_drop_async<T>(
1022         self,
1023         mut store: impl AsContextMut<Data: Send>,
1024     ) -> Result<()> {
1025         let mut store = store.as_context_mut();
1026         assert!(
1027             store.0.async_support(),
1028             "cannot use `resource_drop_async` without enabling async support in the config"
1029         );
1030         store
1031             .on_fiber(|store| self.resource_drop_impl(store))
1032             .await?
1033     }
1034 
1035     fn resource_drop_impl<T: 'static>(self, store: &mut StoreContextMut<'_, T>) -> Result<()> {
1036         // Attempt to remove `self.idx` from the host table in `store`.
1037         //
1038         // This could fail if the index is invalid or if this is removing an
1039         // `Own` entry which is currently being borrowed.
1040         let pair = HostResourceTables::new_host(store.0).host_resource_drop(self.idx)?;
1041 
1042         let (rep, slot) = match (pair, self.owned) {
1043             (Some(pair), true) => pair,
1044 
1045             // A `borrow` was removed from the table and no further
1046             // destruction, e.g. the destructor, is required so we're done.
1047             (None, false) => return Ok(()),
1048 
1049             _ => unreachable!(),
1050         };
1051 
1052         // Implement the reentrance check required by the canonical ABI. Note
1053         // that this happens whether or not a destructor is present.
1054         //
1055         // Note that this should be safe because the raw pointer access in
1056         // `flags` is valid due to `store` being the owner of the flags and
1057         // flags are never destroyed within the store.
1058         if let Some(flags) = slot.flags {
1059             unsafe {
1060                 if !flags.may_enter() {
1061                     bail!(Trap::CannotEnterComponent);
1062                 }
1063             }
1064         }
1065 
1066         let dtor = match slot.dtor {
1067             Some(dtor) => dtor.as_non_null(),
1068             None => return Ok(()),
1069         };
1070         let mut args = [ValRaw::u32(rep)];
1071 
1072         // This should be safe because `dtor` has been checked to belong to the
1073         // `store` provided which means it's valid and still alive. Additionally
1074         // destructors have al been previously type-checked and are guaranteed
1075         // to take one i32 argument and return no results, so the parameters
1076         // here should be configured correctly.
1077         unsafe { crate::Func::call_unchecked_raw(store, dtor, NonNull::from(&mut args)) }
1078     }
1079 
1080     fn lower_to_index<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result<u32> {
1081         match ty {
1082             InterfaceType::Own(t) => {
1083                 if cx.resource_type(t) != self.ty {
1084                     bail!("mismatched resource types");
1085                 }
1086                 let rep = cx.host_resource_lift_own(self.idx)?;
1087                 cx.guest_resource_lower_own(t, rep)
1088             }
1089             InterfaceType::Borrow(t) => {
1090                 if cx.resource_type(t) != self.ty {
1091                     bail!("mismatched resource types");
1092                 }
1093                 let rep = cx.host_resource_lift_borrow(self.idx)?;
1094                 cx.guest_resource_lower_borrow(t, rep)
1095             }
1096             _ => bad_type_info(),
1097         }
1098     }
1099 
1100     fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
1101         match ty {
1102             InterfaceType::Own(t) => {
1103                 let ty = cx.resource_type(t);
1104                 let (rep, dtor, flags) = cx.guest_resource_lift_own(t, index)?;
1105                 let idx = cx.host_resource_lower_own(rep, dtor, flags)?;
1106                 Ok(ResourceAny {
1107                     idx,
1108                     ty,
1109                     owned: true,
1110                 })
1111             }
1112             InterfaceType::Borrow(t) => {
1113                 let ty = cx.resource_type(t);
1114                 let rep = cx.guest_resource_lift_borrow(t, index)?;
1115                 let idx = cx.host_resource_lower_borrow(rep)?;
1116                 Ok(ResourceAny {
1117                     idx,
1118                     ty,
1119                     owned: false,
1120                 })
1121             }
1122             _ => bad_type_info(),
1123         }
1124     }
1125 }
1126 
1127 unsafe impl ComponentType for ResourceAny {
1128     const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1129 
1130     type Lower = <u32 as ComponentType>::Lower;
1131 
1132     fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1133         match ty {
1134             InterfaceType::Own(_) | InterfaceType::Borrow(_) => Ok(()),
1135             other => bail!("expected `own` or `borrow`, found `{}`", desc(other)),
1136         }
1137     }
1138 }
1139 
1140 unsafe impl Lower for ResourceAny {
1141     fn linear_lower_to_flat<T>(
1142         &self,
1143         cx: &mut LowerContext<'_, T>,
1144         ty: InterfaceType,
1145         dst: &mut MaybeUninit<Self::Lower>,
1146     ) -> Result<()> {
1147         self.lower_to_index(cx, ty)?
1148             .linear_lower_to_flat(cx, InterfaceType::U32, dst)
1149     }
1150 
1151     fn linear_lower_to_memory<T>(
1152         &self,
1153         cx: &mut LowerContext<'_, T>,
1154         ty: InterfaceType,
1155         offset: usize,
1156     ) -> Result<()> {
1157         self.lower_to_index(cx, ty)?
1158             .linear_lower_to_memory(cx, InterfaceType::U32, offset)
1159     }
1160 }
1161 
1162 unsafe impl Lift for ResourceAny {
1163     fn linear_lift_from_flat(
1164         cx: &mut LiftContext<'_>,
1165         ty: InterfaceType,
1166         src: &Self::Lower,
1167     ) -> Result<Self> {
1168         let index = u32::linear_lift_from_flat(cx, InterfaceType::U32, src)?;
1169         ResourceAny::lift_from_index(cx, ty, index)
1170     }
1171 
1172     fn linear_lift_from_memory(
1173         cx: &mut LiftContext<'_>,
1174         ty: InterfaceType,
1175         bytes: &[u8],
1176     ) -> Result<Self> {
1177         let index = u32::linear_lift_from_memory(cx, InterfaceType::U32, bytes)?;
1178         ResourceAny::lift_from_index(cx, ty, index)
1179     }
1180 }
1181