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