1 use crate::Engine;
2 use crate::prelude::*;
3 use std::borrow::Cow;
4 use std::path::Path;
5 
6 #[cfg(feature = "compile-time-builtins")]
7 use crate::hash_map::HashMap;
8 
9 #[cfg(feature = "compile-time-builtins")]
10 mod compile_time_builtins;
11 
12 /// Builder-style structure used to create a [`Module`](crate::module::Module) or
13 /// pre-compile a module to a serialized list of bytes.
14 ///
15 /// This structure can be used for more advanced configuration when compiling a
16 /// WebAssembly module. Most configuration can use simpler constructors such as:
17 ///
18 /// * [`Module::new`](crate::Module::new)
19 /// * [`Module::from_file`](crate::Module::from_file)
20 /// * [`Module::from_binary`](crate::Module::from_binary)
21 ///
22 /// Note that a [`CodeBuilder`] always involves compiling WebAssembly bytes
23 /// to machine code. To deserialize a list of bytes use
24 /// [`Module::deserialize`](crate::Module::deserialize) instead.
25 ///
26 /// A [`CodeBuilder`] requires a source of WebAssembly bytes to be configured
27 /// before calling [`compile_module_serialized`] or [`compile_module`]. This can
28 /// be provided with either the [`wasm_binary`] or [`wasm_binary_file`] method.
29 /// Note that only a single source of bytes can be provided.
30 ///
31 /// # WebAssembly Text Format
32 ///
33 /// This builder supports the WebAssembly Text Format (`*.wat` files) through
34 /// the [`CodeBuilder::wasm_binary_or_text`] and
35 /// [`CodeBuilder::wasm_binary_or_text_file`] methods. These methods
36 /// automatically convert WebAssembly text files to binary. Note though that
37 /// this behavior is disabled if the `wat` crate feature is not enabled.
38 ///
39 /// [`compile_module_serialized`]: CodeBuilder::compile_module_serialized
40 /// [`compile_module`]: CodeBuilder::compile_module
41 /// [`wasm_binary`]: CodeBuilder::wasm_binary
42 /// [`wasm_binary_file`]: CodeBuilder::wasm_binary_file
43 pub struct CodeBuilder<'a> {
44     pub(super) engine: &'a Engine,
45     wasm: Option<Cow<'a, [u8]>>,
46     wasm_path: Option<Cow<'a, Path>>,
47     dwarf_package: Option<Cow<'a, [u8]>>,
48     dwarf_package_path: Option<Cow<'a, Path>>,
49     unsafe_intrinsics_import: Option<String>,
50 
51     /// A map from import name to the Wasm bytes of the associated compile-time
52     /// builtin and its file path, if any.
53     //
54     // XXX: we can't use `'a` here without forcing us to change a bunch of
55     // callers because `HashMap` has a `Drop` implementation, so `dropck` thinks
56     // that all `'a` borrows could be used by `CodeBuilder`'s `Drop`, which
57     // means that a bunch of the existing calls to `.wasm_bytes` and such would
58     // need to be reordered with the `CodeBuilder`'s construction.
59     #[cfg(feature = "compile-time-builtins")]
60     compile_time_builtins: HashMap<Cow<'a, str>, Cow<'a, [u8]>>,
61 }
62 
63 /// Return value of [`CodeBuilder::hint`]
64 pub enum CodeHint {
65     /// Hint that the code being compiled is a module.
66     Module,
67     /// Hint that the code being compiled is a component.
68     Component,
69 }
70 
71 impl<'a> CodeBuilder<'a> {
72     /// Creates a new builder which will insert modules into the specified
73     /// [`Engine`].
74     pub fn new(engine: &'a Engine) -> Self {
75         CodeBuilder {
76             engine,
77             wasm: None,
78             wasm_path: None,
79             dwarf_package: None,
80             dwarf_package_path: None,
81             unsafe_intrinsics_import: None,
82             #[cfg(feature = "compile-time-builtins")]
83             compile_time_builtins: HashMap::default(),
84         }
85     }
86 
87     /// Configures the WebAssembly binary that is being compiled.
88     ///
89     /// The `wasm_bytes` parameter must be a binary WebAssembly file.
90     /// This will be stored within the [`CodeBuilder`] for processing later when
91     /// compilation is finalized.
92     ///
93     /// The optional `wasm_path` parameter is the path to the `wasm_bytes` on
94     /// disk, if any. This may be used for diagnostics and other
95     /// debugging-related purposes, but this method will not read the path
96     /// specified.
97     ///
98     /// # Errors
99     ///
100     /// This method will return an error if WebAssembly bytes have already been
101     /// configured.
102     pub fn wasm_binary(
103         &mut self,
104         wasm_bytes: impl Into<Cow<'a, [u8]>>,
105         wasm_path: Option<&'a Path>,
106     ) -> Result<&mut Self> {
107         if self.wasm.is_some() {
108             bail!("cannot configure wasm bytes twice");
109         }
110         self.wasm = Some(wasm_bytes.into());
111         self.wasm_path = wasm_path.map(|p| p.into());
112 
113         if self.wasm_path.is_some() {
114             self.dwarf_package_from_wasm_path()?;
115         }
116 
117         Ok(self)
118     }
119 
120     /// Equivalent of [`CodeBuilder::wasm_binary`] that also accepts the
121     /// WebAssembly text format.
122     ///
123     /// This method will configure the WebAssembly binary to be compiled. The
124     /// input `wasm_bytes` may either be the wasm text format or the binary
125     /// format. If the `wat` crate feature is enabled, which is enabled by
126     /// default, then the text format will automatically be converted to the
127     /// binary format.
128     ///
129     /// # Errors
130     ///
131     /// This method will return an error if WebAssembly bytes have already been
132     /// configured. This method will also return an error if `wasm_bytes` is the
133     /// wasm text format and the text syntax is not valid.
134     pub fn wasm_binary_or_text(
135         &mut self,
136         wasm_bytes: &'a [u8],
137         wasm_path: Option<&'a Path>,
138     ) -> Result<&mut Self> {
139         #[cfg(feature = "wat")]
140         let wasm_bytes = wat::parse_bytes(wasm_bytes).map_err(|mut e| {
141             if let Some(path) = wasm_path {
142                 e.set_path(path);
143             }
144             e
145         })?;
146         self.wasm_binary(wasm_bytes, wasm_path)
147     }
148 
149     /// Reads the `file` specified for the WebAssembly bytes that are going to
150     /// be compiled.
151     ///
152     /// This method will read `file` from the filesystem and interpret it
153     /// as a WebAssembly binary.
154     ///
155     /// A DWARF package file will be probed using the root of `file` and with a
156     /// `.dwp` extension. If found, it will be loaded and DWARF fusion
157     /// performed.
158     ///
159     /// # Errors
160     ///
161     /// This method will return an error if WebAssembly bytes have already been
162     /// configured.
163     ///
164     /// If `file` can't be read or an error happens reading it then that will
165     /// also be returned.
166     ///
167     /// If DWARF fusion is performed and the DWARF packaged file cannot be read
168     /// then an error will be returned.
169     pub fn wasm_binary_file(&mut self, file: &'a Path) -> Result<&mut Self> {
170         let wasm = std::fs::read(file)
171             .with_context(|| format!("failed to read input file: {}", file.display()))?;
172         self.wasm_binary(wasm, Some(file))
173     }
174 
175     /// Equivalent of [`CodeBuilder::wasm_binary_file`] that also accepts the
176     /// WebAssembly text format.
177     ///
178     /// This method is will read the file at `path` and interpret the contents
179     /// to determine if it's the wasm text format or binary format. The file
180     /// extension of `file` is not consulted. The text format is automatically
181     /// converted to the binary format if the crate feature `wat` is active.
182     ///
183     /// # Errors
184     ///
185     /// In addition to the errors returned by [`CodeBuilder::wasm_binary_file`]
186     /// this may also fail if the text format is read and the syntax is invalid.
187     pub fn wasm_binary_or_text_file(&mut self, file: &'a Path) -> Result<&mut Self> {
188         #[cfg(feature = "wat")]
189         {
190             let wasm = wat::parse_file(file)?;
191             self.wasm_binary(wasm, Some(file))
192         }
193         #[cfg(not(feature = "wat"))]
194         {
195             self.wasm_binary_file(file)
196         }
197     }
198 
199     /// Get the Wasm to be compiled.
200     ///
201     /// When using compile-time builtins, compose the builtins and the guest
202     /// Wasm together, before returning the Wasm.
203     pub(super) fn get_wasm(&self) -> Result<Cow<'_, [u8]>> {
204         let wasm = self
205             .wasm
206             .as_deref()
207             .ok_or_else(|| format_err!("no wasm bytes have been configured"))?;
208 
209         #[cfg(not(feature = "compile-time-builtins"))]
210         {
211             Ok(wasm.into())
212         }
213 
214         #[cfg(feature = "compile-time-builtins")]
215         {
216             self.compose_compile_time_builtins(wasm)
217                 .context("failed to compose compile-time builtins with the main Wasm")
218         }
219     }
220 
221     /// Expose Wasmtime's unsafe intrinsics under the given import name.
222     ///
223     /// These intrinsics provide native memory loads and stores to Wasm; they
224     /// are *extremely* unsafe! If you are not absolutely sure that you need
225     /// these unsafe intrinsics, *do not use them!* See the safety section below
226     /// for details.
227     ///
228     /// This functionality is intended to be used when implementing
229     /// [compile-time builtins][CodeBuilder::compile_time_builtins_binary]; that
230     /// is, satisfying a Wasm import via special-cased, embedder-specific code
231     /// at compile time. You should never use these intrinsics to intentionally
232     /// subvert the Wasm sandbox. You should strive to implement safe functions
233     /// that encapsulate your uses of these intrinsics such that, regardless of
234     /// any value given as arguments, your functions *cannot* result in loading
235     /// from or storing to invalid pointers, or any other kind of unsafety. See
236     /// below for an example of the intended use cases.
237     ///
238     /// Wasmtime's unsafe intrinsics can only be exposed to Wasm components, not
239     /// core modules, currently.
240     ///
241     /// Note that when compile-time builtins are defined on a `CodeBuilder`,
242     /// only the compile-time builtins can import the unsafe intrinsics, and the
243     /// main guest program cannot import them.
244     ///
245     /// # Safety
246     ///
247     /// Extreme care must be taken when using these intrinsics.
248     ///
249     /// All loads of or stores to pointers derived from `store-data-address` are
250     /// inherently tied to a particular `T` type in a `Store<T>`. It is wildly
251     /// unsafe to run a Wasm program that uses unsafe intrinsics to access the
252     /// store's `T` inside a `Store<U>`. You must only run Wasm that uses unsafe
253     /// intrinsics in a `Store<T>` where the `T` is the type expected by the
254     /// Wasm's unsafe-intrinsics usage.
255     ///
256     /// Furthermore, usage of these intrinsics is not only tied to a particular
257     /// `T` type, but also to `T`'s layout on the host platform. The size and
258     /// alignment of `T`, the offsets of its fields, and those fields' size and
259     /// alignment can all vary across not only architecture but also operating
260     /// system. With care, you can define your `T` type such that its layout is
261     /// identical across the platforms that you run Wasm on, allowing you to
262     /// reuse the same Wasm binary and its unsafe-intrinsics usage on all your
263     /// platforms. Failing that, you must only run a Wasm program that uses
264     /// unsafe intrinsics on the host platform that its unsafe-intrinsic usage
265     /// is specialized to. See the portability section and example below for
266     /// more details.
267     ///
268     /// You are *strongly* encouraged to add assertions for the layout
269     /// properties that your unsafe-intrinsic usage's safety relies upon:
270     ///
271     /// ```rust
272     /// /// This type is used as `wasmtime::Store<MyData>` and accessed by Wasm via
273     /// /// unsafe intrinsics.
274     /// #[repr(C, align(8))]
275     /// struct MyData {
276     ///     id: u64,
277     ///     counter: u32,
278     ///     buf: [u8; 4],
279     /// }
280     ///
281     /// // Assert that the layout is what our Wasm's unsafe-intrinsics usage expects.
282     /// static _MY_DATA_LAYOUT_ASSERTIONS: () = {
283     ///     assert!(core::mem::size_of::<MyData>() == 16);
284     ///     assert!(core::mem::align_of::<MyData>() == 8);
285     ///     assert!(core::mem::offset_of!(MyData, id) == 0);
286     ///     assert!(core::mem::offset_of!(MyData, counter) == 8);
287     ///     assert!(core::mem::offset_of!(MyData, buf) == 12);
288     /// };
289     /// ```
290     ///
291     /// Finally, every pointer loaded from or stored to must:
292     ///
293     /// * Be non-null
294     ///
295     /// * Be aligned to the access type's natural alignment (e.g. 8-byte alignment
296     ///   for `u64`, 4-byte alignment for `u32`, etc...)
297     ///
298     /// * Point to a memory block that is valid to read from (for loads) or
299     ///   valid to write to (for stores) under Rust's pointer provenance rules
300     ///
301     /// * Point to a memory block that is at least as large as the access type's
302     ///   natural size (e.g. 1 byte for `u8`, 2 bytes for `u16`, etc...)
303     ///
304     /// * Point to a memory block that is not accessed concurrently by any other
305     ///   threads
306     ///
307     /// Failure to uphold any of these invariants will lead to unsafety,
308     /// undefined behavior, and/or data races.
309     ///
310     /// # Intrinsics
311     ///
312     /// | Name                 | Parameters   | Results |
313     /// |----------------------|--------------|---------|
314     /// | `u8-native-load`     | `u64`        | `u8`    |
315     /// | `u16-native-load`    | `u64`        | `u16`   |
316     /// | `u32-native-load`    | `u64`        | `u32`   |
317     /// | `u64-native-load`    | `u64`        | `u64`   |
318     /// | `u8-native-store`    | `u64`, `u8`  | -       |
319     /// | `u16-native-load`    | `u64`, `u16` | -       |
320     /// | `u32-native-load`    | `u64`, `u32` | -       |
321     /// | `u64-native-load`    | `u64`, `u64` | -       |
322     /// | `store-data-address` | -            | `u64`   |
323     ///
324     /// ## `*-native-load`
325     ///
326     /// These intrinsics perform an unsandboxed, unsynchronized load from native
327     /// memory, using the native endianness.
328     ///
329     /// ## `*-native-store`
330     ///
331     /// These intrinsics perform an unsandboxed, unsynchronized store to native
332     /// memory, using the native endianness.
333     ///
334     /// ## `store-data-address`
335     ///
336     /// This intrinsic function returns the pointer to the embedder's `T` data
337     /// inside a `Store<T>`.
338     ///
339     /// In general, all native load and store intinsics should operate on memory
340     /// addresses that are derived from a call to this intrinsic. If you want to
341     /// expose data for raw memory access by Wasm, put it inside the `T` in your
342     /// `Store<T>` and Wasm's access to that data should derive from this
343     /// intrinsic.
344     ///
345     /// # Portability
346     ///
347     /// Loads and stores are always performed using the architecture's native
348     /// endianness.
349     ///
350     /// Addresses passed to and returned from these intrinsics are always
351     /// 64-bits large. The upper half of the value is simply ignored on 32-bit
352     /// architectures.
353     ///
354     /// With care, you can design your store's `T` type such that accessing it
355     /// via these intrinsics is portable, and you can reuse a single Wasm binary
356     /// (and its set of intrinsic calls) across all of the platforms, with the
357     /// following rules of thumb:
358     ///
359     /// * Only access `u8`, `u16`, `u32`, and `u64` data via these intrinsics.
360     ///
361     /// * If you need to access other types of data, encode it into those types
362     ///   and then access the encoded data from the intrinsics.
363     ///
364     /// * Use `union`s to encode pointers and pointer-sized data as a `u64` and
365     ///   then access it via the `u64-native-{load,store}` intrinsics. See
366     ///   `ExposedPointer` in the example below.
367     ///
368     /// # Example
369     ///
370     /// The following example shows how you can use unsafe intrinsics and
371     /// compile-time builtins to give Wasm direct zero-copy access to a host
372     /// buffer.
373     ///
374     /// ```rust
375     /// use std::mem;
376     /// use wasmtime::*;
377     ///
378     /// // A `*mut u8` pointer that is exposed directly to Wasm via unsafe intrinsics.
379     /// #[repr(align(8))]
380     /// union ExposedPointer {
381     ///     pointer: *mut u8,
382     ///     padding: u64,
383     /// }
384     ///
385     /// static _EXPOSED_POINTER_LAYOUT_ASSERTIONS: () = {
386     ///     assert!(mem::size_of::<ExposedPointer>() == 8);
387     ///     assert!(mem::align_of::<ExposedPointer>() == 8);
388     /// };
389     ///
390     /// impl ExposedPointer {
391     ///     /// Wrap the given pointer into an `ExposedPointer`.
392     ///     fn new(pointer: *mut u8) -> Self {
393     ///         // NB: Zero-initialize to avoid potential footguns with accessing
394     ///         // undefined bytes.
395     ///         let mut p = Self { padding: 0 };
396     ///         p.pointer = pointer;
397     ///         p
398     ///     }
399     ///
400     ///     /// Get the wrapped pointer.
401     ///     fn get(&self) -> *mut u8 {
402     ///         unsafe { self.pointer }
403     ///     }
404     /// }
405     ///
406     /// /// This is the `T` type we will put inside our
407     /// /// `wasmtime::Store<T>`s. It contains a pointer to a heap-allocated buffer
408     /// /// in host memory, which we will give Wasm zero-copy access to via unsafe
409     /// /// intrinsics.
410     /// #[repr(C)]
411     /// struct StoreData {
412     ///     buf_ptr: ExposedPointer,
413     ///     buf_len: u64,
414     /// }
415     ///
416     /// static _STORE_DATA_LAYOUT_ASSERTIONS: () = {
417     ///     assert!(mem::size_of::<StoreData>() == 16);
418     ///     assert!(mem::align_of::<StoreData>() == 8);
419     ///     assert!(mem::offset_of!(StoreData, buf_ptr) == 0);
420     ///     assert!(mem::offset_of!(StoreData, buf_len) == 8);
421     /// };
422     ///
423     /// impl Drop for StoreData {
424     ///     fn drop(&mut self) {
425     ///         let len = usize::try_from(self.buf_len).unwrap();
426     ///         let ptr = std::ptr::slice_from_raw_parts_mut(self.buf_ptr.get(), len);
427     ///         unsafe {
428     ///             let _ = Box::from_raw(ptr);
429     ///         }
430     ///     }
431     /// }
432     ///
433     /// impl StoreData {
434     ///     /// Create a new `StoreData`, allocating an inner buffer containing
435     ///     /// `bytes`.
436     ///     fn new(bytes: impl IntoIterator<Item = u8>) -> Self {
437     ///         let buf: Box<[u8]> = bytes.into_iter().collect();
438     ///         let ptr = Box::into_raw(buf);
439     ///         Self {
440     ///             buf_ptr: ExposedPointer::new(ptr.cast::<u8>()),
441     ///             buf_len: u64::try_from(ptr.len()).unwrap(),
442     ///         }
443     ///     }
444     ///
445     ///     /// Get the inner buffer as a shared slice.
446     ///     fn buf(&self) -> &[u8] {
447     ///         let ptr = self.buf_ptr.get().cast_const();
448     ///         let len = usize::try_from(self.buf_len).unwrap();
449     ///         unsafe {
450     ///             std::slice::from_raw_parts(ptr, len)
451     ///         }
452     ///     }
453     /// }
454     ///
455     /// # fn main() -> Result<()> {
456     /// // Enable function inlining during compilation. If you are using unsafe intrinsics, you
457     /// // almost assuredly want them inlined to avoid function call overheads.
458     /// let mut config = Config::new();
459     /// config.compiler_inlining(true);
460     ///
461     /// let engine = Engine::new(&config)?;
462     /// let linker = wasmtime::component::Linker::new(&engine);
463     ///
464     /// // Create a new builder for configuring a Wasm compilation.
465     /// let mut builder = CodeBuilder::new(&engine);
466     ///
467     /// // Allow the code we are building to use Wasmtime's unsafe intrinsics.
468     /// //
469     /// // SAFETY: we wrap all usage of the intrinsics in safe APIs and only instantiate the code
470     /// // within a `Store<T>` where `T = StoreData`, as the code expects.
471     /// unsafe {
472     ///     builder.expose_unsafe_intrinsics("unsafe-intrinsics");
473     /// }
474     ///
475     /// // Define the compile-time builtin that encapsulates the
476     /// // intrinsics' unsafety and builds a safe API on top of them.
477     /// unsafe {
478     ///     builder.compile_time_builtins_binary_or_text(
479     ///         "safe-api",
480     ///         r#"
481     ///             (component
482     ///                 (import "unsafe-intrinsics"
483     ///                     (instance $intrinsics
484     ///                         (export "store-data-address" (func (result u64)))
485     ///                         (export "u64-native-load" (func (param "pointer" u64) (result u64)))
486     ///                         (export "u8-native-load" (func (param "pointer" u64) (result u8)))
487     ///                         (export "u8-native-store" (func (param "pointer" u64) (param "value" u8)))
488     ///                     )
489     ///                 )
490     ///
491     ///                 ;; The core Wasm module that implements the safe API.
492     ///                 (core module $safe-api-impl
493     ///                     (import "" "store-data-address" (func $store-data-address (result i64)))
494     ///                     (import "" "u64-native-load" (func $u64-native-load (param i64) (result i64)))
495     ///                     (import "" "u8-native-load" (func $u8-native-load (param i64) (result i32)))
496     ///                     (import "" "u8-native-store" (func $u8-native-store (param i64 i32)))
497     ///
498     ///                     ;; Load the `StoreData::buf_ptr` field
499     ///                     (func $get-buf-ptr (result i64)
500     ///                         (call $u64-native-load (i64.add (call $store-data-address) (i64.const 0)))
501     ///                     )
502     ///
503     ///                     ;; Load the `StoreData::buf_len` field
504     ///                     (func $get-buf-len (result i64)
505     ///                         (call $u64-native-load (i64.add (call $store-data-address) (i64.const 8)))
506     ///                     )
507     ///
508     ///                     ;; Check that `$i` is within `StoreData` buffer's bounds, raising a trap
509     ///                     ;; otherwise.
510     ///                     (func $bounds-check (param $i i64)
511     ///                         (if (i64.lt_u (local.get $i) (call $get-buf-len))
512     ///                             (then (return))
513     ///                             (else (unreachable))
514     ///                         )
515     ///                     )
516     ///
517     ///                     ;; A safe function to get the `i`th byte from `StoreData`'s buffer,
518     ///                     ;; raising a trap on out-of-bounds accesses.
519     ///                     (func (export "get") (param $i i64) (result i32)
520     ///                         (call $bounds-check (local.get $i))
521     ///                         (call $u8-native-load (i64.add (call $get-buf-ptr) (local.get $i)))
522     ///                     )
523     ///
524     ///                     ;; A safe function to set the `i`th byte in `StoreData`'s buffer,
525     ///                     ;; raising a trap on out-of-bounds accesses.
526     ///                     (func (export "set") (param $i i64) (param $value i32)
527     ///                         (call $bounds-check (local.get $i))
528     ///                         (call $u8-native-store (i64.add (call $get-buf-ptr) (local.get $i))
529     ///                                                (local.get $value))
530     ///                     )
531     ///
532     ///                     ;; A safe function to get the length of the `StoreData` buffer.
533     ///                     (func (export "len") (result i64)
534     ///                         (call $get-buf-len)
535     ///                     )
536     ///                 )
537     ///
538     ///                 ;; Lower the imported intrinsics from component functions to core functions.
539     ///                 (core func $store-data-address' (canon lower (func $intrinsics "store-data-address")))
540     ///                 (core func $u64-native-load' (canon lower (func $intrinsics "u64-native-load")))
541     ///                 (core func $u8-native-load' (canon lower (func $intrinsics "u8-native-load")))
542     ///                 (core func $u8-native-store' (canon lower (func $intrinsics "u8-native-store")))
543     ///
544     ///                 ;; Instantiate our safe API implementation, passing in the lowered unsafe
545     ///                 ;; intrinsics as its imports.
546     ///                 (core instance $instance
547     ///                     (instantiate $safe-api-impl
548     ///                         (with "" (instance
549     ///                             (export "store-data-address" (func $store-data-address'))
550     ///                             (export "u64-native-load" (func $u64-native-load'))
551     ///                             (export "u8-native-load" (func $u8-native-load'))
552     ///                             (export "u8-native-store" (func $u8-native-store'))
553     ///                         ))
554     ///                     )
555     ///                 )
556     ///
557     ///                 ;; Lift the safe API's exports from core functions to component functions
558     ///                 ;; and export them.
559     ///                 (func (export "get") (param "i" u64) (result u8)
560     ///                     (canon lift (core func $instance "get"))
561     ///                 )
562     ///                 (func (export "set") (param "i" u64) (param "value" u8)
563     ///                     (canon lift (core func $instance "set"))
564     ///                 )
565     ///                 (func (export "len") (result u64)
566     ///                     (canon lift (core func $instance "len"))
567     ///                 )
568     ///             )
569     ///         "#.as_bytes(),
570     ///         None,
571     ///     )?;
572     /// }
573     ///
574     /// // Provide the guest Wasm that we are compiling, which uses the safe API we
575     /// // implemented as a compile-time builtin.
576     /// builder.wasm_binary_or_text(
577     ///     r#"
578     ///         (component
579     ///             ;; Import the safe API.
580     ///             (import "safe-api"
581     ///                 (instance $safe-api
582     ///                     (export "get" (func (param "i" u64) (result u8)))
583     ///                     (export "set" (func (param "i" u64) (param "value" u8)))
584     ///                     (export "len" (func (result u64)))
585     ///                 )
586     ///             )
587     ///
588     ///             ;; Define this component's core module implementation.
589     ///             (core module $main-impl
590     ///                 (import "" "get" (func $get (param i64) (result i32)))
591     ///                 (import "" "set" (func $set (param i64 i32)))
592     ///                 (import "" "len" (func $len (result i64)))
593     ///
594     ///                 (func (export "main")
595     ///                     (local $i i64)
596     ///                     (local $n i64)
597     ///
598     ///                     (local.set $i (i64.const 0))
599     ///                     (local.set $n (call $len))
600     ///
601     ///                     (loop $loop
602     ///                         ;; When we have iterated over every byte in the
603     ///                         ;; buffer, exit.
604     ///                         (if (i64.ge_u (local.get $i) (local.get $n))
605     ///                             (then (return)))
606     ///
607     ///                         ;; Increment the `i`th byte in the buffer.
608     ///                         (call $set (local.get $i)
609     ///                                    (i32.add (call $get (local.get $i))
610     ///                                             (i32.const 1)))
611     ///
612     ///                         ;; Increment `i` and continue to the next iteration
613     ///                         ;; of the loop.
614     ///                         (local.set $i (i64.add (local.get $i) (i64.const 1)))
615     ///                         (br $loop)
616     ///                     )
617     ///                 )
618     ///             )
619     ///
620     ///             ;; Lower the imported safe APIs from component functions to core functions.
621     ///             (core func $get' (canon lower (func $safe-api "get")))
622     ///             (core func $set' (canon lower (func $safe-api "set")))
623     ///             (core func $len' (canon lower (func $safe-api "len")))
624     ///
625     ///             ;; Instantiate our module, providing the lowered safe APIs as imports.
626     ///             (core instance $instance
627     ///                 (instantiate $main-impl
628     ///                     (with "" (instance
629     ///                         (export "get" (func $get'))
630     ///                         (export "set" (func $set'))
631     ///                         (export "len" (func $len'))
632     ///                     ))
633     ///                 )
634     ///             )
635     ///
636     ///             ;; Lift the implementation's `main` from a core function to a component function
637     ///             ;; and export it!
638     ///             (func (export "main")
639     ///                 (canon lift (core func $instance "main"))
640     ///             )
641     ///         )
642     ///     "#.as_bytes(),
643     ///     None,
644     /// )?;
645     ///
646     /// // Finish the builder and compile the component.
647     /// let component = builder.compile_component()?;
648     ///
649     /// // Create a new `Store<StoreData>`, wrapping a buffer of the given elements.
650     /// let mut store = Store::new(&engine, StoreData::new([0, 10, 20, 30, 40, 50]));
651     ///
652     /// // Instantiate our component into the store.
653     /// let instance = linker.instantiate(&mut store, &component)?;
654     ///
655     /// // Get the instance's exported `main` function and call it.
656     /// instance
657     ///     .get_typed_func::<(), ()>(&mut store, "main")?
658     ///     .call(&mut store, ())?;
659     ///
660     /// // Our `StoreData`'s buffer had each element incremented directly from Wasm!
661     /// assert_eq!(store.data().buf(), &[1, 11, 21, 31, 41, 51]);
662     /// # Ok(())
663     /// # }
664     /// ```
665     pub unsafe fn expose_unsafe_intrinsics(&mut self, import_name: impl Into<String>) -> &mut Self {
666         self.unsafe_intrinsics_import = Some(import_name.into());
667         self
668     }
669 
670     /// Explicitly specify DWARF `.dwp` path.
671     ///
672     /// # Errors
673     ///
674     /// This method will return an error if the `.dwp` file has already been set
675     /// through [`CodeBuilder::dwarf_package`] or auto-detection in
676     /// [`CodeBuilder::wasm_binary_file`].
677     ///
678     /// This method will also return an error if `file` cannot be read.
679     pub fn dwarf_package_file(&mut self, file: &Path) -> Result<&mut Self> {
680         if self.dwarf_package.is_some() {
681             bail!("cannot call `dwarf_package` or `dwarf_package_file` twice");
682         }
683 
684         let dwarf_package = std::fs::read(file)
685             .with_context(|| format!("failed to read dwarf input file: {}", file.display()))?;
686         self.dwarf_package_path = Some(Cow::Owned(file.to_owned()));
687         self.dwarf_package = Some(dwarf_package.into());
688 
689         Ok(self)
690     }
691 
692     fn dwarf_package_from_wasm_path(&mut self) -> Result<&mut Self> {
693         let dwarf_package_path_buf = self.wasm_path.as_ref().unwrap().with_extension("dwp");
694         if dwarf_package_path_buf.exists() {
695             return self.dwarf_package_file(dwarf_package_path_buf.as_path());
696         }
697 
698         Ok(self)
699     }
700 
701     /// Gets the DWARF package.
702     pub(super) fn get_dwarf_package(&self) -> Option<&[u8]> {
703         self.dwarf_package.as_deref()
704     }
705 
706     /// Set the DWARF package binary.
707     ///
708     /// Initializes `dwarf_package` from `dwp_bytes` in preparation for
709     /// DWARF fusion. Allows the DWARF package to be supplied as a byte array
710     /// when the file probing performed in `wasm_file` is not appropriate.
711     ///
712     /// # Errors
713     ///
714     /// Returns an error if the `*.dwp` file is already set via auto-probing in
715     /// [`CodeBuilder::wasm_binary_file`] or explicitly via
716     /// [`CodeBuilder::dwarf_package_file`].
717     pub fn dwarf_package(&mut self, dwp_bytes: &'a [u8]) -> Result<&mut Self> {
718         if self.dwarf_package.is_some() {
719             bail!("cannot call `dwarf_package` or `dwarf_package_file` twice");
720         }
721         self.dwarf_package = Some(dwp_bytes.into());
722         Ok(self)
723     }
724 
725     /// Returns a hint, if possible, of what the provided bytes are.
726     ///
727     /// This method can be use to detect what the previously supplied bytes to
728     /// methods such as [`CodeBuilder::wasm_binary_or_text`] are. This will
729     /// return whether a module or a component was found in the provided bytes.
730     ///
731     /// This method will return `None` if wasm bytes have not been configured
732     /// or if the provided bytes don't look like either a component or a
733     /// module.
734     pub fn hint(&self) -> Option<CodeHint> {
735         let wasm = self.wasm.as_ref()?;
736         if wasmparser::Parser::is_component(wasm) {
737             Some(CodeHint::Component)
738         } else if wasmparser::Parser::is_core_wasm(wasm) {
739             Some(CodeHint::Module)
740         } else {
741             None
742         }
743     }
744 
745     /// Finishes this compilation and produces a serialized list of bytes.
746     ///
747     /// This method requires that either [`CodeBuilder::wasm_binary`] or
748     /// related methods were invoked prior to indicate what is being compiled.
749     ///
750     /// This method will block the current thread until compilation has
751     /// finished, and when done the serialized artifact will be returned.
752     ///
753     /// Note that this method will never cache compilations, even if the
754     /// `cache` feature is enabled.
755     ///
756     /// # Errors
757     ///
758     /// This can fail if the input wasm module was not valid or if another
759     /// compilation-related error is encountered.
760     pub fn compile_module_serialized(&self) -> Result<Vec<u8>> {
761         ensure!(
762             self.unsafe_intrinsics_import.is_none(),
763             "`CodeBuilder::expose_unsafe_intrinsics` can only be used with components"
764         );
765 
766         #[cfg(feature = "compile-time-builtins")]
767         ensure!(
768             self.get_compile_time_builtins().is_empty(),
769             "compile-time builtins can only be used with components"
770         );
771 
772         let wasm = self.get_wasm()?;
773         let dwarf_package = self.get_dwarf_package();
774         let (v, _) =
775             super::build_module_artifacts(self.engine, &wasm, dwarf_package.as_deref(), &())?;
776         Ok(v)
777     }
778 
779     /// Same as [`CodeBuilder::compile_module_serialized`] except that it
780     /// compiles a serialized [`Component`](crate::component::Component)
781     /// instead of a module.
782     #[cfg(feature = "component-model")]
783     pub fn compile_component_serialized(&self) -> Result<Vec<u8>> {
784         let wasm = self.get_wasm()?;
785         let (v, _) = super::build_component_artifacts(
786             self.engine,
787             &wasm,
788             None,
789             self.get_unsafe_intrinsics_import(),
790             &(),
791         )?;
792         Ok(v)
793     }
794 
795     pub(super) fn get_unsafe_intrinsics_import(&self) -> Option<&str> {
796         self.unsafe_intrinsics_import.as_deref()
797     }
798 }
799 
800 /// This is a helper struct used when caching to hash the state of an `Engine`
801 /// used for module compilation.
802 ///
803 /// The hash computed for this structure is used to key the global wasmtime
804 /// cache and dictates whether artifacts are reused. Consequently the contents
805 /// of this hash dictate when artifacts are or aren't re-used.
806 pub struct HashedEngineCompileEnv<'a>(pub &'a Engine);
807 
808 impl std::hash::Hash for HashedEngineCompileEnv<'_> {
809     fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
810         // Hash the compiler's state based on its target and configuration.
811         if let Some(compiler) = self.0.compiler() {
812             compiler.triple().hash(hasher);
813             compiler.flags().hash(hasher);
814             compiler.isa_flags().hash(hasher);
815         }
816 
817         // Hash configuration state read for compilation
818         let config = self.0.config();
819         self.0.tunables().hash(hasher);
820         self.0.features().hash(hasher);
821         config.wmemcheck.hash(hasher);
822 
823         // Catch accidental bugs of reusing across crate versions.
824         config.module_version.hash(hasher);
825     }
826 }
827