use crate::component::*;
use crate::ScopeVec;
use crate::{
EntityIndex, ModuleEnvironment, ModuleTranslation, PrimaryMap, SignatureIndex, Tunables,
};
use anyhow::{bail, Result};
use indexmap::IndexMap;
use std::collections::HashMap;
use std::mem;
use wasmparser::{Chunk, Encoding, Parser, Payload, Validator};
mod adapt;
pub use self::adapt::*;
mod inline;
pub struct Translator<'a, 'data> {
result: Translation<'data>,
parser: Parser,
lexical_scopes: Vec<LexicalScope<'data>>,
validator: &'a mut Validator,
types: &'a mut ComponentTypesBuilder,
tunables: &'a Tunables,
scope_vec: &'data ScopeVec<u8>,
static_modules: PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
static_components: PrimaryMap<StaticComponentIndex, Translation<'data>>,
synthetic_instance_types:
PrimaryMap<SyntheticInstanceTypeIndex, HashMap<&'data str, ComponentItemType>>,
}
struct LexicalScope<'data> {
parser: Parser,
translation: Translation<'data>,
closure_args: ClosedOverVars,
}
#[derive(Default)]
struct Translation<'data> {
initializers: Vec<LocalInitializer<'data>>,
exports: IndexMap<&'data str, ComponentItem>,
funcs: PrimaryMap<FuncIndex, SignatureIndex>,
components: PrimaryMap<ComponentIndex, ComponentType>,
component_funcs: PrimaryMap<ComponentFuncIndex, TypeFuncIndex>,
component_instances: PrimaryMap<ComponentInstanceIndex, ComponentInstanceType>,
}
#[allow(missing_docs)]
enum LocalInitializer<'data> {
Import(&'data str, TypeDef),
Lower(ComponentFuncIndex, LocalCanonicalOptions),
Lift(TypeFuncIndex, FuncIndex, LocalCanonicalOptions),
ModuleStatic(StaticModuleIndex),
ModuleInstantiate(ModuleIndex, HashMap<&'data str, ModuleInstanceIndex>),
ModuleSynthetic(HashMap<&'data str, EntityIndex>),
ComponentStatic(StaticComponentIndex, ClosedOverVars),
ComponentInstantiate(ComponentIndex, HashMap<&'data str, ComponentItem>),
ComponentSynthetic(HashMap<&'data str, ComponentItem>),
AliasExportFunc(ModuleInstanceIndex, &'data str),
AliasExportTable(ModuleInstanceIndex, &'data str),
AliasExportGlobal(ModuleInstanceIndex, &'data str),
AliasExportMemory(ModuleInstanceIndex, &'data str),
AliasComponentExport(ComponentInstanceIndex, &'data str),
AliasModule(ClosedOverModule),
AliasComponent(ClosedOverComponent),
}
#[derive(Default)]
struct ClosedOverVars {
components: PrimaryMap<ComponentUpvarIndex, ClosedOverComponent>,
modules: PrimaryMap<ModuleUpvarIndex, ClosedOverModule>,
}
enum ClosedOverComponent {
Local(ComponentIndex),
Upvar(ComponentUpvarIndex),
}
enum ClosedOverModule {
Local(ModuleIndex),
Upvar(ModuleUpvarIndex),
}
struct LocalCanonicalOptions {
string_encoding: StringEncoding,
memory: Option<MemoryIndex>,
realloc: Option<FuncIndex>,
post_return: Option<FuncIndex>,
}
#[derive(Copy, Clone)]
enum ComponentType {
Index(TypeComponentIndex),
Static(StaticComponentIndex),
}
#[derive(Copy, Clone)]
enum ComponentInstanceType {
Index(TypeComponentInstanceIndex),
InstantiatedIndex(TypeComponentIndex),
InstantiatedStatic(StaticComponentIndex),
Synthetic(SyntheticInstanceTypeIndex),
}
#[derive(Copy, Clone)]
enum ComponentItemType {
Func(TypeFuncIndex),
Component(ComponentType),
Instance(ComponentInstanceType),
}
#[derive(Copy, Clone, PartialEq, Eq)]
struct SyntheticInstanceTypeIndex(u32);
cranelift_entity::entity_impl!(SyntheticInstanceTypeIndex);
enum Action {
KeepGoing,
Skip(usize),
Done,
}
impl<'a, 'data> Translator<'a, 'data> {
pub fn new(
tunables: &'a Tunables,
validator: &'a mut Validator,
types: &'a mut ComponentTypesBuilder,
scope_vec: &'data ScopeVec<u8>,
) -> Self {
Self {
result: Translation::default(),
tunables,
validator,
types,
parser: Parser::new(0),
lexical_scopes: Vec::new(),
static_components: Default::default(),
static_modules: Default::default(),
synthetic_instance_types: Default::default(),
scope_vec,
}
}
pub fn translate(
mut self,
component: &'data [u8],
) -> Result<(
Component,
PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
)> {
let mut remaining = component;
loop {
let payload = match self.parser.parse(remaining, true)? {
Chunk::Parsed { payload, consumed } => {
remaining = &remaining[consumed..];
payload
}
Chunk::NeedMoreData(_) => unreachable!(),
};
match self.translate_payload(payload, component)? {
Action::KeepGoing => {}
Action::Skip(n) => remaining = &remaining[n..],
Action::Done => break,
}
}
assert!(remaining.is_empty());
assert!(self.lexical_scopes.is_empty());
let mut component = inline::run(
&self.types,
&self.result,
&self.static_modules,
&self.static_components,
)?;
self.partition_adapter_modules(&mut component);
Ok((component.finish(), self.static_modules))
}
fn translate_payload(
&mut self,
payload: Payload<'data>,
component: &'data [u8],
) -> Result<Action> {
match payload {
Payload::Version {
num,
encoding,
range,
} => {
self.validator.version(num, encoding, &range)?;
match encoding {
Encoding::Component => {}
Encoding::Module => {
bail!("attempted to parse a wasm module with a component parser");
}
}
self.types.push_type_scope();
}
Payload::End(offset) => {
let types = self.validator.end(offset)?;
for idx in 0.. {
let lowered_function_type = match types.function_at(idx) {
Some(ty) => ty,
None => break,
};
let ty = self
.types
.module_types_builder()
.wasm_func_type(lowered_function_type.clone().try_into()?);
self.result.funcs.push(ty);
}
self.types.pop_type_scope();
let LexicalScope {
parser,
translation,
closure_args,
} = match self.lexical_scopes.pop() {
Some(frame) => frame,
None => return Ok(Action::Done),
};
self.parser = parser;
let component = mem::replace(&mut self.result, translation);
let static_idx = self.static_components.push(component);
self.result
.initializers
.push(LocalInitializer::ComponentStatic(static_idx, closure_args));
self.result
.components
.push(ComponentType::Static(static_idx));
}
Payload::ComponentTypeSection(s) => {
self.validator.component_type_section(&s)?;
for ty in s {
let ty = self.types.intern_component_type(&ty?)?;
self.types.push_component_typedef(ty);
}
}
Payload::CoreTypeSection(s) => {
self.validator.core_type_section(&s)?;
for ty in s {
let ty = self.types.intern_core_type(&ty?)?;
self.types.push_core_typedef(ty);
}
}
Payload::ComponentImportSection(s) => {
self.validator.component_import_section(&s)?;
for import in s {
let import = import?;
let ty = self.types.component_type_ref(&import.ty);
self.result.push_typedef(ty);
self.result
.initializers
.push(LocalInitializer::Import(import.name, ty));
}
}
Payload::ComponentCanonicalSection(s) => {
self.validator.component_canonical_section(&s)?;
for func in s {
match func? {
wasmparser::CanonicalFunction::Lift {
type_index,
core_func_index,
options,
} => {
let ty = ComponentTypeIndex::from_u32(type_index);
let ty = match self.types.component_outer_type(0, ty) {
TypeDef::ComponentFunc(ty) => ty,
_ => unreachable!(),
};
let func = FuncIndex::from_u32(core_func_index);
let options = self.canonical_options(&options);
self.result
.initializers
.push(LocalInitializer::Lift(ty, func, options));
self.result.component_funcs.push(ty);
}
wasmparser::CanonicalFunction::Lower {
func_index,
options,
} => {
let func = ComponentFuncIndex::from_u32(func_index);
let options = self.canonical_options(&options);
self.result
.initializers
.push(LocalInitializer::Lower(func, options));
}
}
}
}
Payload::ModuleSection { parser, range } => {
self.validator.module_section(&range)?;
let translation = ModuleEnvironment::new(
self.tunables,
self.validator,
self.types.module_types_builder(),
)
.translate(parser, &component[range.start..range.end])?;
let static_idx = self.static_modules.push(translation);
self.result
.initializers
.push(LocalInitializer::ModuleStatic(static_idx));
return Ok(Action::Skip(range.end - range.start));
}
Payload::ComponentSection { parser, range } => {
self.validator.component_section(&range)?;
self.lexical_scopes.push(LexicalScope {
parser: mem::replace(&mut self.parser, parser),
translation: mem::take(&mut self.result),
closure_args: ClosedOverVars::default(),
});
}
Payload::InstanceSection(s) => {
self.validator.instance_section(&s)?;
for instance in s {
let init = match instance? {
wasmparser::Instance::Instantiate { module_index, args } => {
let index = ModuleIndex::from_u32(module_index);
self.instantiate_module(index, &args)
}
wasmparser::Instance::FromExports(exports) => {
self.instantiate_module_from_exports(&exports)
}
};
self.result.initializers.push(init);
}
}
Payload::ComponentInstanceSection(s) => {
self.validator.component_instance_section(&s)?;
for instance in s {
let init = match instance? {
wasmparser::ComponentInstance::Instantiate {
component_index,
args,
} => {
let index = ComponentIndex::from_u32(component_index);
self.instantiate_component(index, &args)
}
wasmparser::ComponentInstance::FromExports(exports) => {
self.instantiate_component_from_exports(&exports)
}
};
self.result.initializers.push(init);
}
}
Payload::ComponentExportSection(s) => {
self.validator.component_export_section(&s)?;
for export in s {
let export = export?;
let item = self.kind_to_item(export.kind, export.index);
let prev = self.result.exports.insert(export.name, item);
assert!(prev.is_none());
}
}
Payload::ComponentStartSection(s) => {
self.validator.component_start_section(&s)?;
unimplemented!("component start section");
}
Payload::ComponentAliasSection(s) => {
self.validator.component_alias_section(&s)?;
for alias in s {
let init = match alias? {
wasmparser::ComponentAlias::InstanceExport {
kind,
instance_index,
name,
} => {
let instance = ComponentInstanceIndex::from_u32(instance_index);
drop(kind);
self.alias_component_instance_export(instance, name);
LocalInitializer::AliasComponentExport(instance, name)
}
wasmparser::ComponentAlias::Outer { kind, count, index } => {
self.alias_component_outer(kind, count, index);
continue;
}
wasmparser::ComponentAlias::CoreInstanceExport {
kind,
instance_index,
name,
} => {
let instance = ModuleInstanceIndex::from_u32(instance_index);
self.alias_module_instance_export(kind, instance, name)
}
};
self.result.initializers.push(init);
}
}
Payload::CustomSection { .. } => {}
other => {
self.validator.payload(&other)?;
panic!("unimplemented section {other:?}");
}
}
Ok(Action::KeepGoing)
}
fn instantiate_module(
&mut self,
module: ModuleIndex,
raw_args: &[wasmparser::InstantiationArg<'data>],
) -> LocalInitializer<'data> {
let mut args = HashMap::with_capacity(raw_args.len());
for arg in raw_args {
match arg.kind {
wasmparser::InstantiationArgKind::Instance => {
let idx = ModuleInstanceIndex::from_u32(arg.index);
args.insert(arg.name, idx);
}
}
}
LocalInitializer::ModuleInstantiate(module, args)
}
fn instantiate_module_from_exports(
&mut self,
exports: &[wasmparser::Export<'data>],
) -> LocalInitializer<'data> {
let mut map = HashMap::with_capacity(exports.len());
for export in exports {
let idx = match export.kind {
wasmparser::ExternalKind::Func => {
let index = FuncIndex::from_u32(export.index);
EntityIndex::Function(index)
}
wasmparser::ExternalKind::Table => {
let index = TableIndex::from_u32(export.index);
EntityIndex::Table(index)
}
wasmparser::ExternalKind::Memory => {
let index = MemoryIndex::from_u32(export.index);
EntityIndex::Memory(index)
}
wasmparser::ExternalKind::Global => {
let index = GlobalIndex::from_u32(export.index);
EntityIndex::Global(index)
}
wasmparser::ExternalKind::Tag => unimplemented!("wasm exceptions"),
};
map.insert(export.name, idx);
}
LocalInitializer::ModuleSynthetic(map)
}
fn instantiate_component(
&mut self,
component: ComponentIndex,
raw_args: &[wasmparser::ComponentInstantiationArg<'data>],
) -> LocalInitializer<'data> {
let mut args = HashMap::with_capacity(raw_args.len());
for arg in raw_args {
let idx = self.kind_to_item(arg.kind, arg.index);
args.insert(arg.name, idx);
}
self.result
.component_instances
.push(match self.result.components[component] {
ComponentType::Index(i) => ComponentInstanceType::InstantiatedIndex(i),
ComponentType::Static(i) => ComponentInstanceType::InstantiatedStatic(i),
});
LocalInitializer::ComponentInstantiate(component, args)
}
fn instantiate_component_from_exports(
&mut self,
exports: &[wasmparser::ComponentExport<'data>],
) -> LocalInitializer<'data> {
let mut map = HashMap::with_capacity(exports.len());
let mut types = HashMap::with_capacity(exports.len());
for export in exports {
let idx = self.kind_to_item(export.kind, export.index);
let ty = match idx {
ComponentItem::Func(i) => {
Some(ComponentItemType::Func(self.result.component_funcs[i]))
}
ComponentItem::Component(i) => {
Some(ComponentItemType::Component(self.result.components[i]))
}
ComponentItem::ComponentInstance(i) => Some(ComponentItemType::Instance(
self.result.component_instances[i],
)),
ComponentItem::Module(_) | ComponentItem::Type(_) => None,
};
map.insert(export.name, idx);
if let Some(ty) = ty {
types.insert(export.name, ty);
}
}
let index = self.synthetic_instance_types.push(types);
self.result
.component_instances
.push(ComponentInstanceType::Synthetic(index));
LocalInitializer::ComponentSynthetic(map)
}
fn kind_to_item(&self, kind: wasmparser::ComponentExternalKind, index: u32) -> ComponentItem {
match kind {
wasmparser::ComponentExternalKind::Func => {
let index = ComponentFuncIndex::from_u32(index);
ComponentItem::Func(index)
}
wasmparser::ComponentExternalKind::Module => {
let index = ModuleIndex::from_u32(index);
ComponentItem::Module(index)
}
wasmparser::ComponentExternalKind::Instance => {
let index = ComponentInstanceIndex::from_u32(index);
ComponentItem::ComponentInstance(index)
}
wasmparser::ComponentExternalKind::Component => {
let index = ComponentIndex::from_u32(index);
ComponentItem::Component(index)
}
wasmparser::ComponentExternalKind::Value => {
unimplemented!("component values");
}
wasmparser::ComponentExternalKind::Type => {
let index = ComponentTypeIndex::from_u32(index);
let ty = self.types.component_outer_type(0, index);
ComponentItem::Type(ty)
}
}
}
fn alias_module_instance_export(
&mut self,
kind: wasmparser::ExternalKind,
instance: ModuleInstanceIndex,
name: &'data str,
) -> LocalInitializer<'data> {
match kind {
wasmparser::ExternalKind::Func => LocalInitializer::AliasExportFunc(instance, name),
wasmparser::ExternalKind::Memory => LocalInitializer::AliasExportMemory(instance, name),
wasmparser::ExternalKind::Table => LocalInitializer::AliasExportTable(instance, name),
wasmparser::ExternalKind::Global => LocalInitializer::AliasExportGlobal(instance, name),
wasmparser::ExternalKind::Tag => {
unimplemented!("wasm exceptions");
}
}
}
fn alias_component_instance_export(
&mut self,
instance: ComponentInstanceIndex,
name: &'data str,
) {
match self.result.component_instances[instance] {
ComponentInstanceType::Index(ty) => {
self.result.push_typedef(self.types[ty].exports[name])
}
ComponentInstanceType::InstantiatedIndex(ty) => {
self.result.push_typedef(self.types[ty].exports[name])
}
ComponentInstanceType::InstantiatedStatic(idx) => {
let translation = &self.static_components[idx];
match translation.exports[name] {
ComponentItem::Func(idx) => {
self.result
.component_funcs
.push(translation.component_funcs[idx]);
}
ComponentItem::Component(idx) => {
self.result.components.push(translation.components[idx]);
}
ComponentItem::ComponentInstance(idx) => {
self.result
.component_instances
.push(translation.component_instances[idx]);
}
ComponentItem::Type(ty) => {
self.types.push_component_typedef(ty);
}
ComponentItem::Module(_) => {}
}
}
ComponentInstanceType::Synthetic(index) => {
let map = &self.synthetic_instance_types[index];
match map[name] {
ComponentItemType::Func(ty) => {
self.result.component_funcs.push(ty);
}
ComponentItemType::Component(ty) => {
self.result.components.push(ty);
}
ComponentItemType::Instance(ty) => {
self.result.component_instances.push(ty);
}
}
}
}
}
fn alias_component_outer(
&mut self,
kind: wasmparser::ComponentOuterAliasKind,
count: u32,
index: u32,
) {
match kind {
wasmparser::ComponentOuterAliasKind::CoreType => {
let index = TypeIndex::from_u32(index);
let ty = self.types.core_outer_type(count, index);
self.types.push_core_typedef(ty);
}
wasmparser::ComponentOuterAliasKind::Type => {
let index = ComponentTypeIndex::from_u32(index);
let ty = self.types.component_outer_type(count, index);
self.types.push_component_typedef(ty);
}
wasmparser::ComponentOuterAliasKind::CoreModule => {
let index = ModuleIndex::from_u32(index);
let mut module = ClosedOverModule::Local(index);
let depth = self.lexical_scopes.len() - (count as usize);
for frame in self.lexical_scopes[depth..].iter_mut() {
module = ClosedOverModule::Upvar(frame.closure_args.modules.push(module));
}
self.result
.initializers
.push(LocalInitializer::AliasModule(module));
}
wasmparser::ComponentOuterAliasKind::Component => {
let index = ComponentIndex::from_u32(index);
let mut component = ClosedOverComponent::Local(index);
let depth = self.lexical_scopes.len() - (count as usize);
for frame in self.lexical_scopes[depth..].iter_mut() {
component =
ClosedOverComponent::Upvar(frame.closure_args.components.push(component));
}
let component_ty = match self.lexical_scopes.get(depth) {
Some(frame) => frame.translation.components[index],
None => self.result.components[index],
};
self.result
.initializers
.push(LocalInitializer::AliasComponent(component));
self.result.components.push(component_ty);
}
}
}
fn canonical_options(&mut self, opts: &[wasmparser::CanonicalOption]) -> LocalCanonicalOptions {
let mut ret = LocalCanonicalOptions {
string_encoding: StringEncoding::Utf8,
memory: None,
realloc: None,
post_return: None,
};
for opt in opts {
match opt {
wasmparser::CanonicalOption::UTF8 => {
ret.string_encoding = StringEncoding::Utf8;
}
wasmparser::CanonicalOption::UTF16 => {
ret.string_encoding = StringEncoding::Utf16;
}
wasmparser::CanonicalOption::CompactUTF16 => {
ret.string_encoding = StringEncoding::CompactUtf16;
}
wasmparser::CanonicalOption::Memory(idx) => {
let idx = MemoryIndex::from_u32(*idx);
ret.memory = Some(idx);
}
wasmparser::CanonicalOption::Realloc(idx) => {
let idx = FuncIndex::from_u32(*idx);
ret.realloc = Some(idx);
}
wasmparser::CanonicalOption::PostReturn(idx) => {
let idx = FuncIndex::from_u32(*idx);
ret.post_return = Some(idx);
}
}
}
return ret;
}
}
impl Translation<'_> {
fn push_typedef(&mut self, ty: TypeDef) {
match ty {
TypeDef::ComponentInstance(idx) => {
self.component_instances
.push(ComponentInstanceType::Index(idx));
}
TypeDef::ComponentFunc(idx) => {
self.component_funcs.push(idx);
}
TypeDef::Component(idx) => {
self.components.push(ComponentType::Index(idx));
}
TypeDef::Interface(_) | TypeDef::CoreFunc(_) | TypeDef::Module(_) => {}
}
}
}