Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/component/info.rs
1692 views
1
// General runtime type-information about a component.
2
//
3
// Compared to the `Module` structure for core wasm this type is pretty
4
// significantly different. The core wasm `Module` corresponds roughly 1-to-1
5
// with the structure of the wasm module itself, but instead a `Component` is
6
// more of a "compiled" representation where the original structure is thrown
7
// away in favor of a more optimized representation. The considerations for this
8
// are:
9
//
10
// * This representation of a `Component` avoids the need to create a
11
// `PrimaryMap` of some form for each of the index spaces within a component.
12
// This is less so an issue about allocations and more so that this information
13
// generally just isn't needed any time after instantiation. Avoiding creating
14
// these altogether helps components be lighter weight at runtime and
15
// additionally accelerates instantiation.
16
//
17
// * Components can have arbitrary nesting and internally do instantiations via
18
// string-based matching. At instantiation-time, though, we want to do as few
19
// string-lookups in hash maps as much as we can since they're significantly
20
// slower than index-based lookups. Furthermore while the imports of a
21
// component are not statically known the rest of the structure of the
22
// component is statically known which enables the ability to track precisely
23
// what matches up where and do all the string lookups at compile time instead
24
// of instantiation time.
25
//
26
// * Finally by performing this sort of dataflow analysis we are capable of
27
// identifying what adapters need trampolines for compilation or fusion. For
28
// example this tracks when host functions are lowered which enables us to
29
// enumerate what trampolines are required to enter into a component.
30
// Additionally (eventually) this will track all of the "fused" adapter
31
// functions where a function from one component instance is lifted and then
32
// lowered into another component instance. Altogether this enables Wasmtime's
33
// AOT-compilation where the artifact from compilation is suitable for use in
34
// running the component without the support of a compiler at runtime.
35
//
36
// Note, however, that the current design of `Component` has fundamental
37
// limitations which it was not designed for. For example there is no feasible
38
// way to implement either importing or exporting a component itself from the
39
// root component. Currently we rely on the ability to have static knowledge of
40
// what's coming from the host which at this point can only be either functions
41
// or core wasm modules. Additionally one flat list of initializers for a
42
// component are produced instead of initializers-per-component which would
43
// otherwise be required to export a component from a component.
44
//
45
// For now this tradeoff is made as it aligns well with the intended use case
46
// for components in an embedding. This may need to be revisited though if the
47
// requirements of embeddings change over time.
48
49
use crate::component::*;
50
use crate::prelude::*;
51
use crate::{EntityIndex, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
52
use serde_derive::{Deserialize, Serialize};
53
54
/// Metadata as a result of compiling a component.
55
pub struct ComponentTranslation {
56
/// Serializable information that will be emitted into the final artifact.
57
pub component: Component,
58
59
/// Metadata about required trampolines and what they're supposed to do.
60
pub trampolines: PrimaryMap<TrampolineIndex, Trampoline>,
61
}
62
63
/// Run-time-type-information about a `Component`, its structure, and how to
64
/// instantiate it.
65
///
66
/// This type is intended to mirror the `Module` type in this crate which
67
/// provides all the runtime information about the structure of a module and
68
/// how it works.
69
///
70
/// NB: Lots of the component model is not yet implemented in the runtime so
71
/// this is going to undergo a lot of churn.
72
#[derive(Default, Debug, Serialize, Deserialize)]
73
pub struct Component {
74
/// A list of typed values that this component imports.
75
///
76
/// Note that each name is given an `ImportIndex` here for the next map to
77
/// refer back to.
78
pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
79
80
/// A list of "flattened" imports that are used by this instance.
81
///
82
/// This import map represents extracting imports, as necessary, from the
83
/// general imported types by this component. The flattening here refers to
84
/// extracting items from instances. Currently the flat imports are either a
85
/// host function or a core wasm module.
86
///
87
/// For example if `ImportIndex(0)` pointed to an instance then this import
88
/// map represent extracting names from that map, for example extracting an
89
/// exported module or an exported function.
90
///
91
/// Each import item is keyed by a `RuntimeImportIndex` which is referred to
92
/// by types below whenever something refers to an import. The value for
93
/// each `RuntimeImportIndex` in this map is the `ImportIndex` for where
94
/// this items comes from (which can be associated with a name above in the
95
/// `import_types` array) as well as the list of export names if
96
/// `ImportIndex` refers to an instance. The export names array represents
97
/// recursively fetching names within an instance.
98
//
99
// TODO: this is probably a lot of `String` storage and may be something
100
// that needs optimization in the future. For example instead of lots of
101
// different `String` allocations this could instead be a pointer/length
102
// into one large string allocation for the entire component. Alternatively
103
// strings could otherwise be globally intern'd via some other mechanism to
104
// avoid `Linker`-specific intern-ing plus intern-ing here. Unsure what the
105
// best route is or whether such an optimization is even necessary here.
106
pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
107
108
/// This component's own root exports from the component itself.
109
pub exports: NameMap<String, ExportIndex>,
110
111
/// All exports of this component and exported instances of this component.
112
///
113
/// This is indexed by `ExportIndex` for fast lookup and `Export::Instance`
114
/// will refer back into this list.
115
pub export_items: PrimaryMap<ExportIndex, Export>,
116
117
/// Initializers that must be processed when instantiating this component.
118
///
119
/// This list of initializers does not correspond directly to the component
120
/// itself. The general goal with this is that the recursive nature of
121
/// components is "flattened" with an array like this which is a linear
122
/// sequence of instructions of how to instantiate a component. This will
123
/// have instantiations, for example, in addition to entries which
124
/// initialize `VMComponentContext` fields with previously instantiated
125
/// instances.
126
pub initializers: Vec<GlobalInitializer>,
127
128
/// The number of runtime instances (maximum `RuntimeInstanceIndex`) created
129
/// when instantiating this component.
130
pub num_runtime_instances: u32,
131
132
/// Same as `num_runtime_instances`, but for `RuntimeComponentInstanceIndex`
133
/// instead.
134
pub num_runtime_component_instances: u32,
135
136
/// The number of runtime memories (maximum `RuntimeMemoryIndex`) needed to
137
/// instantiate this component.
138
///
139
/// Note that this many memories will be stored in the `VMComponentContext`
140
/// and each memory is intended to be unique (e.g. the same memory isn't
141
/// stored in two different locations).
142
pub num_runtime_memories: u32,
143
144
/// The number of runtime tables (maximum `RuntimeTableIndex`) needed to
145
/// instantiate this component. See notes on `num_runtime_memories`.
146
pub num_runtime_tables: u32,
147
148
/// The number of runtime reallocs (maximum `RuntimeReallocIndex`) needed to
149
/// instantiate this component.
150
///
151
/// Note that this many function pointers will be stored in the
152
/// `VMComponentContext`.
153
pub num_runtime_reallocs: u32,
154
155
/// The number of runtime async callbacks (maximum `RuntimeCallbackIndex`)
156
/// needed to instantiate this component.
157
pub num_runtime_callbacks: u32,
158
159
/// Same as `num_runtime_reallocs`, but for post-return functions.
160
pub num_runtime_post_returns: u32,
161
162
/// WebAssembly type signature of all trampolines.
163
pub trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
164
165
/// The number of lowered host functions (maximum `LoweredIndex`) needed to
166
/// instantiate this component.
167
pub num_lowerings: u32,
168
169
/// Total number of resources both imported and defined within this
170
/// component.
171
pub num_resources: u32,
172
173
/// Maximal number of tables required at runtime for future-related
174
/// information in this component.
175
pub num_future_tables: usize,
176
177
/// Maximal number of tables required at runtime for stream-related
178
/// information in this component.
179
pub num_stream_tables: usize,
180
181
/// Maximal number of tables required at runtime for error-context-related
182
/// information in this component.
183
pub num_error_context_tables: usize,
184
185
/// Metadata about imported resources and where they are within the runtime
186
/// imports array.
187
///
188
/// This map is only as large as the number of imported resources.
189
pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
190
191
/// Metadata about which component instances defined each resource within
192
/// this component.
193
///
194
/// This is used to determine which set of instance flags are inspected when
195
/// testing reentrance.
196
pub defined_resource_instances: PrimaryMap<DefinedResourceIndex, RuntimeComponentInstanceIndex>,
197
198
/// All canonical options used by this component. Stored as a table here
199
/// from index-to-options so the options can be consulted at runtime.
200
pub options: PrimaryMap<OptionsIndex, CanonicalOptions>,
201
}
202
203
impl Component {
204
/// Attempts to convert a resource index into a defined index.
205
///
206
/// Returns `None` if `idx` is for an imported resource in this component or
207
/// `Some` if it's a locally defined resource.
208
pub fn defined_resource_index(&self, idx: ResourceIndex) -> Option<DefinedResourceIndex> {
209
let idx = idx
210
.as_u32()
211
.checked_sub(self.imported_resources.len() as u32)?;
212
Some(DefinedResourceIndex::from_u32(idx))
213
}
214
215
/// Converts a defined resource index to a component-local resource index
216
/// which includes all imports.
217
pub fn resource_index(&self, idx: DefinedResourceIndex) -> ResourceIndex {
218
ResourceIndex::from_u32(self.imported_resources.len() as u32 + idx.as_u32())
219
}
220
}
221
222
/// GlobalInitializer instructions to get processed when instantiating a
223
/// component.
224
///
225
/// The variants of this enum are processed during the instantiation phase of a
226
/// component in-order from front-to-back. These are otherwise emitted as a
227
/// component is parsed and read and translated.
228
//
229
// FIXME(#2639) if processing this list is ever a bottleneck we could
230
// theoretically use cranelift to compile an initialization function which
231
// performs all of these duties for us and skips the overhead of interpreting
232
// all of these instructions.
233
#[derive(Debug, Serialize, Deserialize)]
234
pub enum GlobalInitializer {
235
/// A core wasm module is being instantiated.
236
///
237
/// This will result in a new core wasm instance being created, which may
238
/// involve running the `start` function of the instance as well if it's
239
/// specified. This largely delegates to the same standard instantiation
240
/// process as the rest of the core wasm machinery already uses.
241
InstantiateModule(InstantiateModule),
242
243
/// A host function is being lowered, creating a core wasm function.
244
///
245
/// This initializer entry is intended to be used to fill out the
246
/// `VMComponentContext` and information about this lowering such as the
247
/// cranelift-compiled trampoline function pointer, the host function
248
/// pointer the trampoline calls, and the canonical ABI options.
249
LowerImport {
250
/// The index of the lowered function that's being created.
251
///
252
/// This is guaranteed to be the `n`th `LowerImport` instruction
253
/// if the index is `n`.
254
index: LoweredIndex,
255
256
/// The index of the imported host function that is being lowered.
257
///
258
/// It's guaranteed that this `RuntimeImportIndex` points to a function.
259
import: RuntimeImportIndex,
260
},
261
262
/// A core wasm linear memory is going to be saved into the
263
/// `VMComponentContext`.
264
///
265
/// This instruction indicates that a core wasm linear memory needs to be
266
/// extracted from the `export` and stored into the `VMComponentContext` at
267
/// the `index` specified. This lowering is then used in the future by
268
/// pointers from `CanonicalOptions`.
269
ExtractMemory(ExtractMemory),
270
271
/// Same as `ExtractMemory`, except it's extracting a function pointer to be
272
/// used as a `realloc` function.
273
ExtractRealloc(ExtractRealloc),
274
275
/// Same as `ExtractMemory`, except it's extracting a function pointer to be
276
/// used as an async `callback` function.
277
ExtractCallback(ExtractCallback),
278
279
/// Same as `ExtractMemory`, except it's extracting a function pointer to be
280
/// used as a `post-return` function.
281
ExtractPostReturn(ExtractPostReturn),
282
283
/// A core wasm table is going to be saved into the `VMComponentContext`.
284
///
285
/// This instruction indicates that s core wasm table needs to be extracted
286
/// from its `export` and stored into the `VMComponentContext` at the
287
/// `index` specified. During this extraction, we will also capture the
288
/// table's containing instance pointer to access the table at runtime. This
289
/// extraction is useful for `thread.spawn_indirect`.
290
ExtractTable(ExtractTable),
291
292
/// Declares a new defined resource within this component.
293
///
294
/// Contains information about the destructor, for example.
295
Resource(Resource),
296
}
297
298
/// Metadata for extraction of a memory; contains what's being extracted (the
299
/// memory at `export`) and where it's going (the `index` within a
300
/// `VMComponentContext`).
301
#[derive(Debug, Serialize, Deserialize)]
302
pub struct ExtractMemory {
303
/// The index of the memory being defined.
304
pub index: RuntimeMemoryIndex,
305
/// Where this memory is being extracted from.
306
pub export: CoreExport<MemoryIndex>,
307
}
308
309
/// Same as `ExtractMemory` but for the `realloc` canonical option.
310
#[derive(Debug, Serialize, Deserialize)]
311
pub struct ExtractRealloc {
312
/// The index of the realloc being defined.
313
pub index: RuntimeReallocIndex,
314
/// Where this realloc is being extracted from.
315
pub def: CoreDef,
316
}
317
318
/// Same as `ExtractMemory` but for the `callback` canonical option.
319
#[derive(Debug, Serialize, Deserialize)]
320
pub struct ExtractCallback {
321
/// The index of the callback being defined.
322
pub index: RuntimeCallbackIndex,
323
/// Where this callback is being extracted from.
324
pub def: CoreDef,
325
}
326
327
/// Same as `ExtractMemory` but for the `post-return` canonical option.
328
#[derive(Debug, Serialize, Deserialize)]
329
pub struct ExtractPostReturn {
330
/// The index of the post-return being defined.
331
pub index: RuntimePostReturnIndex,
332
/// Where this post-return is being extracted from.
333
pub def: CoreDef,
334
}
335
336
/// Metadata for extraction of a table.
337
#[derive(Debug, Serialize, Deserialize)]
338
pub struct ExtractTable {
339
/// The index of the table being defined in a `VMComponentContext`.
340
pub index: RuntimeTableIndex,
341
/// Where this table is being extracted from.
342
pub export: CoreExport<TableIndex>,
343
}
344
345
/// Different methods of instantiating a core wasm module.
346
#[derive(Debug, Serialize, Deserialize)]
347
pub enum InstantiateModule {
348
/// A module defined within this component is being instantiated.
349
///
350
/// Note that this is distinct from the case of imported modules because the
351
/// order of imports required is statically known and can be pre-calculated
352
/// to avoid string lookups related to names at runtime, represented by the
353
/// flat list of arguments here.
354
Static(StaticModuleIndex, Box<[CoreDef]>),
355
356
/// An imported module is being instantiated.
357
///
358
/// This is similar to `Upvar` but notably the imports are provided as a
359
/// two-level named map since import resolution order needs to happen at
360
/// runtime.
361
Import(
362
RuntimeImportIndex,
363
IndexMap<String, IndexMap<String, CoreDef>>,
364
),
365
}
366
367
/// Definition of a core wasm item and where it can come from within a
368
/// component.
369
///
370
/// Note that this is sort of a result of data-flow-like analysis on a component
371
/// during compile time of the component itself. References to core wasm items
372
/// are "compiled" to either referring to a previous instance or to some sort of
373
/// lowered host import.
374
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
375
pub enum CoreDef {
376
/// This item refers to an export of a previously instantiated core wasm
377
/// instance.
378
Export(CoreExport<EntityIndex>),
379
/// This is a reference to a wasm global which represents the
380
/// runtime-managed flags for a wasm instance.
381
InstanceFlags(RuntimeComponentInstanceIndex),
382
/// This is a reference to a Cranelift-generated trampoline which is
383
/// described in the `trampolines` array.
384
Trampoline(TrampolineIndex),
385
}
386
387
impl<T> From<CoreExport<T>> for CoreDef
388
where
389
EntityIndex: From<T>,
390
{
391
fn from(export: CoreExport<T>) -> CoreDef {
392
CoreDef::Export(export.map_index(|i| i.into()))
393
}
394
}
395
396
/// Identifier of an exported item from a core WebAssembly module instance.
397
///
398
/// Note that the `T` here is the index type for exports which can be
399
/// identified by index. The `T` is monomorphized with types like
400
/// [`EntityIndex`] or [`FuncIndex`].
401
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
402
pub struct CoreExport<T> {
403
/// The instance that this item is located within.
404
///
405
/// Note that this is intended to index the `instances` map within a
406
/// component. It's validated ahead of time that all instance pointers
407
/// refer only to previously-created instances.
408
pub instance: RuntimeInstanceIndex,
409
410
/// The item that this export is referencing, either by name or by index.
411
pub item: ExportItem<T>,
412
}
413
414
impl<T> CoreExport<T> {
415
/// Maps the index type `T` to another type `U` if this export item indeed
416
/// refers to an index `T`.
417
pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
418
CoreExport {
419
instance: self.instance,
420
item: match self.item {
421
ExportItem::Index(i) => ExportItem::Index(f(i)),
422
ExportItem::Name(s) => ExportItem::Name(s),
423
},
424
}
425
}
426
}
427
428
/// An index at which to find an item within a runtime instance.
429
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
430
pub enum ExportItem<T> {
431
/// An exact index that the target can be found at.
432
///
433
/// This is used where possible to avoid name lookups at runtime during the
434
/// instantiation process. This can only be used on instances where the
435
/// module was statically known at compile time, however.
436
Index(T),
437
438
/// An item which is identified by a name, so at runtime we need to
439
/// perform a name lookup to determine the index that the item is located
440
/// at.
441
///
442
/// This is used for instantiations of imported modules, for example, since
443
/// the precise shape of the module is not known.
444
Name(String),
445
}
446
447
/// Possible exports from a component.
448
#[derive(Debug, Clone, Serialize, Deserialize)]
449
pub enum Export {
450
/// A lifted function being exported which is an adaptation of a core wasm
451
/// function.
452
LiftedFunction {
453
/// The component function type of the function being created.
454
ty: TypeFuncIndex,
455
/// Which core WebAssembly export is being lifted.
456
func: CoreDef,
457
/// Any options, if present, associated with this lifting.
458
options: OptionsIndex,
459
},
460
/// A module defined within this component is exported.
461
ModuleStatic {
462
/// The type of this module
463
ty: TypeModuleIndex,
464
/// Which module this is referring to.
465
index: StaticModuleIndex,
466
},
467
/// A module imported into this component is exported.
468
ModuleImport {
469
/// Module type index
470
ty: TypeModuleIndex,
471
/// Module runtime import index
472
import: RuntimeImportIndex,
473
},
474
/// A nested instance is being exported which has recursively defined
475
/// `Export` items.
476
Instance {
477
/// Instance type index, if such is assigned
478
ty: TypeComponentInstanceIndex,
479
/// Instance export map
480
exports: NameMap<String, ExportIndex>,
481
},
482
/// An exported type from a component or instance, currently only
483
/// informational.
484
Type(TypeDef),
485
}
486
487
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
488
/// Data is stored in a linear memory.
489
pub struct LinearMemoryOptions {
490
/// The memory used by these options, if specified.
491
pub memory: Option<RuntimeMemoryIndex>,
492
/// The realloc function used by these options, if specified.
493
pub realloc: Option<RuntimeReallocIndex>,
494
}
495
496
/// The data model for objects that are not unboxed in locals.
497
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
498
pub enum CanonicalOptionsDataModel {
499
/// Data is stored in GC objects.
500
Gc {},
501
502
/// Data is stored in a linear memory.
503
LinearMemory(LinearMemoryOptions),
504
}
505
506
/// Canonical ABI options associated with a lifted or lowered function.
507
#[derive(Debug, Clone, Serialize, Deserialize)]
508
pub struct CanonicalOptions {
509
/// The component instance that this bundle was associated with.
510
pub instance: RuntimeComponentInstanceIndex,
511
512
/// The encoding used for strings.
513
pub string_encoding: StringEncoding,
514
515
/// The async callback function used by these options, if specified.
516
pub callback: Option<RuntimeCallbackIndex>,
517
518
/// The post-return function used by these options, if specified.
519
pub post_return: Option<RuntimePostReturnIndex>,
520
521
/// Whether to use the async ABI for lifting or lowering.
522
pub async_: bool,
523
524
/// The core function type that is being lifted from / lowered to.
525
pub core_type: ModuleInternedTypeIndex,
526
527
/// The data model (GC objects or linear memory) used with these canonical
528
/// options.
529
pub data_model: CanonicalOptionsDataModel,
530
}
531
532
/// Possible encodings of strings within the component model.
533
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
534
#[expect(missing_docs, reason = "self-describing variants")]
535
pub enum StringEncoding {
536
Utf8,
537
Utf16,
538
CompactUtf16,
539
}
540
541
impl StringEncoding {
542
/// Decodes the `u8` provided back into a `StringEncoding`, if it's valid.
543
pub fn from_u8(val: u8) -> Option<StringEncoding> {
544
if val == StringEncoding::Utf8 as u8 {
545
return Some(StringEncoding::Utf8);
546
}
547
if val == StringEncoding::Utf16 as u8 {
548
return Some(StringEncoding::Utf16);
549
}
550
if val == StringEncoding::CompactUtf16 as u8 {
551
return Some(StringEncoding::CompactUtf16);
552
}
553
None
554
}
555
}
556
557
/// Possible transcoding operations that must be provided by the host.
558
///
559
/// Note that each transcoding operation may have a unique signature depending
560
/// on the precise operation.
561
#[expect(missing_docs, reason = "self-describing variants")]
562
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
563
pub enum Transcode {
564
Copy(FixedEncoding),
565
Latin1ToUtf16,
566
Latin1ToUtf8,
567
Utf16ToCompactProbablyUtf16,
568
Utf16ToCompactUtf16,
569
Utf16ToLatin1,
570
Utf16ToUtf8,
571
Utf8ToCompactUtf16,
572
Utf8ToLatin1,
573
Utf8ToUtf16,
574
}
575
576
impl Transcode {
577
/// Get this transcoding's symbol fragment.
578
pub fn symbol_fragment(&self) -> &'static str {
579
match self {
580
Transcode::Copy(x) => match x {
581
FixedEncoding::Utf8 => "copy_utf8",
582
FixedEncoding::Utf16 => "copy_utf16",
583
FixedEncoding::Latin1 => "copy_latin1",
584
},
585
Transcode::Latin1ToUtf16 => "latin1_to_utf16",
586
Transcode::Latin1ToUtf8 => "latin1_to_utf8",
587
Transcode::Utf16ToCompactProbablyUtf16 => "utf16_to_compact_probably_utf16",
588
Transcode::Utf16ToCompactUtf16 => "utf16_to_compact_utf16",
589
Transcode::Utf16ToLatin1 => "utf16_to_latin1",
590
Transcode::Utf16ToUtf8 => "utf16_to_utf8",
591
Transcode::Utf8ToCompactUtf16 => "utf8_to_compact_utf16",
592
Transcode::Utf8ToLatin1 => "utf8_to_latin1",
593
Transcode::Utf8ToUtf16 => "utf8_to_utf16",
594
}
595
}
596
597
/// Returns a human-readable description for this transcoding operation.
598
pub fn desc(&self) -> &'static str {
599
match self {
600
Transcode::Copy(FixedEncoding::Utf8) => "utf8-to-utf8",
601
Transcode::Copy(FixedEncoding::Utf16) => "utf16-to-utf16",
602
Transcode::Copy(FixedEncoding::Latin1) => "latin1-to-latin1",
603
Transcode::Latin1ToUtf16 => "latin1-to-utf16",
604
Transcode::Latin1ToUtf8 => "latin1-to-utf8",
605
Transcode::Utf16ToCompactProbablyUtf16 => "utf16-to-compact-probably-utf16",
606
Transcode::Utf16ToCompactUtf16 => "utf16-to-compact-utf16",
607
Transcode::Utf16ToLatin1 => "utf16-to-latin1",
608
Transcode::Utf16ToUtf8 => "utf16-to-utf8",
609
Transcode::Utf8ToCompactUtf16 => "utf8-to-compact-utf16",
610
Transcode::Utf8ToLatin1 => "utf8-to-latin1",
611
Transcode::Utf8ToUtf16 => "utf8-to-utf16",
612
}
613
}
614
}
615
616
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
617
#[expect(missing_docs, reason = "self-describing variants")]
618
pub enum FixedEncoding {
619
Utf8,
620
Utf16,
621
Latin1,
622
}
623
624
impl FixedEncoding {
625
/// Returns the byte width of unit loads/stores for this encoding, for
626
/// example the unit length is multiplied by this return value to get the
627
/// byte width of a string.
628
pub fn width(&self) -> u8 {
629
match self {
630
FixedEncoding::Utf8 => 1,
631
FixedEncoding::Utf16 => 2,
632
FixedEncoding::Latin1 => 1,
633
}
634
}
635
}
636
637
/// Description of a new resource declared in a `GlobalInitializer::Resource`
638
/// variant.
639
///
640
/// This will have the effect of initializing runtime state for this resource,
641
/// namely the destructor is fetched and stored.
642
#[derive(Debug, Serialize, Deserialize)]
643
pub struct Resource {
644
/// The local index of the resource being defined.
645
pub index: DefinedResourceIndex,
646
/// Core wasm representation of this resource.
647
pub rep: WasmValType,
648
/// Optionally-specified destructor and where it comes from.
649
pub dtor: Option<CoreDef>,
650
/// Which component instance this resource logically belongs to.
651
pub instance: RuntimeComponentInstanceIndex,
652
}
653
654
/// A list of all possible trampolines that may be required to compile a
655
/// component completely.
656
///
657
/// These trampolines are used often as core wasm definitions and require
658
/// Cranelift support to generate these functions. Each trampoline serves a
659
/// different purpose for implementing bits and pieces of the component model.
660
///
661
/// All trampolines have a core wasm function signature associated with them
662
/// which is stored in the `Component::trampolines` array.
663
///
664
/// Note that this type does not implement `Serialize` or `Deserialize` and
665
/// that's intentional as this isn't stored in the final compilation artifact.
666
#[derive(Debug)]
667
pub enum Trampoline {
668
/// Description of a lowered import used in conjunction with
669
/// `GlobalInitializer::LowerImport`.
670
LowerImport {
671
/// The runtime lowering state that this trampoline will access.
672
index: LoweredIndex,
673
674
/// The type of the function that is being lowered, as perceived by the
675
/// component doing the lowering.
676
lower_ty: TypeFuncIndex,
677
678
/// The canonical ABI options used when lowering this function specified
679
/// in the original component.
680
options: OptionsIndex,
681
},
682
683
/// Information about a string transcoding function required by an adapter
684
/// module.
685
///
686
/// A transcoder is used when strings are passed between adapter modules,
687
/// optionally changing string encodings at the same time. The transcoder is
688
/// implemented in a few different layers:
689
///
690
/// * Each generated adapter module has some glue around invoking the
691
/// transcoder represented by this item. This involves bounds-checks and
692
/// handling `realloc` for example.
693
/// * Each transcoder gets a cranelift-generated trampoline which has the
694
/// appropriate signature for the adapter module in question. Existence of
695
/// this initializer indicates that this should be compiled by Cranelift.
696
/// * The cranelift-generated trampoline will invoke a "transcoder libcall"
697
/// which is implemented natively in Rust that has a signature independent
698
/// of memory64 configuration options for example.
699
Transcoder {
700
/// The transcoding operation being performed.
701
op: Transcode,
702
/// The linear memory that the string is being read from.
703
from: RuntimeMemoryIndex,
704
/// Whether or not the source linear memory is 64-bit or not.
705
from64: bool,
706
/// The linear memory that the string is being written to.
707
to: RuntimeMemoryIndex,
708
/// Whether or not the destination linear memory is 64-bit or not.
709
to64: bool,
710
},
711
712
/// A small adapter which simply traps, used for degenerate lift/lower
713
/// combinations.
714
AlwaysTrap,
715
716
/// A `resource.new` intrinsic which will inject a new resource into the
717
/// table specified.
718
ResourceNew(TypeResourceTableIndex),
719
720
/// Same as `ResourceNew`, but for the `resource.rep` intrinsic.
721
ResourceRep(TypeResourceTableIndex),
722
723
/// Same as `ResourceNew`, but for the `resource.drop` intrinsic.
724
ResourceDrop(TypeResourceTableIndex),
725
726
/// A `backpressure.set` intrinsic, which tells the host to enable or
727
/// disable backpressure for the caller's instance.
728
BackpressureSet {
729
/// The specific component instance which is calling the intrinsic.
730
instance: RuntimeComponentInstanceIndex,
731
},
732
733
/// A `task.return` intrinsic, which returns a result to the caller of a
734
/// lifted export function. This allows the callee to continue executing
735
/// after returning a result.
736
TaskReturn {
737
/// Tuple representing the result types this intrinsic accepts.
738
results: TypeTupleIndex,
739
740
/// The canonical ABI options specified for this intrinsic.
741
options: OptionsIndex,
742
},
743
744
/// A `task.cancel` intrinsic, which acknowledges a `CANCELLED` event
745
/// delivered to a guest task previously created by a call to an async
746
/// export.
747
TaskCancel {
748
/// The specific component instance which is calling the intrinsic.
749
instance: RuntimeComponentInstanceIndex,
750
},
751
752
/// A `waitable-set.new` intrinsic.
753
WaitableSetNew {
754
/// The specific component instance which is calling the intrinsic.
755
instance: RuntimeComponentInstanceIndex,
756
},
757
758
/// A `waitable-set.wait` intrinsic, which waits for at least one
759
/// outstanding async task/stream/future to make progress, returning the
760
/// first such event.
761
WaitableSetWait {
762
/// Configuration options for this intrinsic call.
763
options: OptionsIndex,
764
},
765
766
/// A `waitable-set.poll` intrinsic, which checks whether any outstanding
767
/// async task/stream/future has made progress. Unlike `task.wait`, this
768
/// does not block and may return nothing if no such event has occurred.
769
WaitableSetPoll {
770
/// Configuration options for this intrinsic call.
771
options: OptionsIndex,
772
},
773
774
/// A `waitable-set.drop` intrinsic.
775
WaitableSetDrop {
776
/// The specific component instance which is calling the intrinsic.
777
instance: RuntimeComponentInstanceIndex,
778
},
779
780
/// A `waitable.join` intrinsic.
781
WaitableJoin {
782
/// The specific component instance which is calling the intrinsic.
783
instance: RuntimeComponentInstanceIndex,
784
},
785
786
/// A `yield` intrinsic, which yields control to the host so that other
787
/// tasks are able to make progress, if any.
788
Yield {
789
/// If `true`, indicates the caller instance maybe reentered.
790
async_: bool,
791
},
792
793
/// A `subtask.drop` intrinsic to drop a specified task which has completed.
794
SubtaskDrop {
795
/// The specific component instance which is calling the intrinsic.
796
instance: RuntimeComponentInstanceIndex,
797
},
798
799
/// A `subtask.cancel` intrinsic to drop an in-progress task.
800
SubtaskCancel {
801
/// The specific component instance which is calling the intrinsic.
802
instance: RuntimeComponentInstanceIndex,
803
/// If `false`, block until cancellation completes rather than return
804
/// `BLOCKED`.
805
async_: bool,
806
},
807
808
/// A `stream.new` intrinsic to create a new `stream` handle of the
809
/// specified type.
810
StreamNew {
811
/// The table index for the specific `stream` type and caller instance.
812
ty: TypeStreamTableIndex,
813
},
814
815
/// A `stream.read` intrinsic to read from a `stream` of the specified type.
816
StreamRead {
817
/// The table index for the specific `stream` type and caller instance.
818
ty: TypeStreamTableIndex,
819
820
/// Any options (e.g. string encoding) to use when storing values to
821
/// memory.
822
options: OptionsIndex,
823
},
824
825
/// A `stream.write` intrinsic to write to a `stream` of the specified type.
826
StreamWrite {
827
/// The table index for the specific `stream` type and caller instance.
828
ty: TypeStreamTableIndex,
829
830
/// Any options (e.g. string encoding) to use when storing values to
831
/// memory.
832
options: OptionsIndex,
833
},
834
835
/// A `stream.cancel-read` intrinsic to cancel an in-progress read from a
836
/// `stream` of the specified type.
837
StreamCancelRead {
838
/// The table index for the specific `stream` type and caller instance.
839
ty: TypeStreamTableIndex,
840
/// If `false`, block until cancellation completes rather than return
841
/// `BLOCKED`.
842
async_: bool,
843
},
844
845
/// A `stream.cancel-write` intrinsic to cancel an in-progress write from a
846
/// `stream` of the specified type.
847
StreamCancelWrite {
848
/// The table index for the specific `stream` type and caller instance.
849
ty: TypeStreamTableIndex,
850
/// If `false`, block until cancellation completes rather than return
851
/// `BLOCKED`.
852
async_: bool,
853
},
854
855
/// A `stream.drop-readable` intrinsic to drop the readable end of a
856
/// `stream` of the specified type.
857
StreamDropReadable {
858
/// The table index for the specific `stream` type and caller instance.
859
ty: TypeStreamTableIndex,
860
},
861
862
/// A `stream.drop-writable` intrinsic to drop the writable end of a
863
/// `stream` of the specified type.
864
StreamDropWritable {
865
/// The table index for the specific `stream` type and caller instance.
866
ty: TypeStreamTableIndex,
867
},
868
869
/// A `future.new` intrinsic to create a new `future` handle of the
870
/// specified type.
871
FutureNew {
872
/// The table index for the specific `future` type and caller instance.
873
ty: TypeFutureTableIndex,
874
},
875
876
/// A `future.read` intrinsic to read from a `future` of the specified type.
877
FutureRead {
878
/// The table index for the specific `future` type and caller instance.
879
ty: TypeFutureTableIndex,
880
881
/// Any options (e.g. string encoding) to use when storing values to
882
/// memory.
883
options: OptionsIndex,
884
},
885
886
/// A `future.write` intrinsic to write to a `future` of the specified type.
887
FutureWrite {
888
/// The table index for the specific `future` type and caller instance.
889
ty: TypeFutureTableIndex,
890
891
/// Any options (e.g. string encoding) to use when storing values to
892
/// memory.
893
options: OptionsIndex,
894
},
895
896
/// A `future.cancel-read` intrinsic to cancel an in-progress read from a
897
/// `future` of the specified type.
898
FutureCancelRead {
899
/// The table index for the specific `future` type and caller instance.
900
ty: TypeFutureTableIndex,
901
/// If `false`, block until cancellation completes rather than return
902
/// `BLOCKED`.
903
async_: bool,
904
},
905
906
/// A `future.cancel-write` intrinsic to cancel an in-progress write from a
907
/// `future` of the specified type.
908
FutureCancelWrite {
909
/// The table index for the specific `future` type and caller instance.
910
ty: TypeFutureTableIndex,
911
/// If `false`, block until cancellation completes rather than return
912
/// `BLOCKED`.
913
async_: bool,
914
},
915
916
/// A `future.drop-readable` intrinsic to drop the readable end of a
917
/// `future` of the specified type.
918
FutureDropReadable {
919
/// The table index for the specific `future` type and caller instance.
920
ty: TypeFutureTableIndex,
921
},
922
923
/// A `future.drop-writable` intrinsic to drop the writable end of a
924
/// `future` of the specified type.
925
FutureDropWritable {
926
/// The table index for the specific `future` type and caller instance.
927
ty: TypeFutureTableIndex,
928
},
929
930
/// A `error-context.new` intrinsic to create a new `error-context` with a
931
/// specified debug message.
932
ErrorContextNew {
933
/// The table index for the `error-context` type in the caller instance.
934
ty: TypeComponentLocalErrorContextTableIndex,
935
/// String encoding, memory, etc. to use when loading debug message.
936
options: OptionsIndex,
937
},
938
939
/// A `error-context.debug-message` intrinsic to get the debug message for a
940
/// specified `error-context`.
941
///
942
/// Note that the debug message might not necessarily match what was passed
943
/// to `error.new`.
944
ErrorContextDebugMessage {
945
/// The table index for the `error-context` type in the caller instance.
946
ty: TypeComponentLocalErrorContextTableIndex,
947
/// String encoding, memory, etc. to use when storing debug message.
948
options: OptionsIndex,
949
},
950
951
/// A `error-context.drop` intrinsic to drop a specified `error-context`.
952
ErrorContextDrop {
953
/// The table index for the `error-context` type in the caller instance.
954
ty: TypeComponentLocalErrorContextTableIndex,
955
},
956
957
/// An intrinsic used by FACT-generated modules which will transfer an owned
958
/// resource from one table to another. Used in component-to-component
959
/// adapter trampolines.
960
ResourceTransferOwn,
961
962
/// Same as `ResourceTransferOwn` but for borrows.
963
ResourceTransferBorrow,
964
965
/// An intrinsic used by FACT-generated modules which indicates that a call
966
/// is being entered and resource-related metadata needs to be configured.
967
///
968
/// Note that this is currently only invoked when borrowed resources are
969
/// detected, otherwise this is "optimized out".
970
ResourceEnterCall,
971
972
/// Same as `ResourceEnterCall` except for when exiting a call.
973
ResourceExitCall,
974
975
/// An intrinsic used by FACT-generated modules to prepare a call involving
976
/// an async-lowered import and/or an async-lifted export.
977
PrepareCall {
978
/// The memory used to verify that the memory specified for the
979
/// `task.return` that is called at runtime matches the one specified in
980
/// the lifted export.
981
memory: Option<RuntimeMemoryIndex>,
982
},
983
984
/// An intrinsic used by FACT-generated modules to start a call involving a
985
/// sync-lowered import and async-lifted export.
986
SyncStartCall {
987
/// The callee's callback function, if any.
988
callback: Option<RuntimeCallbackIndex>,
989
},
990
991
/// An intrinsic used by FACT-generated modules to start a call involving
992
/// an async-lowered import function.
993
///
994
/// Note that `AsyncPrepareCall` and `AsyncStartCall` could theoretically be
995
/// combined into a single `AsyncCall` intrinsic, but we separate them to
996
/// allow the FACT-generated module to optionally call the callee directly
997
/// without an intermediate host stack frame.
998
AsyncStartCall {
999
/// The callee's callback, if any.
1000
callback: Option<RuntimeCallbackIndex>,
1001
1002
/// The callee's post-return function, if any.
1003
post_return: Option<RuntimePostReturnIndex>,
1004
},
1005
1006
/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1007
/// ownership of a `future`.
1008
///
1009
/// Transferring a `future` can either mean giving away the readable end
1010
/// while retaining the writable end or only the former, depending on the
1011
/// ownership status of the `future`.
1012
FutureTransfer,
1013
1014
/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1015
/// ownership of a `stream`.
1016
///
1017
/// Transferring a `stream` can either mean giving away the readable end
1018
/// while retaining the writable end or only the former, depending on the
1019
/// ownership status of the `stream`.
1020
StreamTransfer,
1021
1022
/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1023
/// ownership of an `error-context`.
1024
///
1025
/// Unlike futures, streams, and resource handles, `error-context` handles
1026
/// are reference counted, meaning that sharing the handle with another
1027
/// component does not invalidate the handle in the original component.
1028
ErrorContextTransfer,
1029
1030
/// Intrinsic used to implement the `context.get` component model builtin.
1031
///
1032
/// The payload here represents that this is accessing the Nth slot of local
1033
/// storage.
1034
ContextGet(u32),
1035
1036
/// Intrinsic used to implement the `context.set` component model builtin.
1037
///
1038
/// The payload here represents that this is accessing the Nth slot of local
1039
/// storage.
1040
ContextSet(u32),
1041
}
1042
1043
impl Trampoline {
1044
/// Returns the name to use for the symbol of this trampoline in the final
1045
/// compiled artifact
1046
pub fn symbol_name(&self) -> String {
1047
use Trampoline::*;
1048
match self {
1049
LowerImport { index, .. } => {
1050
format!("component-lower-import[{}]", index.as_u32())
1051
}
1052
Transcoder {
1053
op, from64, to64, ..
1054
} => {
1055
let op = op.symbol_fragment();
1056
let from = if *from64 { "64" } else { "32" };
1057
let to = if *to64 { "64" } else { "32" };
1058
format!("component-transcode-{op}-m{from}-m{to}")
1059
}
1060
AlwaysTrap => format!("component-always-trap"),
1061
ResourceNew(i) => format!("component-resource-new[{}]", i.as_u32()),
1062
ResourceRep(i) => format!("component-resource-rep[{}]", i.as_u32()),
1063
ResourceDrop(i) => format!("component-resource-drop[{}]", i.as_u32()),
1064
BackpressureSet { .. } => format!("backpressure-set"),
1065
TaskReturn { .. } => format!("task-return"),
1066
TaskCancel { .. } => format!("task-cancel"),
1067
WaitableSetNew { .. } => format!("waitable-set-new"),
1068
WaitableSetWait { .. } => format!("waitable-set-wait"),
1069
WaitableSetPoll { .. } => format!("waitable-set-poll"),
1070
WaitableSetDrop { .. } => format!("waitable-set-drop"),
1071
WaitableJoin { .. } => format!("waitable-join"),
1072
Yield { .. } => format!("yield"),
1073
SubtaskDrop { .. } => format!("subtask-drop"),
1074
SubtaskCancel { .. } => format!("subtask-cancel"),
1075
StreamNew { .. } => format!("stream-new"),
1076
StreamRead { .. } => format!("stream-read"),
1077
StreamWrite { .. } => format!("stream-write"),
1078
StreamCancelRead { .. } => format!("stream-cancel-read"),
1079
StreamCancelWrite { .. } => format!("stream-cancel-write"),
1080
StreamDropReadable { .. } => format!("stream-drop-readable"),
1081
StreamDropWritable { .. } => format!("stream-drop-writable"),
1082
FutureNew { .. } => format!("future-new"),
1083
FutureRead { .. } => format!("future-read"),
1084
FutureWrite { .. } => format!("future-write"),
1085
FutureCancelRead { .. } => format!("future-cancel-read"),
1086
FutureCancelWrite { .. } => format!("future-cancel-write"),
1087
FutureDropReadable { .. } => format!("future-drop-readable"),
1088
FutureDropWritable { .. } => format!("future-drop-writable"),
1089
ErrorContextNew { .. } => format!("error-context-new"),
1090
ErrorContextDebugMessage { .. } => format!("error-context-debug-message"),
1091
ErrorContextDrop { .. } => format!("error-context-drop"),
1092
ResourceTransferOwn => format!("component-resource-transfer-own"),
1093
ResourceTransferBorrow => format!("component-resource-transfer-borrow"),
1094
ResourceEnterCall => format!("component-resource-enter-call"),
1095
ResourceExitCall => format!("component-resource-exit-call"),
1096
PrepareCall { .. } => format!("component-prepare-call"),
1097
SyncStartCall { .. } => format!("component-sync-start-call"),
1098
AsyncStartCall { .. } => format!("component-async-start-call"),
1099
FutureTransfer => format!("future-transfer"),
1100
StreamTransfer => format!("stream-transfer"),
1101
ErrorContextTransfer => format!("error-context-transfer"),
1102
ContextGet(_) => format!("context-get"),
1103
ContextSet(_) => format!("context-set"),
1104
}
1105
}
1106
}
1107
1108