Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/component/translate.rs
3073 views
1
use crate::Abi;
2
use crate::component::dfg::AbstractInstantiations;
3
use crate::component::*;
4
use crate::prelude::*;
5
use crate::{
6
EngineOrModuleTypeIndex, EntityIndex, FuncKey, ModuleEnvironment, ModuleInternedTypeIndex,
7
ModuleTranslation, ModuleTypesBuilder, PrimaryMap, ScopeVec, TagIndex, Tunables, TypeConvert,
8
WasmHeapType, WasmResult, WasmValType,
9
};
10
use core::str::FromStr;
11
use cranelift_entity::SecondaryMap;
12
use cranelift_entity::packed_option::PackedOption;
13
use indexmap::IndexMap;
14
use std::collections::HashMap;
15
use std::mem;
16
use wasmparser::component_types::{
17
AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType,
18
ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType,
19
};
20
use wasmparser::types::Types;
21
use wasmparser::{Chunk, ComponentImportName, Encoding, Parser, Payload, Validator};
22
23
mod adapt;
24
pub use self::adapt::*;
25
mod inline;
26
27
/// Structure used to translate a component and parse it.
28
pub struct Translator<'a, 'data> {
29
/// The current component being translated.
30
///
31
/// This will get swapped out as translation traverses the body of a
32
/// component and a sub-component is entered or left.
33
result: Translation<'data>,
34
35
/// Current state of parsing a binary component. Note that like `result`
36
/// this will change as the component is traversed.
37
parser: Parser,
38
39
/// Stack of lexical scopes that are in-progress but not finished yet.
40
///
41
/// This is pushed to whenever a component is entered and popped from
42
/// whenever a component is left. Each lexical scope also contains
43
/// information about the variables that it is currently required to close
44
/// over which is threaded into the current in-progress translation of
45
/// the sub-component which pushed a scope here.
46
lexical_scopes: Vec<LexicalScope<'data>>,
47
48
/// The validator in use to verify that the raw input binary is a valid
49
/// component.
50
validator: &'a mut Validator,
51
52
/// Type information shared for the entire component.
53
///
54
/// This builder is also used for all core wasm modules found to intern
55
/// signatures across all modules.
56
types: PreInliningComponentTypes<'a>,
57
58
/// The compiler configuration provided by the embedder.
59
tunables: &'a Tunables,
60
61
/// Auxiliary location to push generated adapter modules onto.
62
scope_vec: &'data ScopeVec<u8>,
63
64
/// Completely translated core wasm modules that have been found so far.
65
///
66
/// Note that this translation only involves learning about type
67
/// information and functions are not actually compiled here.
68
static_modules: PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
69
70
/// Completely translated components that have been found so far.
71
///
72
/// As frames are popped from `lexical_scopes` their completed component
73
/// will be pushed onto this list.
74
static_components: PrimaryMap<StaticComponentIndex, Translation<'data>>,
75
76
/// The top-level import name for Wasmtime's unsafe intrinsics, if any.
77
unsafe_intrinsics_import: Option<&'a str>,
78
}
79
80
/// Representation of the syntactic scope of a component meaning where it is
81
/// and what its state is at in the binary format.
82
///
83
/// These scopes are pushed and popped when a sub-component starts being
84
/// parsed and finishes being parsed. The main purpose of this frame is to
85
/// have a `ClosedOverVars` field which encapsulates data that is inherited
86
/// from the scope specified into the component being translated just beneath
87
/// it.
88
///
89
/// This structure exists to implement outer aliases to components and modules.
90
/// When a component or module is closed over then that means it needs to be
91
/// inherited in a sense to the component which actually had the alias. This is
92
/// achieved with a deceptively simple scheme where each parent of the
93
/// component with the alias will inherit the component from the desired
94
/// location.
95
///
96
/// For example with a component structure that looks like:
97
///
98
/// ```wasm
99
/// (component $A
100
/// (core module $M)
101
/// (component $B
102
/// (component $C
103
/// (alias outer $A $M (core module))
104
/// )
105
/// )
106
/// )
107
/// ```
108
///
109
/// here the `C` component is closing over `M` located in the root component
110
/// `A`. When `C` is being translated the `lexical_scopes` field will look like
111
/// `[A, B]`. When the alias is encountered (for module index 0) this will
112
/// place a `ClosedOverModule::Local(0)` entry into the `closure_args` field of
113
/// `A`'s frame. This will in turn give a `ModuleUpvarIndex` which is then
114
/// inserted into `closure_args` in `B`'s frame. This produces yet another
115
/// `ModuleUpvarIndex` which is finally inserted into `C`'s module index space
116
/// via `LocalInitializer::AliasModuleUpvar` with the last index.
117
///
118
/// All of these upvar indices and such are interpreted in the "inline" phase
119
/// of compilation and not at runtime. This means that when `A` is being
120
/// instantiated one of its initializers will be
121
/// `LocalInitializer::ComponentStatic`. This starts to create `B` and the
122
/// variables captured for `B` are listed as local module 0, or `M`. This list
123
/// is then preserved in the definition of the component `B` and later reused
124
/// by `C` again to finally get access to the closed over component.
125
///
126
/// Effectively the scopes are managed hierarchically where a reference to an
127
/// outer variable automatically injects references into all parents up to
128
/// where the reference is. This variable scopes are the processed during
129
/// inlining where a component definition is a reference to the static
130
/// component information (`Translation`) plus closed over variables
131
/// (`ComponentClosure` during inlining).
132
struct LexicalScope<'data> {
133
/// Current state of translating the `translation` below.
134
parser: Parser,
135
/// Current state of the component's translation as found so far.
136
translation: Translation<'data>,
137
/// List of captures that `translation` will need to process to create the
138
/// sub-component which is directly beneath this lexical scope.
139
closure_args: ClosedOverVars,
140
}
141
142
/// A "local" translation of a component.
143
///
144
/// This structure is used as a sort of in-progress translation of a component.
145
/// This is not `Component` which is the final form as consumed by Wasmtime
146
/// at runtime. Instead this is a fairly simple representation of a component
147
/// where almost everything is ordered as a list of initializers. The binary
148
/// format is translated to a list of initializers here which is later processed
149
/// during "inlining" to produce a final component with the final set of
150
/// initializers.
151
#[derive(Default)]
152
struct Translation<'data> {
153
/// Instructions which form this component.
154
///
155
/// There is one initializer for all members of each index space, and all
156
/// index spaces are incrementally built here as the initializer list is
157
/// processed.
158
initializers: Vec<LocalInitializer<'data>>,
159
160
/// The list of exports from this component, as pairs of names and an
161
/// index into an index space of what's being exported.
162
exports: IndexMap<&'data str, ComponentItem>,
163
164
/// Type information produced by `wasmparser` for this component.
165
///
166
/// This type information is available after the translation of the entire
167
/// component has finished, e.g. for the `inline` pass, but beforehand this
168
/// is set to `None`.
169
types: Option<Types>,
170
}
171
172
// NB: the type information contained in `LocalInitializer` should always point
173
// to `wasmparser`'s type information, not Wasmtime's. Component types cannot be
174
// fully determined due to resources until instantiations are known which is
175
// tracked during the inlining phase. This means that all type information below
176
// is straight from `wasmparser`'s passes.
177
enum LocalInitializer<'data> {
178
// imports
179
Import(ComponentImportName<'data>, ComponentEntityType),
180
181
// An import of an intrinsic for compile-time builtins.
182
IntrinsicsImport,
183
184
// canonical function sections
185
Lower {
186
func: ComponentFuncIndex,
187
lower_ty: ComponentFuncTypeId,
188
options: LocalCanonicalOptions,
189
},
190
Lift(ComponentFuncTypeId, FuncIndex, LocalCanonicalOptions),
191
192
// resources
193
Resource(AliasableResourceId, WasmValType, Option<FuncIndex>),
194
ResourceNew(AliasableResourceId, ModuleInternedTypeIndex),
195
ResourceRep(AliasableResourceId, ModuleInternedTypeIndex),
196
ResourceDrop(AliasableResourceId, ModuleInternedTypeIndex),
197
198
BackpressureInc {
199
func: ModuleInternedTypeIndex,
200
},
201
BackpressureDec {
202
func: ModuleInternedTypeIndex,
203
},
204
TaskReturn {
205
result: Option<ComponentValType>,
206
options: LocalCanonicalOptions,
207
},
208
TaskCancel {
209
func: ModuleInternedTypeIndex,
210
},
211
WaitableSetNew {
212
func: ModuleInternedTypeIndex,
213
},
214
WaitableSetWait {
215
options: LocalCanonicalOptions,
216
},
217
WaitableSetPoll {
218
options: LocalCanonicalOptions,
219
},
220
WaitableSetDrop {
221
func: ModuleInternedTypeIndex,
222
},
223
WaitableJoin {
224
func: ModuleInternedTypeIndex,
225
},
226
ThreadYield {
227
func: ModuleInternedTypeIndex,
228
cancellable: bool,
229
},
230
SubtaskDrop {
231
func: ModuleInternedTypeIndex,
232
},
233
SubtaskCancel {
234
func: ModuleInternedTypeIndex,
235
async_: bool,
236
},
237
StreamNew {
238
ty: ComponentDefinedTypeId,
239
func: ModuleInternedTypeIndex,
240
},
241
StreamRead {
242
ty: ComponentDefinedTypeId,
243
options: LocalCanonicalOptions,
244
},
245
StreamWrite {
246
ty: ComponentDefinedTypeId,
247
options: LocalCanonicalOptions,
248
},
249
StreamCancelRead {
250
ty: ComponentDefinedTypeId,
251
func: ModuleInternedTypeIndex,
252
async_: bool,
253
},
254
StreamCancelWrite {
255
ty: ComponentDefinedTypeId,
256
func: ModuleInternedTypeIndex,
257
async_: bool,
258
},
259
StreamDropReadable {
260
ty: ComponentDefinedTypeId,
261
func: ModuleInternedTypeIndex,
262
},
263
StreamDropWritable {
264
ty: ComponentDefinedTypeId,
265
func: ModuleInternedTypeIndex,
266
},
267
FutureNew {
268
ty: ComponentDefinedTypeId,
269
func: ModuleInternedTypeIndex,
270
},
271
FutureRead {
272
ty: ComponentDefinedTypeId,
273
options: LocalCanonicalOptions,
274
},
275
FutureWrite {
276
ty: ComponentDefinedTypeId,
277
options: LocalCanonicalOptions,
278
},
279
FutureCancelRead {
280
ty: ComponentDefinedTypeId,
281
func: ModuleInternedTypeIndex,
282
async_: bool,
283
},
284
FutureCancelWrite {
285
ty: ComponentDefinedTypeId,
286
func: ModuleInternedTypeIndex,
287
async_: bool,
288
},
289
FutureDropReadable {
290
ty: ComponentDefinedTypeId,
291
func: ModuleInternedTypeIndex,
292
},
293
FutureDropWritable {
294
ty: ComponentDefinedTypeId,
295
func: ModuleInternedTypeIndex,
296
},
297
ErrorContextNew {
298
options: LocalCanonicalOptions,
299
},
300
ErrorContextDebugMessage {
301
options: LocalCanonicalOptions,
302
},
303
ErrorContextDrop {
304
func: ModuleInternedTypeIndex,
305
},
306
ContextGet {
307
func: ModuleInternedTypeIndex,
308
i: u32,
309
},
310
ContextSet {
311
func: ModuleInternedTypeIndex,
312
i: u32,
313
},
314
ThreadIndex {
315
func: ModuleInternedTypeIndex,
316
},
317
ThreadNewIndirect {
318
func: ModuleInternedTypeIndex,
319
start_func_ty: ComponentTypeIndex,
320
start_func_table_index: TableIndex,
321
},
322
ThreadSwitchTo {
323
func: ModuleInternedTypeIndex,
324
cancellable: bool,
325
},
326
ThreadSuspend {
327
func: ModuleInternedTypeIndex,
328
cancellable: bool,
329
},
330
ThreadResumeLater {
331
func: ModuleInternedTypeIndex,
332
},
333
ThreadYieldTo {
334
func: ModuleInternedTypeIndex,
335
cancellable: bool,
336
},
337
338
// core wasm modules
339
ModuleStatic(StaticModuleIndex, ComponentCoreModuleTypeId),
340
341
// core wasm module instances
342
ModuleInstantiate(ModuleIndex, HashMap<&'data str, ModuleInstanceIndex>),
343
ModuleSynthetic(HashMap<&'data str, EntityIndex>),
344
345
// components
346
ComponentStatic(StaticComponentIndex, ClosedOverVars),
347
348
// component instances
349
ComponentInstantiate(
350
ComponentIndex,
351
HashMap<&'data str, ComponentItem>,
352
ComponentInstanceTypeId,
353
),
354
ComponentSynthetic(HashMap<&'data str, ComponentItem>, ComponentInstanceTypeId),
355
356
// alias section
357
AliasExportFunc(ModuleInstanceIndex, &'data str),
358
AliasExportTable(ModuleInstanceIndex, &'data str),
359
AliasExportGlobal(ModuleInstanceIndex, &'data str),
360
AliasExportMemory(ModuleInstanceIndex, &'data str),
361
AliasExportTag(ModuleInstanceIndex, &'data str),
362
AliasComponentExport(ComponentInstanceIndex, &'data str),
363
AliasModule(ClosedOverModule),
364
AliasComponent(ClosedOverComponent),
365
366
// export section
367
Export(ComponentItem),
368
}
369
370
/// The "closure environment" of components themselves.
371
///
372
/// For more information see `LexicalScope`.
373
#[derive(Default)]
374
struct ClosedOverVars {
375
components: PrimaryMap<ComponentUpvarIndex, ClosedOverComponent>,
376
modules: PrimaryMap<ModuleUpvarIndex, ClosedOverModule>,
377
}
378
379
/// Description how a component is closed over when the closure variables for
380
/// a component are being created.
381
///
382
/// For more information see `LexicalScope`.
383
enum ClosedOverComponent {
384
/// A closed over component is coming from the local component's index
385
/// space, meaning a previously defined component is being captured.
386
Local(ComponentIndex),
387
/// A closed over component is coming from our own component's list of
388
/// upvars. This list was passed to us by our enclosing component, which
389
/// will eventually have bottomed out in closing over a `Local` component
390
/// index for some parent component.
391
Upvar(ComponentUpvarIndex),
392
}
393
394
/// Same as `ClosedOverComponent`, but for modules.
395
enum ClosedOverModule {
396
Local(ModuleIndex),
397
Upvar(ModuleUpvarIndex),
398
}
399
400
/// The data model for objects that are not unboxed in locals.
401
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
402
pub enum LocalDataModel {
403
/// Data is stored in GC objects.
404
Gc {},
405
406
/// Data is stored in a linear memory.
407
LinearMemory {
408
/// An optional memory definition supplied.
409
memory: Option<MemoryIndex>,
410
/// An optional definition of `realloc` to used.
411
realloc: Option<FuncIndex>,
412
},
413
}
414
415
/// Representation of canonical ABI options.
416
struct LocalCanonicalOptions {
417
string_encoding: StringEncoding,
418
post_return: Option<FuncIndex>,
419
async_: bool,
420
cancellable: bool,
421
callback: Option<FuncIndex>,
422
/// The type index of the core GC types signature.
423
core_type: ModuleInternedTypeIndex,
424
data_model: LocalDataModel,
425
}
426
427
enum Action {
428
KeepGoing,
429
Skip(usize),
430
Done,
431
}
432
433
impl<'a, 'data> Translator<'a, 'data> {
434
/// Creates a new translation state ready to translate a component.
435
pub fn new(
436
tunables: &'a Tunables,
437
validator: &'a mut Validator,
438
types: &'a mut ComponentTypesBuilder,
439
scope_vec: &'data ScopeVec<u8>,
440
) -> Self {
441
let mut parser = Parser::new(0);
442
parser.set_features(*validator.features());
443
Self {
444
result: Translation::default(),
445
tunables,
446
validator,
447
types: PreInliningComponentTypes::new(types),
448
parser,
449
lexical_scopes: Vec::new(),
450
static_components: Default::default(),
451
static_modules: Default::default(),
452
scope_vec,
453
unsafe_intrinsics_import: None,
454
}
455
}
456
457
/// Expose Wasmtime's unsafe intrinsics under the given top-level import
458
/// name.
459
pub fn expose_unsafe_intrinsics(&mut self, name: &'a str) -> &mut Self {
460
assert!(self.unsafe_intrinsics_import.is_none());
461
self.unsafe_intrinsics_import = Some(name);
462
self
463
}
464
465
/// Translates the binary `component`.
466
///
467
/// This is the workhorse of compilation which will parse all of
468
/// `component` and create type information for Wasmtime and such. The
469
/// `component` does not have to be valid and it will be validated during
470
/// compilation.
471
///
472
/// The result of this function is a tuple of the final component's
473
/// description plus a list of core wasm modules found within the
474
/// component. The component's description actually erases internal
475
/// components, instances, etc, as much as it can. Instead `Component`
476
/// retains a flat list of initializers (no nesting) which was created
477
/// as part of compilation from the nested structure of the original
478
/// component.
479
///
480
/// The list of core wasm modules found is provided to allow compiling
481
/// modules externally in parallel. Additionally initializers in
482
/// `Component` may refer to the modules in the map returned by index.
483
///
484
/// # Errors
485
///
486
/// This function will return an error if the `component` provided is
487
/// invalid.
488
pub fn translate(
489
mut self,
490
component: &'data [u8],
491
) -> Result<(
492
ComponentTranslation,
493
PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
494
)> {
495
// First up wasmparser is used to actually perform the translation and
496
// validation of this component. This will produce a list of core wasm
497
// modules in addition to components which are found during the
498
// translation process. When doing this only a `Translation` is created
499
// which is a simple representation of a component.
500
let mut remaining = component;
501
loop {
502
let payload = match self.parser.parse(remaining, true)? {
503
Chunk::Parsed { payload, consumed } => {
504
remaining = &remaining[consumed..];
505
payload
506
}
507
Chunk::NeedMoreData(_) => unreachable!(),
508
};
509
510
match self.translate_payload(payload, component)? {
511
Action::KeepGoing => {}
512
Action::Skip(n) => remaining = &remaining[n..],
513
Action::Done => break,
514
}
515
}
516
assert!(remaining.is_empty());
517
assert!(self.lexical_scopes.is_empty());
518
519
// ... after translation initially finishes the next pass is performed
520
// which we're calling "inlining". This will "instantiate" the root
521
// component, following nested component instantiations, creating a
522
// global list of initializers along the way. This phase uses the simple
523
// initializers in each component to track dataflow of host imports and
524
// internal references to items throughout a component at compile-time.
525
// The produce initializers in the final `Component` are intended to be
526
// much simpler than the original component and more efficient for
527
// Wasmtime to process at runtime as well (e.g. no string lookups as
528
// most everything is done through indices instead).
529
let mut component = inline::run(
530
self.types.types_mut_for_inlining(),
531
&self.result,
532
&self.static_modules,
533
&self.static_components,
534
)?;
535
536
self.partition_adapter_modules(&mut component);
537
538
let translation =
539
component.finish(self.types.types_mut_for_inlining(), self.result.types_ref())?;
540
541
self.analyze_function_imports(&translation);
542
543
Ok((translation, self.static_modules))
544
}
545
546
fn analyze_function_imports(&mut self, translation: &ComponentTranslation) {
547
// First, abstract interpret the initializers to create a map from each
548
// static module to its abstract set of instantiations.
549
let mut instantiations = SecondaryMap::<StaticModuleIndex, AbstractInstantiations>::new();
550
let mut instance_to_module =
551
PrimaryMap::<RuntimeInstanceIndex, PackedOption<StaticModuleIndex>>::new();
552
for init in &translation.component.initializers {
553
match init {
554
GlobalInitializer::InstantiateModule(instantiation, _) => match instantiation {
555
InstantiateModule::Static(module, args) => {
556
instantiations[*module].join(AbstractInstantiations::One(&*args));
557
instance_to_module.push(Some(*module).into());
558
}
559
_ => {
560
instance_to_module.push(None.into());
561
}
562
},
563
_ => continue,
564
}
565
}
566
567
// Second, make sure to mark exported modules as instantiated many
568
// times, since they could be linked with who-knows-what at runtime.
569
for item in translation.component.export_items.values() {
570
if let Export::ModuleStatic { index, .. } = item {
571
instantiations[*index].join(AbstractInstantiations::Many)
572
}
573
}
574
575
// Finally, iterate over our instantiations and record statically-known
576
// function imports so that they can get translated into direct calls
577
// (and eventually get inlined) rather than indirect calls through the
578
// imports table.
579
for (module, instantiations) in instantiations.iter() {
580
let args = match instantiations {
581
dfg::AbstractInstantiations::Many | dfg::AbstractInstantiations::None => continue,
582
dfg::AbstractInstantiations::One(args) => args,
583
};
584
585
let mut imported_func_counter = 0_u32;
586
for (i, arg) in args.iter().enumerate() {
587
// Only consider function imports.
588
let (_, _, crate::types::EntityType::Function(_)) =
589
self.static_modules[module].module.import(i).unwrap()
590
else {
591
continue;
592
};
593
594
let imported_func = FuncIndex::from_u32(imported_func_counter);
595
imported_func_counter += 1;
596
debug_assert!(
597
self.static_modules[module]
598
.module
599
.defined_func_index(imported_func)
600
.is_none()
601
);
602
603
let known_func = match arg {
604
CoreDef::InstanceFlags(_) => unreachable!("instance flags are not a function"),
605
CoreDef::TaskMayBlock => unreachable!("task_may_block is not a function"),
606
607
// We could in theory inline these trampolines, so it could
608
// potentially make sense to record that we know this
609
// imported function is this particular trampoline. However,
610
// everything else is based around (module,
611
// defined-function) pairs and these trampolines don't fit
612
// that paradigm. Also, inlining trampolines gets really
613
// tricky when we consider the stack pointer, frame pointer,
614
// and return address note-taking that they do for the
615
// purposes of stack walking. We could, with enough effort,
616
// turn them into direct calls even though we probably
617
// wouldn't ever inline them, but it just doesn't seem worth
618
// the effort.
619
CoreDef::Trampoline(_) => continue,
620
621
// This import is a compile-time builtin intrinsic, we
622
// should inline its implementation during function
623
// translation.
624
CoreDef::UnsafeIntrinsic(i) => FuncKey::UnsafeIntrinsic(Abi::Wasm, *i),
625
626
// This imported function is an export from another
627
// instance, a perfect candidate for becoming an inlinable
628
// direct call!
629
CoreDef::Export(export) => {
630
let Some(arg_module) = &instance_to_module[export.instance].expand() else {
631
// Instance of a dynamic module that is not part of
632
// this component, not a statically-known module
633
// inside this component. We have to do an indirect
634
// call.
635
continue;
636
};
637
638
let ExportItem::Index(EntityIndex::Function(arg_func)) = &export.item
639
else {
640
unreachable!("function imports must be functions")
641
};
642
643
let Some(arg_module_def_func) = self.static_modules[*arg_module]
644
.module
645
.defined_func_index(*arg_func)
646
else {
647
// TODO: we should ideally follow re-export chains
648
// to bottom out the instantiation argument in
649
// either a definition or an import at the root
650
// component boundary. In practice, this pattern is
651
// rare, so following these chains is left for the
652
// Future.
653
continue;
654
};
655
656
FuncKey::DefinedWasmFunction(*arg_module, arg_module_def_func)
657
}
658
};
659
660
assert!(
661
self.static_modules[module].known_imported_functions[imported_func].is_none()
662
);
663
self.static_modules[module].known_imported_functions[imported_func] =
664
Some(known_func);
665
}
666
}
667
}
668
669
fn translate_payload(
670
&mut self,
671
payload: Payload<'data>,
672
component: &'data [u8],
673
) -> Result<Action> {
674
match payload {
675
Payload::Version {
676
num,
677
encoding,
678
range,
679
} => {
680
self.validator.version(num, encoding, &range)?;
681
682
match encoding {
683
Encoding::Component => {}
684
Encoding::Module => {
685
bail!("attempted to parse a wasm module with a component parser");
686
}
687
}
688
}
689
690
Payload::End(offset) => {
691
assert!(self.result.types.is_none());
692
self.result.types = Some(self.validator.end(offset)?);
693
694
// Exit the current lexical scope. If there is no parent (no
695
// frame currently on the stack) then translation is finished.
696
// Otherwise that means that a nested component has been
697
// completed and is recorded as such.
698
let LexicalScope {
699
parser,
700
translation,
701
closure_args,
702
} = match self.lexical_scopes.pop() {
703
Some(frame) => frame,
704
None => return Ok(Action::Done),
705
};
706
self.parser = parser;
707
let component = mem::replace(&mut self.result, translation);
708
let static_idx = self.static_components.push(component);
709
self.result
710
.initializers
711
.push(LocalInitializer::ComponentStatic(static_idx, closure_args));
712
}
713
714
// When we see a type section the types are validated and then
715
// translated into Wasmtime's representation. Each active type
716
// definition is recorded in the `ComponentTypesBuilder` tables, or
717
// this component's active scope.
718
//
719
// Note that the push/pop of the component types scope happens above
720
// in `Version` and `End` since multiple type sections can appear
721
// within a component.
722
Payload::ComponentTypeSection(s) => {
723
let mut component_type_index =
724
self.validator.types(0).unwrap().component_type_count();
725
self.validator.component_type_section(&s)?;
726
727
// Look for resource types and if a local resource is defined
728
// then an initializer is added to define that resource type and
729
// reference its destructor.
730
let types = self.validator.types(0).unwrap();
731
for ty in s {
732
match ty? {
733
wasmparser::ComponentType::Resource { rep, dtor } => {
734
let rep = self.types.convert_valtype(rep)?;
735
let id = types
736
.component_any_type_at(component_type_index)
737
.unwrap_resource();
738
let dtor = dtor.map(FuncIndex::from_u32);
739
self.result
740
.initializers
741
.push(LocalInitializer::Resource(id, rep, dtor));
742
}
743
744
// no extra processing needed
745
wasmparser::ComponentType::Defined(_)
746
| wasmparser::ComponentType::Func(_)
747
| wasmparser::ComponentType::Instance(_)
748
| wasmparser::ComponentType::Component(_) => {}
749
}
750
751
component_type_index += 1;
752
}
753
}
754
Payload::CoreTypeSection(s) => {
755
self.validator.core_type_section(&s)?;
756
}
757
758
// Processing the import section at this point is relatively simple
759
// which is to simply record the name of the import and the type
760
// information associated with it.
761
Payload::ComponentImportSection(s) => {
762
self.validator.component_import_section(&s)?;
763
for import in s {
764
let import = import?;
765
let types = self.validator.types(0).unwrap();
766
let ty = types
767
.component_entity_type_of_import(import.name.0)
768
.unwrap();
769
770
if self.is_unsafe_intrinsics_import(import.name.0) {
771
self.check_unsafe_intrinsics_import(import.name.0, ty)?;
772
self.result
773
.initializers
774
.push(LocalInitializer::IntrinsicsImport);
775
} else {
776
self.result
777
.initializers
778
.push(LocalInitializer::Import(import.name, ty));
779
}
780
}
781
}
782
783
// Entries in the canonical section will get initializers recorded
784
// with the listed options for lifting/lowering.
785
Payload::ComponentCanonicalSection(s) => {
786
let types = self.validator.types(0).unwrap();
787
let mut core_func_index = types.function_count();
788
self.validator.component_canonical_section(&s)?;
789
for func in s {
790
let init = match func? {
791
wasmparser::CanonicalFunction::Lift {
792
type_index,
793
core_func_index,
794
options,
795
} => {
796
let ty = self
797
.validator
798
.types(0)
799
.unwrap()
800
.component_any_type_at(type_index)
801
.unwrap_func();
802
803
let func = FuncIndex::from_u32(core_func_index);
804
let options = self.canonical_options(&options, core_func_index)?;
805
LocalInitializer::Lift(ty, func, options)
806
}
807
wasmparser::CanonicalFunction::Lower {
808
func_index,
809
options,
810
} => {
811
let lower_ty = self
812
.validator
813
.types(0)
814
.unwrap()
815
.component_function_at(func_index);
816
let func = ComponentFuncIndex::from_u32(func_index);
817
let options = self.canonical_options(&options, core_func_index)?;
818
core_func_index += 1;
819
LocalInitializer::Lower {
820
func,
821
options,
822
lower_ty,
823
}
824
}
825
wasmparser::CanonicalFunction::ResourceNew { resource } => {
826
let resource = self
827
.validator
828
.types(0)
829
.unwrap()
830
.component_any_type_at(resource)
831
.unwrap_resource();
832
let ty = self.core_func_signature(core_func_index)?;
833
core_func_index += 1;
834
LocalInitializer::ResourceNew(resource, ty)
835
}
836
wasmparser::CanonicalFunction::ResourceDrop { resource } => {
837
let resource = self
838
.validator
839
.types(0)
840
.unwrap()
841
.component_any_type_at(resource)
842
.unwrap_resource();
843
let ty = self.core_func_signature(core_func_index)?;
844
core_func_index += 1;
845
LocalInitializer::ResourceDrop(resource, ty)
846
}
847
wasmparser::CanonicalFunction::ResourceDropAsync { resource } => {
848
let _ = resource;
849
bail!("support for `resource.drop async` not implemented yet")
850
}
851
wasmparser::CanonicalFunction::ResourceRep { resource } => {
852
let resource = self
853
.validator
854
.types(0)
855
.unwrap()
856
.component_any_type_at(resource)
857
.unwrap_resource();
858
let ty = self.core_func_signature(core_func_index)?;
859
core_func_index += 1;
860
LocalInitializer::ResourceRep(resource, ty)
861
}
862
wasmparser::CanonicalFunction::ThreadSpawnRef { .. }
863
| wasmparser::CanonicalFunction::ThreadSpawnIndirect { .. }
864
| wasmparser::CanonicalFunction::ThreadAvailableParallelism => {
865
bail!("unsupported intrinsic")
866
}
867
wasmparser::CanonicalFunction::BackpressureInc => {
868
let core_type = self.core_func_signature(core_func_index)?;
869
core_func_index += 1;
870
LocalInitializer::BackpressureInc { func: core_type }
871
}
872
wasmparser::CanonicalFunction::BackpressureDec => {
873
let core_type = self.core_func_signature(core_func_index)?;
874
core_func_index += 1;
875
LocalInitializer::BackpressureDec { func: core_type }
876
}
877
878
wasmparser::CanonicalFunction::TaskReturn { result, options } => {
879
let result = result.map(|ty| match ty {
880
wasmparser::ComponentValType::Primitive(ty) => {
881
ComponentValType::Primitive(ty)
882
}
883
wasmparser::ComponentValType::Type(ty) => ComponentValType::Type(
884
self.validator
885
.types(0)
886
.unwrap()
887
.component_defined_type_at(ty),
888
),
889
});
890
let options = self.canonical_options(&options, core_func_index)?;
891
core_func_index += 1;
892
LocalInitializer::TaskReturn { result, options }
893
}
894
wasmparser::CanonicalFunction::TaskCancel => {
895
let func = self.core_func_signature(core_func_index)?;
896
core_func_index += 1;
897
LocalInitializer::TaskCancel { func }
898
}
899
wasmparser::CanonicalFunction::WaitableSetNew => {
900
let func = self.core_func_signature(core_func_index)?;
901
core_func_index += 1;
902
LocalInitializer::WaitableSetNew { func }
903
}
904
wasmparser::CanonicalFunction::WaitableSetWait {
905
cancellable,
906
memory,
907
} => {
908
let core_type = self.core_func_signature(core_func_index)?;
909
core_func_index += 1;
910
LocalInitializer::WaitableSetWait {
911
options: LocalCanonicalOptions {
912
core_type,
913
cancellable,
914
async_: false,
915
data_model: LocalDataModel::LinearMemory {
916
memory: Some(MemoryIndex::from_u32(memory)),
917
realloc: None,
918
},
919
post_return: None,
920
callback: None,
921
string_encoding: StringEncoding::Utf8,
922
},
923
}
924
}
925
wasmparser::CanonicalFunction::WaitableSetPoll {
926
cancellable,
927
memory,
928
} => {
929
let core_type = self.core_func_signature(core_func_index)?;
930
core_func_index += 1;
931
LocalInitializer::WaitableSetPoll {
932
options: LocalCanonicalOptions {
933
core_type,
934
async_: false,
935
cancellable,
936
data_model: LocalDataModel::LinearMemory {
937
memory: Some(MemoryIndex::from_u32(memory)),
938
realloc: None,
939
},
940
post_return: None,
941
callback: None,
942
string_encoding: StringEncoding::Utf8,
943
},
944
}
945
}
946
wasmparser::CanonicalFunction::WaitableSetDrop => {
947
let func = self.core_func_signature(core_func_index)?;
948
core_func_index += 1;
949
LocalInitializer::WaitableSetDrop { func }
950
}
951
wasmparser::CanonicalFunction::WaitableJoin => {
952
let func = self.core_func_signature(core_func_index)?;
953
core_func_index += 1;
954
LocalInitializer::WaitableJoin { func }
955
}
956
wasmparser::CanonicalFunction::ThreadYield { cancellable } => {
957
let func = self.core_func_signature(core_func_index)?;
958
core_func_index += 1;
959
LocalInitializer::ThreadYield { func, cancellable }
960
}
961
wasmparser::CanonicalFunction::SubtaskDrop => {
962
let func = self.core_func_signature(core_func_index)?;
963
core_func_index += 1;
964
LocalInitializer::SubtaskDrop { func }
965
}
966
wasmparser::CanonicalFunction::SubtaskCancel { async_ } => {
967
let func = self.core_func_signature(core_func_index)?;
968
core_func_index += 1;
969
LocalInitializer::SubtaskCancel { func, async_ }
970
}
971
wasmparser::CanonicalFunction::StreamNew { ty } => {
972
let ty = self
973
.validator
974
.types(0)
975
.unwrap()
976
.component_defined_type_at(ty);
977
let func = self.core_func_signature(core_func_index)?;
978
core_func_index += 1;
979
LocalInitializer::StreamNew { ty, func }
980
}
981
wasmparser::CanonicalFunction::StreamRead { ty, options } => {
982
let ty = self
983
.validator
984
.types(0)
985
.unwrap()
986
.component_defined_type_at(ty);
987
let options = self.canonical_options(&options, core_func_index)?;
988
core_func_index += 1;
989
LocalInitializer::StreamRead { ty, options }
990
}
991
wasmparser::CanonicalFunction::StreamWrite { ty, options } => {
992
let ty = self
993
.validator
994
.types(0)
995
.unwrap()
996
.component_defined_type_at(ty);
997
let options = self.canonical_options(&options, core_func_index)?;
998
core_func_index += 1;
999
LocalInitializer::StreamWrite { ty, options }
1000
}
1001
wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => {
1002
let ty = self
1003
.validator
1004
.types(0)
1005
.unwrap()
1006
.component_defined_type_at(ty);
1007
let func = self.core_func_signature(core_func_index)?;
1008
core_func_index += 1;
1009
LocalInitializer::StreamCancelRead { ty, func, async_ }
1010
}
1011
wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1012
let ty = self
1013
.validator
1014
.types(0)
1015
.unwrap()
1016
.component_defined_type_at(ty);
1017
let func = self.core_func_signature(core_func_index)?;
1018
core_func_index += 1;
1019
LocalInitializer::StreamCancelWrite { ty, func, async_ }
1020
}
1021
wasmparser::CanonicalFunction::StreamDropReadable { ty } => {
1022
let ty = self
1023
.validator
1024
.types(0)
1025
.unwrap()
1026
.component_defined_type_at(ty);
1027
let func = self.core_func_signature(core_func_index)?;
1028
core_func_index += 1;
1029
LocalInitializer::StreamDropReadable { ty, func }
1030
}
1031
wasmparser::CanonicalFunction::StreamDropWritable { ty } => {
1032
let ty = self
1033
.validator
1034
.types(0)
1035
.unwrap()
1036
.component_defined_type_at(ty);
1037
let func = self.core_func_signature(core_func_index)?;
1038
core_func_index += 1;
1039
LocalInitializer::StreamDropWritable { ty, func }
1040
}
1041
wasmparser::CanonicalFunction::FutureNew { ty } => {
1042
let ty = self
1043
.validator
1044
.types(0)
1045
.unwrap()
1046
.component_defined_type_at(ty);
1047
let func = self.core_func_signature(core_func_index)?;
1048
core_func_index += 1;
1049
LocalInitializer::FutureNew { ty, func }
1050
}
1051
wasmparser::CanonicalFunction::FutureRead { ty, options } => {
1052
let ty = self
1053
.validator
1054
.types(0)
1055
.unwrap()
1056
.component_defined_type_at(ty);
1057
let options = self.canonical_options(&options, core_func_index)?;
1058
core_func_index += 1;
1059
LocalInitializer::FutureRead { ty, options }
1060
}
1061
wasmparser::CanonicalFunction::FutureWrite { ty, options } => {
1062
let ty = self
1063
.validator
1064
.types(0)
1065
.unwrap()
1066
.component_defined_type_at(ty);
1067
let options = self.canonical_options(&options, core_func_index)?;
1068
core_func_index += 1;
1069
LocalInitializer::FutureWrite { ty, options }
1070
}
1071
wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => {
1072
let ty = self
1073
.validator
1074
.types(0)
1075
.unwrap()
1076
.component_defined_type_at(ty);
1077
let func = self.core_func_signature(core_func_index)?;
1078
core_func_index += 1;
1079
LocalInitializer::FutureCancelRead { ty, func, async_ }
1080
}
1081
wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1082
let ty = self
1083
.validator
1084
.types(0)
1085
.unwrap()
1086
.component_defined_type_at(ty);
1087
let func = self.core_func_signature(core_func_index)?;
1088
core_func_index += 1;
1089
LocalInitializer::FutureCancelWrite { ty, func, async_ }
1090
}
1091
wasmparser::CanonicalFunction::FutureDropReadable { ty } => {
1092
let ty = self
1093
.validator
1094
.types(0)
1095
.unwrap()
1096
.component_defined_type_at(ty);
1097
let func = self.core_func_signature(core_func_index)?;
1098
core_func_index += 1;
1099
LocalInitializer::FutureDropReadable { ty, func }
1100
}
1101
wasmparser::CanonicalFunction::FutureDropWritable { ty } => {
1102
let ty = self
1103
.validator
1104
.types(0)
1105
.unwrap()
1106
.component_defined_type_at(ty);
1107
let func = self.core_func_signature(core_func_index)?;
1108
core_func_index += 1;
1109
LocalInitializer::FutureDropWritable { ty, func }
1110
}
1111
wasmparser::CanonicalFunction::ErrorContextNew { options } => {
1112
let options = self.canonical_options(&options, core_func_index)?;
1113
core_func_index += 1;
1114
LocalInitializer::ErrorContextNew { options }
1115
}
1116
wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => {
1117
let options = self.canonical_options(&options, core_func_index)?;
1118
core_func_index += 1;
1119
LocalInitializer::ErrorContextDebugMessage { options }
1120
}
1121
wasmparser::CanonicalFunction::ErrorContextDrop => {
1122
let func = self.core_func_signature(core_func_index)?;
1123
core_func_index += 1;
1124
LocalInitializer::ErrorContextDrop { func }
1125
}
1126
wasmparser::CanonicalFunction::ContextGet(i) => {
1127
let func = self.core_func_signature(core_func_index)?;
1128
core_func_index += 1;
1129
LocalInitializer::ContextGet { i, func }
1130
}
1131
wasmparser::CanonicalFunction::ContextSet(i) => {
1132
let func = self.core_func_signature(core_func_index)?;
1133
core_func_index += 1;
1134
LocalInitializer::ContextSet { i, func }
1135
}
1136
wasmparser::CanonicalFunction::ThreadIndex => {
1137
let func = self.core_func_signature(core_func_index)?;
1138
core_func_index += 1;
1139
LocalInitializer::ThreadIndex { func }
1140
}
1141
wasmparser::CanonicalFunction::ThreadNewIndirect {
1142
func_ty_index,
1143
table_index,
1144
} => {
1145
let func = self.core_func_signature(core_func_index)?;
1146
core_func_index += 1;
1147
LocalInitializer::ThreadNewIndirect {
1148
func,
1149
start_func_ty: ComponentTypeIndex::from_u32(func_ty_index),
1150
start_func_table_index: TableIndex::from_u32(table_index),
1151
}
1152
}
1153
wasmparser::CanonicalFunction::ThreadSwitchTo { cancellable } => {
1154
let func = self.core_func_signature(core_func_index)?;
1155
core_func_index += 1;
1156
LocalInitializer::ThreadSwitchTo { func, cancellable }
1157
}
1158
wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => {
1159
let func = self.core_func_signature(core_func_index)?;
1160
core_func_index += 1;
1161
LocalInitializer::ThreadSuspend { func, cancellable }
1162
}
1163
wasmparser::CanonicalFunction::ThreadResumeLater => {
1164
let func = self.core_func_signature(core_func_index)?;
1165
core_func_index += 1;
1166
LocalInitializer::ThreadResumeLater { func }
1167
}
1168
wasmparser::CanonicalFunction::ThreadYieldTo { cancellable } => {
1169
let func = self.core_func_signature(core_func_index)?;
1170
core_func_index += 1;
1171
LocalInitializer::ThreadYieldTo { func, cancellable }
1172
}
1173
};
1174
self.result.initializers.push(init);
1175
}
1176
}
1177
1178
// Core wasm modules are translated inline directly here with the
1179
// `ModuleEnvironment` from core wasm compilation. This will return
1180
// to the caller the size of the module so it knows how many bytes
1181
// of the input are skipped.
1182
//
1183
// Note that this is just initial type translation of the core wasm
1184
// module and actual function compilation is deferred until this
1185
// entire process has completed.
1186
Payload::ModuleSection {
1187
parser,
1188
unchecked_range,
1189
} => {
1190
let index = self.validator.types(0).unwrap().module_count();
1191
self.validator.module_section(&unchecked_range)?;
1192
let static_module_index = self.static_modules.next_key();
1193
let translation = ModuleEnvironment::new(
1194
self.tunables,
1195
self.validator,
1196
self.types.module_types_builder(),
1197
static_module_index,
1198
)
1199
.translate(
1200
parser,
1201
component
1202
.get(unchecked_range.start..unchecked_range.end)
1203
.ok_or_else(|| {
1204
format_err!(
1205
"section range {}..{} is out of bounds (bound = {})",
1206
unchecked_range.start,
1207
unchecked_range.end,
1208
component.len()
1209
)
1210
.context("wasm component contains an invalid module section")
1211
})?,
1212
)?;
1213
let static_module_index2 = self.static_modules.push(translation);
1214
assert_eq!(static_module_index, static_module_index2);
1215
let types = self.validator.types(0).unwrap();
1216
let ty = types.module_at(index);
1217
self.result
1218
.initializers
1219
.push(LocalInitializer::ModuleStatic(static_module_index, ty));
1220
return Ok(Action::Skip(unchecked_range.end - unchecked_range.start));
1221
}
1222
1223
// When a sub-component is found then the current translation state
1224
// is pushed onto the `lexical_scopes` stack. This will subsequently
1225
// get popped as part of `Payload::End` processing above.
1226
//
1227
// Note that the set of closure args for this new lexical scope
1228
// starts empty since it will only get populated if translation of
1229
// the nested component ends up aliasing some outer module or
1230
// component.
1231
Payload::ComponentSection {
1232
parser,
1233
unchecked_range,
1234
} => {
1235
self.validator.component_section(&unchecked_range)?;
1236
self.lexical_scopes.push(LexicalScope {
1237
parser: mem::replace(&mut self.parser, parser),
1238
translation: mem::take(&mut self.result),
1239
closure_args: ClosedOverVars::default(),
1240
});
1241
}
1242
1243
// Both core wasm instances and component instances record
1244
// initializers of what form of instantiation is performed which
1245
// largely just records the arguments given from wasmparser into a
1246
// `HashMap` for processing later during inlining.
1247
Payload::InstanceSection(s) => {
1248
self.validator.instance_section(&s)?;
1249
for instance in s {
1250
let init = match instance? {
1251
wasmparser::Instance::Instantiate { module_index, args } => {
1252
let index = ModuleIndex::from_u32(module_index);
1253
self.instantiate_module(index, &args)
1254
}
1255
wasmparser::Instance::FromExports(exports) => {
1256
self.instantiate_module_from_exports(&exports)
1257
}
1258
};
1259
self.result.initializers.push(init);
1260
}
1261
}
1262
Payload::ComponentInstanceSection(s) => {
1263
let mut index = self.validator.types(0).unwrap().component_instance_count();
1264
self.validator.component_instance_section(&s)?;
1265
for instance in s {
1266
let types = self.validator.types(0).unwrap();
1267
let ty = types.component_instance_at(index);
1268
let init = match instance? {
1269
wasmparser::ComponentInstance::Instantiate {
1270
component_index,
1271
args,
1272
} => {
1273
let index = ComponentIndex::from_u32(component_index);
1274
self.instantiate_component(index, &args, ty)?
1275
}
1276
wasmparser::ComponentInstance::FromExports(exports) => {
1277
self.instantiate_component_from_exports(&exports, ty)?
1278
}
1279
};
1280
self.result.initializers.push(init);
1281
index += 1;
1282
}
1283
}
1284
1285
// Exports don't actually fill out the `initializers` array but
1286
// instead fill out the one other field in a `Translation`, the
1287
// `exports` field (as one might imagine). This for now simply
1288
// records the index of what's exported and that's tracked further
1289
// later during inlining.
1290
Payload::ComponentExportSection(s) => {
1291
self.validator.component_export_section(&s)?;
1292
for export in s {
1293
let export = export?;
1294
let item = self.kind_to_item(export.kind, export.index)?;
1295
let prev = self.result.exports.insert(export.name.0, item);
1296
assert!(prev.is_none());
1297
self.result
1298
.initializers
1299
.push(LocalInitializer::Export(item));
1300
}
1301
}
1302
1303
Payload::ComponentStartSection { start, range } => {
1304
self.validator.component_start_section(&start, &range)?;
1305
unimplemented!("component start section");
1306
}
1307
1308
// Aliases of instance exports (either core or component) will be
1309
// recorded as an initializer of the appropriate type with outer
1310
// aliases handled specially via upvars and type processing.
1311
Payload::ComponentAliasSection(s) => {
1312
self.validator.component_alias_section(&s)?;
1313
for alias in s {
1314
let init = match alias? {
1315
wasmparser::ComponentAlias::InstanceExport {
1316
kind: _,
1317
instance_index,
1318
name,
1319
} => {
1320
let instance = ComponentInstanceIndex::from_u32(instance_index);
1321
LocalInitializer::AliasComponentExport(instance, name)
1322
}
1323
wasmparser::ComponentAlias::Outer { kind, count, index } => {
1324
self.alias_component_outer(kind, count, index);
1325
continue;
1326
}
1327
wasmparser::ComponentAlias::CoreInstanceExport {
1328
kind,
1329
instance_index,
1330
name,
1331
} => {
1332
let instance = ModuleInstanceIndex::from_u32(instance_index);
1333
self.alias_module_instance_export(kind, instance, name)
1334
}
1335
};
1336
self.result.initializers.push(init);
1337
}
1338
}
1339
1340
// All custom sections are ignored by Wasmtime at this time.
1341
//
1342
// FIXME(WebAssembly/component-model#14): probably want to specify
1343
// and parse a `name` section here.
1344
Payload::CustomSection { .. } => {}
1345
1346
// Anything else is either not reachable since we never enable the
1347
// feature in Wasmtime or we do enable it and it's a bug we don't
1348
// implement it, so let validation take care of most errors here and
1349
// if it gets past validation provide a helpful error message to
1350
// debug.
1351
other => {
1352
self.validator.payload(&other)?;
1353
panic!("unimplemented section {other:?}");
1354
}
1355
}
1356
1357
Ok(Action::KeepGoing)
1358
}
1359
1360
fn instantiate_module(
1361
&mut self,
1362
module: ModuleIndex,
1363
raw_args: &[wasmparser::InstantiationArg<'data>],
1364
) -> LocalInitializer<'data> {
1365
let mut args = HashMap::with_capacity(raw_args.len());
1366
for arg in raw_args {
1367
match arg.kind {
1368
wasmparser::InstantiationArgKind::Instance => {
1369
let idx = ModuleInstanceIndex::from_u32(arg.index);
1370
args.insert(arg.name, idx);
1371
}
1372
}
1373
}
1374
LocalInitializer::ModuleInstantiate(module, args)
1375
}
1376
1377
/// Creates a synthetic module from the list of items currently in the
1378
/// module and their given names.
1379
fn instantiate_module_from_exports(
1380
&mut self,
1381
exports: &[wasmparser::Export<'data>],
1382
) -> LocalInitializer<'data> {
1383
let mut map = HashMap::with_capacity(exports.len());
1384
for export in exports {
1385
let idx = match export.kind {
1386
wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {
1387
let index = FuncIndex::from_u32(export.index);
1388
EntityIndex::Function(index)
1389
}
1390
wasmparser::ExternalKind::Table => {
1391
let index = TableIndex::from_u32(export.index);
1392
EntityIndex::Table(index)
1393
}
1394
wasmparser::ExternalKind::Memory => {
1395
let index = MemoryIndex::from_u32(export.index);
1396
EntityIndex::Memory(index)
1397
}
1398
wasmparser::ExternalKind::Global => {
1399
let index = GlobalIndex::from_u32(export.index);
1400
EntityIndex::Global(index)
1401
}
1402
wasmparser::ExternalKind::Tag => {
1403
let index = TagIndex::from_u32(export.index);
1404
EntityIndex::Tag(index)
1405
}
1406
};
1407
map.insert(export.name, idx);
1408
}
1409
LocalInitializer::ModuleSynthetic(map)
1410
}
1411
1412
fn instantiate_component(
1413
&mut self,
1414
component: ComponentIndex,
1415
raw_args: &[wasmparser::ComponentInstantiationArg<'data>],
1416
ty: ComponentInstanceTypeId,
1417
) -> Result<LocalInitializer<'data>> {
1418
let mut args = HashMap::with_capacity(raw_args.len());
1419
for arg in raw_args {
1420
let idx = self.kind_to_item(arg.kind, arg.index)?;
1421
args.insert(arg.name, idx);
1422
}
1423
1424
Ok(LocalInitializer::ComponentInstantiate(component, args, ty))
1425
}
1426
1427
/// Creates a synthetic module from the list of items currently in the
1428
/// module and their given names.
1429
fn instantiate_component_from_exports(
1430
&mut self,
1431
exports: &[wasmparser::ComponentExport<'data>],
1432
ty: ComponentInstanceTypeId,
1433
) -> Result<LocalInitializer<'data>> {
1434
let mut map = HashMap::with_capacity(exports.len());
1435
for export in exports {
1436
let idx = self.kind_to_item(export.kind, export.index)?;
1437
map.insert(export.name.0, idx);
1438
}
1439
1440
Ok(LocalInitializer::ComponentSynthetic(map, ty))
1441
}
1442
1443
fn kind_to_item(
1444
&mut self,
1445
kind: wasmparser::ComponentExternalKind,
1446
index: u32,
1447
) -> Result<ComponentItem> {
1448
Ok(match kind {
1449
wasmparser::ComponentExternalKind::Func => {
1450
let index = ComponentFuncIndex::from_u32(index);
1451
ComponentItem::Func(index)
1452
}
1453
wasmparser::ComponentExternalKind::Module => {
1454
let index = ModuleIndex::from_u32(index);
1455
ComponentItem::Module(index)
1456
}
1457
wasmparser::ComponentExternalKind::Instance => {
1458
let index = ComponentInstanceIndex::from_u32(index);
1459
ComponentItem::ComponentInstance(index)
1460
}
1461
wasmparser::ComponentExternalKind::Component => {
1462
let index = ComponentIndex::from_u32(index);
1463
ComponentItem::Component(index)
1464
}
1465
wasmparser::ComponentExternalKind::Value => {
1466
unimplemented!("component values");
1467
}
1468
wasmparser::ComponentExternalKind::Type => {
1469
let types = self.validator.types(0).unwrap();
1470
let ty = types.component_any_type_at(index);
1471
ComponentItem::Type(ty)
1472
}
1473
})
1474
}
1475
1476
fn alias_module_instance_export(
1477
&mut self,
1478
kind: wasmparser::ExternalKind,
1479
instance: ModuleInstanceIndex,
1480
name: &'data str,
1481
) -> LocalInitializer<'data> {
1482
match kind {
1483
wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {
1484
LocalInitializer::AliasExportFunc(instance, name)
1485
}
1486
wasmparser::ExternalKind::Memory => LocalInitializer::AliasExportMemory(instance, name),
1487
wasmparser::ExternalKind::Table => LocalInitializer::AliasExportTable(instance, name),
1488
wasmparser::ExternalKind::Global => LocalInitializer::AliasExportGlobal(instance, name),
1489
wasmparser::ExternalKind::Tag => LocalInitializer::AliasExportTag(instance, name),
1490
}
1491
}
1492
1493
fn alias_component_outer(
1494
&mut self,
1495
kind: wasmparser::ComponentOuterAliasKind,
1496
count: u32,
1497
index: u32,
1498
) {
1499
match kind {
1500
wasmparser::ComponentOuterAliasKind::CoreType
1501
| wasmparser::ComponentOuterAliasKind::Type => {}
1502
1503
// For more information about the implementation of outer aliases
1504
// see the documentation of `LexicalScope`. Otherwise though the
1505
// main idea here is that the data to close over starts as `Local`
1506
// and then transitions to `Upvar` as its inserted into the parents
1507
// in order from target we're aliasing back to the current
1508
// component.
1509
wasmparser::ComponentOuterAliasKind::CoreModule => {
1510
let index = ModuleIndex::from_u32(index);
1511
let mut module = ClosedOverModule::Local(index);
1512
let depth = self.lexical_scopes.len() - (count as usize);
1513
for frame in self.lexical_scopes[depth..].iter_mut() {
1514
module = ClosedOverModule::Upvar(frame.closure_args.modules.push(module));
1515
}
1516
1517
// If the `module` is still `Local` then the `depth` was 0 and
1518
// it's an alias into our own space. Otherwise it's switched to
1519
// an upvar and will index into the upvar space. Either way
1520
// it's just plumbed directly into the initializer.
1521
self.result
1522
.initializers
1523
.push(LocalInitializer::AliasModule(module));
1524
}
1525
wasmparser::ComponentOuterAliasKind::Component => {
1526
let index = ComponentIndex::from_u32(index);
1527
let mut component = ClosedOverComponent::Local(index);
1528
let depth = self.lexical_scopes.len() - (count as usize);
1529
for frame in self.lexical_scopes[depth..].iter_mut() {
1530
component =
1531
ClosedOverComponent::Upvar(frame.closure_args.components.push(component));
1532
}
1533
1534
self.result
1535
.initializers
1536
.push(LocalInitializer::AliasComponent(component));
1537
}
1538
}
1539
}
1540
1541
fn canonical_options(
1542
&mut self,
1543
opts: &[wasmparser::CanonicalOption],
1544
core_func_index: u32,
1545
) -> WasmResult<LocalCanonicalOptions> {
1546
let core_type = self.core_func_signature(core_func_index)?;
1547
1548
let mut string_encoding = StringEncoding::Utf8;
1549
let mut post_return = None;
1550
let mut async_ = false;
1551
let mut callback = None;
1552
let mut memory = None;
1553
let mut realloc = None;
1554
let mut gc = false;
1555
1556
for opt in opts {
1557
match opt {
1558
wasmparser::CanonicalOption::UTF8 => {
1559
string_encoding = StringEncoding::Utf8;
1560
}
1561
wasmparser::CanonicalOption::UTF16 => {
1562
string_encoding = StringEncoding::Utf16;
1563
}
1564
wasmparser::CanonicalOption::CompactUTF16 => {
1565
string_encoding = StringEncoding::CompactUtf16;
1566
}
1567
wasmparser::CanonicalOption::Memory(idx) => {
1568
let idx = MemoryIndex::from_u32(*idx);
1569
memory = Some(idx);
1570
}
1571
wasmparser::CanonicalOption::Realloc(idx) => {
1572
let idx = FuncIndex::from_u32(*idx);
1573
realloc = Some(idx);
1574
}
1575
wasmparser::CanonicalOption::PostReturn(idx) => {
1576
let idx = FuncIndex::from_u32(*idx);
1577
post_return = Some(idx);
1578
}
1579
wasmparser::CanonicalOption::Async => async_ = true,
1580
wasmparser::CanonicalOption::Callback(idx) => {
1581
let idx = FuncIndex::from_u32(*idx);
1582
callback = Some(idx);
1583
}
1584
wasmparser::CanonicalOption::CoreType(idx) => {
1585
if cfg!(debug_assertions) {
1586
let types = self.validator.types(0).unwrap();
1587
let core_ty_id = types.core_type_at_in_component(*idx).unwrap_sub();
1588
let interned = self
1589
.types
1590
.module_types_builder()
1591
.intern_type(types, core_ty_id)?;
1592
debug_assert_eq!(interned, core_type);
1593
}
1594
}
1595
wasmparser::CanonicalOption::Gc => {
1596
gc = true;
1597
}
1598
}
1599
}
1600
1601
Ok(LocalCanonicalOptions {
1602
string_encoding,
1603
post_return,
1604
cancellable: false,
1605
async_,
1606
callback,
1607
core_type,
1608
data_model: if gc {
1609
LocalDataModel::Gc {}
1610
} else {
1611
LocalDataModel::LinearMemory { memory, realloc }
1612
},
1613
})
1614
}
1615
1616
/// Get the interned type index for the `index`th core function.
1617
fn core_func_signature(&mut self, index: u32) -> WasmResult<ModuleInternedTypeIndex> {
1618
let types = self.validator.types(0).unwrap();
1619
let id = types.core_function_at(index);
1620
self.types.module_types_builder().intern_type(types, id)
1621
}
1622
1623
fn is_unsafe_intrinsics_import(&self, import: &str) -> bool {
1624
self.lexical_scopes.is_empty()
1625
&& self
1626
.unsafe_intrinsics_import
1627
.is_some_and(|name| import == name)
1628
}
1629
1630
fn check_unsafe_intrinsics_import(&self, import: &str, ty: ComponentEntityType) -> Result<()> {
1631
let types = &self.validator.types(0).unwrap();
1632
1633
let ComponentEntityType::Instance(instance_ty) = ty else {
1634
bail!("bad unsafe intrinsics import: import `{import}` must be an instance import")
1635
};
1636
let instance_ty = &types[instance_ty];
1637
1638
ensure!(
1639
instance_ty.defined_resources.is_empty(),
1640
"bad unsafe intrinsics import: import `{import}` cannot define any resources"
1641
);
1642
ensure!(
1643
instance_ty.explicit_resources.is_empty(),
1644
"bad unsafe intrinsics import: import `{import}` cannot export any resources"
1645
);
1646
1647
for (name, ty) in &instance_ty.exports {
1648
let ComponentEntityType::Func(func_ty) = ty else {
1649
bail!(
1650
"bad unsafe intrinsics import: imported instance `{import}` must \
1651
only export functions"
1652
)
1653
};
1654
let func_ty = &types[*func_ty];
1655
1656
fn ty_eq(a: &InterfaceType, b: &wasmparser::component_types::ComponentValType) -> bool {
1657
use wasmparser::{PrimitiveValType as P, component_types::ComponentValType as C};
1658
match (a, b) {
1659
(InterfaceType::U8, C::Primitive(P::U8)) => true,
1660
(InterfaceType::U8, _) => false,
1661
1662
(InterfaceType::U16, C::Primitive(P::U16)) => true,
1663
(InterfaceType::U16, _) => false,
1664
1665
(InterfaceType::U32, C::Primitive(P::U32)) => true,
1666
(InterfaceType::U32, _) => false,
1667
1668
(InterfaceType::U64, C::Primitive(P::U64)) => true,
1669
(InterfaceType::U64, _) => false,
1670
1671
(ty, _) => unreachable!("no unsafe intrinsics use {ty:?}"),
1672
}
1673
}
1674
1675
fn check_types<'a>(
1676
expected: impl ExactSizeIterator<Item = &'a InterfaceType>,
1677
actual: impl ExactSizeIterator<Item = &'a wasmparser::component_types::ComponentValType>,
1678
kind: &str,
1679
import: &str,
1680
name: &str,
1681
) -> Result<()> {
1682
let expected_len = expected.len();
1683
let actual_len = actual.len();
1684
ensure!(
1685
expected_len == actual_len,
1686
"bad unsafe intrinsics import at `{import}`: function `{name}` must have \
1687
{expected_len} {kind}, found {actual_len}"
1688
);
1689
1690
for (i, (actual_ty, expected_ty)) in actual.zip(expected).enumerate() {
1691
ensure!(
1692
ty_eq(expected_ty, actual_ty),
1693
"bad unsafe intrinsics import at `{import}`: {kind}[{i}] for function \
1694
`{name}` must be `{expected_ty:?}`, found `{actual_ty:?}`"
1695
);
1696
}
1697
Ok(())
1698
}
1699
1700
let intrinsic = UnsafeIntrinsic::from_str(name)
1701
.with_context(|| format!("bad unsafe intrinsics import at `{import}`"))?;
1702
1703
check_types(
1704
intrinsic.component_params().iter(),
1705
func_ty.params.iter().map(|(_name, ty)| ty),
1706
"parameters",
1707
&import,
1708
&name,
1709
)?;
1710
check_types(
1711
intrinsic.component_results().iter(),
1712
func_ty.result.iter(),
1713
"results",
1714
&import,
1715
&name,
1716
)?;
1717
}
1718
1719
Ok(())
1720
}
1721
}
1722
1723
impl Translation<'_> {
1724
fn types_ref(&self) -> wasmparser::types::TypesRef<'_> {
1725
self.types.as_ref().unwrap().as_ref()
1726
}
1727
}
1728
1729
/// A small helper module which wraps a `ComponentTypesBuilder` and attempts
1730
/// to disallow access to mutable access to the builder before the inlining
1731
/// pass.
1732
///
1733
/// Type information in this translation pass must be preserved at the
1734
/// wasmparser layer of abstraction rather than being lowered into Wasmtime's
1735
/// own type system. Only during inlining are types fully assigned because
1736
/// that's when resource types become available as it's known which instance
1737
/// defines which resource, or more concretely the same component instantiated
1738
/// twice will produce two unique resource types unlike one as seen by
1739
/// wasmparser within the component.
1740
mod pre_inlining {
1741
use super::*;
1742
1743
pub struct PreInliningComponentTypes<'a> {
1744
types: &'a mut ComponentTypesBuilder,
1745
}
1746
1747
impl<'a> PreInliningComponentTypes<'a> {
1748
pub fn new(types: &'a mut ComponentTypesBuilder) -> Self {
1749
Self { types }
1750
}
1751
1752
pub fn module_types_builder(&mut self) -> &mut ModuleTypesBuilder {
1753
self.types.module_types_builder_mut()
1754
}
1755
1756
pub fn types(&self) -> &ComponentTypesBuilder {
1757
self.types
1758
}
1759
1760
// NB: this should in theory only be used for the `inline` phase of
1761
// translation.
1762
pub fn types_mut_for_inlining(&mut self) -> &mut ComponentTypesBuilder {
1763
self.types
1764
}
1765
}
1766
1767
impl TypeConvert for PreInliningComponentTypes<'_> {
1768
fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
1769
self.types.lookup_heap_type(index)
1770
}
1771
1772
fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
1773
self.types.lookup_type_index(index)
1774
}
1775
}
1776
}
1777
use pre_inlining::PreInliningComponentTypes;
1778
1779