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