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