1 use crate::component::matching::InstanceType; 2 use crate::component::types; 3 use crate::{ 4 code::CodeObject, code_memory::CodeMemory, type_registry::TypeCollection, Engine, Module, 5 ResourcesRequired, 6 }; 7 use crate::{FuncType, ValType}; 8 use anyhow::Result; 9 use std::mem; 10 use std::ops::Range; 11 use std::path::Path; 12 use std::ptr::NonNull; 13 use std::sync::Arc; 14 use wasmtime_environ::component::{ 15 AllCallFunc, CompiledComponentInfo, ComponentArtifacts, ComponentTypes, GlobalInitializer, 16 InstantiateModule, StaticModuleIndex, TrampolineIndex, TypeComponentIndex, VMComponentOffsets, 17 }; 18 19 use wasmtime_environ::{FunctionLoc, HostPtr, ObjectKind, PrimaryMap}; 20 use wasmtime_runtime::component::ComponentRuntimeInfo; 21 use wasmtime_runtime::{ 22 VMArrayCallFunction, VMFuncRef, VMFunctionBody, VMNativeCallFunction, VMWasmCallFunction, 23 }; 24 25 /// A compiled WebAssembly Component. 26 /// 27 /// This structure represents a compiled component that is ready to be 28 /// instantiated. This owns a region of virtual memory which contains executable 29 /// code compiled from a WebAssembly binary originally. This is the analog of 30 /// [`Module`](crate::Module) in the component embedding API. 31 /// 32 /// A [`Component`] can be turned into an 33 /// [`Instance`](crate::component::Instance) through a 34 /// [`Linker`](crate::component::Linker). [`Component`]s are safe to share 35 /// across threads. The compilation model of a component is the same as that of 36 /// [a module](crate::Module) which is to say: 37 /// 38 /// * Compilation happens synchronously during [`Component::new`]. 39 /// * The result of compilation can be saved into storage with 40 /// [`Component::serialize`]. 41 /// * A previously compiled artifact can be parsed with 42 /// [`Component::deserialize`]. 43 /// * No compilation happens at runtime for a component — everything is done 44 /// by the time [`Component::new`] returns. 45 /// 46 /// ## Components and `Clone` 47 /// 48 /// Using `clone` on a `Component` is a cheap operation. It will not create an 49 /// entirely new component, but rather just a new reference to the existing 50 /// component. In other words it's a shallow copy, not a deep copy. 51 /// 52 /// ## Examples 53 /// 54 /// For example usage see the documentation of [`Module`](crate::Module) as 55 /// [`Component`] has the same high-level API. 56 #[derive(Clone)] 57 pub struct Component { 58 inner: Arc<ComponentInner>, 59 } 60 61 struct ComponentInner { 62 /// Component type index 63 ty: TypeComponentIndex, 64 65 /// Core wasm modules that the component defined internally, indexed by the 66 /// compile-time-assigned `ModuleUpvarIndex`. 67 static_modules: PrimaryMap<StaticModuleIndex, Module>, 68 69 /// Code-related information such as the compiled artifact, type 70 /// information, etc. 71 /// 72 /// Note that the `Arc` here is used to share this allocation with internal 73 /// modules. 74 code: Arc<CodeObject>, 75 76 /// Metadata produced during compilation. 77 info: CompiledComponentInfo, 78 79 /// A cached handle to the `wasmtime::FuncType` for the canonical ABI's 80 /// `realloc`, to avoid the need to look up types in the registry and take 81 /// locks when calling `realloc` via `TypedFunc::call_raw`. 82 realloc_func_type: Arc<dyn std::any::Any + Send + Sync>, 83 } 84 85 pub(crate) struct AllCallFuncPointers { 86 pub wasm_call: NonNull<VMWasmCallFunction>, 87 pub array_call: VMArrayCallFunction, 88 pub native_call: NonNull<VMNativeCallFunction>, 89 } 90 91 impl Component { 92 /// Compiles a new WebAssembly component from the in-memory list of bytes 93 /// provided. 94 /// 95 /// The `bytes` provided can either be the binary or text format of a 96 /// [WebAssembly component]. Note that the text format requires the `wat` 97 /// feature of this crate to be enabled. This API does not support 98 /// streaming compilation. 99 /// 100 /// This function will synchronously validate the entire component, 101 /// including all core modules, and then compile all components, modules, 102 /// etc., found within the provided bytes. 103 /// 104 /// [WebAssembly component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md 105 /// 106 /// # Errors 107 /// 108 /// This function may fail and return an error. Errors may include 109 /// situations such as: 110 /// 111 /// * The binary provided could not be decoded because it's not a valid 112 /// WebAssembly binary 113 /// * The WebAssembly binary may not validate (e.g. contains type errors) 114 /// * Implementation-specific limits were exceeded with a valid binary (for 115 /// example too many locals) 116 /// * The wasm binary may use features that are not enabled in the 117 /// configuration of `engine` 118 /// * If the `wat` feature is enabled and the input is text, then it may be 119 /// rejected if it fails to parse. 120 /// 121 /// The error returned should contain full information about why compilation 122 /// failed. 123 /// 124 /// # Examples 125 /// 126 /// The `new` function can be invoked with a in-memory array of bytes: 127 /// 128 /// ```no_run 129 /// # use wasmtime::*; 130 /// # use wasmtime::component::Component; 131 /// # fn main() -> anyhow::Result<()> { 132 /// # let engine = Engine::default(); 133 /// # let wasm_bytes: Vec<u8> = Vec::new(); 134 /// let component = Component::new(&engine, &wasm_bytes)?; 135 /// # Ok(()) 136 /// # } 137 /// ``` 138 /// 139 /// Or you can also pass in a string to be parsed as the wasm text 140 /// format: 141 /// 142 /// ``` 143 /// # use wasmtime::*; 144 /// # use wasmtime::component::Component; 145 /// # fn main() -> anyhow::Result<()> { 146 /// # let engine = Engine::default(); 147 /// let component = Component::new(&engine, "(component (core module))")?; 148 /// # Ok(()) 149 /// # } 150 #[cfg(any(feature = "cranelift", feature = "winch"))] 151 #[cfg_attr(docsrs, doc(cfg(any(feature = "cranelift", feature = "winch"))))] 152 pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> { 153 crate::CodeBuilder::new(engine) 154 .wasm(bytes.as_ref(), None)? 155 .compile_component() 156 } 157 158 /// Compiles a new WebAssembly component from a wasm file on disk pointed 159 /// to by `file`. 160 /// 161 /// This is a convenience function for reading the contents of `file` on 162 /// disk and then calling [`Component::new`]. 163 #[cfg(any(feature = "cranelift", feature = "winch"))] 164 #[cfg_attr(docsrs, doc(cfg(any(feature = "cranelift", feature = "winch"))))] 165 pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> { 166 crate::CodeBuilder::new(engine) 167 .wasm_file(file.as_ref())? 168 .compile_component() 169 } 170 171 /// Compiles a new WebAssembly component from the in-memory wasm image 172 /// provided. 173 /// 174 /// This function is the same as [`Component::new`] except that it does not 175 /// accept the text format of WebAssembly. Even if the `wat` feature 176 /// is enabled an error will be returned here if `binary` is the text 177 /// format. 178 /// 179 /// For more information on semantics and errors see [`Component::new`]. 180 #[cfg(any(feature = "cranelift", feature = "winch"))] 181 #[cfg_attr(docsrs, doc(cfg(any(feature = "cranelift", feature = "winch"))))] 182 pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> { 183 crate::CodeBuilder::new(engine) 184 .wasm(binary, None)? 185 .wat(false)? 186 .compile_component() 187 } 188 189 /// Same as [`Module::deserialize`], but for components. 190 /// 191 /// Note that the bytes referenced here must contain contents previously 192 /// produced by [`Engine::precompile_component`] or 193 /// [`Component::serialize`]. 194 /// 195 /// For more information see the [`Module::deserialize`] method. 196 /// 197 /// # Unsafety 198 /// 199 /// The unsafety of this method is the same as that of the 200 /// [`Module::deserialize`] method. 201 /// 202 /// [`Module::deserialize`]: crate::Module::deserialize 203 pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> { 204 let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Component)?; 205 Component::from_parts(engine, code, None) 206 } 207 208 /// Same as [`Module::deserialize_file`], but for components. 209 /// 210 /// Note that the file referenced here must contain contents previously 211 /// produced by [`Engine::precompile_component`] or 212 /// [`Component::serialize`]. 213 /// 214 /// For more information see the [`Module::deserialize_file`] method. 215 /// 216 /// # Unsafety 217 /// 218 /// The unsafety of this method is the same as that of the 219 /// [`Module::deserialize_file`] method. 220 /// 221 /// [`Module::deserialize_file`]: crate::Module::deserialize_file 222 pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Component> { 223 let code = engine.load_code_file(path.as_ref(), ObjectKind::Component)?; 224 Component::from_parts(engine, code, None) 225 } 226 227 /// Returns the type of this component as a [`types::Component`]. 228 /// 229 /// This method enables runtime introspection of the type of a component 230 /// before instantiation, if necessary. 231 /// 232 /// ## Component types and Resources 233 /// 234 /// An important point to note here is that the precise type of imports and 235 /// exports of a component change when it is instantiated with respect to 236 /// resources. For example a [`Component`] represents an un-instantiated 237 /// component meaning that its imported resources are represeted as abstract 238 /// resource types. These abstract types are not equal to any other 239 /// component's types. 240 /// 241 /// For example: 242 /// 243 /// ``` 244 /// # use wasmtime::Engine; 245 /// # use wasmtime::component::Component; 246 /// # use wasmtime::component::types::ComponentItem; 247 /// # fn main() -> wasmtime::Result<()> { 248 /// # let engine = Engine::default(); 249 /// let a = Component::new(&engine, r#" 250 /// (component (import "x" (type (sub resource)))) 251 /// "#)?; 252 /// let b = Component::new(&engine, r#" 253 /// (component (import "x" (type (sub resource)))) 254 /// "#)?; 255 /// 256 /// let (_, a_ty) = a.component_type().imports(&engine).next().unwrap(); 257 /// let (_, b_ty) = b.component_type().imports(&engine).next().unwrap(); 258 /// 259 /// let a_ty = match a_ty { 260 /// ComponentItem::Resource(ty) => ty, 261 /// _ => unreachable!(), 262 /// }; 263 /// let b_ty = match b_ty { 264 /// ComponentItem::Resource(ty) => ty, 265 /// _ => unreachable!(), 266 /// }; 267 /// assert!(a_ty != b_ty); 268 /// # Ok(()) 269 /// # } 270 /// ``` 271 /// 272 /// Additionally, however, these abstract types are "substituted" during 273 /// instantiation meaning that a component type will appear to have changed 274 /// once it is instantiated. 275 /// 276 /// ``` 277 /// # use wasmtime::{Engine, Store}; 278 /// # use wasmtime::component::{Component, Linker, ResourceType}; 279 /// # use wasmtime::component::types::ComponentItem; 280 /// # fn main() -> wasmtime::Result<()> { 281 /// # let engine = Engine::default(); 282 /// // Here this component imports a resource and then exports it as-is 283 /// // which means that the export is equal to the import. 284 /// let a = Component::new(&engine, r#" 285 /// (component 286 /// (import "x" (type $x (sub resource))) 287 /// (export "x" (type $x)) 288 /// ) 289 /// "#)?; 290 /// 291 /// let (_, import) = a.component_type().imports(&engine).next().unwrap(); 292 /// let (_, export) = a.component_type().exports(&engine).next().unwrap(); 293 /// 294 /// let import = match import { 295 /// ComponentItem::Resource(ty) => ty, 296 /// _ => unreachable!(), 297 /// }; 298 /// let export = match export { 299 /// ComponentItem::Resource(ty) => ty, 300 /// _ => unreachable!(), 301 /// }; 302 /// assert_eq!(import, export); 303 /// 304 /// // However after instantiation the resource type "changes" 305 /// let mut store = Store::new(&engine, ()); 306 /// let mut linker = Linker::new(&engine); 307 /// linker.root().resource("x", ResourceType::host::<()>(), |_, _| Ok(()))?; 308 /// let instance = linker.instantiate(&mut store, &a)?; 309 /// let instance_ty = instance.exports(&mut store).root().resource("x").unwrap(); 310 /// 311 /// // Here `instance_ty` is not the same as either `import` or `export`, 312 /// // but it is equal to what we provided as an import. 313 /// assert!(instance_ty != import); 314 /// assert!(instance_ty != export); 315 /// assert!(instance_ty == ResourceType::host::<()>()); 316 /// # Ok(()) 317 /// # } 318 /// ``` 319 /// 320 /// Finally, each instantiation of an exported resource from a component is 321 /// considered "fresh" for all instantiations meaning that different 322 /// instantiations will have different exported resource types: 323 /// 324 /// ``` 325 /// # use wasmtime::{Engine, Store}; 326 /// # use wasmtime::component::{Component, Linker}; 327 /// # fn main() -> wasmtime::Result<()> { 328 /// # let engine = Engine::default(); 329 /// let a = Component::new(&engine, r#" 330 /// (component 331 /// (type $x (resource (rep i32))) 332 /// (export "x" (type $x)) 333 /// ) 334 /// "#)?; 335 /// 336 /// let mut store = Store::new(&engine, ()); 337 /// let linker = Linker::new(&engine); 338 /// let instance1 = linker.instantiate(&mut store, &a)?; 339 /// let instance2 = linker.instantiate(&mut store, &a)?; 340 /// 341 /// let x1 = instance1.exports(&mut store).root().resource("x").unwrap(); 342 /// let x2 = instance2.exports(&mut store).root().resource("x").unwrap(); 343 /// 344 /// // Despite these two resources being the same export of the same 345 /// // component they come from two different instances meaning that their 346 /// // types will be unique. 347 /// assert!(x1 != x2); 348 /// # Ok(()) 349 /// # } 350 /// ``` 351 pub fn component_type(&self) -> types::Component { 352 let resources = Arc::new(PrimaryMap::new()); 353 types::Component::from( 354 self.inner.ty, 355 &InstanceType { 356 types: self.types(), 357 resources: &resources, 358 }, 359 ) 360 } 361 362 /// Final assembly step for a component from its in-memory representation. 363 /// 364 /// If the `artifacts` are specified as `None` here then they will be 365 /// deserialized from `code_memory`. 366 pub(crate) fn from_parts( 367 engine: &Engine, 368 code_memory: Arc<CodeMemory>, 369 artifacts: Option<ComponentArtifacts>, 370 ) -> Result<Component> { 371 let ComponentArtifacts { 372 ty, 373 info, 374 types, 375 static_modules, 376 } = match artifacts { 377 Some(artifacts) => artifacts, 378 None => postcard::from_bytes(code_memory.wasmtime_info())?, 379 }; 380 381 // Validate that the component can be used with the current instance 382 // allocator. 383 engine.allocator().validate_component( 384 &info.component, 385 &VMComponentOffsets::new(HostPtr, &info.component), 386 &|module_index| &static_modules[module_index].module, 387 )?; 388 389 // Create a signature registration with the `Engine` for all trampolines 390 // and core wasm types found within this component, both for the 391 // component and for all included core wasm modules. 392 let signatures = TypeCollection::new_for_module(engine, types.module_types()); 393 394 // Assemble the `CodeObject` artifact which is shared by all core wasm 395 // modules as well as the final component. 396 let types = Arc::new(types); 397 let code = Arc::new(CodeObject::new(code_memory, signatures, types.into())); 398 399 // Convert all information about static core wasm modules into actual 400 // `Module` instances by converting each `CompiledModuleInfo`, the 401 // `types` type information, and the code memory to a runtime object. 402 let static_modules = static_modules 403 .into_iter() 404 .map(|(_, info)| Module::from_parts_raw(engine, code.clone(), info, false)) 405 .collect::<Result<_>>()?; 406 407 let realloc_func_type = Arc::new(FuncType::new( 408 engine, 409 [ValType::I32, ValType::I32, ValType::I32, ValType::I32], 410 [ValType::I32], 411 )) as _; 412 413 Ok(Component { 414 inner: Arc::new(ComponentInner { 415 ty, 416 static_modules, 417 code, 418 info, 419 realloc_func_type, 420 }), 421 }) 422 } 423 424 pub(crate) fn ty(&self) -> TypeComponentIndex { 425 self.inner.ty 426 } 427 428 pub(crate) fn env_component(&self) -> &wasmtime_environ::component::Component { 429 &self.inner.info.component 430 } 431 432 pub(crate) fn static_module(&self, idx: StaticModuleIndex) -> &Module { 433 &self.inner.static_modules[idx] 434 } 435 436 #[inline] 437 pub(crate) fn types(&self) -> &Arc<ComponentTypes> { 438 self.inner.component_types() 439 } 440 441 pub(crate) fn signatures(&self) -> &TypeCollection { 442 self.inner.code.signatures() 443 } 444 445 pub(crate) fn text(&self) -> &[u8] { 446 self.inner.code.code_memory().text() 447 } 448 449 pub(crate) fn trampoline_ptrs(&self, index: TrampolineIndex) -> AllCallFuncPointers { 450 let AllCallFunc { 451 wasm_call, 452 array_call, 453 native_call, 454 } = &self.inner.info.trampolines[index]; 455 AllCallFuncPointers { 456 wasm_call: self.func(wasm_call).cast(), 457 array_call: unsafe { 458 mem::transmute::<NonNull<VMFunctionBody>, VMArrayCallFunction>( 459 self.func(array_call), 460 ) 461 }, 462 native_call: self.func(native_call).cast(), 463 } 464 } 465 466 fn func(&self, loc: &FunctionLoc) -> NonNull<VMFunctionBody> { 467 let text = self.text(); 468 let trampoline = &text[loc.start as usize..][..loc.length as usize]; 469 NonNull::new(trampoline.as_ptr() as *mut VMFunctionBody).unwrap() 470 } 471 472 pub(crate) fn code_object(&self) -> &Arc<CodeObject> { 473 &self.inner.code 474 } 475 476 /// Same as [`Module::serialize`], except for a component. 477 /// 478 /// Note that the artifact produced here must be passed to 479 /// [`Component::deserialize`] and is not compatible for use with 480 /// [`Module`]. 481 /// 482 /// [`Module::serialize`]: crate::Module::serialize 483 /// [`Module`]: crate::Module 484 pub fn serialize(&self) -> Result<Vec<u8>> { 485 Ok(self.code_object().code_memory().mmap().to_vec()) 486 } 487 488 pub(crate) fn runtime_info(&self) -> Arc<dyn ComponentRuntimeInfo> { 489 self.inner.clone() 490 } 491 492 /// Creates a new `VMFuncRef` with all fields filled out for the destructor 493 /// specified. 494 /// 495 /// The `dtor`'s own `VMFuncRef` won't have `wasm_call` filled out but this 496 /// component may have `resource_drop_wasm_to_native_trampoline` filled out 497 /// if necessary in which case it's filled in here. 498 pub(crate) fn resource_drop_func_ref(&self, dtor: &crate::func::HostFunc) -> VMFuncRef { 499 // Host functions never have their `wasm_call` filled in at this time. 500 assert!(dtor.func_ref().wasm_call.is_none()); 501 502 // Note that if `resource_drop_wasm_to_native_trampoline` is not present 503 // then this can't be called by the component, so it's ok to leave it 504 // blank. 505 let wasm_call = self 506 .inner 507 .info 508 .resource_drop_wasm_to_native_trampoline 509 .as_ref() 510 .map(|i| self.func(i).cast()); 511 VMFuncRef { 512 wasm_call, 513 ..*dtor.func_ref() 514 } 515 } 516 517 /// Returns a summary of the resources required to instantiate this 518 /// [`Component`][crate::component::Component]. 519 /// 520 /// Note that when a component imports and instantiates another component or 521 /// core module, we cannot determine ahead of time how many resources 522 /// instantiating this component will require, and therefore this method 523 /// will return `None` in these scenarios. 524 /// 525 /// Potential uses of the returned information: 526 /// 527 /// * Determining whether your pooling allocator configuration supports 528 /// instantiating this component. 529 /// 530 /// * Deciding how many of which `Component` you want to instantiate within 531 /// a fixed amount of resources, e.g. determining whether to create 5 532 /// instances of component X or 10 instances of component Y. 533 /// 534 /// # Example 535 /// 536 /// ``` 537 /// # fn main() -> wasmtime::Result<()> { 538 /// use wasmtime::{Config, Engine, component::Component}; 539 /// 540 /// let mut config = Config::new(); 541 /// config.wasm_multi_memory(true); 542 /// config.wasm_component_model(true); 543 /// let engine = Engine::new(&config)?; 544 /// 545 /// let component = Component::new(&engine, &r#" 546 /// (component 547 /// ;; Define a core module that uses two memories. 548 /// (core module $m 549 /// (memory 1) 550 /// (memory 6) 551 /// ) 552 /// 553 /// ;; Instantiate that core module three times. 554 /// (core instance $i1 (instantiate (module $m))) 555 /// (core instance $i2 (instantiate (module $m))) 556 /// (core instance $i3 (instantiate (module $m))) 557 /// ) 558 /// "#)?; 559 /// 560 /// let resources = component.resources_required() 561 /// .expect("this component does not import any core modules or instances"); 562 /// 563 /// // Instantiating the component will require allocating two memories per 564 /// // core instance, and there are three instances, so six total memories. 565 /// assert_eq!(resources.num_memories, 6); 566 /// assert_eq!(resources.max_initial_memory_size, Some(6)); 567 /// 568 /// // The component doesn't need any tables. 569 /// assert_eq!(resources.num_tables, 0); 570 /// assert_eq!(resources.max_initial_table_size, None); 571 /// # Ok(()) } 572 /// ``` 573 pub fn resources_required(&self) -> Option<ResourcesRequired> { 574 let mut resources = ResourcesRequired { 575 num_memories: 0, 576 max_initial_memory_size: None, 577 num_tables: 0, 578 max_initial_table_size: None, 579 }; 580 for init in &self.env_component().initializers { 581 match init { 582 GlobalInitializer::InstantiateModule(inst) => match inst { 583 InstantiateModule::Static(index, _) => { 584 let module = self.static_module(*index); 585 resources.add(&module.resources_required()); 586 } 587 InstantiateModule::Import(_, _) => { 588 // We can't statically determine the resources required 589 // to instantiate this component. 590 return None; 591 } 592 }, 593 GlobalInitializer::LowerImport { .. } 594 | GlobalInitializer::ExtractMemory(_) 595 | GlobalInitializer::ExtractRealloc(_) 596 | GlobalInitializer::ExtractPostReturn(_) 597 | GlobalInitializer::Resource(_) => {} 598 } 599 } 600 Some(resources) 601 } 602 603 /// Returns the range, in the host's address space, that this module's 604 /// compiled code resides at. 605 /// 606 /// For more information see 607 /// [`Module;:image_range`](crate::Module::image_range). 608 pub fn image_range(&self) -> Range<*const u8> { 609 self.inner.code.code_memory().mmap().image_range() 610 } 611 } 612 613 impl ComponentRuntimeInfo for ComponentInner { 614 fn component(&self) -> &wasmtime_environ::component::Component { 615 &self.info.component 616 } 617 618 fn component_types(&self) -> &Arc<ComponentTypes> { 619 match self.code.types() { 620 crate::code::Types::Component(types) => types, 621 // The only creator of a `Component` is itself which uses the other 622 // variant, so this shouldn't be possible. 623 crate::code::Types::Module(_) => unreachable!(), 624 } 625 } 626 627 fn realloc_func_type(&self) -> &Arc<dyn std::any::Any + Send + Sync> { 628 &self.realloc_func_type 629 } 630 } 631 632 #[cfg(test)] 633 mod tests { 634 use crate::component::Component; 635 use crate::{Config, Engine}; 636 use wasmtime_environ::MemoryInitialization; 637 638 #[test] 639 fn cow_on_by_default() { 640 let mut config = Config::new(); 641 config.wasm_component_model(true); 642 let engine = Engine::new(&config).unwrap(); 643 let component = Component::new( 644 &engine, 645 r#" 646 (component 647 (core module 648 (memory 1) 649 (data (i32.const 100) "abcd") 650 ) 651 ) 652 "#, 653 ) 654 .unwrap(); 655 656 for (_, module) in component.inner.static_modules.iter() { 657 let init = &module.env_module().memory_initialization; 658 assert!(matches!(init, MemoryInitialization::Static { .. })); 659 } 660 } 661 } 662