use crate::ir::component::refs::IndexedRef;
use crate::ir::component::section::ComponentSection;
use crate::ir::types::CustomSection;
use crate::{Component, Module};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Debug;
use std::rc::Rc;
use wasmparser::{
CanonicalFunction, ComponentAlias, ComponentExport, ComponentExternalKind, ComponentImport,
ComponentInstance, ComponentOuterAliasKind, ComponentStartFunction, ComponentType,
ComponentTypeDeclaration, ComponentTypeRef, CoreType, ExternalKind, Import, Instance,
InstanceTypeDeclaration, InstantiationArgKind, ModuleTypeDeclaration, OuterAliasKind, RecGroup,
SubType, TypeRef,
};
pub(crate) type ScopeId = usize;
pub(crate) type StoreHandle = Rc<RefCell<IndexStore>>;
#[derive(Default, Debug)]
pub(crate) struct IndexStore {
pub scopes: HashMap<ScopeId, IndexScope>,
next_id: usize,
}
impl IndexStore {
pub fn new_scope(&mut self) -> ScopeId {
let id = self.use_next_id();
self.scopes.insert(id, IndexScope::new(id));
id
}
pub fn index_from_assumed_id_no_cache(
&self,
id: &ScopeId,
r: &IndexedRef,
) -> (SpaceSubtype, usize, Option<usize>) {
self.get(id).index_from_assumed_id_no_cache(r)
}
pub fn assign_assumed_id(
&mut self,
id: &ScopeId,
space: &Space,
section: &ComponentSection,
curr_idx: usize,
) -> Option<usize> {
self.get_mut(id).assign_assumed_id(space, section, curr_idx)
}
pub fn assign_assumed_id_for<I: Debug + IndexSpaceOf>(
&mut self,
id: &ScopeId,
items: &[I],
curr_idx: usize,
sections: &Vec<ComponentSection>,
) {
self.get_mut(id)
.assign_assumed_id_for(items, curr_idx, sections)
}
pub fn assign_assumed_id_for_boxed<I: Debug + IndexSpaceOf>(
&mut self,
id: &ScopeId,
items: &[Box<I>],
curr_idx: usize,
sections: &Vec<ComponentSection>,
) {
self.get_mut(id)
.assign_assumed_id_for_boxed(items, curr_idx, sections)
}
fn use_next_id(&mut self) -> ScopeId {
let next = self.next_id;
self.next_id += 1;
next
}
fn get_mut(&mut self, id: &ScopeId) -> &mut IndexScope {
self.scopes.get_mut(id).unwrap()
}
fn get(&self, id: &ScopeId) -> &IndexScope {
self.scopes.get(id).unwrap()
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct IndexScope {
pub(crate) id: ScopeId,
pub comp: IdxSpace,
pub comp_func: IdxSpace,
pub comp_val: IdxSpace,
pub comp_type: IdxSpace,
pub comp_inst: IdxSpace,
pub core_inst: IdxSpace, pub module: IdxSpace,
pub core_type: IdxSpace,
pub core_func: IdxSpace, pub core_memory: IdxSpace,
pub core_table: IdxSpace,
pub core_global: IdxSpace,
pub core_tag: IdxSpace,
}
impl IndexScope {
pub fn new(id: ScopeId) -> Self {
Self {
id,
..Self::default()
}
}
pub fn assign_assumed_id_for<I: Debug + IndexSpaceOf>(
&mut self,
items: &[I],
curr_idx: usize,
sections: &Vec<ComponentSection>, ) {
debug_assert_eq!(items.len(), sections.len());
for ((i, item), section) in items.iter().enumerate().zip(sections) {
self.assign_assumed_id(&item.index_space_of(), section, curr_idx + i);
}
}
pub fn assign_assumed_id_for_boxed<I: Debug + IndexSpaceOf>(
&mut self,
items: &[Box<I>],
curr_idx: usize,
sections: &Vec<ComponentSection>, ) {
debug_assert_eq!(items.len(), sections.len());
for ((i, item), section) in items.iter().enumerate().zip(sections) {
self.assign_assumed_id(&item.index_space_of(), section, curr_idx + i);
}
}
pub fn assign_assumed_id(
&mut self,
space: &Space,
section: &ComponentSection,
curr_idx: usize,
) -> Option<usize> {
self.get_space_mut(space)
.map(|space| space.assign_assumed_id(section, curr_idx))
}
pub fn lookup_assumed_id(
&self,
space: &Space,
section: &ComponentSection,
vec_idx: usize,
) -> usize {
self.get_space(space)
.and_then(|s| s.lookup_assumed_id(section, vec_idx))
.unwrap_or_else(|| {
panic!("[{space:?}] Internal error: No assumed ID for index: {vec_idx}")
})
}
pub fn lookup_assumed_id_with_subvec(
&self,
space: &Space,
section: &ComponentSection,
vec_idx: usize,
subvec_idx: usize,
) -> usize {
self.get_space(space)
.and_then(|space| space.lookup_assumed_id_with_subvec(section, vec_idx, subvec_idx))
.unwrap_or_else(|| {
panic!("[{space:?}] Internal error: No assumed ID for index: {vec_idx}, subvec index: {subvec_idx}")
})
}
pub fn index_from_assumed_id(
&mut self,
r: &IndexedRef,
) -> (SpaceSubtype, usize, Option<usize>) {
self.get_space_mut(&r.space)
.and_then(|space| space.index_from_assumed_id(r.index as usize))
.unwrap_or_else(|| {
panic!(
"[{:?}@scope{}] Internal error: No index for assumed ID: {}",
r.space, self.id, r.index
)
})
}
pub fn index_from_assumed_id_no_cache(
&self,
r: &IndexedRef,
) -> (SpaceSubtype, usize, Option<usize>) {
self.get_space(&r.space)
.and_then(|space| space.index_from_assumed_id_no_cache(r.index as usize))
.unwrap_or_else(|| {
panic!(
"[{:?}@scope{}] No index for assumed ID: {}. \
This reference may belong to a ComponentType::Instance, \
ComponentType::Component, or CoreType::Module body — if so, this is a \
driver bug: the driver should have pushed the type body onto \
VisitCtxInner::type_body_stack before this callback fired.",
r.space, self.id, r.index
)
})
}
fn get_space_mut(&mut self, space: &Space) -> Option<&mut IdxSpace> {
let s = match space {
Space::Comp => &mut self.comp,
Space::CompFunc => &mut self.comp_func,
Space::CompVal => &mut self.comp_val,
Space::CompType => &mut self.comp_type,
Space::CompInst => &mut self.comp_inst,
Space::CoreInst => &mut self.core_inst,
Space::CoreModule => &mut self.module,
Space::CoreType => &mut self.core_type,
Space::CoreFunc => &mut self.core_func,
Space::CoreMemory => &mut self.core_memory,
Space::CoreTable => &mut self.core_table,
Space::CoreGlobal => &mut self.core_global,
Space::CoreTag => &mut self.core_tag,
Space::NA => return None,
};
Some(s)
}
fn get_space(&self, space: &Space) -> Option<&IdxSpace> {
let s = match space {
Space::Comp => &self.comp,
Space::CompFunc => &self.comp_func,
Space::CompVal => &self.comp_val,
Space::CompType => &self.comp_type,
Space::CompInst => &self.comp_inst,
Space::CoreInst => &self.core_inst,
Space::CoreModule => &self.module,
Space::CoreType => &self.core_type,
Space::CoreFunc => &self.core_func,
Space::CoreMemory => &self.core_memory,
Space::CoreTable => &self.core_table,
Space::CoreGlobal => &self.core_global,
Space::CoreTag => &self.core_tag,
Space::NA => return None,
};
Some(s)
}
}
#[derive(Clone, Debug)]
enum AssumedIdForIdx {
Single(usize),
Multiple(Vec<usize>),
}
impl AssumedIdForIdx {
fn matches(&self, assumed_id: usize) -> (bool, Option<usize>) {
match self {
AssumedIdForIdx::Single(my_id) => return (*my_id == assumed_id, None),
AssumedIdForIdx::Multiple(sub_ids) => {
for (idx, id) in sub_ids.iter().enumerate() {
if *id == assumed_id {
return (true, Some(idx));
}
}
}
}
(false, None)
}
fn append(&mut self, assumed_id: usize) {
match self {
Self::Single(my_id) => *self = AssumedIdForIdx::Multiple(vec![*my_id, assumed_id]),
Self::Multiple(sub_ids) => sub_ids.push(assumed_id),
}
}
fn unwrap_single(&self) -> usize {
match self {
AssumedIdForIdx::Single(my_id) => *my_id,
_ => unreachable!(),
}
}
fn unwrap_for_idx(&self, subvec_idx: usize) -> usize {
match self {
AssumedIdForIdx::Single(my_id) => {
debug_assert_eq!(subvec_idx, 0);
*my_id
}
AssumedIdForIdx::Multiple(subvec) => subvec[subvec_idx],
}
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct IdxSpace {
current_id: usize,
main_assumed_ids: HashMap<usize, AssumedIdForIdx>,
alias_assumed_ids: HashMap<usize, AssumedIdForIdx>,
imports_assumed_ids: HashMap<usize, AssumedIdForIdx>,
exports_assumed_ids: HashMap<usize, AssumedIdForIdx>,
index_from_assumed_id_cache: HashMap<usize, (SpaceSubtype, usize, Option<usize>)>,
}
impl IdxSpace {
pub fn curr_id(&self) -> usize {
self.current_id
}
fn next(&mut self) -> usize {
let curr = self.current_id;
self.current_id += 1;
curr
}
pub fn lookup_assumed_id(&self, section: &ComponentSection, vec_idx: usize) -> Option<usize> {
let (_group, vector) = match section {
ComponentSection::ComponentImport => ("imports", &self.imports_assumed_ids),
ComponentSection::ComponentExport => ("exports", &self.exports_assumed_ids),
ComponentSection::Alias => ("aliases", &self.alias_assumed_ids),
ComponentSection::Component
| ComponentSection::Module
| ComponentSection::CoreType
| ComponentSection::ComponentType
| ComponentSection::CoreInstance
| ComponentSection::ComponentInstance
| ComponentSection::Canon
| ComponentSection::CustomSection
| ComponentSection::ComponentStartSection => ("main", &self.main_assumed_ids),
};
vector.get(&vec_idx).map(|res| res.unwrap_single())
}
pub fn lookup_assumed_id_with_subvec(
&self,
section: &ComponentSection,
vec_idx: usize,
subvec_idx: usize,
) -> Option<usize> {
let (_group, vector) = match section {
ComponentSection::ComponentImport => ("imports", &self.imports_assumed_ids),
ComponentSection::ComponentExport => ("exports", &self.exports_assumed_ids),
ComponentSection::Alias => ("aliases", &self.alias_assumed_ids),
ComponentSection::Component
| ComponentSection::Module
| ComponentSection::CoreType
| ComponentSection::ComponentType
| ComponentSection::CoreInstance
| ComponentSection::ComponentInstance
| ComponentSection::Canon
| ComponentSection::CustomSection
| ComponentSection::ComponentStartSection => ("main", &self.main_assumed_ids),
};
vector
.get(&vec_idx)
.map(|res| res.unwrap_for_idx(subvec_idx))
}
pub fn index_from_assumed_id(
&mut self,
assumed_id: usize,
) -> Option<(SpaceSubtype, usize, Option<usize>)> {
if let Some(cached_data) = self.index_from_assumed_id_cache.get(&assumed_id) {
return Some(*cached_data);
}
let maps = [
(SpaceSubtype::Main, &self.main_assumed_ids),
(SpaceSubtype::Import, &self.imports_assumed_ids),
(SpaceSubtype::Export, &self.exports_assumed_ids),
(SpaceSubtype::Alias, &self.alias_assumed_ids),
];
for (subty, map) in maps.iter() {
for (idx, assumed) in map.iter() {
let (matches, opt_subidx) = assumed.matches(assumed_id);
if matches {
let result = (*subty, *idx, opt_subidx);
self.index_from_assumed_id_cache.insert(assumed_id, result);
return Some(result);
}
}
}
None
}
pub fn index_from_assumed_id_no_cache(
&self,
assumed_id: usize,
) -> Option<(SpaceSubtype, usize, Option<usize>)> {
if let Some(cached_data) = self.index_from_assumed_id_cache.get(&assumed_id) {
return Some(*cached_data);
}
let maps = [
(SpaceSubtype::Main, &self.main_assumed_ids),
(SpaceSubtype::Import, &self.imports_assumed_ids),
(SpaceSubtype::Export, &self.exports_assumed_ids),
(SpaceSubtype::Alias, &self.alias_assumed_ids),
];
for (subty, map) in maps.iter() {
for (idx, assumed) in map.iter() {
let (matches, opt_subidx) = assumed.matches(assumed_id);
if matches {
let result = (*subty, *idx, opt_subidx);
return Some(result);
}
}
}
None
}
pub fn assign_assumed_id(&mut self, section: &ComponentSection, vec_idx: usize) -> usize {
let assumed_id = self.curr_id();
self.next();
let to_update = match section {
ComponentSection::ComponentImport => &mut self.imports_assumed_ids,
ComponentSection::ComponentExport => &mut self.exports_assumed_ids,
ComponentSection::Alias => &mut self.alias_assumed_ids,
ComponentSection::Component
| ComponentSection::Module
| ComponentSection::CoreType
| ComponentSection::ComponentType
| ComponentSection::CoreInstance
| ComponentSection::ComponentInstance
| ComponentSection::Canon
| ComponentSection::CustomSection
| ComponentSection::ComponentStartSection => &mut self.main_assumed_ids,
};
to_update
.entry(vec_idx)
.and_modify(|entry| {
entry.append(assumed_id);
})
.or_insert(AssumedIdForIdx::Single(assumed_id));
assumed_id
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum SpaceSubtype {
Export,
Import,
Alias,
Main,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Space {
Comp,
CompFunc,
CompVal,
CompType,
CompInst,
CoreInst,
CoreModule,
CoreType,
CoreFunc,
CoreMemory,
CoreTable,
CoreGlobal,
CoreTag,
NA,
}
pub trait IndexSpaceOf {
fn index_space_of(&self) -> Space;
}
impl IndexSpaceOf for CustomSection<'_> {
fn index_space_of(&self) -> Space {
Space::NA
}
}
impl IndexSpaceOf for ComponentStartFunction {
fn index_space_of(&self) -> Space {
Space::NA
}
}
impl IndexSpaceOf for ComponentTypeRef {
fn index_space_of(&self) -> Space {
match self {
Self::Value(_) => Space::CompVal,
Self::Instance(_) => Space::CompInst,
Self::Component(_) => Space::CompType,
Self::Module(_) => Space::CoreModule,
Self::Func(_) | Self::Type(_) => Space::CompType,
}
}
}
impl IndexSpaceOf for ComponentImport<'_> {
fn index_space_of(&self) -> Space {
comp_type_ref_item_space(&self.ty)
}
}
impl IndexSpaceOf for ComponentExport<'_> {
fn index_space_of(&self) -> Space {
match self.kind {
ComponentExternalKind::Module => Space::CoreModule,
ComponentExternalKind::Func => Space::CompFunc,
ComponentExternalKind::Value => Space::CompVal,
ComponentExternalKind::Type => Space::CompType,
ComponentExternalKind::Instance => Space::CompInst,
ComponentExternalKind::Component => Space::CompInst, }
}
}
impl IndexSpaceOf for Instance<'_> {
fn index_space_of(&self) -> Space {
Space::CoreInst
}
}
impl<'a> IndexSpaceOf for ComponentAlias<'a> {
fn index_space_of(&self) -> Space {
match self {
ComponentAlias::InstanceExport { kind, .. } => match kind {
ComponentExternalKind::Func => Space::CompFunc,
ComponentExternalKind::Value => Space::CompVal,
ComponentExternalKind::Type => Space::CompType,
ComponentExternalKind::Instance => Space::CompInst,
ComponentExternalKind::Component => Space::Comp, ComponentExternalKind::Module => Space::CoreModule,
},
ComponentAlias::CoreInstanceExport { kind, .. } => match kind {
ExternalKind::Func => Space::CoreFunc,
ExternalKind::Memory => Space::CoreMemory,
ExternalKind::Table => Space::CoreTable,
ExternalKind::Global => Space::CoreGlobal,
ExternalKind::Tag => Space::CoreTag,
ExternalKind::FuncExact => Space::CoreFunc,
},
ComponentAlias::Outer { kind, .. } => match kind {
ComponentOuterAliasKind::CoreModule => Space::CoreModule,
ComponentOuterAliasKind::CoreType => Space::CoreType,
ComponentOuterAliasKind::Type => Space::CompType,
ComponentOuterAliasKind::Component => Space::Comp, },
}
}
}
impl IndexSpaceOf for CanonicalFunction {
fn index_space_of(&self) -> Space {
match self {
CanonicalFunction::Lower { .. } => Space::CoreFunc,
CanonicalFunction::Lift { .. } => Space::CompFunc,
CanonicalFunction::ResourceNew { .. }
| CanonicalFunction::ResourceDrop { .. }
| CanonicalFunction::ResourceDropAsync { .. }
| CanonicalFunction::ResourceRep { .. } => Space::CoreFunc,
CanonicalFunction::ThreadSpawnRef { .. }
| CanonicalFunction::ThreadSpawnIndirect { .. } => Space::CompFunc,
CanonicalFunction::ThreadNewIndirect { .. } => Space::CoreFunc,
CanonicalFunction::TaskReturn { .. }
| CanonicalFunction::TaskCancel
| CanonicalFunction::SubtaskDrop
| CanonicalFunction::SubtaskCancel { .. } => Space::CoreFunc,
CanonicalFunction::ContextGet(_) | CanonicalFunction::ContextSet(_) => Space::CoreFunc,
CanonicalFunction::StreamCancelRead { .. }
| CanonicalFunction::StreamCancelWrite { .. }
| CanonicalFunction::FutureCancelRead { .. }
| CanonicalFunction::FutureCancelWrite { .. }
| CanonicalFunction::FutureNew { .. }
| CanonicalFunction::FutureRead { .. }
| CanonicalFunction::FutureWrite { .. }
| CanonicalFunction::FutureDropReadable { .. }
| CanonicalFunction::FutureDropWritable { .. }
| CanonicalFunction::StreamNew { .. }
| CanonicalFunction::StreamRead { .. }
| CanonicalFunction::StreamWrite { .. }
| CanonicalFunction::StreamDropReadable { .. }
| CanonicalFunction::StreamDropWritable { .. } => Space::CoreFunc,
CanonicalFunction::ErrorContextNew { .. }
| CanonicalFunction::ErrorContextDebugMessage { .. }
| CanonicalFunction::ErrorContextDrop => Space::CoreFunc,
CanonicalFunction::WaitableSetWait { .. }
| CanonicalFunction::WaitableSetPoll { .. }
| CanonicalFunction::WaitableSetNew
| CanonicalFunction::WaitableSetDrop
| CanonicalFunction::WaitableJoin => Space::CoreFunc,
CanonicalFunction::ThreadIndex
| CanonicalFunction::ThreadSuspend { .. }
| CanonicalFunction::ThreadSuspendToSuspended { .. }
| CanonicalFunction::ThreadSuspendTo { .. }
| CanonicalFunction::ThreadUnsuspend
| CanonicalFunction::ThreadYieldToSuspended { .. }
| CanonicalFunction::ThreadYield { .. }
| CanonicalFunction::ThreadAvailableParallelism => Space::CoreFunc,
CanonicalFunction::BackpressureInc | CanonicalFunction::BackpressureDec => {
Space::CoreFunc
}
}
}
}
impl IndexSpaceOf for Module<'_> {
fn index_space_of(&self) -> Space {
Space::CoreModule
}
}
impl IndexSpaceOf for Component<'_> {
fn index_space_of(&self) -> Space {
Space::Comp }
}
impl IndexSpaceOf for CoreType<'_> {
fn index_space_of(&self) -> Space {
Space::CoreType
}
}
impl IndexSpaceOf for RecGroup {
fn index_space_of(&self) -> Space {
Space::CoreType
}
}
impl IndexSpaceOf for SubType {
fn index_space_of(&self) -> Space {
Space::CoreType
}
}
impl IndexSpaceOf for ComponentType<'_> {
fn index_space_of(&self) -> Space {
Space::CompType
}
}
impl IndexSpaceOf for ComponentInstance<'_> {
fn index_space_of(&self) -> Space {
Space::CompInst
}
}
impl IndexSpaceOf for InstantiationArgKind {
fn index_space_of(&self) -> Space {
match self {
InstantiationArgKind::Instance => Space::CoreInst,
}
}
}
impl IndexSpaceOf for ExternalKind {
fn index_space_of(&self) -> Space {
match self {
ExternalKind::Func => Space::CoreFunc,
ExternalKind::Table => Space::CoreTable,
ExternalKind::Memory => Space::CoreMemory,
ExternalKind::Global => Space::CoreGlobal,
ExternalKind::Tag => Space::CoreTag,
ExternalKind::FuncExact => Space::CoreFunc,
}
}
}
impl IndexSpaceOf for ComponentExternalKind {
fn index_space_of(&self) -> Space {
match self {
ComponentExternalKind::Func => Space::CompFunc,
ComponentExternalKind::Value => Space::CompVal,
ComponentExternalKind::Type => Space::CompType,
ComponentExternalKind::Instance => Space::CompInst,
ComponentExternalKind::Component => Space::Comp, ComponentExternalKind::Module => Space::CoreModule,
}
}
}
impl IndexSpaceOf for ComponentOuterAliasKind {
fn index_space_of(&self) -> Space {
match self {
ComponentOuterAliasKind::CoreModule => Space::CoreModule,
ComponentOuterAliasKind::CoreType => Space::CoreType,
ComponentOuterAliasKind::Type => Space::CompType,
ComponentOuterAliasKind::Component => Space::Comp, }
}
}
impl IndexSpaceOf for ComponentTypeDeclaration<'_> {
fn index_space_of(&self) -> Space {
match self {
ComponentTypeDeclaration::CoreType(ty) => ty.index_space_of(),
ComponentTypeDeclaration::Type(ty) => ty.index_space_of(),
ComponentTypeDeclaration::Alias(alias) => alias.index_space_of(),
ComponentTypeDeclaration::Export { ty, .. } => comp_type_ref_item_space(ty),
ComponentTypeDeclaration::Import(import) => import.index_space_of(),
}
}
}
impl IndexSpaceOf for InstanceTypeDeclaration<'_> {
fn index_space_of(&self) -> Space {
match self {
InstanceTypeDeclaration::CoreType(ty) => ty.index_space_of(),
InstanceTypeDeclaration::Type(ty) => ty.index_space_of(),
InstanceTypeDeclaration::Alias(a) => a.index_space_of(),
InstanceTypeDeclaration::Export { ty, .. } => comp_type_ref_item_space(ty),
}
}
}
fn comp_type_ref_item_space(ty: &ComponentTypeRef) -> Space {
match ty {
ComponentTypeRef::Func(_) => Space::CompFunc,
ComponentTypeRef::Value(_) => Space::CompVal,
ComponentTypeRef::Type(_) => Space::CompType,
ComponentTypeRef::Instance(_) => Space::CompInst,
ComponentTypeRef::Component(_) => Space::Comp,
ComponentTypeRef::Module(_) => Space::CoreModule,
}
}
impl IndexSpaceOf for ModuleTypeDeclaration<'_> {
fn index_space_of(&self) -> Space {
match self {
ModuleTypeDeclaration::Type(_) => Space::CoreType,
ModuleTypeDeclaration::Export { ty, .. } => ty.index_space_of(),
ModuleTypeDeclaration::OuterAlias { kind, .. } => kind.index_space_of(),
ModuleTypeDeclaration::Import(Import { ty, .. }) => ty.index_space_of(),
}
}
}
impl IndexSpaceOf for TypeRef {
fn index_space_of(&self) -> Space {
Space::CoreType
}
}
impl IndexSpaceOf for OuterAliasKind {
fn index_space_of(&self) -> Space {
match self {
OuterAliasKind::Type => Space::CoreType,
}
}
}