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