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