2019-06-10 07:09:51 -07:00
|
|
|
use crate::webidl::{NonstandardIncoming, NonstandardOutgoing};
|
|
|
|
use crate::webidl::{NonstandardWebidlSection, WasmBindgenAux};
|
2019-05-31 10:54:03 -07:00
|
|
|
use failure::Error;
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use walrus::Module;
|
2019-06-03 11:36:18 -07:00
|
|
|
use wasm_bindgen_anyref_xform::Context;
|
2019-06-10 07:09:51 -07:00
|
|
|
use wasm_webidl_bindings::ast;
|
2019-05-31 10:54:03 -07:00
|
|
|
|
|
|
|
pub fn process(module: &mut Module) -> Result<(), Error> {
|
2019-06-03 11:36:18 -07:00
|
|
|
let mut cfg = Context::default();
|
2019-05-31 10:54:03 -07:00
|
|
|
cfg.prepare(module)?;
|
|
|
|
let bindings = module
|
|
|
|
.customs
|
2019-06-10 07:09:51 -07:00
|
|
|
.get_typed_mut::<NonstandardWebidlSection>()
|
2019-05-31 10:54:03 -07:00
|
|
|
.expect("webidl custom section should exist");
|
|
|
|
|
2019-06-10 07:09:51 -07:00
|
|
|
// Transform all exported functions in the module, using the bindings listed
|
|
|
|
// for each exported function.
|
2019-06-03 11:36:18 -07:00
|
|
|
for (export, binding) in bindings.exports.iter_mut() {
|
2019-06-10 07:09:51 -07:00
|
|
|
let ty = module.types.get(binding.wasm_ty);
|
|
|
|
let args = Arguments::Incoming(&mut binding.incoming);
|
|
|
|
let (args, ret) = extract_anyrefs(ty, args);
|
2019-05-31 10:54:03 -07:00
|
|
|
cfg.export_xform(*export, &args, ret);
|
|
|
|
}
|
|
|
|
|
2019-06-10 07:09:51 -07:00
|
|
|
// Transform all imported functions in the module, using the bindings listed
|
|
|
|
// for each imported function.
|
|
|
|
for (import, binding) in bindings.imports.iter_mut() {
|
|
|
|
let ty = module.types.get(binding.wasm_ty);
|
|
|
|
let args = Arguments::Outgoing(&mut binding.outgoing);
|
|
|
|
let (args, ret) = extract_anyrefs(ty, args);
|
2019-05-31 10:54:03 -07:00
|
|
|
cfg.import_xform(*import, &args, ret);
|
|
|
|
}
|
|
|
|
|
2019-06-10 07:09:51 -07:00
|
|
|
// And finally transform all table elements that are used as function
|
|
|
|
// pointers for closures and such.
|
|
|
|
for (idx, binding) in bindings.elems.iter_mut() {
|
|
|
|
let ty = module.types.get(binding.wasm_ty);
|
|
|
|
let args = Arguments::Incoming(&mut binding.incoming);
|
|
|
|
let (args, ret) = extract_anyrefs(ty, args);
|
|
|
|
if let Some(new) = cfg.table_element_xform(*idx, &args, ret) {
|
|
|
|
*idx = new;
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg.run(module)?;
|
|
|
|
walrus::passes::gc::run(module);
|
|
|
|
|
|
|
|
// The GC pass above may end up removing some imported intrinsics. For
|
|
|
|
// example `__wbindgen_object_clone_ref` is no longer needed after the
|
|
|
|
// anyref pass. Make sure to delete the associated metadata for those
|
|
|
|
// intrinsics so we don't try to access stale intrinsics later on.
|
|
|
|
let remaining_imports = module
|
|
|
|
.imports
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.id())
|
|
|
|
.collect::<HashSet<_>>();
|
|
|
|
module
|
|
|
|
.customs
|
2019-06-10 07:09:51 -07:00
|
|
|
.get_typed_mut::<NonstandardWebidlSection>()
|
2019-05-31 10:54:03 -07:00
|
|
|
.expect("webidl custom section should exist")
|
|
|
|
.imports
|
|
|
|
.retain(|id, _| remaining_imports.contains(id));
|
|
|
|
module
|
|
|
|
.customs
|
|
|
|
.get_typed_mut::<WasmBindgenAux>()
|
|
|
|
.expect("wasm-bindgen aux section should exist")
|
|
|
|
.import_map
|
|
|
|
.retain(|id, _| remaining_imports.contains(id));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-06-10 07:09:51 -07:00
|
|
|
enum Arguments<'a> {
|
|
|
|
Incoming(&'a mut [NonstandardIncoming]),
|
|
|
|
Outgoing(&'a mut [NonstandardOutgoing]),
|
2019-06-03 11:36:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Extract a description of the anyref arguments from the function signature
|
|
|
|
/// described by `f`.
|
|
|
|
///
|
|
|
|
/// The returned values are expected to be passed to the anyref transformation
|
|
|
|
/// pass, and indicate which arguments (by index) in the wasm signature should
|
|
|
|
/// be transformed from `i32` to `anyref` as well as whether the returned value
|
|
|
|
/// is an `anyref` or not.
|
|
|
|
///
|
|
|
|
/// The `offset` argument here is typically 0 and indicates the offset at which
|
|
|
|
/// the wasm abi arguments described by `f` start at. For closures this is 2
|
|
|
|
/// because two synthetic arguments are injected into the wasm signature which
|
|
|
|
/// aren't present in the `Function` signature.
|
2019-06-10 07:09:51 -07:00
|
|
|
fn extract_anyrefs(ty: &walrus::Type, args: Arguments<'_>) -> (Vec<(usize, bool)>, bool) {
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
|
|
|
// First find all the `anyref` arguments in the input type, and we'll
|
|
|
|
// assume that they're owned anyref arguments for now (the `true`)
|
|
|
|
for (i, arg) in ty.params().iter().enumerate() {
|
|
|
|
if *arg == walrus::ValType::Anyref {
|
|
|
|
ret.push((i, true));
|
|
|
|
}
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|
2019-06-10 07:09:51 -07:00
|
|
|
|
|
|
|
// Afterwards look through the argument list (specified with various
|
|
|
|
// bindings) to find any borrowed anyref values and update our
|
|
|
|
// transformation metadata accordingly. if we find one then the binding no
|
|
|
|
// longer needs to remember its borrowed but rather it's just a simple cast
|
|
|
|
// from wasm anyref to JS any.
|
|
|
|
match args {
|
|
|
|
Arguments::Incoming(incoming) => {
|
|
|
|
for binding in incoming {
|
|
|
|
let expr = match binding {
|
|
|
|
NonstandardIncoming::BorrowedAnyref {
|
|
|
|
val: ast::IncomingBindingExpression::Get(expr),
|
|
|
|
} => expr.clone(),
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
ret.iter_mut().find(|p| p.0 == expr.idx as usize).unwrap().1 = false;
|
|
|
|
let new_binding = ast::IncomingBindingExpressionAs {
|
|
|
|
ty: walrus::ValType::Anyref,
|
|
|
|
expr: Box::new(expr.into()),
|
|
|
|
};
|
|
|
|
*binding = NonstandardIncoming::Standard(new_binding.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Arguments::Outgoing(outgoing) => {
|
|
|
|
for binding in outgoing {
|
|
|
|
let idx = match binding {
|
|
|
|
NonstandardOutgoing::BorrowedAnyref { idx } => *idx,
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
ret.iter_mut().find(|p| p.0 == idx as usize).unwrap().1 = false;
|
|
|
|
let new_binding = ast::OutgoingBindingExpressionAs {
|
|
|
|
idx,
|
|
|
|
ty: ast::WebidlScalarType::Any.into(),
|
|
|
|
};
|
|
|
|
*binding = NonstandardOutgoing::Standard(new_binding.into());
|
|
|
|
}
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|
|
|
|
}
|
2019-06-10 07:09:51 -07:00
|
|
|
(ret, ty.results() == &[walrus::ValType::Anyref])
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|