1 use crate::component::ResourceType;
2 use crate::component::matching::InstanceType;
3 use crate::component::resources::{HostResourceData, HostResourceIndex, HostResourceTables};
4 use crate::prelude::*;
5 use crate::runtime::vm::component::{
6     CallContexts, ComponentInstance, InstanceFlags, ResourceTable, ResourceTables,
7 };
8 use crate::runtime::vm::{VMFuncRef, VMMemoryDefinition};
9 use crate::store::{StoreId, StoreOpaque};
10 use crate::{FuncType, StoreContextMut};
11 use alloc::sync::Arc;
12 use core::ptr::NonNull;
13 use wasmtime_environ::component::{ComponentTypes, StringEncoding, TypeResourceTableIndex};
14 
15 /// Runtime representation of canonical ABI options in the component model.
16 ///
17 /// This structure packages up the runtime representation of each option from
18 /// memories to reallocs to string encodings. Note that this is a "standalone"
19 /// structure which has raw pointers internally. This allows it to be created
20 /// out of thin air for a host function import, for example. The `store_id`
21 /// field, however, is what is used to pair this set of options with a store
22 /// reference to actually use the pointers.
23 #[derive(Copy, Clone)]
24 pub struct Options {
25     /// The store from which this options originated from.
26     store_id: StoreId,
27 
28     /// An optional pointer for the memory that this set of options is referring
29     /// to. This option is not required to be specified in the canonical ABI
30     /// hence the `Option`.
31     ///
32     /// Note that this pointer cannot be safely dereferenced unless a store,
33     /// verified with `self.store_id`, has the appropriate borrow available.
34     memory: Option<NonNull<VMMemoryDefinition>>,
35 
36     /// Similar to `memory` but corresponds to the `canonical_abi_realloc`
37     /// function.
38     ///
39     /// Safely using this pointer has the same restrictions as `memory` above.
40     realloc: Option<NonNull<VMFuncRef>>,
41 
42     /// The encoding used for strings, if found.
43     ///
44     /// This defaults to utf-8 but can be changed if necessary.
45     string_encoding: StringEncoding,
46 }
47 
48 // The `Options` structure stores raw pointers but they're never used unless a
49 // `Store` is available so this should be threadsafe and largely inherit the
50 // thread-safety story of `Store<T>` itself.
51 unsafe impl Send for Options {}
52 unsafe impl Sync for Options {}
53 
54 impl Options {
55     // FIXME(#4311): prevent a ctor where the memory is memory64
56 
57     /// Creates a new set of options with the specified components.
58     ///
59     /// # Unsafety
60     ///
61     /// This is unsafety as there is no way to statically verify the validity of
62     /// the arguments. For example pointers must be valid pointers, the
63     /// `StoreId` must be valid for the pointers, etc.
64     pub unsafe fn new(
65         store_id: StoreId,
66         memory: Option<NonNull<VMMemoryDefinition>>,
67         realloc: Option<NonNull<VMFuncRef>>,
68         string_encoding: StringEncoding,
69     ) -> Options {
70         Options {
71             store_id,
72             memory,
73             realloc,
74             string_encoding,
75         }
76     }
77 
78     fn realloc<'a, T>(
79         &self,
80         store: &'a mut StoreContextMut<'_, T>,
81         realloc_ty: &FuncType,
82         old: usize,
83         old_size: usize,
84         old_align: u32,
85         new_size: usize,
86     ) -> Result<(&'a mut [u8], usize)> {
87         self.store_id.assert_belongs_to(store.0.id());
88 
89         let realloc = self.realloc.unwrap();
90 
91         let params = (
92             u32::try_from(old)?,
93             u32::try_from(old_size)?,
94             old_align,
95             u32::try_from(new_size)?,
96         );
97 
98         type ReallocFunc = crate::TypedFunc<(u32, u32, u32, u32), u32>;
99 
100         // This call doesn't take any GC refs, and therefore we shouldn't ever
101         // need to GC before entering Wasm.
102         #[cfg(feature = "gc")]
103         debug_assert!(!ReallocFunc::need_gc_before_call_raw(store.0, &params));
104 
105         // Invoke the wasm malloc function using its raw and statically known
106         // signature.
107         let result = unsafe { ReallocFunc::call_raw(store, realloc_ty, realloc, params)? };
108 
109         if result % old_align != 0 {
110             bail!("realloc return: result not aligned");
111         }
112         let result = usize::try_from(result)?;
113 
114         let memory = self.memory_mut(store.0);
115 
116         let result_slice = match memory.get_mut(result..).and_then(|s| s.get_mut(..new_size)) {
117             Some(end) => end,
118             None => bail!("realloc return: beyond end of memory"),
119         };
120 
121         Ok((result_slice, result))
122     }
123 
124     /// Asserts that this function has an associated memory attached to it and
125     /// then returns the slice of memory tied to the lifetime of the provided
126     /// store.
127     pub fn memory<'a>(&self, store: &'a StoreOpaque) -> &'a [u8] {
128         self.store_id.assert_belongs_to(store.id());
129 
130         // The unsafety here is intended to be encapsulated by the two
131         // preceding assertions. Namely we assert that the `store` is the same
132         // as the original store of this `Options`, meaning that we safely have
133         // either a shared reference or a mutable reference (as below) which
134         // means it's safe to view the memory (aka it's not a different store
135         // where our original store is on some other thread or something like
136         // that).
137         //
138         // Additionally the memory itself is asserted to be present as memory
139         // is an optional configuration in canonical ABI options.
140         unsafe {
141             let memory = self.memory.unwrap().as_ref();
142             core::slice::from_raw_parts(memory.base.as_ptr(), memory.current_length())
143         }
144     }
145 
146     /// Same as above, just `_mut`
147     pub fn memory_mut<'a>(&self, store: &'a mut StoreOpaque) -> &'a mut [u8] {
148         self.store_id.assert_belongs_to(store.id());
149 
150         // See comments in `memory` about the unsafety
151         unsafe {
152             let memory = self.memory.unwrap().as_ref();
153             core::slice::from_raw_parts_mut(memory.base.as_ptr(), memory.current_length())
154         }
155     }
156 
157     /// Returns the underlying encoding used for strings in this
158     /// lifting/lowering.
159     pub fn string_encoding(&self) -> StringEncoding {
160         self.string_encoding
161     }
162 
163     /// Returns the id of the store that this `Options` is connected to.
164     pub fn store_id(&self) -> StoreId {
165         self.store_id
166     }
167 }
168 
169 /// A helper structure which is a "package" of the context used during lowering
170 /// values into a component (or storing them into memory).
171 ///
172 /// This type is used by the `Lower` trait extensively and contains any
173 /// contextual information necessary related to the context in which the
174 /// lowering is happening.
175 #[doc(hidden)]
176 pub struct LowerContext<'a, T: 'static> {
177     /// Lowering may involve invoking memory allocation functions so part of the
178     /// context here is carrying access to the entire store that wasm is
179     /// executing within. This store serves as proof-of-ability to actually
180     /// execute wasm safely.
181     pub store: StoreContextMut<'a, T>,
182 
183     /// Lowering always happens into a function that's been `canon lift`'d or
184     /// `canon lower`'d, both of which specify a set of options for the
185     /// canonical ABI. For example details like string encoding are contained
186     /// here along with which memory pointers are relative to or what the memory
187     /// allocation function is.
188     pub options: &'a Options,
189 
190     /// Lowering happens within the context of a component instance and this
191     /// field stores the type information of that component instance. This is
192     /// used for type lookups and general type queries during the
193     /// lifting/lowering process.
194     pub types: &'a ComponentTypes,
195 
196     /// A raw unsafe pointer to the component instance that's being lowered
197     /// into.
198     ///
199     /// This pointer is required to be owned by the `store` provided.
200     instance: *mut ComponentInstance,
201 }
202 
203 #[doc(hidden)]
204 impl<'a, T: 'static> LowerContext<'a, T> {
205     /// Creates a new lowering context from the specified parameters.
206     ///
207     /// # Unsafety
208     ///
209     /// This function is unsafe as it needs to be guaranteed by the caller that
210     /// the `instance` here is valid within `store` and is a valid component
211     /// instance.
212     pub unsafe fn new(
213         store: StoreContextMut<'a, T>,
214         options: &'a Options,
215         types: &'a ComponentTypes,
216         instance: *mut ComponentInstance,
217     ) -> LowerContext<'a, T> {
218         LowerContext {
219             store,
220             options,
221             types,
222             instance,
223         }
224     }
225 
226     /// Returns a view into memory as a mutable slice of bytes.
227     ///
228     /// # Panics
229     ///
230     /// This will panic if memory has not been configured for this lowering
231     /// (e.g. it wasn't present during the specification of canonical options).
232     pub fn as_slice_mut(&mut self) -> &mut [u8] {
233         self.options.memory_mut(self.store.0)
234     }
235 
236     /// Invokes the memory allocation function (which is style after `realloc`)
237     /// with the specified parameters.
238     ///
239     /// # Panics
240     ///
241     /// This will panic if realloc hasn't been configured for this lowering via
242     /// its canonical options.
243     pub fn realloc(
244         &mut self,
245         old: usize,
246         old_size: usize,
247         old_align: u32,
248         new_size: usize,
249     ) -> Result<usize> {
250         let realloc_func_ty = Arc::clone(unsafe { (*self.instance).realloc_func_ty() });
251         let realloc_func_ty = realloc_func_ty.downcast_ref::<FuncType>().unwrap();
252         self.options
253             .realloc(
254                 &mut self.store,
255                 &realloc_func_ty,
256                 old,
257                 old_size,
258                 old_align,
259                 new_size,
260             )
261             .map(|(_, ptr)| ptr)
262     }
263 
264     /// Returns a fixed mutable slice of memory `N` bytes large starting at
265     /// offset `N`, panicking on out-of-bounds.
266     ///
267     /// It should be previously verified that `offset` is in-bounds via
268     /// bounds-checks.
269     ///
270     /// # Panics
271     ///
272     /// This will panic if memory has not been configured for this lowering
273     /// (e.g. it wasn't present during the specification of canonical options).
274     pub fn get<const N: usize>(&mut self, offset: usize) -> &mut [u8; N] {
275         // FIXME: this bounds check shouldn't actually be necessary, all
276         // callers of `ComponentType::store` have already performed a bounds
277         // check so we're guaranteed that `offset..offset+N` is in-bounds. That
278         // being said we at least should do bounds checks in debug mode and
279         // it's not clear to me how to easily structure this so that it's
280         // "statically obvious" the bounds check isn't necessary.
281         //
282         // For now I figure we can leave in this bounds check and if it becomes
283         // an issue we can optimize further later, probably with judicious use
284         // of `unsafe`.
285         self.as_slice_mut()[offset..].first_chunk_mut().unwrap()
286     }
287 
288     /// Lowers an `own` resource into the guest, converting the `rep` specified
289     /// into a guest-local index.
290     ///
291     /// The `ty` provided is which table to put this into.
292     pub fn guest_resource_lower_own(
293         &mut self,
294         ty: TypeResourceTableIndex,
295         rep: u32,
296     ) -> Result<u32> {
297         self.resource_tables().guest_resource_lower_own(rep, ty)
298     }
299 
300     /// Lowers a `borrow` resource into the guest, converting the `rep` to a
301     /// guest-local index in the `ty` table specified.
302     pub fn guest_resource_lower_borrow(
303         &mut self,
304         ty: TypeResourceTableIndex,
305         rep: u32,
306     ) -> Result<u32> {
307         // Implement `lower_borrow`'s special case here where if a borrow is
308         // inserted into a table owned by the instance which implemented the
309         // original resource then no borrow tracking is employed and instead the
310         // `rep` is returned "raw".
311         //
312         // This check is performed by comparing the owning instance of `ty`
313         // against the owning instance of the resource that `ty` is working
314         // with.
315         //
316         // Note that the unsafety here should be valid given the contract of
317         // `LowerContext::new`.
318         if unsafe { (*self.instance).resource_owned_by_own_instance(ty) } {
319             return Ok(rep);
320         }
321         self.resource_tables().guest_resource_lower_borrow(rep, ty)
322     }
323 
324     /// Lifts a host-owned `own` resource at the `idx` specified into the
325     /// representation of that resource.
326     pub fn host_resource_lift_own(&mut self, idx: HostResourceIndex) -> Result<u32> {
327         self.resource_tables().host_resource_lift_own(idx)
328     }
329 
330     /// Lifts a host-owned `borrow` resource at the `idx` specified into the
331     /// representation of that resource.
332     pub fn host_resource_lift_borrow(&mut self, idx: HostResourceIndex) -> Result<u32> {
333         self.resource_tables().host_resource_lift_borrow(idx)
334     }
335 
336     /// Lowers a resource into the host-owned table, returning the index it was
337     /// inserted at.
338     ///
339     /// Note that this is a special case for `Resource<T>`. Most of the time a
340     /// host value shouldn't be lowered with a lowering context.
341     pub fn host_resource_lower_own(
342         &mut self,
343         rep: u32,
344         dtor: Option<NonNull<VMFuncRef>>,
345         flags: Option<InstanceFlags>,
346     ) -> Result<HostResourceIndex> {
347         self.resource_tables()
348             .host_resource_lower_own(rep, dtor, flags)
349     }
350 
351     /// Returns the underlying resource type for the `ty` table specified.
352     pub fn resource_type(&self, ty: TypeResourceTableIndex) -> ResourceType {
353         self.instance_type().resource_type(ty)
354     }
355 
356     /// Returns the instance type information corresponding to the instance that
357     /// this context is lowering into.
358     pub fn instance_type(&self) -> InstanceType<'_> {
359         // Note that the unsafety here should be valid given the contract of
360         // `LowerContext::new`.
361         InstanceType::new(unsafe { &*self.instance })
362     }
363 
364     fn resource_tables(&mut self) -> HostResourceTables<'_> {
365         let (calls, host_table, host_resource_data) = self.store.0.component_resource_state();
366         HostResourceTables::from_parts(
367             ResourceTables {
368                 host_table: Some(host_table),
369                 calls,
370                 // Note that the unsafety here should be valid given the contract of
371                 // `LowerContext::new`.
372                 guest: Some(unsafe { (*self.instance).guest_tables() }),
373             },
374             host_resource_data,
375         )
376     }
377 
378     /// See [`HostResourceTables::enter_call`].
379     #[inline]
380     pub fn enter_call(&mut self) {
381         self.resource_tables().enter_call()
382     }
383 
384     /// See [`HostResourceTables::exit_call`].
385     #[inline]
386     pub fn exit_call(&mut self) -> Result<()> {
387         self.resource_tables().exit_call()
388     }
389 }
390 
391 /// Contextual information used when lifting a type from a component into the
392 /// host.
393 ///
394 /// This structure is the analogue of `LowerContext` except used during lifting
395 /// operations (or loading from memory).
396 #[doc(hidden)]
397 pub struct LiftContext<'a> {
398     /// Like lowering, lifting always has options configured.
399     pub options: &'a Options,
400 
401     /// Instance type information, like with lowering.
402     pub types: &'a Arc<ComponentTypes>,
403 
404     memory: Option<&'a [u8]>,
405 
406     instance: *mut ComponentInstance,
407 
408     host_table: &'a mut ResourceTable,
409     host_resource_data: &'a mut HostResourceData,
410 
411     calls: &'a mut CallContexts,
412 }
413 
414 #[doc(hidden)]
415 impl<'a> LiftContext<'a> {
416     /// Creates a new lifting context given the provided context.
417     ///
418     /// # Unsafety
419     ///
420     /// This is unsafe for the same reasons as `LowerContext::new` where the
421     /// validity of `instance` is required to be upheld by the caller.
422     #[inline]
423     pub unsafe fn new(
424         store: &'a mut StoreOpaque,
425         options: &'a Options,
426         types: &'a Arc<ComponentTypes>,
427         instance: *mut ComponentInstance,
428     ) -> LiftContext<'a> {
429         // From `&mut StoreOpaque` provided the goal here is to project out
430         // three different disjoint fields owned by the store: memory,
431         // `CallContexts`, and `ResourceTable`. There's no native API for that
432         // so it's hacked around a bit. This unsafe pointer cast could be fixed
433         // with more methods in more places, but it doesn't seem worth doing it
434         // at this time.
435         let (calls, host_table, host_resource_data) =
436             (&mut *(store as *mut StoreOpaque)).component_resource_state();
437         let memory = options.memory.map(|_| options.memory(store));
438 
439         LiftContext {
440             memory,
441             options,
442             types,
443             instance,
444             calls,
445             host_table,
446             host_resource_data,
447         }
448     }
449 
450     /// Returns the entire contents of linear memory for this set of lifting
451     /// options.
452     ///
453     /// # Panics
454     ///
455     /// This will panic if memory has not been configured for this lifting
456     /// operation.
457     pub fn memory(&self) -> &'a [u8] {
458         self.memory.unwrap()
459     }
460 
461     /// Returns an identifier for the store from which this `LiftContext` was
462     /// created.
463     pub fn store_id(&self) -> StoreId {
464         self.options.store_id
465     }
466 
467     /// Returns the component instance raw pointer that is being lifted from.
468     pub fn instance_ptr(&self) -> *mut ComponentInstance {
469         self.instance
470     }
471 
472     /// Lifts an `own` resource from the guest at the `idx` specified into its
473     /// representation.
474     ///
475     /// Additionally returns a destructor/instance flags to go along with the
476     /// representation so the host knows how to destroy this resource.
477     pub fn guest_resource_lift_own(
478         &mut self,
479         ty: TypeResourceTableIndex,
480         idx: u32,
481     ) -> Result<(u32, Option<NonNull<VMFuncRef>>, Option<InstanceFlags>)> {
482         let idx = self.resource_tables().guest_resource_lift_own(idx, ty)?;
483         // Note that the unsafety here should be valid given the contract of
484         // `LiftContext::new`.
485         let (dtor, flags) = unsafe { (*self.instance).dtor_and_flags(ty) };
486         Ok((idx, dtor, flags))
487     }
488 
489     /// Lifts a `borrow` resource from the guest at the `idx` specified.
490     pub fn guest_resource_lift_borrow(
491         &mut self,
492         ty: TypeResourceTableIndex,
493         idx: u32,
494     ) -> Result<u32> {
495         self.resource_tables().guest_resource_lift_borrow(idx, ty)
496     }
497 
498     /// Lowers a resource into the host-owned table, returning the index it was
499     /// inserted at.
500     pub fn host_resource_lower_own(
501         &mut self,
502         rep: u32,
503         dtor: Option<NonNull<VMFuncRef>>,
504         flags: Option<InstanceFlags>,
505     ) -> Result<HostResourceIndex> {
506         self.resource_tables()
507             .host_resource_lower_own(rep, dtor, flags)
508     }
509 
510     /// Lowers a resource into the host-owned table, returning the index it was
511     /// inserted at.
512     pub fn host_resource_lower_borrow(&mut self, rep: u32) -> Result<HostResourceIndex> {
513         self.resource_tables().host_resource_lower_borrow(rep)
514     }
515 
516     /// Returns the underlying type of the resource table specified by `ty`.
517     pub fn resource_type(&self, ty: TypeResourceTableIndex) -> ResourceType {
518         self.instance_type().resource_type(ty)
519     }
520 
521     /// Returns instance type information for the component instance that is
522     /// being lifted from.
523     pub fn instance_type(&self) -> InstanceType<'_> {
524         // Note that the unsafety here should be valid given the contract of
525         // `LiftContext::new`.
526         InstanceType::new(unsafe { &*self.instance })
527     }
528 
529     fn resource_tables(&mut self) -> HostResourceTables<'_> {
530         HostResourceTables::from_parts(
531             ResourceTables {
532                 host_table: Some(self.host_table),
533                 calls: self.calls,
534                 // Note that the unsafety here should be valid given the contract of
535                 // `LiftContext::new`.
536                 guest: Some(unsafe { (*self.instance).guest_tables() }),
537             },
538             self.host_resource_data,
539         )
540     }
541 
542     /// See [`HostResourceTables::enter_call`].
543     #[inline]
544     pub fn enter_call(&mut self) {
545         self.resource_tables().enter_call()
546     }
547 
548     /// See [`HostResourceTables::exit_call`].
549     #[inline]
550     pub fn exit_call(&mut self) -> Result<()> {
551         self.resource_tables().exit_call()
552     }
553 }
554