use crate::descriptor::Descriptor;
use crate::interpreter::Interpreter;
use anyhow::Error;
use std::borrow::Cow;
use std::collections::hash_map::HashMap;
use walrus::{CustomSection, FunctionId, Module, TypedCustomSectionId};
#[derive(Default, Debug)]
pub struct WasmBindgenDescriptorsSection {
pub descriptors: HashMap<String, Descriptor>,
pub cast_imports: HashMap<Descriptor, Vec<FunctionId>>,
}
pub type WasmBindgenDescriptorsSectionId = TypedCustomSectionId<WasmBindgenDescriptorsSection>;
pub fn execute(module: &mut Module) -> Result<WasmBindgenDescriptorsSectionId, Error> {
let mut section = WasmBindgenDescriptorsSection::default();
let mut interpreter = Interpreter::new(module)?;
section.execute_exports(module, &mut interpreter)?;
section.execute_casts(module, &mut interpreter)?;
Ok(module.customs.add(section))
}
impl WasmBindgenDescriptorsSection {
fn execute_exports(
&mut self,
module: &mut Module,
interpreter: &mut Interpreter,
) -> Result<(), Error> {
let mut to_remove = Vec::new();
if let Some(id) = interpreter.skip_interpret() {
to_remove.push(id);
}
for export in module.exports.iter() {
let prefix = "__wbindgen_describe_";
if !export.name.starts_with(prefix) {
continue;
}
let id = match export.item {
walrus::ExportItem::Function(id) => id,
_ => panic!("{} export not a function", export.name),
};
let d = interpreter.interpret_descriptor(id, module);
let name = &export.name[prefix.len()..];
let descriptor = Descriptor::decode(d);
self.descriptors.insert(name.to_string(), descriptor);
to_remove.push(export.id());
}
for id in to_remove {
module.exports.delete(id);
}
Ok(())
}
fn execute_casts(
&mut self,
module: &mut Module,
interpreter: &mut Interpreter,
) -> Result<(), Error> {
use walrus::ir::*;
let wbindgen_describe_cast = match interpreter.describe_cast_id() {
Some(i) => i,
None => return Ok(()),
};
let mut replace_with_imports = Vec::new();
for (func_id, local) in module.funcs.iter_local() {
let mut find = FindDescribeCast {
wbindgen_describe_cast,
found: false,
};
dfs_in_order(&mut find, local, local.entry_block());
if find.found {
replace_with_imports.push(func_id);
}
}
for func_id in replace_with_imports {
let descriptor = interpreter.interpret_descriptor(func_id, module);
let descriptor = Descriptor::decode(descriptor);
self.cast_imports
.entry(descriptor)
.or_default()
.push(func_id);
}
return Ok(());
struct FindDescribeCast {
wbindgen_describe_cast: FunctionId,
found: bool,
}
impl Visitor<'_> for FindDescribeCast {
fn visit_call(&mut self, call: &Call) {
if call.func == self.wbindgen_describe_cast {
self.found = true;
}
}
}
}
}
impl CustomSection for WasmBindgenDescriptorsSection {
fn name(&self) -> &str {
"wasm-bindgen descriptors"
}
fn data(&self, _: &walrus::IdsToIndices) -> Cow<'_, [u8]> {
panic!("shouldn't emit custom sections just yet");
}
}