Path: blob/main/crates/environ/src/component/translate.rs
3073 views
use crate::Abi;1use crate::component::dfg::AbstractInstantiations;2use crate::component::*;3use crate::prelude::*;4use crate::{5EngineOrModuleTypeIndex, EntityIndex, FuncKey, ModuleEnvironment, ModuleInternedTypeIndex,6ModuleTranslation, ModuleTypesBuilder, PrimaryMap, ScopeVec, TagIndex, Tunables, TypeConvert,7WasmHeapType, WasmResult, WasmValType,8};9use core::str::FromStr;10use cranelift_entity::SecondaryMap;11use cranelift_entity::packed_option::PackedOption;12use indexmap::IndexMap;13use std::collections::HashMap;14use std::mem;15use wasmparser::component_types::{16AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType,17ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType,18};19use wasmparser::types::Types;20use wasmparser::{Chunk, ComponentImportName, Encoding, Parser, Payload, Validator};2122mod adapt;23pub use self::adapt::*;24mod inline;2526/// Structure used to translate a component and parse it.27pub struct Translator<'a, 'data> {28/// The current component being translated.29///30/// This will get swapped out as translation traverses the body of a31/// component and a sub-component is entered or left.32result: Translation<'data>,3334/// Current state of parsing a binary component. Note that like `result`35/// this will change as the component is traversed.36parser: Parser,3738/// Stack of lexical scopes that are in-progress but not finished yet.39///40/// This is pushed to whenever a component is entered and popped from41/// whenever a component is left. Each lexical scope also contains42/// information about the variables that it is currently required to close43/// over which is threaded into the current in-progress translation of44/// the sub-component which pushed a scope here.45lexical_scopes: Vec<LexicalScope<'data>>,4647/// The validator in use to verify that the raw input binary is a valid48/// component.49validator: &'a mut Validator,5051/// Type information shared for the entire component.52///53/// This builder is also used for all core wasm modules found to intern54/// signatures across all modules.55types: PreInliningComponentTypes<'a>,5657/// The compiler configuration provided by the embedder.58tunables: &'a Tunables,5960/// Auxiliary location to push generated adapter modules onto.61scope_vec: &'data ScopeVec<u8>,6263/// Completely translated core wasm modules that have been found so far.64///65/// Note that this translation only involves learning about type66/// information and functions are not actually compiled here.67static_modules: PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,6869/// Completely translated components that have been found so far.70///71/// As frames are popped from `lexical_scopes` their completed component72/// will be pushed onto this list.73static_components: PrimaryMap<StaticComponentIndex, Translation<'data>>,7475/// The top-level import name for Wasmtime's unsafe intrinsics, if any.76unsafe_intrinsics_import: Option<&'a str>,77}7879/// Representation of the syntactic scope of a component meaning where it is80/// and what its state is at in the binary format.81///82/// These scopes are pushed and popped when a sub-component starts being83/// parsed and finishes being parsed. The main purpose of this frame is to84/// have a `ClosedOverVars` field which encapsulates data that is inherited85/// from the scope specified into the component being translated just beneath86/// it.87///88/// This structure exists to implement outer aliases to components and modules.89/// When a component or module is closed over then that means it needs to be90/// inherited in a sense to the component which actually had the alias. This is91/// achieved with a deceptively simple scheme where each parent of the92/// component with the alias will inherit the component from the desired93/// location.94///95/// For example with a component structure that looks like:96///97/// ```wasm98/// (component $A99/// (core module $M)100/// (component $B101/// (component $C102/// (alias outer $A $M (core module))103/// )104/// )105/// )106/// ```107///108/// here the `C` component is closing over `M` located in the root component109/// `A`. When `C` is being translated the `lexical_scopes` field will look like110/// `[A, B]`. When the alias is encountered (for module index 0) this will111/// place a `ClosedOverModule::Local(0)` entry into the `closure_args` field of112/// `A`'s frame. This will in turn give a `ModuleUpvarIndex` which is then113/// inserted into `closure_args` in `B`'s frame. This produces yet another114/// `ModuleUpvarIndex` which is finally inserted into `C`'s module index space115/// via `LocalInitializer::AliasModuleUpvar` with the last index.116///117/// All of these upvar indices and such are interpreted in the "inline" phase118/// of compilation and not at runtime. This means that when `A` is being119/// instantiated one of its initializers will be120/// `LocalInitializer::ComponentStatic`. This starts to create `B` and the121/// variables captured for `B` are listed as local module 0, or `M`. This list122/// is then preserved in the definition of the component `B` and later reused123/// by `C` again to finally get access to the closed over component.124///125/// Effectively the scopes are managed hierarchically where a reference to an126/// outer variable automatically injects references into all parents up to127/// where the reference is. This variable scopes are the processed during128/// inlining where a component definition is a reference to the static129/// component information (`Translation`) plus closed over variables130/// (`ComponentClosure` during inlining).131struct LexicalScope<'data> {132/// Current state of translating the `translation` below.133parser: Parser,134/// Current state of the component's translation as found so far.135translation: Translation<'data>,136/// List of captures that `translation` will need to process to create the137/// sub-component which is directly beneath this lexical scope.138closure_args: ClosedOverVars,139}140141/// A "local" translation of a component.142///143/// This structure is used as a sort of in-progress translation of a component.144/// This is not `Component` which is the final form as consumed by Wasmtime145/// at runtime. Instead this is a fairly simple representation of a component146/// where almost everything is ordered as a list of initializers. The binary147/// format is translated to a list of initializers here which is later processed148/// during "inlining" to produce a final component with the final set of149/// initializers.150#[derive(Default)]151struct Translation<'data> {152/// Instructions which form this component.153///154/// There is one initializer for all members of each index space, and all155/// index spaces are incrementally built here as the initializer list is156/// processed.157initializers: Vec<LocalInitializer<'data>>,158159/// The list of exports from this component, as pairs of names and an160/// index into an index space of what's being exported.161exports: IndexMap<&'data str, ComponentItem>,162163/// Type information produced by `wasmparser` for this component.164///165/// This type information is available after the translation of the entire166/// component has finished, e.g. for the `inline` pass, but beforehand this167/// is set to `None`.168types: Option<Types>,169}170171// NB: the type information contained in `LocalInitializer` should always point172// to `wasmparser`'s type information, not Wasmtime's. Component types cannot be173// fully determined due to resources until instantiations are known which is174// tracked during the inlining phase. This means that all type information below175// is straight from `wasmparser`'s passes.176enum LocalInitializer<'data> {177// imports178Import(ComponentImportName<'data>, ComponentEntityType),179180// An import of an intrinsic for compile-time builtins.181IntrinsicsImport,182183// canonical function sections184Lower {185func: ComponentFuncIndex,186lower_ty: ComponentFuncTypeId,187options: LocalCanonicalOptions,188},189Lift(ComponentFuncTypeId, FuncIndex, LocalCanonicalOptions),190191// resources192Resource(AliasableResourceId, WasmValType, Option<FuncIndex>),193ResourceNew(AliasableResourceId, ModuleInternedTypeIndex),194ResourceRep(AliasableResourceId, ModuleInternedTypeIndex),195ResourceDrop(AliasableResourceId, ModuleInternedTypeIndex),196197BackpressureInc {198func: ModuleInternedTypeIndex,199},200BackpressureDec {201func: ModuleInternedTypeIndex,202},203TaskReturn {204result: Option<ComponentValType>,205options: LocalCanonicalOptions,206},207TaskCancel {208func: ModuleInternedTypeIndex,209},210WaitableSetNew {211func: ModuleInternedTypeIndex,212},213WaitableSetWait {214options: LocalCanonicalOptions,215},216WaitableSetPoll {217options: LocalCanonicalOptions,218},219WaitableSetDrop {220func: ModuleInternedTypeIndex,221},222WaitableJoin {223func: ModuleInternedTypeIndex,224},225ThreadYield {226func: ModuleInternedTypeIndex,227cancellable: bool,228},229SubtaskDrop {230func: ModuleInternedTypeIndex,231},232SubtaskCancel {233func: ModuleInternedTypeIndex,234async_: bool,235},236StreamNew {237ty: ComponentDefinedTypeId,238func: ModuleInternedTypeIndex,239},240StreamRead {241ty: ComponentDefinedTypeId,242options: LocalCanonicalOptions,243},244StreamWrite {245ty: ComponentDefinedTypeId,246options: LocalCanonicalOptions,247},248StreamCancelRead {249ty: ComponentDefinedTypeId,250func: ModuleInternedTypeIndex,251async_: bool,252},253StreamCancelWrite {254ty: ComponentDefinedTypeId,255func: ModuleInternedTypeIndex,256async_: bool,257},258StreamDropReadable {259ty: ComponentDefinedTypeId,260func: ModuleInternedTypeIndex,261},262StreamDropWritable {263ty: ComponentDefinedTypeId,264func: ModuleInternedTypeIndex,265},266FutureNew {267ty: ComponentDefinedTypeId,268func: ModuleInternedTypeIndex,269},270FutureRead {271ty: ComponentDefinedTypeId,272options: LocalCanonicalOptions,273},274FutureWrite {275ty: ComponentDefinedTypeId,276options: LocalCanonicalOptions,277},278FutureCancelRead {279ty: ComponentDefinedTypeId,280func: ModuleInternedTypeIndex,281async_: bool,282},283FutureCancelWrite {284ty: ComponentDefinedTypeId,285func: ModuleInternedTypeIndex,286async_: bool,287},288FutureDropReadable {289ty: ComponentDefinedTypeId,290func: ModuleInternedTypeIndex,291},292FutureDropWritable {293ty: ComponentDefinedTypeId,294func: ModuleInternedTypeIndex,295},296ErrorContextNew {297options: LocalCanonicalOptions,298},299ErrorContextDebugMessage {300options: LocalCanonicalOptions,301},302ErrorContextDrop {303func: ModuleInternedTypeIndex,304},305ContextGet {306func: ModuleInternedTypeIndex,307i: u32,308},309ContextSet {310func: ModuleInternedTypeIndex,311i: u32,312},313ThreadIndex {314func: ModuleInternedTypeIndex,315},316ThreadNewIndirect {317func: ModuleInternedTypeIndex,318start_func_ty: ComponentTypeIndex,319start_func_table_index: TableIndex,320},321ThreadSwitchTo {322func: ModuleInternedTypeIndex,323cancellable: bool,324},325ThreadSuspend {326func: ModuleInternedTypeIndex,327cancellable: bool,328},329ThreadResumeLater {330func: ModuleInternedTypeIndex,331},332ThreadYieldTo {333func: ModuleInternedTypeIndex,334cancellable: bool,335},336337// core wasm modules338ModuleStatic(StaticModuleIndex, ComponentCoreModuleTypeId),339340// core wasm module instances341ModuleInstantiate(ModuleIndex, HashMap<&'data str, ModuleInstanceIndex>),342ModuleSynthetic(HashMap<&'data str, EntityIndex>),343344// components345ComponentStatic(StaticComponentIndex, ClosedOverVars),346347// component instances348ComponentInstantiate(349ComponentIndex,350HashMap<&'data str, ComponentItem>,351ComponentInstanceTypeId,352),353ComponentSynthetic(HashMap<&'data str, ComponentItem>, ComponentInstanceTypeId),354355// alias section356AliasExportFunc(ModuleInstanceIndex, &'data str),357AliasExportTable(ModuleInstanceIndex, &'data str),358AliasExportGlobal(ModuleInstanceIndex, &'data str),359AliasExportMemory(ModuleInstanceIndex, &'data str),360AliasExportTag(ModuleInstanceIndex, &'data str),361AliasComponentExport(ComponentInstanceIndex, &'data str),362AliasModule(ClosedOverModule),363AliasComponent(ClosedOverComponent),364365// export section366Export(ComponentItem),367}368369/// The "closure environment" of components themselves.370///371/// For more information see `LexicalScope`.372#[derive(Default)]373struct ClosedOverVars {374components: PrimaryMap<ComponentUpvarIndex, ClosedOverComponent>,375modules: PrimaryMap<ModuleUpvarIndex, ClosedOverModule>,376}377378/// Description how a component is closed over when the closure variables for379/// a component are being created.380///381/// For more information see `LexicalScope`.382enum ClosedOverComponent {383/// A closed over component is coming from the local component's index384/// space, meaning a previously defined component is being captured.385Local(ComponentIndex),386/// A closed over component is coming from our own component's list of387/// upvars. This list was passed to us by our enclosing component, which388/// will eventually have bottomed out in closing over a `Local` component389/// index for some parent component.390Upvar(ComponentUpvarIndex),391}392393/// Same as `ClosedOverComponent`, but for modules.394enum ClosedOverModule {395Local(ModuleIndex),396Upvar(ModuleUpvarIndex),397}398399/// The data model for objects that are not unboxed in locals.400#[derive(Debug, Clone, Hash, Eq, PartialEq)]401pub enum LocalDataModel {402/// Data is stored in GC objects.403Gc {},404405/// Data is stored in a linear memory.406LinearMemory {407/// An optional memory definition supplied.408memory: Option<MemoryIndex>,409/// An optional definition of `realloc` to used.410realloc: Option<FuncIndex>,411},412}413414/// Representation of canonical ABI options.415struct LocalCanonicalOptions {416string_encoding: StringEncoding,417post_return: Option<FuncIndex>,418async_: bool,419cancellable: bool,420callback: Option<FuncIndex>,421/// The type index of the core GC types signature.422core_type: ModuleInternedTypeIndex,423data_model: LocalDataModel,424}425426enum Action {427KeepGoing,428Skip(usize),429Done,430}431432impl<'a, 'data> Translator<'a, 'data> {433/// Creates a new translation state ready to translate a component.434pub fn new(435tunables: &'a Tunables,436validator: &'a mut Validator,437types: &'a mut ComponentTypesBuilder,438scope_vec: &'data ScopeVec<u8>,439) -> Self {440let mut parser = Parser::new(0);441parser.set_features(*validator.features());442Self {443result: Translation::default(),444tunables,445validator,446types: PreInliningComponentTypes::new(types),447parser,448lexical_scopes: Vec::new(),449static_components: Default::default(),450static_modules: Default::default(),451scope_vec,452unsafe_intrinsics_import: None,453}454}455456/// Expose Wasmtime's unsafe intrinsics under the given top-level import457/// name.458pub fn expose_unsafe_intrinsics(&mut self, name: &'a str) -> &mut Self {459assert!(self.unsafe_intrinsics_import.is_none());460self.unsafe_intrinsics_import = Some(name);461self462}463464/// Translates the binary `component`.465///466/// This is the workhorse of compilation which will parse all of467/// `component` and create type information for Wasmtime and such. The468/// `component` does not have to be valid and it will be validated during469/// compilation.470///471/// The result of this function is a tuple of the final component's472/// description plus a list of core wasm modules found within the473/// component. The component's description actually erases internal474/// components, instances, etc, as much as it can. Instead `Component`475/// retains a flat list of initializers (no nesting) which was created476/// as part of compilation from the nested structure of the original477/// component.478///479/// The list of core wasm modules found is provided to allow compiling480/// modules externally in parallel. Additionally initializers in481/// `Component` may refer to the modules in the map returned by index.482///483/// # Errors484///485/// This function will return an error if the `component` provided is486/// invalid.487pub fn translate(488mut self,489component: &'data [u8],490) -> Result<(491ComponentTranslation,492PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,493)> {494// First up wasmparser is used to actually perform the translation and495// validation of this component. This will produce a list of core wasm496// modules in addition to components which are found during the497// translation process. When doing this only a `Translation` is created498// which is a simple representation of a component.499let mut remaining = component;500loop {501let payload = match self.parser.parse(remaining, true)? {502Chunk::Parsed { payload, consumed } => {503remaining = &remaining[consumed..];504payload505}506Chunk::NeedMoreData(_) => unreachable!(),507};508509match self.translate_payload(payload, component)? {510Action::KeepGoing => {}511Action::Skip(n) => remaining = &remaining[n..],512Action::Done => break,513}514}515assert!(remaining.is_empty());516assert!(self.lexical_scopes.is_empty());517518// ... after translation initially finishes the next pass is performed519// which we're calling "inlining". This will "instantiate" the root520// component, following nested component instantiations, creating a521// global list of initializers along the way. This phase uses the simple522// initializers in each component to track dataflow of host imports and523// internal references to items throughout a component at compile-time.524// The produce initializers in the final `Component` are intended to be525// much simpler than the original component and more efficient for526// Wasmtime to process at runtime as well (e.g. no string lookups as527// most everything is done through indices instead).528let mut component = inline::run(529self.types.types_mut_for_inlining(),530&self.result,531&self.static_modules,532&self.static_components,533)?;534535self.partition_adapter_modules(&mut component);536537let translation =538component.finish(self.types.types_mut_for_inlining(), self.result.types_ref())?;539540self.analyze_function_imports(&translation);541542Ok((translation, self.static_modules))543}544545fn analyze_function_imports(&mut self, translation: &ComponentTranslation) {546// First, abstract interpret the initializers to create a map from each547// static module to its abstract set of instantiations.548let mut instantiations = SecondaryMap::<StaticModuleIndex, AbstractInstantiations>::new();549let mut instance_to_module =550PrimaryMap::<RuntimeInstanceIndex, PackedOption<StaticModuleIndex>>::new();551for init in &translation.component.initializers {552match init {553GlobalInitializer::InstantiateModule(instantiation, _) => match instantiation {554InstantiateModule::Static(module, args) => {555instantiations[*module].join(AbstractInstantiations::One(&*args));556instance_to_module.push(Some(*module).into());557}558_ => {559instance_to_module.push(None.into());560}561},562_ => continue,563}564}565566// Second, make sure to mark exported modules as instantiated many567// times, since they could be linked with who-knows-what at runtime.568for item in translation.component.export_items.values() {569if let Export::ModuleStatic { index, .. } = item {570instantiations[*index].join(AbstractInstantiations::Many)571}572}573574// Finally, iterate over our instantiations and record statically-known575// function imports so that they can get translated into direct calls576// (and eventually get inlined) rather than indirect calls through the577// imports table.578for (module, instantiations) in instantiations.iter() {579let args = match instantiations {580dfg::AbstractInstantiations::Many | dfg::AbstractInstantiations::None => continue,581dfg::AbstractInstantiations::One(args) => args,582};583584let mut imported_func_counter = 0_u32;585for (i, arg) in args.iter().enumerate() {586// Only consider function imports.587let (_, _, crate::types::EntityType::Function(_)) =588self.static_modules[module].module.import(i).unwrap()589else {590continue;591};592593let imported_func = FuncIndex::from_u32(imported_func_counter);594imported_func_counter += 1;595debug_assert!(596self.static_modules[module]597.module598.defined_func_index(imported_func)599.is_none()600);601602let known_func = match arg {603CoreDef::InstanceFlags(_) => unreachable!("instance flags are not a function"),604CoreDef::TaskMayBlock => unreachable!("task_may_block is not a function"),605606// We could in theory inline these trampolines, so it could607// potentially make sense to record that we know this608// imported function is this particular trampoline. However,609// everything else is based around (module,610// defined-function) pairs and these trampolines don't fit611// that paradigm. Also, inlining trampolines gets really612// tricky when we consider the stack pointer, frame pointer,613// and return address note-taking that they do for the614// purposes of stack walking. We could, with enough effort,615// turn them into direct calls even though we probably616// wouldn't ever inline them, but it just doesn't seem worth617// the effort.618CoreDef::Trampoline(_) => continue,619620// This import is a compile-time builtin intrinsic, we621// should inline its implementation during function622// translation.623CoreDef::UnsafeIntrinsic(i) => FuncKey::UnsafeIntrinsic(Abi::Wasm, *i),624625// This imported function is an export from another626// instance, a perfect candidate for becoming an inlinable627// direct call!628CoreDef::Export(export) => {629let Some(arg_module) = &instance_to_module[export.instance].expand() else {630// Instance of a dynamic module that is not part of631// this component, not a statically-known module632// inside this component. We have to do an indirect633// call.634continue;635};636637let ExportItem::Index(EntityIndex::Function(arg_func)) = &export.item638else {639unreachable!("function imports must be functions")640};641642let Some(arg_module_def_func) = self.static_modules[*arg_module]643.module644.defined_func_index(*arg_func)645else {646// TODO: we should ideally follow re-export chains647// to bottom out the instantiation argument in648// either a definition or an import at the root649// component boundary. In practice, this pattern is650// rare, so following these chains is left for the651// Future.652continue;653};654655FuncKey::DefinedWasmFunction(*arg_module, arg_module_def_func)656}657};658659assert!(660self.static_modules[module].known_imported_functions[imported_func].is_none()661);662self.static_modules[module].known_imported_functions[imported_func] =663Some(known_func);664}665}666}667668fn translate_payload(669&mut self,670payload: Payload<'data>,671component: &'data [u8],672) -> Result<Action> {673match payload {674Payload::Version {675num,676encoding,677range,678} => {679self.validator.version(num, encoding, &range)?;680681match encoding {682Encoding::Component => {}683Encoding::Module => {684bail!("attempted to parse a wasm module with a component parser");685}686}687}688689Payload::End(offset) => {690assert!(self.result.types.is_none());691self.result.types = Some(self.validator.end(offset)?);692693// Exit the current lexical scope. If there is no parent (no694// frame currently on the stack) then translation is finished.695// Otherwise that means that a nested component has been696// completed and is recorded as such.697let LexicalScope {698parser,699translation,700closure_args,701} = match self.lexical_scopes.pop() {702Some(frame) => frame,703None => return Ok(Action::Done),704};705self.parser = parser;706let component = mem::replace(&mut self.result, translation);707let static_idx = self.static_components.push(component);708self.result709.initializers710.push(LocalInitializer::ComponentStatic(static_idx, closure_args));711}712713// When we see a type section the types are validated and then714// translated into Wasmtime's representation. Each active type715// definition is recorded in the `ComponentTypesBuilder` tables, or716// this component's active scope.717//718// Note that the push/pop of the component types scope happens above719// in `Version` and `End` since multiple type sections can appear720// within a component.721Payload::ComponentTypeSection(s) => {722let mut component_type_index =723self.validator.types(0).unwrap().component_type_count();724self.validator.component_type_section(&s)?;725726// Look for resource types and if a local resource is defined727// then an initializer is added to define that resource type and728// reference its destructor.729let types = self.validator.types(0).unwrap();730for ty in s {731match ty? {732wasmparser::ComponentType::Resource { rep, dtor } => {733let rep = self.types.convert_valtype(rep)?;734let id = types735.component_any_type_at(component_type_index)736.unwrap_resource();737let dtor = dtor.map(FuncIndex::from_u32);738self.result739.initializers740.push(LocalInitializer::Resource(id, rep, dtor));741}742743// no extra processing needed744wasmparser::ComponentType::Defined(_)745| wasmparser::ComponentType::Func(_)746| wasmparser::ComponentType::Instance(_)747| wasmparser::ComponentType::Component(_) => {}748}749750component_type_index += 1;751}752}753Payload::CoreTypeSection(s) => {754self.validator.core_type_section(&s)?;755}756757// Processing the import section at this point is relatively simple758// which is to simply record the name of the import and the type759// information associated with it.760Payload::ComponentImportSection(s) => {761self.validator.component_import_section(&s)?;762for import in s {763let import = import?;764let types = self.validator.types(0).unwrap();765let ty = types766.component_entity_type_of_import(import.name.0)767.unwrap();768769if self.is_unsafe_intrinsics_import(import.name.0) {770self.check_unsafe_intrinsics_import(import.name.0, ty)?;771self.result772.initializers773.push(LocalInitializer::IntrinsicsImport);774} else {775self.result776.initializers777.push(LocalInitializer::Import(import.name, ty));778}779}780}781782// Entries in the canonical section will get initializers recorded783// with the listed options for lifting/lowering.784Payload::ComponentCanonicalSection(s) => {785let types = self.validator.types(0).unwrap();786let mut core_func_index = types.function_count();787self.validator.component_canonical_section(&s)?;788for func in s {789let init = match func? {790wasmparser::CanonicalFunction::Lift {791type_index,792core_func_index,793options,794} => {795let ty = self796.validator797.types(0)798.unwrap()799.component_any_type_at(type_index)800.unwrap_func();801802let func = FuncIndex::from_u32(core_func_index);803let options = self.canonical_options(&options, core_func_index)?;804LocalInitializer::Lift(ty, func, options)805}806wasmparser::CanonicalFunction::Lower {807func_index,808options,809} => {810let lower_ty = self811.validator812.types(0)813.unwrap()814.component_function_at(func_index);815let func = ComponentFuncIndex::from_u32(func_index);816let options = self.canonical_options(&options, core_func_index)?;817core_func_index += 1;818LocalInitializer::Lower {819func,820options,821lower_ty,822}823}824wasmparser::CanonicalFunction::ResourceNew { resource } => {825let resource = self826.validator827.types(0)828.unwrap()829.component_any_type_at(resource)830.unwrap_resource();831let ty = self.core_func_signature(core_func_index)?;832core_func_index += 1;833LocalInitializer::ResourceNew(resource, ty)834}835wasmparser::CanonicalFunction::ResourceDrop { resource } => {836let resource = self837.validator838.types(0)839.unwrap()840.component_any_type_at(resource)841.unwrap_resource();842let ty = self.core_func_signature(core_func_index)?;843core_func_index += 1;844LocalInitializer::ResourceDrop(resource, ty)845}846wasmparser::CanonicalFunction::ResourceDropAsync { resource } => {847let _ = resource;848bail!("support for `resource.drop async` not implemented yet")849}850wasmparser::CanonicalFunction::ResourceRep { resource } => {851let resource = self852.validator853.types(0)854.unwrap()855.component_any_type_at(resource)856.unwrap_resource();857let ty = self.core_func_signature(core_func_index)?;858core_func_index += 1;859LocalInitializer::ResourceRep(resource, ty)860}861wasmparser::CanonicalFunction::ThreadSpawnRef { .. }862| wasmparser::CanonicalFunction::ThreadSpawnIndirect { .. }863| wasmparser::CanonicalFunction::ThreadAvailableParallelism => {864bail!("unsupported intrinsic")865}866wasmparser::CanonicalFunction::BackpressureInc => {867let core_type = self.core_func_signature(core_func_index)?;868core_func_index += 1;869LocalInitializer::BackpressureInc { func: core_type }870}871wasmparser::CanonicalFunction::BackpressureDec => {872let core_type = self.core_func_signature(core_func_index)?;873core_func_index += 1;874LocalInitializer::BackpressureDec { func: core_type }875}876877wasmparser::CanonicalFunction::TaskReturn { result, options } => {878let result = result.map(|ty| match ty {879wasmparser::ComponentValType::Primitive(ty) => {880ComponentValType::Primitive(ty)881}882wasmparser::ComponentValType::Type(ty) => ComponentValType::Type(883self.validator884.types(0)885.unwrap()886.component_defined_type_at(ty),887),888});889let options = self.canonical_options(&options, core_func_index)?;890core_func_index += 1;891LocalInitializer::TaskReturn { result, options }892}893wasmparser::CanonicalFunction::TaskCancel => {894let func = self.core_func_signature(core_func_index)?;895core_func_index += 1;896LocalInitializer::TaskCancel { func }897}898wasmparser::CanonicalFunction::WaitableSetNew => {899let func = self.core_func_signature(core_func_index)?;900core_func_index += 1;901LocalInitializer::WaitableSetNew { func }902}903wasmparser::CanonicalFunction::WaitableSetWait {904cancellable,905memory,906} => {907let core_type = self.core_func_signature(core_func_index)?;908core_func_index += 1;909LocalInitializer::WaitableSetWait {910options: LocalCanonicalOptions {911core_type,912cancellable,913async_: false,914data_model: LocalDataModel::LinearMemory {915memory: Some(MemoryIndex::from_u32(memory)),916realloc: None,917},918post_return: None,919callback: None,920string_encoding: StringEncoding::Utf8,921},922}923}924wasmparser::CanonicalFunction::WaitableSetPoll {925cancellable,926memory,927} => {928let core_type = self.core_func_signature(core_func_index)?;929core_func_index += 1;930LocalInitializer::WaitableSetPoll {931options: LocalCanonicalOptions {932core_type,933async_: false,934cancellable,935data_model: LocalDataModel::LinearMemory {936memory: Some(MemoryIndex::from_u32(memory)),937realloc: None,938},939post_return: None,940callback: None,941string_encoding: StringEncoding::Utf8,942},943}944}945wasmparser::CanonicalFunction::WaitableSetDrop => {946let func = self.core_func_signature(core_func_index)?;947core_func_index += 1;948LocalInitializer::WaitableSetDrop { func }949}950wasmparser::CanonicalFunction::WaitableJoin => {951let func = self.core_func_signature(core_func_index)?;952core_func_index += 1;953LocalInitializer::WaitableJoin { func }954}955wasmparser::CanonicalFunction::ThreadYield { cancellable } => {956let func = self.core_func_signature(core_func_index)?;957core_func_index += 1;958LocalInitializer::ThreadYield { func, cancellable }959}960wasmparser::CanonicalFunction::SubtaskDrop => {961let func = self.core_func_signature(core_func_index)?;962core_func_index += 1;963LocalInitializer::SubtaskDrop { func }964}965wasmparser::CanonicalFunction::SubtaskCancel { async_ } => {966let func = self.core_func_signature(core_func_index)?;967core_func_index += 1;968LocalInitializer::SubtaskCancel { func, async_ }969}970wasmparser::CanonicalFunction::StreamNew { ty } => {971let ty = self972.validator973.types(0)974.unwrap()975.component_defined_type_at(ty);976let func = self.core_func_signature(core_func_index)?;977core_func_index += 1;978LocalInitializer::StreamNew { ty, func }979}980wasmparser::CanonicalFunction::StreamRead { ty, options } => {981let ty = self982.validator983.types(0)984.unwrap()985.component_defined_type_at(ty);986let options = self.canonical_options(&options, core_func_index)?;987core_func_index += 1;988LocalInitializer::StreamRead { ty, options }989}990wasmparser::CanonicalFunction::StreamWrite { ty, options } => {991let ty = self992.validator993.types(0)994.unwrap()995.component_defined_type_at(ty);996let options = self.canonical_options(&options, core_func_index)?;997core_func_index += 1;998LocalInitializer::StreamWrite { ty, options }999}1000wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => {1001let ty = self1002.validator1003.types(0)1004.unwrap()1005.component_defined_type_at(ty);1006let func = self.core_func_signature(core_func_index)?;1007core_func_index += 1;1008LocalInitializer::StreamCancelRead { ty, func, async_ }1009}1010wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => {1011let ty = self1012.validator1013.types(0)1014.unwrap()1015.component_defined_type_at(ty);1016let func = self.core_func_signature(core_func_index)?;1017core_func_index += 1;1018LocalInitializer::StreamCancelWrite { ty, func, async_ }1019}1020wasmparser::CanonicalFunction::StreamDropReadable { ty } => {1021let ty = self1022.validator1023.types(0)1024.unwrap()1025.component_defined_type_at(ty);1026let func = self.core_func_signature(core_func_index)?;1027core_func_index += 1;1028LocalInitializer::StreamDropReadable { ty, func }1029}1030wasmparser::CanonicalFunction::StreamDropWritable { ty } => {1031let ty = self1032.validator1033.types(0)1034.unwrap()1035.component_defined_type_at(ty);1036let func = self.core_func_signature(core_func_index)?;1037core_func_index += 1;1038LocalInitializer::StreamDropWritable { ty, func }1039}1040wasmparser::CanonicalFunction::FutureNew { ty } => {1041let ty = self1042.validator1043.types(0)1044.unwrap()1045.component_defined_type_at(ty);1046let func = self.core_func_signature(core_func_index)?;1047core_func_index += 1;1048LocalInitializer::FutureNew { ty, func }1049}1050wasmparser::CanonicalFunction::FutureRead { ty, options } => {1051let ty = self1052.validator1053.types(0)1054.unwrap()1055.component_defined_type_at(ty);1056let options = self.canonical_options(&options, core_func_index)?;1057core_func_index += 1;1058LocalInitializer::FutureRead { ty, options }1059}1060wasmparser::CanonicalFunction::FutureWrite { ty, options } => {1061let ty = self1062.validator1063.types(0)1064.unwrap()1065.component_defined_type_at(ty);1066let options = self.canonical_options(&options, core_func_index)?;1067core_func_index += 1;1068LocalInitializer::FutureWrite { ty, options }1069}1070wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => {1071let ty = self1072.validator1073.types(0)1074.unwrap()1075.component_defined_type_at(ty);1076let func = self.core_func_signature(core_func_index)?;1077core_func_index += 1;1078LocalInitializer::FutureCancelRead { ty, func, async_ }1079}1080wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => {1081let ty = self1082.validator1083.types(0)1084.unwrap()1085.component_defined_type_at(ty);1086let func = self.core_func_signature(core_func_index)?;1087core_func_index += 1;1088LocalInitializer::FutureCancelWrite { ty, func, async_ }1089}1090wasmparser::CanonicalFunction::FutureDropReadable { ty } => {1091let ty = self1092.validator1093.types(0)1094.unwrap()1095.component_defined_type_at(ty);1096let func = self.core_func_signature(core_func_index)?;1097core_func_index += 1;1098LocalInitializer::FutureDropReadable { ty, func }1099}1100wasmparser::CanonicalFunction::FutureDropWritable { ty } => {1101let ty = self1102.validator1103.types(0)1104.unwrap()1105.component_defined_type_at(ty);1106let func = self.core_func_signature(core_func_index)?;1107core_func_index += 1;1108LocalInitializer::FutureDropWritable { ty, func }1109}1110wasmparser::CanonicalFunction::ErrorContextNew { options } => {1111let options = self.canonical_options(&options, core_func_index)?;1112core_func_index += 1;1113LocalInitializer::ErrorContextNew { options }1114}1115wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => {1116let options = self.canonical_options(&options, core_func_index)?;1117core_func_index += 1;1118LocalInitializer::ErrorContextDebugMessage { options }1119}1120wasmparser::CanonicalFunction::ErrorContextDrop => {1121let func = self.core_func_signature(core_func_index)?;1122core_func_index += 1;1123LocalInitializer::ErrorContextDrop { func }1124}1125wasmparser::CanonicalFunction::ContextGet(i) => {1126let func = self.core_func_signature(core_func_index)?;1127core_func_index += 1;1128LocalInitializer::ContextGet { i, func }1129}1130wasmparser::CanonicalFunction::ContextSet(i) => {1131let func = self.core_func_signature(core_func_index)?;1132core_func_index += 1;1133LocalInitializer::ContextSet { i, func }1134}1135wasmparser::CanonicalFunction::ThreadIndex => {1136let func = self.core_func_signature(core_func_index)?;1137core_func_index += 1;1138LocalInitializer::ThreadIndex { func }1139}1140wasmparser::CanonicalFunction::ThreadNewIndirect {1141func_ty_index,1142table_index,1143} => {1144let func = self.core_func_signature(core_func_index)?;1145core_func_index += 1;1146LocalInitializer::ThreadNewIndirect {1147func,1148start_func_ty: ComponentTypeIndex::from_u32(func_ty_index),1149start_func_table_index: TableIndex::from_u32(table_index),1150}1151}1152wasmparser::CanonicalFunction::ThreadSwitchTo { cancellable } => {1153let func = self.core_func_signature(core_func_index)?;1154core_func_index += 1;1155LocalInitializer::ThreadSwitchTo { func, cancellable }1156}1157wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => {1158let func = self.core_func_signature(core_func_index)?;1159core_func_index += 1;1160LocalInitializer::ThreadSuspend { func, cancellable }1161}1162wasmparser::CanonicalFunction::ThreadResumeLater => {1163let func = self.core_func_signature(core_func_index)?;1164core_func_index += 1;1165LocalInitializer::ThreadResumeLater { func }1166}1167wasmparser::CanonicalFunction::ThreadYieldTo { cancellable } => {1168let func = self.core_func_signature(core_func_index)?;1169core_func_index += 1;1170LocalInitializer::ThreadYieldTo { func, cancellable }1171}1172};1173self.result.initializers.push(init);1174}1175}11761177// Core wasm modules are translated inline directly here with the1178// `ModuleEnvironment` from core wasm compilation. This will return1179// to the caller the size of the module so it knows how many bytes1180// of the input are skipped.1181//1182// Note that this is just initial type translation of the core wasm1183// module and actual function compilation is deferred until this1184// entire process has completed.1185Payload::ModuleSection {1186parser,1187unchecked_range,1188} => {1189let index = self.validator.types(0).unwrap().module_count();1190self.validator.module_section(&unchecked_range)?;1191let static_module_index = self.static_modules.next_key();1192let translation = ModuleEnvironment::new(1193self.tunables,1194self.validator,1195self.types.module_types_builder(),1196static_module_index,1197)1198.translate(1199parser,1200component1201.get(unchecked_range.start..unchecked_range.end)1202.ok_or_else(|| {1203format_err!(1204"section range {}..{} is out of bounds (bound = {})",1205unchecked_range.start,1206unchecked_range.end,1207component.len()1208)1209.context("wasm component contains an invalid module section")1210})?,1211)?;1212let static_module_index2 = self.static_modules.push(translation);1213assert_eq!(static_module_index, static_module_index2);1214let types = self.validator.types(0).unwrap();1215let ty = types.module_at(index);1216self.result1217.initializers1218.push(LocalInitializer::ModuleStatic(static_module_index, ty));1219return Ok(Action::Skip(unchecked_range.end - unchecked_range.start));1220}12211222// When a sub-component is found then the current translation state1223// is pushed onto the `lexical_scopes` stack. This will subsequently1224// get popped as part of `Payload::End` processing above.1225//1226// Note that the set of closure args for this new lexical scope1227// starts empty since it will only get populated if translation of1228// the nested component ends up aliasing some outer module or1229// component.1230Payload::ComponentSection {1231parser,1232unchecked_range,1233} => {1234self.validator.component_section(&unchecked_range)?;1235self.lexical_scopes.push(LexicalScope {1236parser: mem::replace(&mut self.parser, parser),1237translation: mem::take(&mut self.result),1238closure_args: ClosedOverVars::default(),1239});1240}12411242// Both core wasm instances and component instances record1243// initializers of what form of instantiation is performed which1244// largely just records the arguments given from wasmparser into a1245// `HashMap` for processing later during inlining.1246Payload::InstanceSection(s) => {1247self.validator.instance_section(&s)?;1248for instance in s {1249let init = match instance? {1250wasmparser::Instance::Instantiate { module_index, args } => {1251let index = ModuleIndex::from_u32(module_index);1252self.instantiate_module(index, &args)1253}1254wasmparser::Instance::FromExports(exports) => {1255self.instantiate_module_from_exports(&exports)1256}1257};1258self.result.initializers.push(init);1259}1260}1261Payload::ComponentInstanceSection(s) => {1262let mut index = self.validator.types(0).unwrap().component_instance_count();1263self.validator.component_instance_section(&s)?;1264for instance in s {1265let types = self.validator.types(0).unwrap();1266let ty = types.component_instance_at(index);1267let init = match instance? {1268wasmparser::ComponentInstance::Instantiate {1269component_index,1270args,1271} => {1272let index = ComponentIndex::from_u32(component_index);1273self.instantiate_component(index, &args, ty)?1274}1275wasmparser::ComponentInstance::FromExports(exports) => {1276self.instantiate_component_from_exports(&exports, ty)?1277}1278};1279self.result.initializers.push(init);1280index += 1;1281}1282}12831284// Exports don't actually fill out the `initializers` array but1285// instead fill out the one other field in a `Translation`, the1286// `exports` field (as one might imagine). This for now simply1287// records the index of what's exported and that's tracked further1288// later during inlining.1289Payload::ComponentExportSection(s) => {1290self.validator.component_export_section(&s)?;1291for export in s {1292let export = export?;1293let item = self.kind_to_item(export.kind, export.index)?;1294let prev = self.result.exports.insert(export.name.0, item);1295assert!(prev.is_none());1296self.result1297.initializers1298.push(LocalInitializer::Export(item));1299}1300}13011302Payload::ComponentStartSection { start, range } => {1303self.validator.component_start_section(&start, &range)?;1304unimplemented!("component start section");1305}13061307// Aliases of instance exports (either core or component) will be1308// recorded as an initializer of the appropriate type with outer1309// aliases handled specially via upvars and type processing.1310Payload::ComponentAliasSection(s) => {1311self.validator.component_alias_section(&s)?;1312for alias in s {1313let init = match alias? {1314wasmparser::ComponentAlias::InstanceExport {1315kind: _,1316instance_index,1317name,1318} => {1319let instance = ComponentInstanceIndex::from_u32(instance_index);1320LocalInitializer::AliasComponentExport(instance, name)1321}1322wasmparser::ComponentAlias::Outer { kind, count, index } => {1323self.alias_component_outer(kind, count, index);1324continue;1325}1326wasmparser::ComponentAlias::CoreInstanceExport {1327kind,1328instance_index,1329name,1330} => {1331let instance = ModuleInstanceIndex::from_u32(instance_index);1332self.alias_module_instance_export(kind, instance, name)1333}1334};1335self.result.initializers.push(init);1336}1337}13381339// All custom sections are ignored by Wasmtime at this time.1340//1341// FIXME(WebAssembly/component-model#14): probably want to specify1342// and parse a `name` section here.1343Payload::CustomSection { .. } => {}13441345// Anything else is either not reachable since we never enable the1346// feature in Wasmtime or we do enable it and it's a bug we don't1347// implement it, so let validation take care of most errors here and1348// if it gets past validation provide a helpful error message to1349// debug.1350other => {1351self.validator.payload(&other)?;1352panic!("unimplemented section {other:?}");1353}1354}13551356Ok(Action::KeepGoing)1357}13581359fn instantiate_module(1360&mut self,1361module: ModuleIndex,1362raw_args: &[wasmparser::InstantiationArg<'data>],1363) -> LocalInitializer<'data> {1364let mut args = HashMap::with_capacity(raw_args.len());1365for arg in raw_args {1366match arg.kind {1367wasmparser::InstantiationArgKind::Instance => {1368let idx = ModuleInstanceIndex::from_u32(arg.index);1369args.insert(arg.name, idx);1370}1371}1372}1373LocalInitializer::ModuleInstantiate(module, args)1374}13751376/// Creates a synthetic module from the list of items currently in the1377/// module and their given names.1378fn instantiate_module_from_exports(1379&mut self,1380exports: &[wasmparser::Export<'data>],1381) -> LocalInitializer<'data> {1382let mut map = HashMap::with_capacity(exports.len());1383for export in exports {1384let idx = match export.kind {1385wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {1386let index = FuncIndex::from_u32(export.index);1387EntityIndex::Function(index)1388}1389wasmparser::ExternalKind::Table => {1390let index = TableIndex::from_u32(export.index);1391EntityIndex::Table(index)1392}1393wasmparser::ExternalKind::Memory => {1394let index = MemoryIndex::from_u32(export.index);1395EntityIndex::Memory(index)1396}1397wasmparser::ExternalKind::Global => {1398let index = GlobalIndex::from_u32(export.index);1399EntityIndex::Global(index)1400}1401wasmparser::ExternalKind::Tag => {1402let index = TagIndex::from_u32(export.index);1403EntityIndex::Tag(index)1404}1405};1406map.insert(export.name, idx);1407}1408LocalInitializer::ModuleSynthetic(map)1409}14101411fn instantiate_component(1412&mut self,1413component: ComponentIndex,1414raw_args: &[wasmparser::ComponentInstantiationArg<'data>],1415ty: ComponentInstanceTypeId,1416) -> Result<LocalInitializer<'data>> {1417let mut args = HashMap::with_capacity(raw_args.len());1418for arg in raw_args {1419let idx = self.kind_to_item(arg.kind, arg.index)?;1420args.insert(arg.name, idx);1421}14221423Ok(LocalInitializer::ComponentInstantiate(component, args, ty))1424}14251426/// Creates a synthetic module from the list of items currently in the1427/// module and their given names.1428fn instantiate_component_from_exports(1429&mut self,1430exports: &[wasmparser::ComponentExport<'data>],1431ty: ComponentInstanceTypeId,1432) -> Result<LocalInitializer<'data>> {1433let mut map = HashMap::with_capacity(exports.len());1434for export in exports {1435let idx = self.kind_to_item(export.kind, export.index)?;1436map.insert(export.name.0, idx);1437}14381439Ok(LocalInitializer::ComponentSynthetic(map, ty))1440}14411442fn kind_to_item(1443&mut self,1444kind: wasmparser::ComponentExternalKind,1445index: u32,1446) -> Result<ComponentItem> {1447Ok(match kind {1448wasmparser::ComponentExternalKind::Func => {1449let index = ComponentFuncIndex::from_u32(index);1450ComponentItem::Func(index)1451}1452wasmparser::ComponentExternalKind::Module => {1453let index = ModuleIndex::from_u32(index);1454ComponentItem::Module(index)1455}1456wasmparser::ComponentExternalKind::Instance => {1457let index = ComponentInstanceIndex::from_u32(index);1458ComponentItem::ComponentInstance(index)1459}1460wasmparser::ComponentExternalKind::Component => {1461let index = ComponentIndex::from_u32(index);1462ComponentItem::Component(index)1463}1464wasmparser::ComponentExternalKind::Value => {1465unimplemented!("component values");1466}1467wasmparser::ComponentExternalKind::Type => {1468let types = self.validator.types(0).unwrap();1469let ty = types.component_any_type_at(index);1470ComponentItem::Type(ty)1471}1472})1473}14741475fn alias_module_instance_export(1476&mut self,1477kind: wasmparser::ExternalKind,1478instance: ModuleInstanceIndex,1479name: &'data str,1480) -> LocalInitializer<'data> {1481match kind {1482wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {1483LocalInitializer::AliasExportFunc(instance, name)1484}1485wasmparser::ExternalKind::Memory => LocalInitializer::AliasExportMemory(instance, name),1486wasmparser::ExternalKind::Table => LocalInitializer::AliasExportTable(instance, name),1487wasmparser::ExternalKind::Global => LocalInitializer::AliasExportGlobal(instance, name),1488wasmparser::ExternalKind::Tag => LocalInitializer::AliasExportTag(instance, name),1489}1490}14911492fn alias_component_outer(1493&mut self,1494kind: wasmparser::ComponentOuterAliasKind,1495count: u32,1496index: u32,1497) {1498match kind {1499wasmparser::ComponentOuterAliasKind::CoreType1500| wasmparser::ComponentOuterAliasKind::Type => {}15011502// For more information about the implementation of outer aliases1503// see the documentation of `LexicalScope`. Otherwise though the1504// main idea here is that the data to close over starts as `Local`1505// and then transitions to `Upvar` as its inserted into the parents1506// in order from target we're aliasing back to the current1507// component.1508wasmparser::ComponentOuterAliasKind::CoreModule => {1509let index = ModuleIndex::from_u32(index);1510let mut module = ClosedOverModule::Local(index);1511let depth = self.lexical_scopes.len() - (count as usize);1512for frame in self.lexical_scopes[depth..].iter_mut() {1513module = ClosedOverModule::Upvar(frame.closure_args.modules.push(module));1514}15151516// If the `module` is still `Local` then the `depth` was 0 and1517// it's an alias into our own space. Otherwise it's switched to1518// an upvar and will index into the upvar space. Either way1519// it's just plumbed directly into the initializer.1520self.result1521.initializers1522.push(LocalInitializer::AliasModule(module));1523}1524wasmparser::ComponentOuterAliasKind::Component => {1525let index = ComponentIndex::from_u32(index);1526let mut component = ClosedOverComponent::Local(index);1527let depth = self.lexical_scopes.len() - (count as usize);1528for frame in self.lexical_scopes[depth..].iter_mut() {1529component =1530ClosedOverComponent::Upvar(frame.closure_args.components.push(component));1531}15321533self.result1534.initializers1535.push(LocalInitializer::AliasComponent(component));1536}1537}1538}15391540fn canonical_options(1541&mut self,1542opts: &[wasmparser::CanonicalOption],1543core_func_index: u32,1544) -> WasmResult<LocalCanonicalOptions> {1545let core_type = self.core_func_signature(core_func_index)?;15461547let mut string_encoding = StringEncoding::Utf8;1548let mut post_return = None;1549let mut async_ = false;1550let mut callback = None;1551let mut memory = None;1552let mut realloc = None;1553let mut gc = false;15541555for opt in opts {1556match opt {1557wasmparser::CanonicalOption::UTF8 => {1558string_encoding = StringEncoding::Utf8;1559}1560wasmparser::CanonicalOption::UTF16 => {1561string_encoding = StringEncoding::Utf16;1562}1563wasmparser::CanonicalOption::CompactUTF16 => {1564string_encoding = StringEncoding::CompactUtf16;1565}1566wasmparser::CanonicalOption::Memory(idx) => {1567let idx = MemoryIndex::from_u32(*idx);1568memory = Some(idx);1569}1570wasmparser::CanonicalOption::Realloc(idx) => {1571let idx = FuncIndex::from_u32(*idx);1572realloc = Some(idx);1573}1574wasmparser::CanonicalOption::PostReturn(idx) => {1575let idx = FuncIndex::from_u32(*idx);1576post_return = Some(idx);1577}1578wasmparser::CanonicalOption::Async => async_ = true,1579wasmparser::CanonicalOption::Callback(idx) => {1580let idx = FuncIndex::from_u32(*idx);1581callback = Some(idx);1582}1583wasmparser::CanonicalOption::CoreType(idx) => {1584if cfg!(debug_assertions) {1585let types = self.validator.types(0).unwrap();1586let core_ty_id = types.core_type_at_in_component(*idx).unwrap_sub();1587let interned = self1588.types1589.module_types_builder()1590.intern_type(types, core_ty_id)?;1591debug_assert_eq!(interned, core_type);1592}1593}1594wasmparser::CanonicalOption::Gc => {1595gc = true;1596}1597}1598}15991600Ok(LocalCanonicalOptions {1601string_encoding,1602post_return,1603cancellable: false,1604async_,1605callback,1606core_type,1607data_model: if gc {1608LocalDataModel::Gc {}1609} else {1610LocalDataModel::LinearMemory { memory, realloc }1611},1612})1613}16141615/// Get the interned type index for the `index`th core function.1616fn core_func_signature(&mut self, index: u32) -> WasmResult<ModuleInternedTypeIndex> {1617let types = self.validator.types(0).unwrap();1618let id = types.core_function_at(index);1619self.types.module_types_builder().intern_type(types, id)1620}16211622fn is_unsafe_intrinsics_import(&self, import: &str) -> bool {1623self.lexical_scopes.is_empty()1624&& self1625.unsafe_intrinsics_import1626.is_some_and(|name| import == name)1627}16281629fn check_unsafe_intrinsics_import(&self, import: &str, ty: ComponentEntityType) -> Result<()> {1630let types = &self.validator.types(0).unwrap();16311632let ComponentEntityType::Instance(instance_ty) = ty else {1633bail!("bad unsafe intrinsics import: import `{import}` must be an instance import")1634};1635let instance_ty = &types[instance_ty];16361637ensure!(1638instance_ty.defined_resources.is_empty(),1639"bad unsafe intrinsics import: import `{import}` cannot define any resources"1640);1641ensure!(1642instance_ty.explicit_resources.is_empty(),1643"bad unsafe intrinsics import: import `{import}` cannot export any resources"1644);16451646for (name, ty) in &instance_ty.exports {1647let ComponentEntityType::Func(func_ty) = ty else {1648bail!(1649"bad unsafe intrinsics import: imported instance `{import}` must \1650only export functions"1651)1652};1653let func_ty = &types[*func_ty];16541655fn ty_eq(a: &InterfaceType, b: &wasmparser::component_types::ComponentValType) -> bool {1656use wasmparser::{PrimitiveValType as P, component_types::ComponentValType as C};1657match (a, b) {1658(InterfaceType::U8, C::Primitive(P::U8)) => true,1659(InterfaceType::U8, _) => false,16601661(InterfaceType::U16, C::Primitive(P::U16)) => true,1662(InterfaceType::U16, _) => false,16631664(InterfaceType::U32, C::Primitive(P::U32)) => true,1665(InterfaceType::U32, _) => false,16661667(InterfaceType::U64, C::Primitive(P::U64)) => true,1668(InterfaceType::U64, _) => false,16691670(ty, _) => unreachable!("no unsafe intrinsics use {ty:?}"),1671}1672}16731674fn check_types<'a>(1675expected: impl ExactSizeIterator<Item = &'a InterfaceType>,1676actual: impl ExactSizeIterator<Item = &'a wasmparser::component_types::ComponentValType>,1677kind: &str,1678import: &str,1679name: &str,1680) -> Result<()> {1681let expected_len = expected.len();1682let actual_len = actual.len();1683ensure!(1684expected_len == actual_len,1685"bad unsafe intrinsics import at `{import}`: function `{name}` must have \1686{expected_len} {kind}, found {actual_len}"1687);16881689for (i, (actual_ty, expected_ty)) in actual.zip(expected).enumerate() {1690ensure!(1691ty_eq(expected_ty, actual_ty),1692"bad unsafe intrinsics import at `{import}`: {kind}[{i}] for function \1693`{name}` must be `{expected_ty:?}`, found `{actual_ty:?}`"1694);1695}1696Ok(())1697}16981699let intrinsic = UnsafeIntrinsic::from_str(name)1700.with_context(|| format!("bad unsafe intrinsics import at `{import}`"))?;17011702check_types(1703intrinsic.component_params().iter(),1704func_ty.params.iter().map(|(_name, ty)| ty),1705"parameters",1706&import,1707&name,1708)?;1709check_types(1710intrinsic.component_results().iter(),1711func_ty.result.iter(),1712"results",1713&import,1714&name,1715)?;1716}17171718Ok(())1719}1720}17211722impl Translation<'_> {1723fn types_ref(&self) -> wasmparser::types::TypesRef<'_> {1724self.types.as_ref().unwrap().as_ref()1725}1726}17271728/// A small helper module which wraps a `ComponentTypesBuilder` and attempts1729/// to disallow access to mutable access to the builder before the inlining1730/// pass.1731///1732/// Type information in this translation pass must be preserved at the1733/// wasmparser layer of abstraction rather than being lowered into Wasmtime's1734/// own type system. Only during inlining are types fully assigned because1735/// that's when resource types become available as it's known which instance1736/// defines which resource, or more concretely the same component instantiated1737/// twice will produce two unique resource types unlike one as seen by1738/// wasmparser within the component.1739mod pre_inlining {1740use super::*;17411742pub struct PreInliningComponentTypes<'a> {1743types: &'a mut ComponentTypesBuilder,1744}17451746impl<'a> PreInliningComponentTypes<'a> {1747pub fn new(types: &'a mut ComponentTypesBuilder) -> Self {1748Self { types }1749}17501751pub fn module_types_builder(&mut self) -> &mut ModuleTypesBuilder {1752self.types.module_types_builder_mut()1753}17541755pub fn types(&self) -> &ComponentTypesBuilder {1756self.types1757}17581759// NB: this should in theory only be used for the `inline` phase of1760// translation.1761pub fn types_mut_for_inlining(&mut self) -> &mut ComponentTypesBuilder {1762self.types1763}1764}17651766impl TypeConvert for PreInliningComponentTypes<'_> {1767fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {1768self.types.lookup_heap_type(index)1769}17701771fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {1772self.types.lookup_type_index(index)1773}1774}1775}1776use pre_inlining::PreInliningComponentTypes;177717781779