Skip to main content

wasmtime_environ/component/
vmcomponent_offsets.rs

1//! Offsets of the fields within a `VMComponentContext`.
2//!
3//! The layout itself is not defined here: it is defined once, alongside
4//! `VMContext`'s, in `for_each_vmctx_type!`. Everything in this module is either
5//! generated from that definition or is an offset that is not simply the offset
6//! of one of the layout's fields.
7
8use crate::GetPtrSize;
9use crate::PtrSize;
10use crate::component::*;
11
12/// Equivalent of `VMCONTEXT_MAGIC` except for components.
13///
14/// This is stored at the start of all `VMComponentContext` structures and
15/// double-checked on `VMComponentContext::from_opaque`.
16pub const VMCOMPONENT_MAGIC: u32 = u32::from_le_bytes(*b"comp");
17
18/// Runtime offsets within a `VMComponentContext` for a specific component.
19#[derive(Debug, Clone, Copy)]
20pub struct VMComponentOffsets<P> {
21    /// The host pointer size
22    pub ptr: P,
23
24    /// The number of lowered functions this component will be creating.
25    pub num_lowerings: u32,
26    /// The number of memories which are recorded in this component for options.
27    pub num_runtime_memories: u32,
28    /// The number of tables which are recorded in this component for options.
29    pub num_runtime_tables: u32,
30    /// The number of reallocs which are recorded in this component for options.
31    pub num_runtime_reallocs: u32,
32    /// The number of callbacks which are recorded in this component for options.
33    pub num_runtime_callbacks: u32,
34    /// The number of post-returns which are recorded in this component for options.
35    pub num_runtime_post_returns: u32,
36    /// Number of component instances internally in the component (always at
37    /// least 1).
38    pub num_runtime_component_instances: u32,
39    /// Number of cranelift-compiled trampolines required for this component.
40    pub num_trampolines: u32,
41    /// Number of `VMFuncRef`s for unsafe intrinsics within this component's
42    /// context.
43    pub num_unsafe_intrinsics: u32,
44    /// Number of resources within a component which need destructors stored.
45    pub num_resources: u32,
46
47    // Precalculated offsets of the dynamically-positioned fields, one per entry
48    // in `VMComponentContext`'s `dynamic` section in `for_each_vmctx_type!`,
49    // plus this `VMComponentContext`'s total size. These are all computed by the
50    // generated `compute_field_offsets` and read by the generated accessors of
51    // the same names.
52    may_leave: u32,
53    task_may_block: u32,
54    trampoline_func_refs: u32,
55    intrinsic_func_refs: u32,
56    lowerings: u32,
57    memories: u32,
58    tables: u32,
59    reallocs: u32,
60    callbacks: u32,
61    post_returns: u32,
62    resource_destructors: u32,
63    size: u32,
64}
65
66impl<P: PtrSize> GetPtrSize for VMComponentOffsets<P> {
67    type Ptr = P;
68
69    #[inline]
70    fn get_ptr_size(&self) -> &Self::Ptr {
71        &self.ptr
72    }
73}
74
75impl_vmctx_array_index! {
76    RuntimeComponentInstanceIndex,
77    TrampolineIndex,
78    LoweredIndex,
79    RuntimeMemoryIndex,
80    RuntimeTableIndex,
81    RuntimeReallocIndex,
82    RuntimeCallbackIndex,
83    RuntimePostReturnIndex,
84    ResourceIndex,
85}
86
87impl crate::VmctxArrayIndex for UnsafeIntrinsic {
88    #[inline]
89    fn vmctx_array_index(self) -> u32 {
90        self.index()
91    }
92}
93
94/// Generate the offsets of `VMComponentContext`'s dynamically-positioned fields,
95/// ignoring every other vmctx type.
96macro_rules! define_vmcomponent_offsets_dynamic_offsets {
97    (@one VMComponentContext $snake:ident { $($dyn:tt)* }) => {
98        /// Offsets of the dynamically-positioned fields of `VMComponentContext`.
99        impl<P: PtrSize> VMComponentOffsets<P> {
100            define_vmctx_dynamic_offsets!(@accessors (self) [ $($dyn)* ]);
101
102            define_vmctx_dynamic_offsets!(@compute_fn (self, next) $snake [ $($dyn)* ]);
103
104            /// Return the size of the `VMComponentContext` allocation.
105            #[inline]
106            pub fn size_of_vmctx(&self) -> u32 {
107                self.size
108            }
109        }
110    };
111    (@one $other:ident $snake:ident { $($dyn:tt)* }) => {};
112
113    ( $(
114        {
115            $Name:ident $snake:ident
116            static { $($stat:tt)* }
117            dynamic { $($dyn:tt)* }
118        }
119    )* ) => {
120        $( define_vmcomponent_offsets_dynamic_offsets!(@one $Name $snake { $($dyn)* }); )*
121    };
122}
123
124for_each_vmctx_type!(define_vmcomponent_offsets_dynamic_offsets);
125
126impl<P: PtrSize> VMComponentOffsets<P> {
127    /// Creates a new set of offsets for the `component` specified configured
128    /// additionally for the `ptr` size specified.
129    pub fn new(ptr: P, component: &Component) -> Self {
130        // This is required by the implementation of
131        // `VMComponentContext::from_opaque`. If this value changes then this
132        // location needs to be updated.
133        assert_eq!(ptr.vmcomponent().magic(), 0);
134
135        let mut ret = Self {
136            ptr,
137            num_lowerings: component.num_lowerings,
138            num_runtime_memories: component.num_runtime_memories,
139            num_runtime_tables: component.num_runtime_tables,
140            num_runtime_reallocs: component.num_runtime_reallocs,
141            num_runtime_callbacks: component.num_runtime_callbacks,
142            num_runtime_post_returns: component.num_runtime_post_returns,
143            num_runtime_component_instances: component.num_runtime_component_instances,
144            num_trampolines: component.trampolines.len().try_into().unwrap(),
145            num_unsafe_intrinsics: if let Some(i) = component
146                .unsafe_intrinsics
147                .iter()
148                .rposition(|x| x.is_some())
149            {
150                // Note: We do not currently have an indirection between "the
151                // `i`th unsafe intrinsic in the vmctx" and
152                // `UnsafeIntrinsic::from_u32(i)`, so therefore if we are
153                // compiling in *any* intrinsics, we need to include space for
154                // all of them up to the max `i` that is used.
155                //
156                // We _could_ introduce such an indirection via a map in
157                // `Component` like `PrimaryMap<UnsafeIntrinsicIndex,
158                // UnsafeIntrinsic>`, and that would allow us to densely pack
159                // intrinsics in the vmctx. However we do not do that today
160                // because there are very few unsafe intrinsics, and we do not
161                // see that changing anytime soon, so we aren't wasting much
162                // space.
163                u32::try_from(i + 1).unwrap()
164            } else {
165                0
166            },
167            num_resources: component.num_resources,
168            may_leave: 0,
169            task_may_block: 0,
170            trampoline_func_refs: 0,
171            intrinsic_func_refs: 0,
172            lowerings: 0,
173            memories: 0,
174            tables: 0,
175            reallocs: 0,
176            callbacks: 0,
177            post_returns: 0,
178            resource_destructors: 0,
179            size: 0,
180        };
181
182        ret.compute_field_offsets();
183
184        ret
185    }
186
187    /// The size, in bytes, of the host pointer.
188    #[inline]
189    pub fn pointer_size(&self) -> u8 {
190        self.ptr.size()
191    }
192
193    /// The offset of the `callee` for the `index` specified.
194    #[inline]
195    pub fn lowering_callee(&self, index: LoweredIndex) -> u32 {
196        self.lowerings().at(index) + self.lowering_callee_offset()
197    }
198
199    /// The offset of the `data` for the `index` specified.
200    #[inline]
201    pub fn lowering_data(&self, index: LoweredIndex) -> u32 {
202        self.lowerings().at(index) + self.lowering_data_offset()
203    }
204
205    /// The size of the `VMLowering` type
206    #[inline]
207    pub fn lowering_size(&self) -> u8 {
208        2 * self.ptr.size()
209    }
210
211    /// The offset of the `callee` field within the `VMLowering` type.
212    #[inline]
213    pub fn lowering_callee_offset(&self) -> u32 {
214        0
215    }
216
217    /// The offset of the `data` field within the `VMLowering` type.
218    #[inline]
219    pub fn lowering_data_offset(&self) -> u32 {
220        u32::from(self.ptr.size())
221    }
222}