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