Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/component/dfg.rs
1692 views
1
//! A dataflow-graph-like intermediate representation of a component
2
//!
3
//! This module contains `ComponentDfg` which is an intermediate step towards
4
//! becoming a full-fledged `Component`. The main purpose for the existence of
5
//! this representation of a component is to track dataflow between various
6
//! items within a component and support edits to them after the initial inlined
7
//! translation of a component.
8
//!
9
//! Currently fused adapters are represented with a core WebAssembly module
10
//! which gets "injected" into the final component as-if the component already
11
//! bundled it. In doing so the adapter modules need to be partitioned and
12
//! inserted into the final sequence of modules to instantiate. While this is
13
//! possible to do with a flat `GlobalInitializer` list it gets unwieldy really
14
//! quickly especially when other translation features are added.
15
//!
16
//! This module is largely a duplicate of the `component::info` module in this
17
//! crate. The hierarchy here uses `*Id` types instead of `*Index` types to
18
//! represent that they don't have any necessary implicit ordering. Additionally
19
//! nothing is kept in an ordered list and instead this is worked with in a
20
//! general dataflow fashion where dependencies are walked during processing.
21
//!
22
//! The `ComponentDfg::finish` method will convert the dataflow graph to a
23
//! linearized `GlobalInitializer` list which is intended to not be edited after
24
//! it's created.
25
//!
26
//! The `ComponentDfg` is created as part of the `component::inline` phase of
27
//! translation where the dataflow performed there allows identification of
28
//! fused adapters, what arguments make their way to core wasm modules, etc.
29
30
use crate::component::*;
31
use crate::prelude::*;
32
use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
33
use anyhow::Result;
34
use indexmap::IndexMap;
35
use info::LinearMemoryOptions;
36
use std::collections::HashMap;
37
use std::hash::Hash;
38
use std::ops::Index;
39
use wasmparser::component_types::ComponentCoreModuleTypeId;
40
41
/// High-level representation of a component as a "data-flow graph".
42
#[derive(Default)]
43
pub struct ComponentDfg {
44
/// Same as `Component::import_types`
45
pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
46
47
/// Same as `Component::imports`
48
pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
49
50
/// Same as `Component::exports`
51
pub exports: IndexMap<String, Export>,
52
53
/// All trampolines and their type signature which will need to get
54
/// compiled by Cranelift.
55
pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
56
57
/// Know reallocation functions which are used by `lowerings` (e.g. will be
58
/// used by the host)
59
pub reallocs: Intern<ReallocId, CoreDef>,
60
61
/// Same as `reallocs`, but for async-lifted functions.
62
pub callbacks: Intern<CallbackId, CoreDef>,
63
64
/// Same as `reallocs`, but for post-return.
65
pub post_returns: Intern<PostReturnId, CoreDef>,
66
67
/// Same as `reallocs`, but for post-return.
68
pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
69
70
/// Metadata about identified fused adapters.
71
///
72
/// Note that this list is required to be populated in-order where the
73
/// "left" adapters cannot depend on "right" adapters. Currently this falls
74
/// out of the inlining pass of translation.
75
pub adapters: Intern<AdapterId, Adapter>,
76
77
/// Metadata about all known core wasm instances created.
78
///
79
/// This is mostly an ordered list and is not deduplicated based on contents
80
/// unlike the items above. Creation of an `Instance` is side-effectful and
81
/// all instances here are always required to be created. These are
82
/// considered "roots" in dataflow.
83
pub instances: PrimaryMap<InstanceId, Instance>,
84
85
/// Number of component instances that were created during the inlining
86
/// phase (this is not edited after creation).
87
pub num_runtime_component_instances: u32,
88
89
/// Known adapter modules and how they are instantiated.
90
///
91
/// This map is not filled in on the initial creation of a `ComponentDfg`.
92
/// Instead these modules are filled in by the `inline::adapt` phase where
93
/// adapter modules are identified and filled in here.
94
///
95
/// The payload here is the static module index representing the core wasm
96
/// adapter module that was generated as well as the arguments to the
97
/// instantiation of the adapter module.
98
pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
99
100
/// Metadata about where adapters can be found within their respective
101
/// adapter modules.
102
///
103
/// Like `adapter_modules` this is not filled on the initial creation of
104
/// `ComponentDfg` but rather is created alongside `adapter_modules` during
105
/// the `inline::adapt` phase of translation.
106
///
107
/// The values here are the module that the adapter is present within along
108
/// as the core wasm index of the export corresponding to the lowered
109
/// version of the adapter.
110
pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
111
112
/// Defined resources in this component sorted by index with metadata about
113
/// each resource.
114
///
115
/// Note that each index here is a unique resource, and that may mean it was
116
/// the same component instantiated twice for example.
117
pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
118
119
/// Metadata about all imported resources into this component. This records
120
/// both how many imported resources there are (the size of this map) along
121
/// with what the corresponding runtime import is.
122
pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
123
124
/// The total number of future tables that will be used by this component.
125
pub num_future_tables: usize,
126
127
/// The total number of stream tables that will be used by this component.
128
pub num_stream_tables: usize,
129
130
/// The total number of error-context tables that will be used by this
131
/// component.
132
pub num_error_context_tables: usize,
133
134
/// An ordered list of side effects induced by instantiating this component.
135
///
136
/// Currently all side effects are either instantiating core wasm modules or
137
/// declaring a resource. These side effects affect the dataflow processing
138
/// of this component by idnicating what order operations should be
139
/// performed during instantiation.
140
pub side_effects: Vec<SideEffect>,
141
142
/// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by
143
/// this component.
144
pub options: Intern<OptionsId, CanonicalOptions>,
145
}
146
147
/// Possible side effects that are possible with instantiating this component.
148
pub enum SideEffect {
149
/// A core wasm instance was created.
150
///
151
/// Instantiation is side-effectful due to the presence of constructs such
152
/// as traps and the core wasm `start` function which may call component
153
/// imports. Instantiation order from the original component must be done in
154
/// the same order.
155
Instance(InstanceId),
156
157
/// A resource was declared in this component.
158
///
159
/// This is a bit less side-effectful than instantiation but this serves as
160
/// the order in which resources are initialized in a component with their
161
/// destructors. Destructors are loaded from core wasm instances (or
162
/// lowerings) which are produced by prior side-effectful operations.
163
Resource(DefinedResourceIndex),
164
}
165
166
/// A sound approximation of a particular module's set of instantiations.
167
///
168
/// This type forms a simple lattice that we can use in static analyses that in
169
/// turn let us specialize a module's compilation to exactly the imports it is
170
/// given.
171
#[derive(Clone, Copy, Default)]
172
pub enum AbstractInstantiations<'a> {
173
/// The associated module is instantiated many times.
174
Many,
175
176
/// The module is instantiated exactly once, with the given definitions as
177
/// arguments to that instantiation.
178
One(&'a [info::CoreDef]),
179
180
/// The module is never instantiated.
181
#[default]
182
None,
183
}
184
185
impl AbstractInstantiations<'_> {
186
/// Join two facts about a particular module's instantiation together.
187
///
188
/// This is the least-upper-bound operation on the lattice.
189
pub fn join(&mut self, other: Self) {
190
*self = match (*self, other) {
191
(Self::Many, _) | (_, Self::Many) => Self::Many,
192
(Self::One(a), Self::One(b)) if a == b => Self::One(a),
193
(Self::One(_), Self::One(_)) => Self::Many,
194
(Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),
195
(Self::None, Self::None) => Self::None,
196
}
197
}
198
}
199
200
macro_rules! id {
201
($(pub struct $name:ident(u32);)*) => ($(
202
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
203
#[expect(missing_docs, reason = "tedious to document")]
204
pub struct $name(u32);
205
cranelift_entity::entity_impl!($name);
206
)*)
207
}
208
209
id! {
210
pub struct InstanceId(u32);
211
pub struct MemoryId(u32);
212
pub struct TableId(u32);
213
pub struct ReallocId(u32);
214
pub struct CallbackId(u32);
215
pub struct AdapterId(u32);
216
pub struct PostReturnId(u32);
217
pub struct AdapterModuleId(u32);
218
pub struct OptionsId(u32);
219
}
220
221
/// Same as `info::InstantiateModule`
222
#[expect(missing_docs, reason = "tedious to document variants")]
223
pub enum Instance {
224
Static(StaticModuleIndex, Box<[CoreDef]>),
225
Import(
226
RuntimeImportIndex,
227
IndexMap<String, IndexMap<String, CoreDef>>,
228
),
229
}
230
231
/// Same as `info::Export`
232
#[expect(missing_docs, reason = "tedious to document variants")]
233
pub enum Export {
234
LiftedFunction {
235
ty: TypeFuncIndex,
236
func: CoreDef,
237
options: OptionsId,
238
},
239
ModuleStatic {
240
ty: ComponentCoreModuleTypeId,
241
index: StaticModuleIndex,
242
},
243
ModuleImport {
244
ty: TypeModuleIndex,
245
import: RuntimeImportIndex,
246
},
247
Instance {
248
ty: TypeComponentInstanceIndex,
249
exports: IndexMap<String, Export>,
250
},
251
Type(TypeDef),
252
}
253
254
/// Same as `info::CoreDef`, except has an extra `Adapter` variant.
255
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
256
#[expect(missing_docs, reason = "tedious to document variants")]
257
pub enum CoreDef {
258
Export(CoreExport<EntityIndex>),
259
InstanceFlags(RuntimeComponentInstanceIndex),
260
Trampoline(TrampolineIndex),
261
/// This is a special variant not present in `info::CoreDef` which
262
/// represents that this definition refers to a fused adapter function. This
263
/// adapter is fully processed after the initial translation and
264
/// identification of adapters.
265
///
266
/// During translation into `info::CoreDef` this variant is erased and
267
/// replaced by `info::CoreDef::Export` since adapters are always
268
/// represented as the exports of a core wasm instance.
269
Adapter(AdapterId),
270
}
271
272
impl<T> From<CoreExport<T>> for CoreDef
273
where
274
EntityIndex: From<T>,
275
{
276
fn from(export: CoreExport<T>) -> CoreDef {
277
CoreDef::Export(export.map_index(|i| i.into()))
278
}
279
}
280
281
/// Same as `info::CoreExport`
282
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
283
#[expect(missing_docs, reason = "self-describing fields")]
284
pub struct CoreExport<T> {
285
pub instance: InstanceId,
286
pub item: ExportItem<T>,
287
}
288
289
impl<T> CoreExport<T> {
290
#[expect(missing_docs, reason = "self-describing function")]
291
pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
292
CoreExport {
293
instance: self.instance,
294
item: match self.item {
295
ExportItem::Index(i) => ExportItem::Index(f(i)),
296
ExportItem::Name(s) => ExportItem::Name(s),
297
},
298
}
299
}
300
}
301
302
/// Same as `info::Trampoline`
303
#[derive(Clone, PartialEq, Eq, Hash)]
304
#[expect(missing_docs, reason = "self-describing fields")]
305
pub enum Trampoline {
306
LowerImport {
307
import: RuntimeImportIndex,
308
options: OptionsId,
309
lower_ty: TypeFuncIndex,
310
},
311
Transcoder {
312
op: Transcode,
313
from: MemoryId,
314
from64: bool,
315
to: MemoryId,
316
to64: bool,
317
},
318
AlwaysTrap,
319
ResourceNew(TypeResourceTableIndex),
320
ResourceRep(TypeResourceTableIndex),
321
ResourceDrop(TypeResourceTableIndex),
322
BackpressureSet {
323
instance: RuntimeComponentInstanceIndex,
324
},
325
TaskReturn {
326
results: TypeTupleIndex,
327
options: OptionsId,
328
},
329
TaskCancel {
330
instance: RuntimeComponentInstanceIndex,
331
},
332
WaitableSetNew {
333
instance: RuntimeComponentInstanceIndex,
334
},
335
WaitableSetWait {
336
options: OptionsId,
337
},
338
WaitableSetPoll {
339
options: OptionsId,
340
},
341
WaitableSetDrop {
342
instance: RuntimeComponentInstanceIndex,
343
},
344
WaitableJoin {
345
instance: RuntimeComponentInstanceIndex,
346
},
347
Yield {
348
async_: bool,
349
},
350
SubtaskDrop {
351
instance: RuntimeComponentInstanceIndex,
352
},
353
SubtaskCancel {
354
instance: RuntimeComponentInstanceIndex,
355
async_: bool,
356
},
357
StreamNew {
358
ty: TypeStreamTableIndex,
359
},
360
StreamRead {
361
ty: TypeStreamTableIndex,
362
options: OptionsId,
363
},
364
StreamWrite {
365
ty: TypeStreamTableIndex,
366
options: OptionsId,
367
},
368
StreamCancelRead {
369
ty: TypeStreamTableIndex,
370
async_: bool,
371
},
372
StreamCancelWrite {
373
ty: TypeStreamTableIndex,
374
async_: bool,
375
},
376
StreamDropReadable {
377
ty: TypeStreamTableIndex,
378
},
379
StreamDropWritable {
380
ty: TypeStreamTableIndex,
381
},
382
FutureNew {
383
ty: TypeFutureTableIndex,
384
},
385
FutureRead {
386
ty: TypeFutureTableIndex,
387
options: OptionsId,
388
},
389
FutureWrite {
390
ty: TypeFutureTableIndex,
391
options: OptionsId,
392
},
393
FutureCancelRead {
394
ty: TypeFutureTableIndex,
395
async_: bool,
396
},
397
FutureCancelWrite {
398
ty: TypeFutureTableIndex,
399
async_: bool,
400
},
401
FutureDropReadable {
402
ty: TypeFutureTableIndex,
403
},
404
FutureDropWritable {
405
ty: TypeFutureTableIndex,
406
},
407
ErrorContextNew {
408
ty: TypeComponentLocalErrorContextTableIndex,
409
options: OptionsId,
410
},
411
ErrorContextDebugMessage {
412
ty: TypeComponentLocalErrorContextTableIndex,
413
options: OptionsId,
414
},
415
ErrorContextDrop {
416
ty: TypeComponentLocalErrorContextTableIndex,
417
},
418
ResourceTransferOwn,
419
ResourceTransferBorrow,
420
ResourceEnterCall,
421
ResourceExitCall,
422
PrepareCall {
423
memory: Option<MemoryId>,
424
},
425
SyncStartCall {
426
callback: Option<CallbackId>,
427
},
428
AsyncStartCall {
429
callback: Option<CallbackId>,
430
post_return: Option<PostReturnId>,
431
},
432
FutureTransfer,
433
StreamTransfer,
434
ErrorContextTransfer,
435
ContextGet(u32),
436
ContextSet(u32),
437
}
438
439
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
440
#[expect(missing_docs, reason = "self-describing fields")]
441
pub struct FutureInfo {
442
pub instance: RuntimeComponentInstanceIndex,
443
pub payload_type: Option<InterfaceType>,
444
}
445
446
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
447
#[expect(missing_docs, reason = "self-describing fields")]
448
pub struct StreamInfo {
449
pub instance: RuntimeComponentInstanceIndex,
450
pub payload_type: InterfaceType,
451
}
452
453
/// Same as `info::CanonicalOptionsDataModel`.
454
#[derive(Clone, Hash, Eq, PartialEq)]
455
#[expect(missing_docs, reason = "self-describing fields")]
456
pub enum CanonicalOptionsDataModel {
457
Gc {},
458
LinearMemory {
459
memory: Option<MemoryId>,
460
realloc: Option<ReallocId>,
461
},
462
}
463
464
/// Same as `info::CanonicalOptions`
465
#[derive(Clone, Hash, Eq, PartialEq)]
466
#[expect(missing_docs, reason = "self-describing fields")]
467
pub struct CanonicalOptions {
468
pub instance: RuntimeComponentInstanceIndex,
469
pub string_encoding: StringEncoding,
470
pub callback: Option<CallbackId>,
471
pub post_return: Option<PostReturnId>,
472
pub async_: bool,
473
pub core_type: ModuleInternedTypeIndex,
474
pub data_model: CanonicalOptionsDataModel,
475
}
476
477
/// Same as `info::Resource`
478
#[expect(missing_docs, reason = "self-describing fields")]
479
pub struct Resource {
480
pub rep: WasmValType,
481
pub dtor: Option<CoreDef>,
482
pub instance: RuntimeComponentInstanceIndex,
483
}
484
485
/// A helper structure to "intern" and deduplicate values of type `V` with an
486
/// identifying key `K`.
487
///
488
/// Note that this can also be used where `V` can't be intern'd to represent a
489
/// flat list of items.
490
pub struct Intern<K: EntityRef, V> {
491
intern_map: HashMap<V, K>,
492
key_map: PrimaryMap<K, V>,
493
}
494
495
impl<K, V> Intern<K, V>
496
where
497
K: EntityRef,
498
{
499
/// Inserts the `value` specified into this set, returning either a fresh
500
/// key `K` if this value hasn't been seen before or otherwise returning the
501
/// previous `K` used to represent value.
502
///
503
/// Note that this should only be used for component model items where the
504
/// creation of `value` is not side-effectful.
505
pub fn push(&mut self, value: V) -> K
506
where
507
V: Hash + Eq + Clone,
508
{
509
*self
510
.intern_map
511
.entry(value.clone())
512
.or_insert_with(|| self.key_map.push(value))
513
}
514
515
/// Returns an iterator of all the values contained within this set.
516
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
517
self.key_map.iter()
518
}
519
}
520
521
impl<K: EntityRef, V> Index<K> for Intern<K, V> {
522
type Output = V;
523
fn index(&self, key: K) -> &V {
524
&self.key_map[key]
525
}
526
}
527
528
impl<K: EntityRef, V> Default for Intern<K, V> {
529
fn default() -> Intern<K, V> {
530
Intern {
531
intern_map: HashMap::new(),
532
key_map: PrimaryMap::new(),
533
}
534
}
535
}
536
537
impl ComponentDfg {
538
/// Consumes the intermediate `ComponentDfg` to produce a final `Component`
539
/// with a linear initializer list.
540
pub fn finish(
541
self,
542
wasmtime_types: &mut ComponentTypesBuilder,
543
wasmparser_types: wasmparser::types::TypesRef<'_>,
544
) -> Result<ComponentTranslation> {
545
let mut linearize = LinearizeDfg {
546
dfg: &self,
547
initializers: Vec::new(),
548
runtime_memories: Default::default(),
549
runtime_tables: Default::default(),
550
runtime_post_return: Default::default(),
551
runtime_reallocs: Default::default(),
552
runtime_callbacks: Default::default(),
553
runtime_instances: Default::default(),
554
num_lowerings: 0,
555
trampolines: Default::default(),
556
trampoline_defs: Default::default(),
557
trampoline_map: Default::default(),
558
options: Default::default(),
559
options_map: Default::default(),
560
};
561
562
// Handle all side effects of this component in the order that they're
563
// defined. This will, for example, process all instantiations necessary
564
// of core wasm modules.
565
for item in linearize.dfg.side_effects.iter() {
566
linearize.side_effect(item);
567
}
568
569
// Next the exports of the instance are handled which will likely end up
570
// creating some lowered imports, perhaps some saved modules, etc.
571
let mut export_items = PrimaryMap::new();
572
let mut exports = NameMap::default();
573
for (name, export) in self.exports.iter() {
574
let export =
575
linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
576
exports.insert(name, &mut NameMapNoIntern, false, export)?;
577
}
578
579
// With all those pieces done the results of the dataflow-based
580
// linearization are recorded into the `Component`. The number of
581
// runtime values used for each index space is used from the `linearize`
582
// result.
583
Ok(ComponentTranslation {
584
trampolines: linearize.trampoline_defs,
585
component: Component {
586
exports,
587
export_items,
588
initializers: linearize.initializers,
589
trampolines: linearize.trampolines,
590
num_lowerings: linearize.num_lowerings,
591
options: linearize.options,
592
593
num_runtime_memories: linearize.runtime_memories.len() as u32,
594
num_runtime_tables: linearize.runtime_tables.len() as u32,
595
num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
596
num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
597
num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
598
num_runtime_instances: linearize.runtime_instances.len() as u32,
599
imports: self.imports,
600
import_types: self.import_types,
601
num_runtime_component_instances: self.num_runtime_component_instances,
602
num_future_tables: self.num_future_tables,
603
num_stream_tables: self.num_stream_tables,
604
num_error_context_tables: self.num_error_context_tables,
605
num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
606
imported_resources: self.imported_resources,
607
defined_resource_instances: self
608
.resources
609
.iter()
610
.map(|(_, r)| r.instance)
611
.collect(),
612
},
613
})
614
}
615
616
/// Converts the provided defined index into a normal index, adding in the
617
/// number of imported resources.
618
pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
619
ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
620
}
621
}
622
623
struct LinearizeDfg<'a> {
624
dfg: &'a ComponentDfg,
625
initializers: Vec<GlobalInitializer>,
626
trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
627
trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
628
options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
629
trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
630
runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
631
runtime_tables: HashMap<TableId, RuntimeTableIndex>,
632
runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
633
runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
634
runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
635
runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
636
options_map: HashMap<OptionsId, OptionsIndex>,
637
num_lowerings: u32,
638
}
639
640
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
641
enum RuntimeInstance {
642
Normal(InstanceId),
643
Adapter(AdapterModuleId),
644
}
645
646
impl LinearizeDfg<'_> {
647
fn side_effect(&mut self, effect: &SideEffect) {
648
match effect {
649
SideEffect::Instance(i) => {
650
self.instantiate(*i, &self.dfg.instances[*i]);
651
}
652
SideEffect::Resource(i) => {
653
self.resource(*i, &self.dfg.resources[*i]);
654
}
655
}
656
}
657
658
fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
659
log::trace!("creating instance {instance:?}");
660
let instantiation = match args {
661
Instance::Static(index, args) => InstantiateModule::Static(
662
*index,
663
args.iter().map(|def| self.core_def(def)).collect(),
664
),
665
Instance::Import(index, args) => InstantiateModule::Import(
666
*index,
667
args.iter()
668
.map(|(module, values)| {
669
let values = values
670
.iter()
671
.map(|(name, def)| (name.clone(), self.core_def(def)))
672
.collect();
673
(module.clone(), values)
674
})
675
.collect(),
676
),
677
};
678
let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
679
self.initializers
680
.push(GlobalInitializer::InstantiateModule(instantiation));
681
let prev = self
682
.runtime_instances
683
.insert(RuntimeInstance::Normal(instance), index);
684
assert!(prev.is_none());
685
}
686
687
fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
688
let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
689
self.initializers
690
.push(GlobalInitializer::Resource(info::Resource {
691
dtor,
692
index,
693
rep: resource.rep,
694
instance: resource.instance,
695
}));
696
}
697
698
fn export(
699
&mut self,
700
export: &Export,
701
items: &mut PrimaryMap<ExportIndex, info::Export>,
702
wasmtime_types: &mut ComponentTypesBuilder,
703
wasmparser_types: wasmparser::types::TypesRef<'_>,
704
) -> Result<ExportIndex> {
705
let item = match export {
706
Export::LiftedFunction { ty, func, options } => {
707
let func = self.core_def(func);
708
let options = self.options(*options);
709
info::Export::LiftedFunction {
710
ty: *ty,
711
func,
712
options,
713
}
714
}
715
Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
716
ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
717
index: *index,
718
},
719
Export::ModuleImport { ty, import } => info::Export::ModuleImport {
720
ty: *ty,
721
import: *import,
722
},
723
Export::Instance { ty, exports } => info::Export::Instance {
724
ty: *ty,
725
exports: {
726
let mut map = NameMap::default();
727
for (name, export) in exports {
728
let export =
729
self.export(export, items, wasmtime_types, wasmparser_types)?;
730
map.insert(name, &mut NameMapNoIntern, false, export)?;
731
}
732
map
733
},
734
},
735
Export::Type(def) => info::Export::Type(*def),
736
};
737
Ok(items.push(item))
738
}
739
740
fn options(&mut self, options: OptionsId) -> OptionsIndex {
741
self.intern_no_init(
742
options,
743
|me| &mut me.options_map,
744
|me, options| me.convert_options(options),
745
)
746
}
747
748
fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
749
let options = &self.dfg.options[options];
750
let data_model = match options.data_model {
751
CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
752
CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
753
info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
754
memory: memory.map(|mem| self.runtime_memory(mem)),
755
realloc: realloc.map(|mem| self.runtime_realloc(mem)),
756
})
757
}
758
};
759
let callback = options.callback.map(|mem| self.runtime_callback(mem));
760
let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
761
let options = info::CanonicalOptions {
762
instance: options.instance,
763
string_encoding: options.string_encoding,
764
callback,
765
post_return,
766
async_: options.async_,
767
core_type: options.core_type,
768
data_model,
769
};
770
self.options.push(options)
771
}
772
773
fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
774
self.intern(
775
mem,
776
|me| &mut me.runtime_memories,
777
|me, mem| me.core_export(&me.dfg.memories[mem]),
778
|index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
779
)
780
}
781
782
fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
783
self.intern(
784
realloc,
785
|me| &mut me.runtime_reallocs,
786
|me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
787
|index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
788
)
789
}
790
791
fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
792
self.intern(
793
callback,
794
|me| &mut me.runtime_callbacks,
795
|me, callback| me.core_def(&me.dfg.callbacks[callback]),
796
|index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
797
)
798
}
799
800
fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
801
self.intern(
802
post_return,
803
|me| &mut me.runtime_post_return,
804
|me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
805
|index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
806
)
807
}
808
809
fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
810
match def {
811
CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
812
CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
813
CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
814
CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
815
}
816
}
817
818
fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
819
if let Some(idx) = self.trampoline_map.get(&index) {
820
return *idx;
821
}
822
let (signature, trampoline) = &self.dfg.trampolines[index];
823
let trampoline = match trampoline {
824
Trampoline::LowerImport {
825
import,
826
options,
827
lower_ty,
828
} => {
829
let index = LoweredIndex::from_u32(self.num_lowerings);
830
self.num_lowerings += 1;
831
self.initializers.push(GlobalInitializer::LowerImport {
832
index,
833
import: *import,
834
});
835
info::Trampoline::LowerImport {
836
index,
837
options: self.options(*options),
838
lower_ty: *lower_ty,
839
}
840
}
841
Trampoline::Transcoder {
842
op,
843
from,
844
from64,
845
to,
846
to64,
847
} => info::Trampoline::Transcoder {
848
op: *op,
849
from: self.runtime_memory(*from),
850
from64: *from64,
851
to: self.runtime_memory(*to),
852
to64: *to64,
853
},
854
Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
855
Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty),
856
Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty),
857
Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty),
858
Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {
859
instance: *instance,
860
},
861
Trampoline::TaskReturn { results, options } => info::Trampoline::TaskReturn {
862
results: *results,
863
options: self.options(*options),
864
},
865
Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
866
instance: *instance,
867
},
868
Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
869
instance: *instance,
870
},
871
Trampoline::WaitableSetWait { options } => info::Trampoline::WaitableSetWait {
872
options: self.options(*options),
873
},
874
Trampoline::WaitableSetPoll { options } => info::Trampoline::WaitableSetPoll {
875
options: self.options(*options),
876
},
877
Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
878
instance: *instance,
879
},
880
Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
881
instance: *instance,
882
},
883
Trampoline::Yield { async_ } => info::Trampoline::Yield { async_: *async_ },
884
Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
885
instance: *instance,
886
},
887
Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
888
instance: *instance,
889
async_: *async_,
890
},
891
Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },
892
Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {
893
ty: *ty,
894
options: self.options(*options),
895
},
896
Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {
897
ty: *ty,
898
options: self.options(*options),
899
},
900
Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead {
901
ty: *ty,
902
async_: *async_,
903
},
904
Trampoline::StreamCancelWrite { ty, async_ } => info::Trampoline::StreamCancelWrite {
905
ty: *ty,
906
async_: *async_,
907
},
908
Trampoline::StreamDropReadable { ty } => {
909
info::Trampoline::StreamDropReadable { ty: *ty }
910
}
911
Trampoline::StreamDropWritable { ty } => {
912
info::Trampoline::StreamDropWritable { ty: *ty }
913
}
914
Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },
915
Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {
916
ty: *ty,
917
options: self.options(*options),
918
},
919
Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {
920
ty: *ty,
921
options: self.options(*options),
922
},
923
Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead {
924
ty: *ty,
925
async_: *async_,
926
},
927
Trampoline::FutureCancelWrite { ty, async_ } => info::Trampoline::FutureCancelWrite {
928
ty: *ty,
929
async_: *async_,
930
},
931
Trampoline::FutureDropReadable { ty } => {
932
info::Trampoline::FutureDropReadable { ty: *ty }
933
}
934
Trampoline::FutureDropWritable { ty } => {
935
info::Trampoline::FutureDropWritable { ty: *ty }
936
}
937
Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {
938
ty: *ty,
939
options: self.options(*options),
940
},
941
Trampoline::ErrorContextDebugMessage { ty, options } => {
942
info::Trampoline::ErrorContextDebugMessage {
943
ty: *ty,
944
options: self.options(*options),
945
}
946
}
947
Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty },
948
Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
949
Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
950
Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
951
Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
952
Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
953
memory: memory.map(|v| self.runtime_memory(v)),
954
},
955
Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {
956
callback: callback.map(|v| self.runtime_callback(v)),
957
},
958
Trampoline::AsyncStartCall {
959
callback,
960
post_return,
961
} => info::Trampoline::AsyncStartCall {
962
callback: callback.map(|v| self.runtime_callback(v)),
963
post_return: post_return.map(|v| self.runtime_post_return(v)),
964
},
965
Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
966
Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
967
Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
968
Trampoline::ContextGet(i) => info::Trampoline::ContextGet(*i),
969
Trampoline::ContextSet(i) => info::Trampoline::ContextSet(*i),
970
};
971
let i1 = self.trampolines.push(*signature);
972
let i2 = self.trampoline_defs.push(trampoline);
973
assert_eq!(i1, i2);
974
self.trampoline_map.insert(index, i1);
975
i1
976
}
977
978
fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
979
where
980
T: Clone,
981
{
982
let instance = export.instance;
983
log::trace!("referencing export of {instance:?}");
984
info::CoreExport {
985
instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
986
item: export.item.clone(),
987
}
988
}
989
990
fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
991
let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
992
993
// Instantiates the adapter module if it hasn't already been
994
// instantiated or otherwise returns the index that the module was
995
// already instantiated at.
996
let instance = self.adapter_module(adapter_module);
997
998
// This adapter is always an export of the instance.
999
info::CoreExport {
1000
instance,
1001
item: ExportItem::Index(entity_index),
1002
}
1003
}
1004
1005
fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
1006
self.intern(
1007
RuntimeInstance::Adapter(adapter_module),
1008
|me| &mut me.runtime_instances,
1009
|me, _| {
1010
log::debug!("instantiating {adapter_module:?}");
1011
let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
1012
let args = args.iter().map(|arg| me.core_def(arg)).collect();
1013
let instantiate = InstantiateModule::Static(*module_index, args);
1014
GlobalInitializer::InstantiateModule(instantiate)
1015
},
1016
|_, init| init,
1017
)
1018
}
1019
1020
/// Helper function to manage interning of results to avoid duplicate
1021
/// initializers being inserted into the final list.
1022
///
1023
/// * `key` - the key being referenced which is used to deduplicate.
1024
/// * `map` - a closure to access the interning map on `Self`
1025
/// * `gen` - a closure to generate an intermediate value with `Self` from
1026
/// `K`. This is only used if `key` hasn't previously been seen. This
1027
/// closure can recursively intern other values possibly.
1028
/// * `init` - a closure to use the result of `gen` to create the final
1029
/// initializer now that the index `V` of the runtime item is known.
1030
///
1031
/// This is used by all the other interning methods above to lazily append
1032
/// initializers on-demand and avoid pushing more than one initializer at a
1033
/// time.
1034
fn intern<K, V, T>(
1035
&mut self,
1036
key: K,
1037
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1038
generate: impl FnOnce(&mut Self, K) -> T,
1039
init: impl FnOnce(V, T) -> GlobalInitializer,
1040
) -> V
1041
where
1042
K: Hash + Eq + Copy,
1043
V: EntityRef,
1044
{
1045
self.intern_(key, map, generate, |me, key, val| {
1046
me.initializers.push(init(key, val));
1047
})
1048
}
1049
1050
fn intern_no_init<K, V, T>(
1051
&mut self,
1052
key: K,
1053
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1054
generate: impl FnOnce(&mut Self, K) -> T,
1055
) -> V
1056
where
1057
K: Hash + Eq + Copy,
1058
V: EntityRef,
1059
{
1060
self.intern_(key, map, generate, |_me, _key, _val| {})
1061
}
1062
1063
fn intern_<K, V, T>(
1064
&mut self,
1065
key: K,
1066
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1067
generate: impl FnOnce(&mut Self, K) -> T,
1068
init: impl FnOnce(&mut Self, V, T),
1069
) -> V
1070
where
1071
K: Hash + Eq + Copy,
1072
V: EntityRef,
1073
{
1074
if let Some(val) = map(self).get(&key) {
1075
return *val;
1076
}
1077
let tmp = generate(self, key);
1078
let index = V::new(map(self).len());
1079
init(self, index, tmp);
1080
let prev = map(self).insert(key, index);
1081
assert!(prev.is_none());
1082
index
1083
}
1084
}
1085
1086