/src/wasmtime/crates/environ/src/component/translate/inline.rs
Line | Count | Source |
1 | | //! Implementation of "inlining" a component into a flat list of initializers. |
2 | | //! |
3 | | //! After the first phase of compiling a component we're left with a single |
4 | | //! root `Translation` for the original component along with a "static" list of |
5 | | //! child components. Each `Translation` has a list of `LocalInitializer` items |
6 | | //! inside of it which is a primitive representation of how the component |
7 | | //! should be constructed with effectively one initializer per item in the |
8 | | //! index space of a component. This "local initializer" list would be |
9 | | //! relatively inefficient to process at runtime and more importantly doesn't |
10 | | //! convey enough information to understand what trampolines need to be |
11 | | //! compiled or what fused adapters need to be generated. This consequently is |
12 | | //! the motivation for this file. |
13 | | //! |
14 | | //! The second phase of compilation, inlining here, will in a sense interpret |
15 | | //! the initializers, at compile time, into a new list of `GlobalInitializer` entries |
16 | | //! which are a sort of "global initializer". The generated `GlobalInitializer` is |
17 | | //! much more specific than the `LocalInitializer` and additionally far fewer |
18 | | //! `GlobalInitializer` structures are generated (in theory) than there are local |
19 | | //! initializers. |
20 | | //! |
21 | | //! The "inlining" portion of the name of this module indicates how the |
22 | | //! instantiation of a component is interpreted as calling a function. The |
23 | | //! function's arguments are the imports provided to the instantiation of a |
24 | | //! component, and further nested function calls happen on a stack when a |
25 | | //! nested component is instantiated. The inlining then refers to how this |
26 | | //! stack of instantiations is flattened to one list of `GlobalInitializer` |
27 | | //! entries to represent the process of instantiating a component graph, |
28 | | //! similar to how function inlining removes call instructions and creates one |
29 | | //! giant function for a call graph. Here there are no inlining heuristics or |
30 | | //! anything like that, we simply inline everything into the root component's |
31 | | //! list of initializers. |
32 | | //! |
33 | | //! Another primary task this module performs is a form of dataflow analysis |
34 | | //! to represent items in each index space with their definition rather than |
35 | | //! references of relative indices. These definitions (all the `*Def` types in |
36 | | //! this module) are not local to any one nested component and instead |
37 | | //! represent state available at runtime tracked in the final `Component` |
38 | | //! produced. |
39 | | //! |
40 | | //! With all this pieced together the general idea is relatively |
41 | | //! straightforward. All of a component's initializers are processed in sequence |
42 | | //! where instantiating a nested component pushes a "frame" onto a stack to |
43 | | //! start executing and we resume at the old one when we're done. Items are |
44 | | //! tracked where they come from and at the end after processing only the |
45 | | //! side-effectful initializers are emitted to the `GlobalInitializer` list in the |
46 | | //! final `Component`. |
47 | | |
48 | | use crate::component::translate::*; |
49 | | use crate::{EntityType, Memory}; |
50 | | use core::str::FromStr; |
51 | | use std::borrow::Cow; |
52 | | use wasmparser::component_types::{ComponentAnyTypeId, ComponentCoreModuleTypeId}; |
53 | | |
54 | 6.10k | pub(super) fn run( |
55 | 6.10k | types: &mut ComponentTypesBuilder, |
56 | 6.10k | result: &Translation<'_>, |
57 | 6.10k | nested_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>, |
58 | 6.10k | nested_components: &PrimaryMap<StaticComponentIndex, Translation<'_>>, |
59 | 6.10k | ) -> Result<dfg::ComponentDfg> { |
60 | 6.10k | let mut inliner = Inliner { |
61 | 6.10k | nested_modules, |
62 | 6.10k | nested_components, |
63 | 6.10k | result: Default::default(), |
64 | 6.10k | import_path_interner: Default::default(), |
65 | 6.10k | runtime_instances: PrimaryMap::default(), |
66 | 6.10k | }; |
67 | | |
68 | 6.10k | let index = RuntimeComponentInstanceIndex::from_u32(0); |
69 | | |
70 | | // The initial arguments to the root component are all host imports. This |
71 | | // means that they're all using the `ComponentItemDef::Host` variant. Here |
72 | | // an `ImportIndex` is allocated for each item and then the argument is |
73 | | // recorded. |
74 | | // |
75 | | // Note that this is represents the abstract state of a host import of an |
76 | | // item since we don't know the precise structure of the host import. |
77 | 6.10k | let mut args = HashMap::with_capacity(result.exports.len()); |
78 | 6.10k | let mut path = Vec::new(); |
79 | 6.10k | types.resources_mut().set_current_instance(index); |
80 | 6.10k | let types_ref = result.types_ref(); |
81 | 74.9k | for init in result.initializers.iter() { |
82 | 74.9k | let (name, ty) = match *init { |
83 | 831 | LocalInitializer::Import(name, ty) => (name, ty), |
84 | 74.0k | _ => continue, |
85 | | }; |
86 | | |
87 | | // Before `convert_component_entity_type` below all resource types |
88 | | // introduced by this import need to be registered and have indexes |
89 | | // assigned to them. Any fresh new resource type referred to by imports |
90 | | // is a brand new introduction of a resource which needs to have a type |
91 | | // allocated to it, so new runtime imports are injected for each |
92 | | // resource along with updating the `imported_resources` map. |
93 | 831 | let index = inliner.result.import_types.next_key(); |
94 | 831 | types.resources_mut().register_component_entity_type( |
95 | 831 | &types_ref, |
96 | 831 | ty, |
97 | 831 | &mut path, |
98 | 350 | &mut |path| { |
99 | 350 | let index = inliner.runtime_import(&ImportPath { |
100 | 350 | index, |
101 | 350 | path: path.iter().copied().map(Into::into).collect(), |
102 | 350 | }); |
103 | 350 | inliner.result.imported_resources.push(index) |
104 | 350 | }, |
105 | | ); |
106 | | |
107 | | // With resources all taken care of it's now possible to convert this |
108 | | // into Wasmtime's type system. |
109 | 831 | let ty = types.convert_component_entity_type(types_ref, ty)?; |
110 | | |
111 | | // Imports of types that aren't resources are not required to be |
112 | | // specified by the host since it's just for type information within |
113 | | // the component. |
114 | 831 | if let TypeDef::Interface(_) = ty { |
115 | 30 | continue; |
116 | 801 | } |
117 | 801 | let index = inliner.result.import_types.push(( |
118 | 801 | name.name.to_string(), |
119 | 801 | ComponentExtern { |
120 | 801 | ty, |
121 | 801 | data: ComponentExternData::new(name), |
122 | 801 | }, |
123 | 801 | )); |
124 | 801 | let path = ImportPath::root(index); |
125 | 801 | args.insert(name.name, ComponentItemDef::from_import(path, ty)?); |
126 | | } |
127 | | |
128 | | // This will run the inliner to completion after being seeded with the |
129 | | // initial frame. When the inliner finishes it will return the exports of |
130 | | // the root frame which are then used for recording the exports of the |
131 | | // component. |
132 | 6.09k | inliner.result.num_runtime_component_instances += 1; |
133 | 6.09k | let frame = InlinerFrame::new(index, result, ComponentClosure::default(), args, None); |
134 | 6.09k | let resources_snapshot = types.resources_mut().clone(); |
135 | 6.09k | let mut frames = vec![(frame, resources_snapshot)]; |
136 | 6.09k | let exports = inliner.run(types, &mut frames)?; |
137 | 6.09k | assert!(frames.is_empty()); |
138 | | |
139 | 6.09k | let mut export_map = Default::default(); |
140 | 11.0k | for (name, (def, data)) in exports { |
141 | 11.0k | let data = ComponentExternData::new(data); |
142 | 11.0k | inliner.record_export(name, def, data, types, &mut export_map)?; |
143 | | } |
144 | 6.08k | inliner.result.exports = export_map; |
145 | 6.08k | inliner.result.num_future_tables = types.num_future_tables(); |
146 | 6.08k | inliner.result.num_stream_tables = types.num_stream_tables(); |
147 | 6.08k | inliner.result.num_error_context_tables = types.num_error_context_tables(); |
148 | | |
149 | 6.08k | Ok(inliner.result) |
150 | 6.10k | } |
151 | | |
152 | | struct Inliner<'a> { |
153 | | /// The list of static modules that were found during initial translation of |
154 | | /// the component. |
155 | | /// |
156 | | /// This is used during the instantiation of these modules to ahead-of-time |
157 | | /// order the arguments precisely according to what the module is defined as |
158 | | /// needing which avoids the need to do string lookups or permute arguments |
159 | | /// at runtime. |
160 | | nested_modules: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>, |
161 | | |
162 | | /// The list of static components that were found during initial translation of |
163 | | /// the component. |
164 | | /// |
165 | | /// This is used when instantiating nested components to push a new |
166 | | /// `InlinerFrame` with the `Translation`s here. |
167 | | nested_components: &'a PrimaryMap<StaticComponentIndex, Translation<'a>>, |
168 | | |
169 | | /// The final `Component` that is being constructed and returned from this |
170 | | /// inliner. |
171 | | result: dfg::ComponentDfg, |
172 | | |
173 | | // Maps used to "intern" various runtime items to only save them once at |
174 | | // runtime instead of multiple times. |
175 | | import_path_interner: HashMap<ImportPath<'a>, RuntimeImportIndex>, |
176 | | |
177 | | /// Origin information about where each runtime instance came from |
178 | | runtime_instances: PrimaryMap<dfg::InstanceId, InstanceModule>, |
179 | | } |
180 | | |
181 | | /// A "stack frame" as part of the inlining process, or the progress through |
182 | | /// instantiating a component. |
183 | | /// |
184 | | /// All instantiations of a component will create an `InlinerFrame` and are |
185 | | /// incrementally processed via the `initializers` list here. Note that the |
186 | | /// inliner frames are stored on the heap to avoid recursion based on user |
187 | | /// input. |
188 | | struct InlinerFrame<'a> { |
189 | | instance: RuntimeComponentInstanceIndex, |
190 | | |
191 | | /// The remaining initializers to process when instantiating this component. |
192 | | initializers: std::slice::Iter<'a, LocalInitializer<'a>>, |
193 | | |
194 | | /// The component being instantiated. |
195 | | translation: &'a Translation<'a>, |
196 | | |
197 | | /// The "closure arguments" to this component, or otherwise the maps indexed |
198 | | /// by `ModuleUpvarIndex` and `ComponentUpvarIndex`. This is created when |
199 | | /// a component is created and stored as part of a component's state during |
200 | | /// inlining. |
201 | | closure: ComponentClosure<'a>, |
202 | | |
203 | | /// The arguments to the creation of this component. |
204 | | /// |
205 | | /// At the root level these are all imports from the host and between |
206 | | /// components this otherwise tracks how all the arguments are defined. |
207 | | args: HashMap<&'a str, ComponentItemDef<'a>>, |
208 | | |
209 | | // core wasm index spaces |
210 | | funcs: PrimaryMap<FuncIndex, (ModuleInternedTypeIndex, dfg::CoreDef)>, |
211 | | memories: PrimaryMap<MemoryIndex, dfg::CoreExport<EntityIndex>>, |
212 | | tables: PrimaryMap<TableIndex, dfg::CoreExport<EntityIndex>>, |
213 | | globals: PrimaryMap<GlobalIndex, dfg::CoreExport<EntityIndex>>, |
214 | | tags: PrimaryMap<TagIndex, dfg::CoreExport<EntityIndex>>, |
215 | | modules: PrimaryMap<ModuleIndex, ModuleDef<'a>>, |
216 | | |
217 | | // component model index spaces |
218 | | component_funcs: PrimaryMap<ComponentFuncIndex, ComponentFuncDef<'a>>, |
219 | | module_instances: PrimaryMap<ModuleInstanceIndex, ModuleInstanceDef<'a>>, |
220 | | component_instances: PrimaryMap<ComponentInstanceIndex, ComponentInstanceDef<'a>>, |
221 | | components: PrimaryMap<ComponentIndex, ComponentDef<'a>>, |
222 | | |
223 | | /// The type of instance produced by completing the instantiation of this |
224 | | /// frame. |
225 | | /// |
226 | | /// This is a wasmparser-relative piece of type information which is used to |
227 | | /// register resource types after instantiation has completed. |
228 | | /// |
229 | | /// This is `Some` for all subcomponents and `None` for the root component. |
230 | | instance_ty: Option<ComponentInstanceTypeId>, |
231 | | } |
232 | | |
233 | | /// "Closure state" for a component which is resolved from the `ClosedOverVars` |
234 | | /// state that was calculated during translation. |
235 | | // |
236 | | // FIXME: this is cloned quite a lot and given the internal maps if this is a |
237 | | // perf issue we may want to `Rc` these fields. Note that this is only a perf |
238 | | // hit at compile-time though which we in general don't pay too much |
239 | | // attention to. |
240 | | #[derive(Default, Clone)] |
241 | | struct ComponentClosure<'a> { |
242 | | modules: PrimaryMap<ModuleUpvarIndex, ModuleDef<'a>>, |
243 | | components: PrimaryMap<ComponentUpvarIndex, ComponentDef<'a>>, |
244 | | } |
245 | | |
246 | | /// Representation of a "path" into an import. |
247 | | /// |
248 | | /// Imports from the host at this time are one of three things: |
249 | | /// |
250 | | /// * Functions |
251 | | /// * Core wasm modules |
252 | | /// * "Instances" of these three items |
253 | | /// |
254 | | /// The "base" values are functions and core wasm modules, but the abstraction |
255 | | /// of an instance allows embedding functions/modules deeply within other |
256 | | /// instances. This "path" represents optionally walking through a host instance |
257 | | /// to get to the final desired item. At runtime instances are just maps of |
258 | | /// values and so this is used to ensure that we primarily only deal with |
259 | | /// individual functions and modules instead of synthetic instances. |
260 | | #[derive(Clone, PartialEq, Hash, Eq)] |
261 | | struct ImportPath<'a> { |
262 | | index: ImportIndex, |
263 | | path: Vec<Cow<'a, str>>, |
264 | | } |
265 | | |
266 | | /// Representation of all items which can be defined within a component. |
267 | | /// |
268 | | /// This is the "value" of an item defined within a component and is used to |
269 | | /// represent both imports and exports. |
270 | | #[derive(Clone)] |
271 | | enum ComponentItemDef<'a> { |
272 | | Component(ComponentDef<'a>), |
273 | | Instance(ComponentInstanceDef<'a>), |
274 | | Func(ComponentFuncDef<'a>), |
275 | | Module(ModuleDef<'a>), |
276 | | Type(TypeDef), |
277 | | } |
278 | | |
279 | | #[derive(Clone)] |
280 | | enum ModuleDef<'a> { |
281 | | /// A core wasm module statically defined within the original component. |
282 | | /// |
283 | | /// The `StaticModuleIndex` indexes into the `static_modules` map in the |
284 | | /// `Inliner`. |
285 | | Static(StaticModuleIndex, ComponentCoreModuleTypeId), |
286 | | |
287 | | /// A core wasm module that was imported from the host. |
288 | | Import(ImportPath<'a>, TypeModuleIndex), |
289 | | } |
290 | | |
291 | | // Note that unlike all other `*Def` types which are not allowed to have local |
292 | | // indices this type does indeed have local indices. That is represented with |
293 | | // the lack of a `Clone` here where once this is created it's never moved across |
294 | | // components because module instances always stick within one component. |
295 | | enum ModuleInstanceDef<'a> { |
296 | | /// A core wasm module instance was created through the instantiation of a |
297 | | /// module. |
298 | | /// |
299 | | /// The `RuntimeInstanceIndex` was the index allocated as this was the |
300 | | /// `n`th instantiation and the `ModuleIndex` points into an |
301 | | /// `InlinerFrame`'s local index space. |
302 | | Instantiated(dfg::InstanceId, ModuleIndex), |
303 | | |
304 | | /// A "synthetic" core wasm module which is just a bag of named indices. |
305 | | /// |
306 | | /// Note that this can really only be used for passing as an argument to |
307 | | /// another module's instantiation and is used to rename arguments locally. |
308 | | Synthetic(&'a HashMap<&'a str, EntityIndex>), |
309 | | } |
310 | | |
311 | | #[derive(Clone)] |
312 | | enum ComponentFuncDef<'a> { |
313 | | /// A compile-time builtin intrinsic. |
314 | | UnsafeIntrinsic(UnsafeIntrinsic), |
315 | | |
316 | | /// A host-imported component function. |
317 | | Import(ImportPath<'a>), |
318 | | |
319 | | /// A core wasm function was lifted into a component function. |
320 | | Lifted { |
321 | | /// The component function type. |
322 | | ty: TypeFuncIndex, |
323 | | /// The core Wasm function. |
324 | | func: dfg::CoreDef, |
325 | | /// Canonical options. |
326 | | options: AdapterOptions, |
327 | | }, |
328 | | } |
329 | | |
330 | | #[derive(Clone)] |
331 | | enum ComponentInstanceDef<'a> { |
332 | | /// The `__wasmtime_intrinsics` instance that exports all of our |
333 | | /// compile-time builtin intrinsics. |
334 | | Intrinsics, |
335 | | |
336 | | /// A host-imported instance. |
337 | | /// |
338 | | /// This typically means that it's "just" a map of named values. It's not |
339 | | /// actually supported to take a `wasmtime::component::Instance` and pass it |
340 | | /// to another instance at this time. |
341 | | Import(ImportPath<'a>, TypeComponentInstanceIndex), |
342 | | |
343 | | /// A concrete map of values. |
344 | | /// |
345 | | /// This is used for both instantiated components as well as "synthetic" |
346 | | /// components. This variant can be used for both because both are |
347 | | /// represented by simply a bag of items within the entire component |
348 | | /// instantiation process. |
349 | | // |
350 | | // FIXME: same as the issue on `ComponentClosure` where this is cloned a lot |
351 | | // and may need `Rc`. |
352 | | Items( |
353 | | IndexMap<&'a str, (ComponentItemDef<'a>, wasmparser::ComponentExternName<'a>)>, |
354 | | TypeComponentInstanceIndex, |
355 | | ), |
356 | | } |
357 | | |
358 | | #[derive(Clone)] |
359 | | struct ComponentDef<'a> { |
360 | | index: StaticComponentIndex, |
361 | | closure: ComponentClosure<'a>, |
362 | | } |
363 | | |
364 | | impl<'a> Inliner<'a> { |
365 | | /// Symbolically instantiates a component using the type information and |
366 | | /// `frames` provided. |
367 | | /// |
368 | | /// The `types` provided is the type information for the entire component |
369 | | /// translation process. This is a distinct output artifact separate from |
370 | | /// the component metadata. |
371 | | /// |
372 | | /// The `frames` argument is storage to handle a "call stack" of components |
373 | | /// instantiating one another. The youngest frame (last element) of the |
374 | | /// frames list is a component that's currently having its initializers |
375 | | /// processed. The second element of each frame is a snapshot of the |
376 | | /// resource-related information just before the frame was translated. For |
377 | | /// more information on this snapshotting see the documentation on |
378 | | /// `ResourcesBuilder`. |
379 | 6.09k | fn run( |
380 | 6.09k | &mut self, |
381 | 6.09k | types: &mut ComponentTypesBuilder, |
382 | 6.09k | frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>, |
383 | 6.09k | ) -> Result<IndexMap<&'a str, (ComponentItemDef<'a>, wasmparser::ComponentExternName<'a>)>> |
384 | | { |
385 | | // This loop represents the execution of the instantiation of a |
386 | | // component. This is an iterative process which is finished once all |
387 | | // initializers are processed. Currently this is modeled as an infinite |
388 | | // loop which drives the top-most iterator of the `frames` stack |
389 | | // provided as an argument to this function. |
390 | | loop { |
391 | 281k | let (frame, _) = frames.last_mut().unwrap(); |
392 | 281k | types.resources_mut().set_current_instance(frame.instance); |
393 | 281k | match frame.initializers.next() { |
394 | | // Process the initializer and if it started the instantiation |
395 | | // of another component then we push that frame on the stack to |
396 | | // continue onwards. |
397 | 260k | Some(init) => match self.initializer(frames, types, init)? { |
398 | 15.5k | Some(new_frame) => { |
399 | 15.5k | frames.push((new_frame, types.resources_mut().clone())); |
400 | 15.5k | } |
401 | 244k | None => {} |
402 | | }, |
403 | | |
404 | | // If there are no more initializers for this frame then the |
405 | | // component it represents has finished instantiation. The |
406 | | // exports of the component are collected and then the entire |
407 | | // frame is discarded. The exports are then either pushed in the |
408 | | // parent frame, if any, as a new component instance or they're |
409 | | // returned from this function for the root set of exports. |
410 | | None => { |
411 | 21.6k | let exports = frame |
412 | 21.6k | .translation |
413 | 21.6k | .exports |
414 | 21.6k | .iter() |
415 | 33.1k | .map(|(name, (item, data))| Ok((*name, (frame.item(*item, types)?, *data)))) |
416 | 21.6k | .collect::<Result<_>>()?; |
417 | 21.6k | let instance_ty = frame.instance_ty; |
418 | 21.6k | let (_, snapshot) = frames.pop().unwrap(); |
419 | 21.6k | *types.resources_mut() = snapshot; |
420 | 21.6k | match frames.last_mut() { |
421 | 15.5k | Some((parent, _)) => { |
422 | 15.5k | parent.finish_instantiate(exports, instance_ty.unwrap(), types)?; |
423 | | } |
424 | 6.09k | None => break Ok(exports), |
425 | | } |
426 | | } |
427 | | } |
428 | | } |
429 | 6.09k | } |
430 | | |
431 | 260k | fn initializer( |
432 | 260k | &mut self, |
433 | 260k | frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>, |
434 | 260k | types: &mut ComponentTypesBuilder, |
435 | 260k | initializer: &'a LocalInitializer, |
436 | 260k | ) -> Result<Option<InlinerFrame<'a>>> { |
437 | | use LocalInitializer::*; |
438 | | |
439 | 260k | let (frame, _) = frames.last_mut().unwrap(); |
440 | 260k | match initializer { |
441 | | // When a component imports an item the actual definition of the |
442 | | // item is looked up here (not at runtime) via its name. The |
443 | | // arguments provided in our `InlinerFrame` describe how each |
444 | | // argument was defined, so we simply move it from there into the |
445 | | // correct index space. |
446 | | // |
447 | | // Note that for the root component this will add `*::Import` items |
448 | | // but for sub-components this will do resolution to connect what |
449 | | // was provided as an import at the instantiation-site to what was |
450 | | // needed during the component's instantiation. |
451 | 15.6k | Import(name, ty) => { |
452 | 15.6k | let arg = match frame.args.get(name.name) { |
453 | 15.5k | Some(arg) => arg, |
454 | | |
455 | | // Not all arguments need to be provided for instantiation, |
456 | | // namely the root component in Wasmtime doesn't require |
457 | | // structural type imports to be satisfied. These type |
458 | | // imports are relevant for bindings generators and such but |
459 | | // as a runtime there's not really a definition to fit in. |
460 | | // |
461 | | // If no argument was provided for `name` then it's asserted |
462 | | // that this is a type import and additionally it's not a |
463 | | // resource type import (which indeed must be provided). If |
464 | | // all that passes then this initializer is effectively |
465 | | // skipped. |
466 | | None => { |
467 | 30 | match ty { |
468 | | ComponentEntityType::Type { |
469 | | created: ComponentAnyTypeId::Resource(_), |
470 | | .. |
471 | 0 | } => unreachable!(), |
472 | 30 | ComponentEntityType::Type { .. } => {} |
473 | 0 | _ => unreachable!(), |
474 | | } |
475 | 30 | return Ok(None); |
476 | | } |
477 | | }; |
478 | | |
479 | | // Next resource types need to be handled. For example if a |
480 | | // resource is imported into this component then it needs to be |
481 | | // assigned a unique table to provide the isolation guarantees |
482 | | // of resources (this component's table is shared with no |
483 | | // others). Here `register_component_entity_type` will find |
484 | | // imported resources and then `lookup_resource` will find the |
485 | | // resource within `arg` as necessary to lookup the original |
486 | | // true definition of this resource. |
487 | | // |
488 | | // This is what enables tracking true resource origins |
489 | | // throughout component translation while simultaneously also |
490 | | // tracking unique tables for each resource in each component. |
491 | 15.5k | let mut path = Vec::new(); |
492 | 15.5k | let (resources, types) = types.resources_mut_and_types(); |
493 | 15.5k | resources.register_component_entity_type( |
494 | 15.5k | &frame.translation.types_ref(), |
495 | 15.5k | *ty, |
496 | 15.5k | &mut path, |
497 | 947 | &mut |path| arg.lookup_resource(path, types), |
498 | | ); |
499 | | |
500 | | // And now with all the type information out of the way the |
501 | | // `arg` definition is moved into its corresponding index space. |
502 | 15.5k | frame.push_item(arg.clone()); |
503 | | } |
504 | | |
505 | 0 | IntrinsicsImport => { |
506 | 0 | frame |
507 | 0 | .component_instances |
508 | 0 | .push(ComponentInstanceDef::Intrinsics); |
509 | 0 | } |
510 | | |
511 | | // Lowering a component function to a core wasm function is |
512 | | // generally what "triggers compilation". Here various metadata is |
513 | | // recorded and then the final component gets an initializer |
514 | | // recording the lowering. |
515 | | // |
516 | | // NB: at this time only lowered imported functions are supported. |
517 | | Lower { |
518 | 14.6k | func, |
519 | 14.6k | options, |
520 | 14.6k | lower_ty, |
521 | | } => { |
522 | 14.6k | let lower_ty = |
523 | 14.6k | types.convert_component_func_type(frame.translation.types_ref(), *lower_ty)?; |
524 | 14.6k | let options_lower = self.adapter_options(frames, types, options); |
525 | 14.6k | let (frame, _) = frames.last_mut().unwrap(); |
526 | 14.6k | let lower_core_type = options_lower.core_type; |
527 | 14.6k | let func = match &frame.component_funcs[*func] { |
528 | | // If this component function was originally a host import |
529 | | // then this is a lowered host function which needs a |
530 | | // trampoline to enter WebAssembly. That's recorded here |
531 | | // with all relevant information. |
532 | 264 | ComponentFuncDef::Import(path) => { |
533 | 264 | let import = self.runtime_import(path); |
534 | 264 | let options = self.canonical_options(options_lower); |
535 | 264 | let index = self.result.trampolines.push(( |
536 | 264 | lower_core_type, |
537 | 264 | dfg::Trampoline::LowerImport { |
538 | 264 | import, |
539 | 264 | options, |
540 | 264 | lower_ty, |
541 | 264 | }, |
542 | 264 | )); |
543 | 264 | dfg::CoreDef::Trampoline(index) |
544 | | } |
545 | | |
546 | | // Lowering a lifted function means that a "fused adapter" |
547 | | // was just identified. |
548 | | // |
549 | | // Metadata about this fused adapter is recorded in the |
550 | | // `Adapters` output of this compilation pass. Currently the |
551 | | // implementation of fused adapters is to generate a core |
552 | | // wasm module which is instantiated with relevant imports |
553 | | // and the exports are used as the fused adapters. At this |
554 | | // time we don't know when precisely the instance will be |
555 | | // created but we do know that the result of this will be an |
556 | | // export from a previously-created instance. |
557 | | // |
558 | | // To model this the result of this arm is a |
559 | | // `CoreDef::Export`. The actual indices listed within the |
560 | | // export are "fake indices" in the sense of they're not |
561 | | // resolved yet. This resolution will happen at a later |
562 | | // compilation phase. Any usages of the `CoreDef::Export` |
563 | | // here will be detected and rewritten to an actual runtime |
564 | | // instance created. |
565 | | // |
566 | | // The `instance` field of the `CoreExport` has a marker |
567 | | // which indicates that it's a fused adapter. The `item` is |
568 | | // a function where the function index corresponds to the |
569 | | // `adapter_idx` which contains the metadata about this |
570 | | // adapter being created. The metadata is used to learn |
571 | | // about the dependencies and when the adapter module can |
572 | | // be instantiated. |
573 | | ComponentFuncDef::Lifted { |
574 | 14.3k | ty: lift_ty, |
575 | 14.3k | func, |
576 | 14.3k | options: options_lift, |
577 | | } => { |
578 | 14.3k | let adapter_idx = self.result.adapters.push(Adapter { |
579 | 14.3k | lift_ty: *lift_ty, |
580 | 14.3k | lift_options: options_lift.clone(), |
581 | 14.3k | lower_ty, |
582 | 14.3k | lower_options: options_lower, |
583 | 14.3k | func: func.clone(), |
584 | 14.3k | }); |
585 | 14.3k | dfg::CoreDef::Adapter(adapter_idx) |
586 | | } |
587 | | |
588 | 0 | ComponentFuncDef::UnsafeIntrinsic(intrinsic) => { |
589 | 0 | dfg::CoreDef::UnsafeIntrinsic(options.core_type, *intrinsic) |
590 | | } |
591 | | }; |
592 | 14.6k | frame.funcs.push((lower_core_type, func)); |
593 | | } |
594 | | |
595 | | // Lifting a core wasm function is relatively easy for now in that |
596 | | // some metadata about the lifting is simply recorded. This'll get |
597 | | // plumbed through to exports or a fused adapter later on. |
598 | 22.2k | Lift(ty, func, options) => { |
599 | 22.2k | let ty = types.convert_component_func_type(frame.translation.types_ref(), *ty)?; |
600 | 22.2k | let options = self.adapter_options(frames, types, options); |
601 | 22.2k | let (frame, _) = frames.last_mut().unwrap(); |
602 | 22.2k | let func = frame.funcs[*func].1.clone(); |
603 | 22.2k | frame |
604 | 22.2k | .component_funcs |
605 | 22.2k | .push(ComponentFuncDef::Lifted { ty, func, options }); |
606 | | } |
607 | | |
608 | | // A new resource type is being introduced, so it's recorded as a |
609 | | // brand new resource in the final `resources` array. Additionally |
610 | | // for now resource introductions are considered side effects to |
611 | | // know when to register their destructors so that's recorded as |
612 | | // well. |
613 | | // |
614 | | // Note that this has the effect of when a component is instantiated |
615 | | // twice it will produce unique types for the resources from each |
616 | | // instantiation. That's the intended runtime semantics and |
617 | | // implementation here, however. |
618 | 1.03k | Resource(ty, rep, dtor) => { |
619 | 1.03k | let idx = self.result.resources.push(dfg::Resource { |
620 | 1.03k | rep: *rep, |
621 | 1.03k | dtor: dtor.map(|i| frame.funcs[i].1.clone()), |
622 | 1.03k | instance: frame.instance, |
623 | | }); |
624 | 1.03k | self.result |
625 | 1.03k | .side_effects |
626 | 1.03k | .push(dfg::SideEffect::Resource(idx)); |
627 | | |
628 | | // Register with type translation that all future references to |
629 | | // `ty` will refer to `idx`. |
630 | | // |
631 | | // Note that this registration information is lost when this |
632 | | // component finishes instantiation due to the snapshotting |
633 | | // behavior in the frame processing loop above. This is also |
634 | | // intended, though, since `ty` can't be referred to outside of |
635 | | // this component. |
636 | 1.03k | let idx = self.result.resource_index(idx); |
637 | 1.03k | types.resources_mut().register_resource(ty.resource(), idx); |
638 | | } |
639 | | |
640 | | // Resource-related intrinsics are generally all the same. |
641 | | // Wasmparser type information is converted to wasmtime type |
642 | | // information and then new entries for each intrinsic are recorded. |
643 | 870 | ResourceNew(id, ty) => { |
644 | 870 | let id = types.resource_id(id.resource()); |
645 | 870 | let index = self.result.trampolines.push(( |
646 | 870 | *ty, |
647 | 870 | dfg::Trampoline::ResourceNew { |
648 | 870 | instance: frame.instance, |
649 | 870 | ty: id, |
650 | 870 | }, |
651 | 870 | )); |
652 | 870 | frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index))); |
653 | 870 | } |
654 | 80 | ResourceRep(id, ty) => { |
655 | 80 | let id = types.resource_id(id.resource()); |
656 | 80 | let index = self.result.trampolines.push(( |
657 | 80 | *ty, |
658 | 80 | dfg::Trampoline::ResourceRep { |
659 | 80 | instance: frame.instance, |
660 | 80 | ty: id, |
661 | 80 | }, |
662 | 80 | )); |
663 | 80 | frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index))); |
664 | 80 | } |
665 | 943 | ResourceDrop(id, ty) => { |
666 | 943 | let id = types.resource_id(id.resource()); |
667 | 943 | let index = self.result.trampolines.push(( |
668 | 943 | *ty, |
669 | 943 | dfg::Trampoline::ResourceDrop { |
670 | 943 | instance: frame.instance, |
671 | 943 | ty: id, |
672 | 943 | }, |
673 | 943 | )); |
674 | 943 | frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index))); |
675 | 943 | } |
676 | 86 | BackpressureInc { func } => { |
677 | 86 | let index = self.result.trampolines.push(( |
678 | 86 | *func, |
679 | 86 | dfg::Trampoline::BackpressureInc { |
680 | 86 | instance: frame.instance, |
681 | 86 | }, |
682 | 86 | )); |
683 | 86 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
684 | 86 | } |
685 | 73 | BackpressureDec { func } => { |
686 | 73 | let index = self.result.trampolines.push(( |
687 | 73 | *func, |
688 | 73 | dfg::Trampoline::BackpressureDec { |
689 | 73 | instance: frame.instance, |
690 | 73 | }, |
691 | 73 | )); |
692 | 73 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
693 | 73 | } |
694 | 7.09k | TaskReturn { result, options } => { |
695 | 7.09k | let results = result |
696 | 7.09k | .iter() |
697 | 7.09k | .map(|ty| types.valtype(frame.translation.types_ref(), ty)) |
698 | 7.09k | .collect::<Result<_>>()?; |
699 | 7.09k | let results = types.new_tuple_type(results); |
700 | 7.09k | let func = options.core_type; |
701 | 7.09k | let options = self.adapter_options(frames, types, options); |
702 | 7.09k | let (frame, _) = frames.last_mut().unwrap(); |
703 | 7.09k | let options = self.canonical_options(options); |
704 | 7.09k | let index = self.result.trampolines.push(( |
705 | 7.09k | func, |
706 | 7.09k | dfg::Trampoline::TaskReturn { |
707 | 7.09k | instance: frame.instance, |
708 | 7.09k | results, |
709 | 7.09k | options, |
710 | 7.09k | }, |
711 | 7.09k | )); |
712 | 7.09k | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
713 | | } |
714 | 108 | TaskCancel { func } => { |
715 | 108 | let index = self.result.trampolines.push(( |
716 | 108 | *func, |
717 | 108 | dfg::Trampoline::TaskCancel { |
718 | 108 | instance: frame.instance, |
719 | 108 | }, |
720 | 108 | )); |
721 | 108 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
722 | 108 | } |
723 | 2.46k | WaitableSetNew { func } => { |
724 | 2.46k | let index = self.result.trampolines.push(( |
725 | 2.46k | *func, |
726 | 2.46k | dfg::Trampoline::WaitableSetNew { |
727 | 2.46k | instance: frame.instance, |
728 | 2.46k | }, |
729 | 2.46k | )); |
730 | 2.46k | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
731 | 2.46k | } |
732 | 421 | WaitableSetWait { options } => { |
733 | 421 | let func = options.core_type; |
734 | 421 | let options = self.adapter_options(frames, types, options); |
735 | 421 | let (frame, _) = frames.last_mut().unwrap(); |
736 | 421 | let options = self.canonical_options(options); |
737 | 421 | let index = self.result.trampolines.push(( |
738 | 421 | func, |
739 | 421 | dfg::Trampoline::WaitableSetWait { |
740 | 421 | instance: frame.instance, |
741 | 421 | options, |
742 | 421 | }, |
743 | 421 | )); |
744 | 421 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
745 | 421 | } |
746 | 84 | WaitableSetPoll { options } => { |
747 | 84 | let func = options.core_type; |
748 | 84 | let options = self.adapter_options(frames, types, options); |
749 | 84 | let (frame, _) = frames.last_mut().unwrap(); |
750 | 84 | let options = self.canonical_options(options); |
751 | 84 | let index = self.result.trampolines.push(( |
752 | 84 | func, |
753 | 84 | dfg::Trampoline::WaitableSetPoll { |
754 | 84 | instance: frame.instance, |
755 | 84 | options, |
756 | 84 | }, |
757 | 84 | )); |
758 | 84 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
759 | 84 | } |
760 | 69 | WaitableSetDrop { func } => { |
761 | 69 | let index = self.result.trampolines.push(( |
762 | 69 | *func, |
763 | 69 | dfg::Trampoline::WaitableSetDrop { |
764 | 69 | instance: frame.instance, |
765 | 69 | }, |
766 | 69 | )); |
767 | 69 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
768 | 69 | } |
769 | 2.33k | WaitableJoin { func } => { |
770 | 2.33k | let index = self.result.trampolines.push(( |
771 | 2.33k | *func, |
772 | 2.33k | dfg::Trampoline::WaitableJoin { |
773 | 2.33k | instance: frame.instance, |
774 | 2.33k | }, |
775 | 2.33k | )); |
776 | 2.33k | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
777 | 2.33k | } |
778 | 2.09k | SubtaskDrop { func } => { |
779 | 2.09k | let index = self.result.trampolines.push(( |
780 | 2.09k | *func, |
781 | 2.09k | dfg::Trampoline::SubtaskDrop { |
782 | 2.09k | instance: frame.instance, |
783 | 2.09k | }, |
784 | 2.09k | )); |
785 | 2.09k | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
786 | 2.09k | } |
787 | 187 | SubtaskCancel { func, async_ } => { |
788 | 187 | let index = self.result.trampolines.push(( |
789 | 187 | *func, |
790 | 187 | dfg::Trampoline::SubtaskCancel { |
791 | 187 | instance: frame.instance, |
792 | 187 | async_: *async_, |
793 | 187 | }, |
794 | 187 | )); |
795 | 187 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
796 | 187 | } |
797 | 245 | StreamNew { ty, func } => { |
798 | 245 | let InterfaceType::Stream(ty) = |
799 | 245 | types.defined_type(frame.translation.types_ref(), *ty)? |
800 | | else { |
801 | 0 | unreachable!() |
802 | | }; |
803 | 245 | let index = self.result.trampolines.push(( |
804 | 245 | *func, |
805 | 245 | dfg::Trampoline::StreamNew { |
806 | 245 | instance: frame.instance, |
807 | 245 | ty, |
808 | 245 | }, |
809 | 245 | )); |
810 | 245 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
811 | | } |
812 | 211 | StreamRead { ty, options } => { |
813 | 211 | let InterfaceType::Stream(ty) = |
814 | 211 | types.defined_type(frame.translation.types_ref(), *ty)? |
815 | | else { |
816 | 0 | unreachable!() |
817 | | }; |
818 | 211 | let func = options.core_type; |
819 | 211 | let options = self.adapter_options(frames, types, options); |
820 | 211 | let (frame, _) = frames.last_mut().unwrap(); |
821 | 211 | let options = self.canonical_options(options); |
822 | 211 | let index = self.result.trampolines.push(( |
823 | 211 | func, |
824 | 211 | dfg::Trampoline::StreamRead { |
825 | 211 | instance: frame.instance, |
826 | 211 | ty, |
827 | 211 | options, |
828 | 211 | }, |
829 | 211 | )); |
830 | 211 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
831 | | } |
832 | 235 | StreamWrite { ty, options } => { |
833 | 235 | let InterfaceType::Stream(ty) = |
834 | 235 | types.defined_type(frame.translation.types_ref(), *ty)? |
835 | | else { |
836 | 0 | unreachable!() |
837 | | }; |
838 | 235 | let func = options.core_type; |
839 | 235 | let options = self.adapter_options(frames, types, options); |
840 | 235 | let (frame, _) = frames.last_mut().unwrap(); |
841 | 235 | let options = self.canonical_options(options); |
842 | 235 | let index = self.result.trampolines.push(( |
843 | 235 | func, |
844 | 235 | dfg::Trampoline::StreamWrite { |
845 | 235 | instance: frame.instance, |
846 | 235 | ty, |
847 | 235 | options, |
848 | 235 | }, |
849 | 235 | )); |
850 | 235 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
851 | | } |
852 | 57 | StreamCancelRead { ty, func, async_ } => { |
853 | 57 | let InterfaceType::Stream(ty) = |
854 | 57 | types.defined_type(frame.translation.types_ref(), *ty)? |
855 | | else { |
856 | 0 | unreachable!() |
857 | | }; |
858 | 57 | let index = self.result.trampolines.push(( |
859 | 57 | *func, |
860 | 57 | dfg::Trampoline::StreamCancelRead { |
861 | 57 | instance: frame.instance, |
862 | 57 | ty, |
863 | 57 | async_: *async_, |
864 | 57 | }, |
865 | 57 | )); |
866 | 57 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
867 | | } |
868 | 64 | StreamCancelWrite { ty, func, async_ } => { |
869 | 64 | let InterfaceType::Stream(ty) = |
870 | 64 | types.defined_type(frame.translation.types_ref(), *ty)? |
871 | | else { |
872 | 0 | unreachable!() |
873 | | }; |
874 | 64 | let index = self.result.trampolines.push(( |
875 | 64 | *func, |
876 | 64 | dfg::Trampoline::StreamCancelWrite { |
877 | 64 | instance: frame.instance, |
878 | 64 | ty, |
879 | 64 | async_: *async_, |
880 | 64 | }, |
881 | 64 | )); |
882 | 64 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
883 | | } |
884 | 132 | StreamDropReadable { ty, func } => { |
885 | 132 | let InterfaceType::Stream(ty) = |
886 | 132 | types.defined_type(frame.translation.types_ref(), *ty)? |
887 | | else { |
888 | 0 | unreachable!() |
889 | | }; |
890 | 132 | let index = self.result.trampolines.push(( |
891 | 132 | *func, |
892 | 132 | dfg::Trampoline::StreamDropReadable { |
893 | 132 | instance: frame.instance, |
894 | 132 | ty, |
895 | 132 | }, |
896 | 132 | )); |
897 | 132 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
898 | | } |
899 | 163 | StreamDropWritable { ty, func } => { |
900 | 163 | let InterfaceType::Stream(ty) = |
901 | 163 | types.defined_type(frame.translation.types_ref(), *ty)? |
902 | | else { |
903 | 0 | unreachable!() |
904 | | }; |
905 | 163 | let index = self.result.trampolines.push(( |
906 | 163 | *func, |
907 | 163 | dfg::Trampoline::StreamDropWritable { |
908 | 163 | instance: frame.instance, |
909 | 163 | ty, |
910 | 163 | }, |
911 | 163 | )); |
912 | 163 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
913 | | } |
914 | 296 | FutureNew { ty, func } => { |
915 | 296 | let InterfaceType::Future(ty) = |
916 | 296 | types.defined_type(frame.translation.types_ref(), *ty)? |
917 | | else { |
918 | 0 | unreachable!() |
919 | | }; |
920 | 296 | let index = self.result.trampolines.push(( |
921 | 296 | *func, |
922 | 296 | dfg::Trampoline::FutureNew { |
923 | 296 | instance: frame.instance, |
924 | 296 | ty, |
925 | 296 | }, |
926 | 296 | )); |
927 | 296 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
928 | | } |
929 | 258 | FutureRead { ty, options } => { |
930 | 258 | let InterfaceType::Future(ty) = |
931 | 258 | types.defined_type(frame.translation.types_ref(), *ty)? |
932 | | else { |
933 | 0 | unreachable!() |
934 | | }; |
935 | 258 | let func = options.core_type; |
936 | 258 | let options = self.adapter_options(frames, types, options); |
937 | 258 | let (frame, _) = frames.last_mut().unwrap(); |
938 | 258 | let options = self.canonical_options(options); |
939 | 258 | let index = self.result.trampolines.push(( |
940 | 258 | func, |
941 | 258 | dfg::Trampoline::FutureRead { |
942 | 258 | instance: frame.instance, |
943 | 258 | ty, |
944 | 258 | options, |
945 | 258 | }, |
946 | 258 | )); |
947 | 258 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
948 | | } |
949 | 224 | FutureWrite { ty, options } => { |
950 | 224 | let InterfaceType::Future(ty) = |
951 | 224 | types.defined_type(frame.translation.types_ref(), *ty)? |
952 | | else { |
953 | 0 | unreachable!() |
954 | | }; |
955 | 224 | let func = options.core_type; |
956 | 224 | let options = self.adapter_options(frames, types, options); |
957 | 224 | let (frame, _) = frames.last_mut().unwrap(); |
958 | 224 | let options = self.canonical_options(options); |
959 | 224 | let index = self.result.trampolines.push(( |
960 | 224 | func, |
961 | 224 | dfg::Trampoline::FutureWrite { |
962 | 224 | instance: frame.instance, |
963 | 224 | ty, |
964 | 224 | options, |
965 | 224 | }, |
966 | 224 | )); |
967 | 224 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
968 | | } |
969 | 33 | FutureCancelRead { ty, func, async_ } => { |
970 | 33 | let InterfaceType::Future(ty) = |
971 | 33 | types.defined_type(frame.translation.types_ref(), *ty)? |
972 | | else { |
973 | 0 | unreachable!() |
974 | | }; |
975 | 33 | let index = self.result.trampolines.push(( |
976 | 33 | *func, |
977 | 33 | dfg::Trampoline::FutureCancelRead { |
978 | 33 | instance: frame.instance, |
979 | 33 | ty, |
980 | 33 | async_: *async_, |
981 | 33 | }, |
982 | 33 | )); |
983 | 33 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
984 | | } |
985 | 37 | FutureCancelWrite { ty, func, async_ } => { |
986 | 37 | let InterfaceType::Future(ty) = |
987 | 37 | types.defined_type(frame.translation.types_ref(), *ty)? |
988 | | else { |
989 | 0 | unreachable!() |
990 | | }; |
991 | 37 | let index = self.result.trampolines.push(( |
992 | 37 | *func, |
993 | 37 | dfg::Trampoline::FutureCancelWrite { |
994 | 37 | instance: frame.instance, |
995 | 37 | ty, |
996 | 37 | async_: *async_, |
997 | 37 | }, |
998 | 37 | )); |
999 | 37 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1000 | | } |
1001 | 76 | FutureDropReadable { ty, func } => { |
1002 | 76 | let InterfaceType::Future(ty) = |
1003 | 76 | types.defined_type(frame.translation.types_ref(), *ty)? |
1004 | | else { |
1005 | 0 | unreachable!() |
1006 | | }; |
1007 | 76 | let index = self.result.trampolines.push(( |
1008 | 76 | *func, |
1009 | 76 | dfg::Trampoline::FutureDropReadable { |
1010 | 76 | instance: frame.instance, |
1011 | 76 | ty, |
1012 | 76 | }, |
1013 | 76 | )); |
1014 | 76 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1015 | | } |
1016 | 67 | FutureDropWritable { ty, func } => { |
1017 | 67 | let InterfaceType::Future(ty) = |
1018 | 67 | types.defined_type(frame.translation.types_ref(), *ty)? |
1019 | | else { |
1020 | 0 | unreachable!() |
1021 | | }; |
1022 | 67 | let index = self.result.trampolines.push(( |
1023 | 67 | *func, |
1024 | 67 | dfg::Trampoline::FutureDropWritable { |
1025 | 67 | instance: frame.instance, |
1026 | 67 | ty, |
1027 | 67 | }, |
1028 | 67 | )); |
1029 | 67 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1030 | | } |
1031 | 10 | ErrorContextNew { options } => { |
1032 | 10 | let ty = types.error_context_table_type()?; |
1033 | 10 | let func = options.core_type; |
1034 | 10 | let options = self.adapter_options(frames, types, options); |
1035 | 10 | let (frame, _) = frames.last_mut().unwrap(); |
1036 | 10 | let options = self.canonical_options(options); |
1037 | 10 | let index = self.result.trampolines.push(( |
1038 | 10 | func, |
1039 | 10 | dfg::Trampoline::ErrorContextNew { |
1040 | 10 | instance: frame.instance, |
1041 | 10 | ty, |
1042 | 10 | options, |
1043 | 10 | }, |
1044 | 10 | )); |
1045 | 10 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
1046 | | } |
1047 | 10 | ErrorContextDebugMessage { options } => { |
1048 | 10 | let ty = types.error_context_table_type()?; |
1049 | 10 | let func = options.core_type; |
1050 | 10 | let options = self.adapter_options(frames, types, options); |
1051 | 10 | let (frame, _) = frames.last_mut().unwrap(); |
1052 | 10 | let options = self.canonical_options(options); |
1053 | 10 | let index = self.result.trampolines.push(( |
1054 | 10 | func, |
1055 | 10 | dfg::Trampoline::ErrorContextDebugMessage { |
1056 | 10 | instance: frame.instance, |
1057 | 10 | ty, |
1058 | 10 | options, |
1059 | 10 | }, |
1060 | 10 | )); |
1061 | 10 | frame.funcs.push((func, dfg::CoreDef::Trampoline(index))); |
1062 | | } |
1063 | 10 | ErrorContextDrop { func } => { |
1064 | 10 | let ty = types.error_context_table_type()?; |
1065 | 10 | let index = self.result.trampolines.push(( |
1066 | 10 | *func, |
1067 | 10 | dfg::Trampoline::ErrorContextDrop { |
1068 | 10 | instance: frame.instance, |
1069 | 10 | ty, |
1070 | 10 | }, |
1071 | 10 | )); |
1072 | 10 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1073 | | } |
1074 | 2.13k | ContextGet { func, i } => { |
1075 | 2.13k | let intrinsic = match i { |
1076 | 2.12k | 0 => UnsafeIntrinsic::ContextGetI32_0, |
1077 | 16 | 1 => UnsafeIntrinsic::ContextGetI32_1, |
1078 | 0 | _ => unreachable!(), |
1079 | | }; |
1080 | 2.13k | frame |
1081 | 2.13k | .funcs |
1082 | 2.13k | .push((*func, dfg::CoreDef::UnsafeIntrinsic(*func, intrinsic))); |
1083 | | } |
1084 | 2.16k | ContextSet { func, i } => { |
1085 | 2.16k | let intrinsic = match i { |
1086 | 2.15k | 0 => UnsafeIntrinsic::ContextSetI32_0, |
1087 | 16 | 1 => UnsafeIntrinsic::ContextSetI32_1, |
1088 | 0 | _ => unreachable!(), |
1089 | | }; |
1090 | 2.16k | frame |
1091 | 2.16k | .funcs |
1092 | 2.16k | .push((*func, dfg::CoreDef::UnsafeIntrinsic(*func, intrinsic))); |
1093 | | } |
1094 | 107 | ThreadIndex { func } => { |
1095 | 107 | let index = self.result.trampolines.push(( |
1096 | 107 | *func, |
1097 | 107 | dfg::Trampoline::ThreadIndex { |
1098 | 107 | instance: frame.instance, |
1099 | 107 | }, |
1100 | 107 | )); |
1101 | 107 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1102 | 107 | } |
1103 | | ThreadNewIndirect { |
1104 | 130 | func, |
1105 | 130 | start_func_table_index, |
1106 | 130 | start_func_ty, |
1107 | | } => { |
1108 | 130 | let table_export = frame.tables[*start_func_table_index] |
1109 | 130 | .clone() |
1110 | 130 | .map_index(|i| match i { |
1111 | 130 | EntityIndex::Table(i) => i, |
1112 | 0 | _ => unreachable!(), |
1113 | 130 | }); |
1114 | | |
1115 | 130 | let table_id = self.result.tables.push(table_export); |
1116 | 130 | let index = self.result.trampolines.push(( |
1117 | 130 | *func, |
1118 | 130 | dfg::Trampoline::ThreadNewIndirect { |
1119 | 130 | instance: frame.instance, |
1120 | 130 | start_func_ty_idx: *start_func_ty, |
1121 | 130 | start_func_table_id: table_id, |
1122 | 130 | }, |
1123 | 130 | )); |
1124 | 130 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1125 | | } |
1126 | 137 | ThreadResumeLater { func } => { |
1127 | 137 | let index = self.result.trampolines.push(( |
1128 | 137 | *func, |
1129 | 137 | dfg::Trampoline::ThreadResumeLater { |
1130 | 137 | instance: frame.instance, |
1131 | 137 | }, |
1132 | 137 | )); |
1133 | 137 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1134 | 137 | } |
1135 | 73 | ThreadSuspend { func } => { |
1136 | 73 | let index = self.result.trampolines.push(( |
1137 | 73 | *func, |
1138 | 73 | dfg::Trampoline::ThreadSuspend { |
1139 | 73 | instance: frame.instance, |
1140 | 73 | }, |
1141 | 73 | )); |
1142 | 73 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1143 | 73 | } |
1144 | 152 | ThreadYield { func } => { |
1145 | 152 | let index = self.result.trampolines.push(( |
1146 | 152 | *func, |
1147 | 152 | dfg::Trampoline::ThreadYield { |
1148 | 152 | instance: frame.instance, |
1149 | 152 | }, |
1150 | 152 | )); |
1151 | 152 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1152 | 152 | } |
1153 | 52 | ThreadSuspendThenResume { func } => { |
1154 | 52 | let index = self.result.trampolines.push(( |
1155 | 52 | *func, |
1156 | 52 | dfg::Trampoline::ThreadSuspendThenResume { |
1157 | 52 | instance: frame.instance, |
1158 | 52 | }, |
1159 | 52 | )); |
1160 | 52 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1161 | 52 | } |
1162 | 66 | ThreadYieldThenResume { func } => { |
1163 | 66 | let index = self.result.trampolines.push(( |
1164 | 66 | *func, |
1165 | 66 | dfg::Trampoline::ThreadYieldThenResume { |
1166 | 66 | instance: frame.instance, |
1167 | 66 | }, |
1168 | 66 | )); |
1169 | 66 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1170 | 66 | } |
1171 | 53 | ThreadSuspendThenPromote { func } => { |
1172 | 53 | let index = self.result.trampolines.push(( |
1173 | 53 | *func, |
1174 | 53 | dfg::Trampoline::ThreadSuspendThenPromote { |
1175 | 53 | instance: frame.instance, |
1176 | 53 | }, |
1177 | 53 | )); |
1178 | 53 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1179 | 53 | } |
1180 | 105 | ThreadYieldThenPromote { func } => { |
1181 | 105 | let index = self.result.trampolines.push(( |
1182 | 105 | *func, |
1183 | 105 | dfg::Trampoline::ThreadYieldThenPromote { |
1184 | 105 | instance: frame.instance, |
1185 | 105 | }, |
1186 | 105 | )); |
1187 | 105 | frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); |
1188 | 105 | } |
1189 | 20.9k | ModuleStatic(idx, ty) => { |
1190 | 20.9k | frame.modules.push(ModuleDef::Static(*idx, *ty)); |
1191 | 20.9k | } |
1192 | | |
1193 | | // Instantiation of a module is one of the meatier initializers that |
1194 | | // we'll generate. The main magic here is that for a statically |
1195 | | // known module we can order the imports as a list to exactly what |
1196 | | // the static module needs to be instantiated. For imported modules, |
1197 | | // however, the runtime string resolution must happen at runtime so |
1198 | | // that is deferred here by organizing the arguments as a two-layer |
1199 | | // `IndexMap` of what we're providing. |
1200 | | // |
1201 | | // In both cases though a new `RuntimeInstanceIndex` is allocated |
1202 | | // and an initializer is recorded to indicate that it's being |
1203 | | // instantiated. |
1204 | 21.7k | ModuleInstantiate(module, args) => { |
1205 | 21.7k | let (instance_module, init) = match &frame.modules[*module] { |
1206 | 21.7k | ModuleDef::Static(idx, _ty) => { |
1207 | 21.7k | let mut defs = Vec::new(); |
1208 | 43.9k | for (module, name, _ty) in self.nested_modules[*idx].module.imports() { |
1209 | 43.9k | let instance = args[module]; |
1210 | 43.9k | defs.push( |
1211 | 43.9k | self.core_def_of_module_instance_export(frame, instance, name), |
1212 | 43.9k | ); |
1213 | 43.9k | } |
1214 | 21.7k | ( |
1215 | 21.7k | InstanceModule::Static(*idx), |
1216 | 21.7k | dfg::Instance::Static(*idx, defs.into()), |
1217 | 21.7k | ) |
1218 | | } |
1219 | 33 | ModuleDef::Import(path, ty) => { |
1220 | 33 | let mut defs = IndexMap::new(); |
1221 | 33 | for ((module, name), _) in types[*ty].imports.iter() { |
1222 | 21 | let instance = args[module.as_str()]; |
1223 | 21 | let def = |
1224 | 21 | self.core_def_of_module_instance_export(frame, instance, name); |
1225 | 21 | defs.entry(module.to_string()) |
1226 | 21 | .or_insert(IndexMap::new()) |
1227 | 21 | .insert(name.to_string(), def); |
1228 | 21 | } |
1229 | 33 | let index = self.runtime_import(path); |
1230 | 33 | ( |
1231 | 33 | InstanceModule::Import(*ty), |
1232 | 33 | dfg::Instance::Import(index, defs), |
1233 | 33 | ) |
1234 | | } |
1235 | | }; |
1236 | | |
1237 | 21.7k | let instance = self.result.instances.push(init); |
1238 | 21.7k | let instance2 = self.runtime_instances.push(instance_module); |
1239 | 21.7k | assert_eq!(instance, instance2); |
1240 | | |
1241 | 21.7k | self.result |
1242 | 21.7k | .side_effects |
1243 | 21.7k | .push(dfg::SideEffect::Instance(instance, frame.instance)); |
1244 | | |
1245 | 21.7k | frame |
1246 | 21.7k | .module_instances |
1247 | 21.7k | .push(ModuleInstanceDef::Instantiated(instance, *module)); |
1248 | | } |
1249 | | |
1250 | 12.5k | ModuleSynthetic(map) => { |
1251 | 12.5k | frame |
1252 | 12.5k | .module_instances |
1253 | 12.5k | .push(ModuleInstanceDef::Synthetic(map)); |
1254 | 12.5k | } |
1255 | | |
1256 | | // This is one of the stages of the "magic" of implementing outer |
1257 | | // aliases to components and modules. For more information on this |
1258 | | // see the documentation on `LexicalScope`. This stage of the |
1259 | | // implementation of outer aliases is where the `ClosedOverVars` is |
1260 | | // transformed into a `ComponentClosure` state using the current |
1261 | | // `InlinerFrame`'s state. This will capture the "runtime" state of |
1262 | | // outer components and upvars and such naturally as part of the |
1263 | | // inlining process. |
1264 | 9.95k | ComponentStatic(index, vars) => { |
1265 | 9.95k | frame.components.push(ComponentDef { |
1266 | 9.95k | index: *index, |
1267 | | closure: ComponentClosure { |
1268 | 9.95k | modules: vars |
1269 | 9.95k | .modules |
1270 | 9.95k | .iter() |
1271 | 9.95k | .map(|(_, m)| frame.closed_over_module(m)) |
1272 | 9.95k | .collect(), |
1273 | 9.95k | components: vars |
1274 | 9.95k | .components |
1275 | 9.95k | .iter() |
1276 | 9.95k | .map(|(_, m)| frame.closed_over_component(m)) |
1277 | 9.95k | .collect(), |
1278 | | }, |
1279 | | }); |
1280 | | } |
1281 | | |
1282 | | // Like module instantiation is this is a "meaty" part, and don't be |
1283 | | // fooled by the relative simplicity of this case. This is |
1284 | | // implemented primarily by the `Inliner` structure and the design |
1285 | | // of this entire module, so the "easy" step here is to simply |
1286 | | // create a new inliner frame and return it to get pushed onto the |
1287 | | // stack. |
1288 | 15.5k | ComponentInstantiate(component, args, ty) => { |
1289 | 15.5k | let component: &ComponentDef<'a> = &frame.components[*component]; |
1290 | 15.5k | let index = RuntimeComponentInstanceIndex::from_u32( |
1291 | 15.5k | self.result.num_runtime_component_instances, |
1292 | | ); |
1293 | 15.5k | self.result.num_runtime_component_instances += 1; |
1294 | 15.5k | let frame = InlinerFrame::new( |
1295 | 15.5k | index, |
1296 | 15.5k | &self.nested_components[component.index], |
1297 | 15.5k | component.closure.clone(), |
1298 | 15.5k | args.iter() |
1299 | 15.5k | .map(|(name, item)| Ok((*name, frame.item(*item, types)?))) |
1300 | 15.5k | .collect::<Result<_>>()?, |
1301 | 15.5k | Some(*ty), |
1302 | | ); |
1303 | 15.5k | return Ok(Some(frame)); |
1304 | | } |
1305 | | |
1306 | 241 | ComponentSynthetic(map, ty) => { |
1307 | 241 | let items = map |
1308 | 241 | .iter() |
1309 | 242 | .map(|(name, (index, data))| Ok((*name, (frame.item(*index, types)?, *data)))) |
1310 | 241 | .collect::<Result<_>>()?; |
1311 | 241 | let types_ref = frame.translation.types_ref(); |
1312 | 241 | let ty = types.convert_instance(types_ref, *ty)?; |
1313 | 241 | frame |
1314 | 241 | .component_instances |
1315 | 241 | .push(ComponentInstanceDef::Items(items, ty)); |
1316 | | } |
1317 | | |
1318 | | // Core wasm aliases, this and the cases below, are creating |
1319 | | // `CoreExport` items primarily to insert into the index space so we |
1320 | | // can create a unique identifier pointing to each core wasm export |
1321 | | // with the instance and relevant index/name as necessary. |
1322 | 32.0k | AliasExportFunc(instance, name) => { |
1323 | 32.0k | let (ty, def) = match &frame.module_instances[*instance] { |
1324 | 32.0k | ModuleInstanceDef::Instantiated(instance, module) => { |
1325 | 32.0k | let (ty, item) = match &frame.modules[*module] { |
1326 | 32.0k | ModuleDef::Static(idx, _ty) => { |
1327 | 32.0k | let name = self.nested_modules[*idx] |
1328 | 32.0k | .module |
1329 | 32.0k | .strings |
1330 | 32.0k | .get_atom(name) |
1331 | 32.0k | .unwrap(); |
1332 | 32.0k | let entity = self.nested_modules[*idx].module.exports[&name]; |
1333 | 32.0k | let ty = match entity { |
1334 | 32.0k | EntityIndex::Function(f) => { |
1335 | 32.0k | self.nested_modules[*idx].module.functions[f] |
1336 | 32.0k | .signature |
1337 | 32.0k | .unwrap_module_type_index() |
1338 | | } |
1339 | 0 | _ => unreachable!(), |
1340 | | }; |
1341 | 32.0k | (ty, ExportItem::Index(entity)) |
1342 | | } |
1343 | 0 | ModuleDef::Import(_path, module_ty) => { |
1344 | 0 | let module_ty = &types.component_types()[*module_ty]; |
1345 | 0 | let entity_ty = &module_ty.exports[&**name]; |
1346 | 0 | let ty = entity_ty.unwrap_func().unwrap_module_type_index(); |
1347 | 0 | (ty, ExportItem::Name((*name).to_string())) |
1348 | | } |
1349 | | }; |
1350 | 32.0k | let def = dfg::CoreExport { |
1351 | 32.0k | instance: *instance, |
1352 | 32.0k | item, |
1353 | 32.0k | } |
1354 | 32.0k | .into(); |
1355 | 32.0k | (ty, def) |
1356 | | } |
1357 | 9 | ModuleInstanceDef::Synthetic(instance) => match instance[*name] { |
1358 | 9 | EntityIndex::Function(i) => frame.funcs[i].clone(), |
1359 | 0 | _ => unreachable!(), |
1360 | | }, |
1361 | | }; |
1362 | 32.0k | frame.funcs.push((ty, def)); |
1363 | | } |
1364 | | |
1365 | 287 | AliasExportTable(instance, name) => { |
1366 | 287 | frame.tables.push( |
1367 | 287 | match self.core_def_of_module_instance_export(frame, *instance, *name) { |
1368 | 287 | dfg::CoreDef::Export(e) => e, |
1369 | 0 | _ => unreachable!(), |
1370 | | }, |
1371 | | ); |
1372 | | } |
1373 | | |
1374 | 158 | AliasExportGlobal(instance, name) => { |
1375 | 158 | frame.globals.push( |
1376 | 158 | match self.core_def_of_module_instance_export(frame, *instance, *name) { |
1377 | 158 | dfg::CoreDef::Export(e) => e, |
1378 | 0 | _ => unreachable!(), |
1379 | | }, |
1380 | | ); |
1381 | | } |
1382 | | |
1383 | 10.4k | AliasExportMemory(instance, name) => { |
1384 | 10.4k | frame.memories.push( |
1385 | 10.4k | match self.core_def_of_module_instance_export(frame, *instance, *name) { |
1386 | 10.4k | dfg::CoreDef::Export(e) => e, |
1387 | 0 | _ => unreachable!(), |
1388 | | }, |
1389 | | ); |
1390 | | } |
1391 | | |
1392 | 54 | AliasExportTag(instance, name) => { |
1393 | 54 | frame.tags.push( |
1394 | 54 | match self.core_def_of_module_instance_export(frame, *instance, *name) { |
1395 | 54 | dfg::CoreDef::Export(e) => e, |
1396 | 0 | _ => unreachable!(), |
1397 | | }, |
1398 | | ); |
1399 | | } |
1400 | | |
1401 | 24.9k | AliasComponentExport(instance, name) => { |
1402 | 24.9k | match &frame.component_instances[*instance] { |
1403 | | ComponentInstanceDef::Intrinsics => { |
1404 | 0 | frame.push_item(ComponentItemDef::Func(ComponentFuncDef::UnsafeIntrinsic( |
1405 | 0 | UnsafeIntrinsic::from_str(name)?, |
1406 | | ))); |
1407 | | } |
1408 | | |
1409 | | // Aliasing an export from an imported instance means that |
1410 | | // we're extending the `ImportPath` by one name, represented |
1411 | | // with the clone + push here. Afterwards an appropriate |
1412 | | // item is then pushed in the relevant index space. |
1413 | 431 | ComponentInstanceDef::Import(path, ty) => { |
1414 | 431 | let path = path.push(*name); |
1415 | 431 | let def = |
1416 | 431 | ComponentItemDef::from_import(path, types[*ty].exports[*name].ty)?; |
1417 | 431 | frame.push_item(def); |
1418 | | } |
1419 | | |
1420 | | // Given a component instance which was either created |
1421 | | // through instantiation of a component or through a |
1422 | | // synthetic renaming of items we just schlep around the |
1423 | | // definitions of various items here. |
1424 | 24.4k | ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].0.clone()), |
1425 | | } |
1426 | | } |
1427 | | |
1428 | | // For more information on these see `LexicalScope` but otherwise |
1429 | | // this is just taking a closed over variable and inserting the |
1430 | | // actual definition into the local index space since this |
1431 | | // represents an outer alias to a module/component |
1432 | 246 | AliasModule(idx) => { |
1433 | 246 | frame.modules.push(frame.closed_over_module(idx)); |
1434 | 246 | } |
1435 | 109 | AliasComponent(idx) => { |
1436 | 109 | frame.components.push(frame.closed_over_component(idx)); |
1437 | 109 | } |
1438 | | |
1439 | 33.1k | Export(item) => match item { |
1440 | 30.8k | ComponentItem::Func(i) => { |
1441 | 30.8k | frame |
1442 | 30.8k | .component_funcs |
1443 | 30.8k | .push(frame.component_funcs[*i].clone()); |
1444 | 30.8k | } |
1445 | 357 | ComponentItem::Module(i) => { |
1446 | 357 | frame.modules.push(frame.modules[*i].clone()); |
1447 | 357 | } |
1448 | 378 | ComponentItem::Component(i) => { |
1449 | 378 | frame.components.push(frame.components[*i].clone()); |
1450 | 378 | } |
1451 | 263 | ComponentItem::ComponentInstance(i) => { |
1452 | 263 | frame |
1453 | 263 | .component_instances |
1454 | 263 | .push(frame.component_instances[*i].clone()); |
1455 | 263 | } |
1456 | | |
1457 | | // Type index spaces aren't maintained during this inlining pass |
1458 | | // so ignore this. |
1459 | 1.23k | ComponentItem::Type(_) => {} |
1460 | | }, |
1461 | | } |
1462 | | |
1463 | 244k | Ok(None) |
1464 | 260k | } |
1465 | | |
1466 | | /// "Commits" a path of an import to an actual index which is something that |
1467 | | /// will be calculated at runtime. |
1468 | | /// |
1469 | | /// Note that the cost of calculating an item for a `RuntimeImportIndex` at |
1470 | | /// runtime is amortized with an `InstancePre` which represents "all the |
1471 | | /// runtime imports are lined up" and after that no more name resolution is |
1472 | | /// necessary. |
1473 | 648 | fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex { |
1474 | 648 | *self |
1475 | 648 | .import_path_interner |
1476 | 648 | .entry(path.clone()) |
1477 | 648 | .or_insert_with(|| { |
1478 | 632 | self.result.imports.push(( |
1479 | 632 | path.index, |
1480 | 632 | path.path.iter().map(|s| s.to_string()).collect(), |
1481 | | )) |
1482 | 632 | }) |
1483 | 648 | } |
1484 | | |
1485 | | /// Returns the `CoreDef`, the canonical definition for a core wasm item, |
1486 | | /// for the export `name` of `instance` within `frame`. |
1487 | 54.9k | fn core_def_of_module_instance_export( |
1488 | 54.9k | &self, |
1489 | 54.9k | frame: &InlinerFrame<'a>, |
1490 | 54.9k | instance: ModuleInstanceIndex, |
1491 | 54.9k | name: &'a str, |
1492 | 54.9k | ) -> dfg::CoreDef { |
1493 | 54.9k | match &frame.module_instances[instance] { |
1494 | | // Instantiations of a statically known module means that we can |
1495 | | // refer to the exported item by a precise index, skipping name |
1496 | | // lookups at runtime. |
1497 | | // |
1498 | | // Instantiations of an imported module, however, must do name |
1499 | | // lookups at runtime since we don't know the structure ahead of |
1500 | | // time here. |
1501 | 13.0k | ModuleInstanceDef::Instantiated(instance, module) => { |
1502 | 13.0k | let item = match frame.modules[*module] { |
1503 | 13.0k | ModuleDef::Static(idx, _ty) => { |
1504 | 13.0k | let name = self.nested_modules[idx] |
1505 | 13.0k | .module |
1506 | 13.0k | .strings |
1507 | 13.0k | .get_atom(name) |
1508 | 13.0k | .unwrap(); |
1509 | 13.0k | let entity = self.nested_modules[idx].module.exports[&name]; |
1510 | 13.0k | ExportItem::Index(entity) |
1511 | | } |
1512 | 29 | ModuleDef::Import(..) => ExportItem::Name(name.to_string()), |
1513 | | }; |
1514 | 13.0k | dfg::CoreExport { |
1515 | 13.0k | instance: *instance, |
1516 | 13.0k | item, |
1517 | 13.0k | } |
1518 | 13.0k | .into() |
1519 | | } |
1520 | | |
1521 | | // This is a synthetic instance so the canonical definition of the |
1522 | | // original item is returned. |
1523 | 41.8k | ModuleInstanceDef::Synthetic(instance) => match instance[name] { |
1524 | 38.7k | EntityIndex::Function(i) => frame.funcs[i].1.clone(), |
1525 | 231 | EntityIndex::Table(i) => frame.tables[i].clone().into(), |
1526 | 147 | EntityIndex::Global(i) => frame.globals[i].clone().into(), |
1527 | 2.64k | EntityIndex::Memory(i) => frame.memories[i].clone().into(), |
1528 | 68 | EntityIndex::Tag(i) => frame.tags[i].clone().into(), |
1529 | | }, |
1530 | | } |
1531 | 54.9k | } |
1532 | | |
1533 | 7.83k | fn memory( |
1534 | 7.83k | &mut self, |
1535 | 7.83k | frame: &InlinerFrame<'a>, |
1536 | 7.83k | types: &ComponentTypesBuilder, |
1537 | 7.83k | memory: MemoryIndex, |
1538 | 7.83k | ) -> (dfg::CoreExport<MemoryIndex>, Memory) { |
1539 | 7.83k | let memory = frame.memories[memory].clone().map_index(|i| match i { |
1540 | 7.83k | EntityIndex::Memory(i) => i, |
1541 | 0 | _ => unreachable!(), |
1542 | 7.83k | }); |
1543 | 7.83k | let ty = match &self.runtime_instances[memory.instance] { |
1544 | 7.83k | InstanceModule::Static(idx) => match &memory.item { |
1545 | 7.83k | ExportItem::Index(i) => self.nested_modules[*idx].module.memories[*i], |
1546 | 0 | ExportItem::Name(_) => unreachable!(), |
1547 | | }, |
1548 | 0 | InstanceModule::Import(ty) => match &memory.item { |
1549 | 0 | ExportItem::Name(name) => match types[*ty].exports[name] { |
1550 | 0 | EntityType::Memory(m) => m, |
1551 | 0 | _ => unreachable!(), |
1552 | | }, |
1553 | 0 | ExportItem::Index(_) => unreachable!(), |
1554 | | }, |
1555 | | }; |
1556 | 7.83k | (memory, ty) |
1557 | 7.83k | } |
1558 | | |
1559 | | /// Translates a `LocalCanonicalOptions` which indexes into the `frame` |
1560 | | /// specified into a runtime representation. |
1561 | 45.4k | fn adapter_options( |
1562 | 45.4k | &mut self, |
1563 | 45.4k | frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>, |
1564 | 45.4k | types: &ComponentTypesBuilder, |
1565 | 45.4k | options: &LocalCanonicalOptions, |
1566 | 45.4k | ) -> AdapterOptions { |
1567 | 45.4k | let (frame, _) = frames.last_mut().unwrap(); |
1568 | 45.4k | let data_model = match options.data_model { |
1569 | 4 | LocalDataModel::Gc {} => DataModel::Gc {}, |
1570 | 45.4k | LocalDataModel::LinearMemory { memory, realloc } => { |
1571 | 45.4k | let memory = memory.map(|i| self.memory(frame, types, i)); |
1572 | 45.4k | let realloc = realloc.map(|i| frame.funcs[i].1.clone()); |
1573 | 45.4k | DataModel::LinearMemory { memory, realloc } |
1574 | | } |
1575 | | }; |
1576 | 45.4k | let callback = options.callback.map(|i| frame.funcs[i].1.clone()); |
1577 | 45.4k | let post_return = options.post_return.map(|i| frame.funcs[i].1.clone()); |
1578 | 45.4k | AdapterOptions { |
1579 | 45.4k | instance: frame.instance, |
1580 | 45.4k | string_encoding: options.string_encoding, |
1581 | 45.4k | callback, |
1582 | 45.4k | post_return, |
1583 | 45.4k | async_: options.async_, |
1584 | 45.4k | core_type: options.core_type, |
1585 | 45.4k | data_model, |
1586 | 45.4k | } |
1587 | 45.4k | } |
1588 | | |
1589 | | /// Translates an `AdapterOptions` into a `CanonicalOptions` where |
1590 | | /// memories/functions are inserted into the global initializer list for |
1591 | | /// use at runtime. This is only used for lowered host functions and lifted |
1592 | | /// functions exported to the host. |
1593 | 19.3k | fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId { |
1594 | 19.3k | let data_model = match options.data_model { |
1595 | 0 | DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {}, |
1596 | 19.3k | DataModel::LinearMemory { memory, realloc } => { |
1597 | | dfg::CanonicalOptionsDataModel::LinearMemory { |
1598 | 19.3k | memory: memory.map(|(export, _)| self.result.memories.push(export)), |
1599 | 19.3k | realloc: realloc.map(|def| self.result.reallocs.push(def)), |
1600 | | } |
1601 | | } |
1602 | | }; |
1603 | 19.3k | let callback = options.callback.map(|def| self.result.callbacks.push(def)); |
1604 | 19.3k | let post_return = options |
1605 | 19.3k | .post_return |
1606 | 19.3k | .map(|def| self.result.post_returns.push(def)); |
1607 | 19.3k | self.result.options.push(dfg::CanonicalOptions { |
1608 | 19.3k | instance: options.instance, |
1609 | 19.3k | string_encoding: options.string_encoding, |
1610 | 19.3k | callback, |
1611 | 19.3k | post_return, |
1612 | 19.3k | async_: options.async_, |
1613 | 19.3k | core_type: options.core_type, |
1614 | 19.3k | data_model, |
1615 | 19.3k | }) |
1616 | 19.3k | } |
1617 | | |
1618 | 11.0k | fn record_export( |
1619 | 11.0k | &mut self, |
1620 | 11.0k | name: &str, |
1621 | 11.0k | def: ComponentItemDef<'a>, |
1622 | 11.0k | data: ComponentExternData, |
1623 | 11.0k | types: &'a ComponentTypesBuilder, |
1624 | 11.0k | map: &mut IndexMap<String, (dfg::Export, ComponentExternData)>, |
1625 | 11.0k | ) -> Result<()> { |
1626 | 11.0k | let export = match def { |
1627 | | // Exported modules are currently saved in a `PrimaryMap`, at |
1628 | | // runtime, so an index (`RuntimeModuleIndex`) is assigned here and |
1629 | | // then an initializer is recorded about where the module comes |
1630 | | // from. |
1631 | 46 | ComponentItemDef::Module(module) => match module { |
1632 | 45 | ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index }, |
1633 | 1 | ModuleDef::Import(path, ty) => dfg::Export::ModuleImport { |
1634 | 1 | ty, |
1635 | 1 | import: self.runtime_import(&path), |
1636 | 1 | }, |
1637 | | }, |
1638 | | |
1639 | 10.5k | ComponentItemDef::Func(func) => match func { |
1640 | | // If this is a lifted function from something lowered in this |
1641 | | // component then the configured options are plumbed through |
1642 | | // here. |
1643 | 10.5k | ComponentFuncDef::Lifted { ty, func, options } => { |
1644 | 10.5k | let options = self.canonical_options(options); |
1645 | 10.5k | dfg::Export::LiftedFunction { ty, func, options } |
1646 | | } |
1647 | | |
1648 | | // Currently reexported functions from an import are not |
1649 | | // supported. Being able to actually call these functions is |
1650 | | // somewhat tricky and needs something like temporary scratch |
1651 | | // space that isn't implemented. |
1652 | | ComponentFuncDef::Import(_) => { |
1653 | 4 | bail!( |
1654 | | "component export `{name}` is a reexport of an imported function which is not implemented" |
1655 | | ) |
1656 | | } |
1657 | | |
1658 | | ComponentFuncDef::UnsafeIntrinsic(_) => { |
1659 | 0 | bail!( |
1660 | | "component export `{name}` is a reexport of an intrinsic function which is not supported" |
1661 | | ) |
1662 | | } |
1663 | | }, |
1664 | | |
1665 | 73 | ComponentItemDef::Instance(instance) => { |
1666 | 73 | let mut exports = IndexMap::new(); |
1667 | 73 | match instance { |
1668 | | ComponentInstanceDef::Intrinsics => { |
1669 | 0 | bail!( |
1670 | | "component export `{name}` is a reexport of the intrinsics instance which is not supported" |
1671 | | ) |
1672 | | } |
1673 | | |
1674 | | // If this instance is one that was originally imported by |
1675 | | // the component itself then the imports are translated here |
1676 | | // by converting to a `ComponentItemDef` and then |
1677 | | // recursively recording the export as a reexport. |
1678 | | // |
1679 | | // Note that for now this would only work with |
1680 | | // module-exporting instances. |
1681 | 9 | ComponentInstanceDef::Import(path, ty) => { |
1682 | 9 | for (name, ty) in types[ty].exports.iter() { |
1683 | 0 | let path = path.push(name); |
1684 | 0 | let def = ComponentItemDef::from_import(path, ty.ty)?; |
1685 | 0 | self.record_export(name, def, ty.data.clone(), types, &mut exports)?; |
1686 | | } |
1687 | 9 | dfg::Export::Instance { ty, exports } |
1688 | | } |
1689 | | |
1690 | | // An exported instance which is itself a bag of items is |
1691 | | // translated recursively here to our `exports` map which is |
1692 | | // the bag of items we're exporting. |
1693 | 64 | ComponentInstanceDef::Items(map, ty) => { |
1694 | 64 | for (name, (def, data)) in map { |
1695 | 40 | let data = ComponentExternData::new(data); |
1696 | 40 | self.record_export(name, def, data.clone(), types, &mut exports)?; |
1697 | | } |
1698 | 64 | dfg::Export::Instance { ty, exports } |
1699 | | } |
1700 | | } |
1701 | | } |
1702 | | |
1703 | | // FIXME(#4283) should make an official decision on whether this is |
1704 | | // the final treatment of this or not. |
1705 | | ComponentItemDef::Component(_) => { |
1706 | 4 | bail!("exporting a component from the root component is not supported") |
1707 | | } |
1708 | | |
1709 | 340 | ComponentItemDef::Type(def) => dfg::Export::Type(def), |
1710 | | }; |
1711 | | |
1712 | 11.0k | map.insert(name.to_string(), (export, data)); |
1713 | 11.0k | Ok(()) |
1714 | 11.0k | } |
1715 | | } |
1716 | | |
1717 | | impl<'a> InlinerFrame<'a> { |
1718 | 21.6k | fn new( |
1719 | 21.6k | instance: RuntimeComponentInstanceIndex, |
1720 | 21.6k | translation: &'a Translation<'a>, |
1721 | 21.6k | closure: ComponentClosure<'a>, |
1722 | 21.6k | args: HashMap<&'a str, ComponentItemDef<'a>>, |
1723 | 21.6k | instance_ty: Option<ComponentInstanceTypeId>, |
1724 | 21.6k | ) -> Self { |
1725 | | // FIXME: should iterate over the initializers of `translation` and |
1726 | | // calculate the size of each index space to use `with_capacity` for |
1727 | | // all the maps below. Given that doing such would be wordy and compile |
1728 | | // time is otherwise not super crucial it's not done at this time. |
1729 | 21.6k | InlinerFrame { |
1730 | 21.6k | instance, |
1731 | 21.6k | translation, |
1732 | 21.6k | closure, |
1733 | 21.6k | args, |
1734 | 21.6k | instance_ty, |
1735 | 21.6k | initializers: translation.initializers.iter(), |
1736 | 21.6k | |
1737 | 21.6k | funcs: Default::default(), |
1738 | 21.6k | memories: Default::default(), |
1739 | 21.6k | tables: Default::default(), |
1740 | 21.6k | globals: Default::default(), |
1741 | 21.6k | tags: Default::default(), |
1742 | 21.6k | |
1743 | 21.6k | component_instances: Default::default(), |
1744 | 21.6k | component_funcs: Default::default(), |
1745 | 21.6k | module_instances: Default::default(), |
1746 | 21.6k | components: Default::default(), |
1747 | 21.6k | modules: Default::default(), |
1748 | 21.6k | } |
1749 | 21.6k | } |
1750 | | |
1751 | 48.1k | fn item( |
1752 | 48.1k | &self, |
1753 | 48.1k | index: ComponentItem, |
1754 | 48.1k | types: &mut ComponentTypesBuilder, |
1755 | 48.1k | ) -> Result<ComponentItemDef<'a>> { |
1756 | 48.1k | Ok(match index { |
1757 | 42.5k | ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()), |
1758 | 789 | ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()), |
1759 | 2.19k | ComponentItem::ComponentInstance(i) => { |
1760 | 2.19k | ComponentItemDef::Instance(self.component_instances[i].clone()) |
1761 | | } |
1762 | 998 | ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()), |
1763 | 1.66k | ComponentItem::Type(t) => { |
1764 | 1.66k | let types_ref = self.translation.types_ref(); |
1765 | 1.66k | ComponentItemDef::Type(types.convert_type(types_ref, t)?) |
1766 | | } |
1767 | | }) |
1768 | 48.1k | } |
1769 | | |
1770 | | /// Pushes the component `item` definition provided into the appropriate |
1771 | | /// index space within this component. |
1772 | 56.0k | fn push_item(&mut self, item: ComponentItemDef<'a>) { |
1773 | 56.0k | match item { |
1774 | 34.5k | ComponentItemDef::Func(i) => { |
1775 | 34.5k | self.component_funcs.push(i); |
1776 | 34.5k | } |
1777 | 997 | ComponentItemDef::Module(i) => { |
1778 | 997 | self.modules.push(i); |
1779 | 997 | } |
1780 | 773 | ComponentItemDef::Component(i) => { |
1781 | 773 | self.components.push(i); |
1782 | 773 | } |
1783 | 18.1k | ComponentItemDef::Instance(i) => { |
1784 | 18.1k | self.component_instances.push(i); |
1785 | 18.1k | } |
1786 | | |
1787 | | // In short, type definitions aren't tracked here. |
1788 | | // |
1789 | | // The longer form explanation for this is that structural types |
1790 | | // like lists and records don't need to be tracked at all and the |
1791 | | // only significant type which needs tracking is resource types |
1792 | | // themselves. Resource types, however, are tracked within the |
1793 | | // `ResourcesBuilder` state rather than an `InlinerFrame` so they're |
1794 | | // ignored here as well. The general reason for that is that type |
1795 | | // information is everywhere and this `InlinerFrame` is not |
1796 | | // everywhere so it seemed like it would make sense to split the |
1797 | | // two. |
1798 | | // |
1799 | | // Note though that this case is actually frequently hit, so it |
1800 | | // can't be `unreachable!()`. Instead callers are responsible for |
1801 | | // handling this appropriately with respect to resources. |
1802 | 1.55k | ComponentItemDef::Type(_ty) => {} |
1803 | | } |
1804 | 56.0k | } |
1805 | | |
1806 | 552 | fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> { |
1807 | 552 | match *index { |
1808 | 214 | ClosedOverModule::Local(i) => self.modules[i].clone(), |
1809 | 338 | ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(), |
1810 | | } |
1811 | 552 | } |
1812 | | |
1813 | 160 | fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> { |
1814 | 160 | match *index { |
1815 | 64 | ClosedOverComponent::Local(i) => self.components[i].clone(), |
1816 | 96 | ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(), |
1817 | | } |
1818 | 160 | } |
1819 | | |
1820 | | /// Completes the instantiation of a subcomponent and records type |
1821 | | /// information for the instance that was produced. |
1822 | | /// |
1823 | | /// This method is invoked when an `InlinerFrame` finishes for a |
1824 | | /// subcomponent. The `def` provided represents the instance that was |
1825 | | /// produced from instantiation, and `ty` is the wasmparser-defined type of |
1826 | | /// the instance produced. |
1827 | | /// |
1828 | | /// The purpose of this method is to record type information about resources |
1829 | | /// in the instance produced. In the component model all instantiations of a |
1830 | | /// component produce fresh new types for all resources which are unequal to |
1831 | | /// all prior resources. This means that if wasmparser's `ty` type |
1832 | | /// information references a unique resource within `def` that has never |
1833 | | /// been registered before then that means it's a defined resource within |
1834 | | /// the component that was just instantiated (as opposed to an imported |
1835 | | /// resource which was reexported). |
1836 | | /// |
1837 | | /// Further type translation after this instantiation can refer to these |
1838 | | /// resource types and a mapping from those types to the wasmtime-internal |
1839 | | /// types is required, so this method builds up those mappings. |
1840 | | /// |
1841 | | /// Essentially what happens here is that the `ty` type is registered and |
1842 | | /// any new unique resources are registered so new tables can be introduced |
1843 | | /// along with origin information about the actual underlying resource type |
1844 | | /// and which component instantiated it. |
1845 | 15.5k | fn finish_instantiate( |
1846 | 15.5k | &mut self, |
1847 | 15.5k | exports: IndexMap<&'a str, (ComponentItemDef<'a>, wasmparser::ComponentExternName<'a>)>, |
1848 | 15.5k | ty: ComponentInstanceTypeId, |
1849 | 15.5k | types: &mut ComponentTypesBuilder, |
1850 | 15.5k | ) -> Result<()> { |
1851 | 15.5k | let types_ref = self.translation.types_ref(); |
1852 | | { |
1853 | 15.5k | let (resources, types) = types.resources_mut_and_types(); |
1854 | 15.5k | let mut path = Vec::new(); |
1855 | 15.5k | resources.register_component_entity_type( |
1856 | 15.5k | &types_ref, |
1857 | 15.5k | ComponentEntityType::Instance(ty), |
1858 | 15.5k | &mut path, |
1859 | 669 | &mut |path| match path { |
1860 | 669 | [] => unreachable!(), |
1861 | 669 | [name, rest @ ..] => exports[name].0.lookup_resource(rest, types), |
1862 | 669 | }, |
1863 | | ); |
1864 | | } |
1865 | 15.5k | let ty = types.convert_instance(types_ref, ty)?; |
1866 | 15.5k | let def = ComponentInstanceDef::Items(exports, ty); |
1867 | 15.5k | let arg = ComponentItemDef::Instance(def); |
1868 | 15.5k | self.push_item(arg); |
1869 | 15.5k | Ok(()) |
1870 | 15.5k | } |
1871 | | } |
1872 | | |
1873 | | impl<'a> ImportPath<'a> { |
1874 | 801 | fn root(index: ImportIndex) -> ImportPath<'a> { |
1875 | 801 | ImportPath { |
1876 | 801 | index, |
1877 | 801 | path: Vec::new(), |
1878 | 801 | } |
1879 | 801 | } |
1880 | | |
1881 | 440 | fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> { |
1882 | 440 | let mut new = self.clone(); |
1883 | 440 | new.path.push(s.into()); |
1884 | 440 | new |
1885 | 440 | } Unexecuted instantiation: <wasmtime_environ::component::translate::inline::ImportPath>::push::<&alloc::string::String> <wasmtime_environ::component::translate::inline::ImportPath>::push::<&str> Line | Count | Source | 1881 | 440 | fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> { | 1882 | 440 | let mut new = self.clone(); | 1883 | 440 | new.path.push(s.into()); | 1884 | 440 | new | 1885 | 440 | } |
|
1886 | | } |
1887 | | |
1888 | | impl<'a> ComponentItemDef<'a> { |
1889 | 1.24k | fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> { |
1890 | 1.24k | let item = match ty { |
1891 | 57 | TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)), |
1892 | 471 | TypeDef::ComponentInstance(ty) => { |
1893 | 471 | ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty)) |
1894 | | } |
1895 | 386 | TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)), |
1896 | | // FIXME(#4283) should commit one way or another to how this |
1897 | | // should be treated. |
1898 | 6 | TypeDef::Component(_ty) => bail!("root-level component imports are not supported"), |
1899 | 321 | TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty), |
1900 | 0 | TypeDef::CoreFunc(_) => unreachable!(), |
1901 | | }; |
1902 | 1.23k | Ok(item) |
1903 | 1.24k | } |
1904 | | |
1905 | | /// Walks the `path` within `self` to find a resource at that path. |
1906 | | /// |
1907 | | /// This method is used when resources are found within wasmparser's type |
1908 | | /// information and they need to be correlated with actual concrete |
1909 | | /// definitions from this inlining pass. The `path` here is a list of |
1910 | | /// instance export names (or empty) to walk to reach down into the final |
1911 | | /// definition which should refer to a resource itself. |
1912 | 1.61k | fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex { |
1913 | 1.61k | let mut cur = self.clone(); |
1914 | | |
1915 | | // Each element of `path` represents unwrapping a layer of an instance |
1916 | | // type, so handle those here by updating `cur` iteratively. |
1917 | 1.61k | for element in path.iter().copied() { |
1918 | 670 | let instance = match cur { |
1919 | 670 | ComponentItemDef::Instance(def) => def, |
1920 | 0 | _ => unreachable!(), |
1921 | | }; |
1922 | 670 | cur = match instance { |
1923 | | // If this instance is a "bag of things" then this is as easy as |
1924 | | // looking up the name in the bag of names. |
1925 | 661 | ComponentInstanceDef::Items(names, _) => names[element].0.clone(), |
1926 | | |
1927 | | // If, however, this instance is an imported instance then this |
1928 | | // is a further projection within the import with one more path |
1929 | | // element. The `types` type information is used to lookup the |
1930 | | // type of `element` within the instance type, and that's used |
1931 | | // in conjunction with a one-longer `path` to produce a new item |
1932 | | // definition. |
1933 | 9 | ComponentInstanceDef::Import(path, ty) => { |
1934 | 9 | ComponentItemDef::from_import(path.push(element), types[ty].exports[element].ty) |
1935 | 9 | .unwrap() |
1936 | | } |
1937 | | ComponentInstanceDef::Intrinsics => { |
1938 | 0 | unreachable!("intrinsics do not define resources") |
1939 | | } |
1940 | | }; |
1941 | | } |
1942 | | |
1943 | | // Once `path` has been iterated over it must be the case that the final |
1944 | | // item is a resource type, in which case a lookup can be performed. |
1945 | 1.61k | match cur { |
1946 | 1.61k | ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].unwrap_concrete_ty(), |
1947 | 0 | _ => unreachable!(), |
1948 | | } |
1949 | 1.61k | } |
1950 | | } |
1951 | | |
1952 | | #[derive(Clone, Copy)] |
1953 | | enum InstanceModule { |
1954 | | Static(StaticModuleIndex), |
1955 | | Import(TypeModuleIndex), |
1956 | | } |
1957 | | |
1958 | | impl ComponentExternData { |
1959 | 11.8k | fn new(data: wasmparser::ComponentExternName<'_>) -> Self { |
1960 | | ComponentExternData { |
1961 | 11.8k | implements: data.implements.map(|s| s.to_string()), |
1962 | 11.8k | external_id: data.external_id.map(|s| s.to_string()), |
1963 | | } |
1964 | 11.8k | } |
1965 | | } |