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