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