2019-06-03 11:36:18 -07:00
|
|
|
use crate::descriptor::{Closure, Descriptor, Function};
|
|
|
|
use crate::webidl::{AuxImport, ImportBinding, WasmBindgenAux, WebidlCustomSection};
|
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-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-03 11:36:18 -07:00
|
|
|
.get_typed_mut::<WebidlCustomSection>()
|
2019-05-31 10:54:03 -07:00
|
|
|
.expect("webidl custom section should exist");
|
|
|
|
|
2019-06-03 11:36:18 -07:00
|
|
|
for (export, binding) in bindings.exports.iter_mut() {
|
|
|
|
let (args, ret) = extract_anyrefs(binding, 0);
|
2019-05-31 10:54:03 -07:00
|
|
|
cfg.export_xform(*export, &args, ret);
|
2019-06-03 11:36:18 -07:00
|
|
|
process_closure_arguments(&mut cfg, binding);
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|
|
|
|
|
2019-06-03 11:36:18 -07:00
|
|
|
for (import, kind) in bindings.imports.iter_mut() {
|
2019-05-31 10:54:03 -07:00
|
|
|
let binding = match kind {
|
|
|
|
ImportBinding::Function(f) => f,
|
|
|
|
ImportBinding::Constructor(f) => f,
|
|
|
|
ImportBinding::Method(f) => f,
|
|
|
|
};
|
2019-06-03 11:36:18 -07:00
|
|
|
let (args, ret) = extract_anyrefs(binding, 0);
|
2019-05-31 10:54:03 -07:00
|
|
|
cfg.import_xform(*import, &args, ret);
|
2019-06-03 11:36:18 -07:00
|
|
|
process_closure_arguments(&mut cfg, binding);
|
2019-05-31 10:54:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let aux = module
|
|
|
|
.customs
|
|
|
|
.get_typed_mut::<WasmBindgenAux>()
|
|
|
|
.expect("webidl custom section should exist");
|
|
|
|
for import in aux.import_map.values_mut() {
|
2019-06-03 11:36:18 -07:00
|
|
|
match import {
|
|
|
|
AuxImport::Closure(f) => process_closure(&mut cfg, f),
|
|
|
|
_ => {}
|
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
|
|
|
|
.get_typed_mut::<WebidlCustomSection>()
|
|
|
|
.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-03 11:36:18 -07:00
|
|
|
/// Process the `function` provided to ensure that all references to `Closure`
|
|
|
|
/// descriptors are processed below.
|
|
|
|
fn process_closure_arguments(cfg: &mut Context, function: &mut Function) {
|
|
|
|
for arg in function.arguments.iter_mut() {
|
|
|
|
process_descriptor(cfg, arg);
|
|
|
|
}
|
|
|
|
process_descriptor(cfg, &mut function.ret);
|
|
|
|
|
|
|
|
fn process_descriptor(cfg: &mut Context, descriptor: &mut Descriptor) {
|
|
|
|
match descriptor {
|
|
|
|
Descriptor::Ref(d)
|
|
|
|
| Descriptor::RefMut(d)
|
|
|
|
| Descriptor::Option(d)
|
|
|
|
| Descriptor::Slice(d)
|
|
|
|
| Descriptor::Vector(d) => process_descriptor(cfg, d),
|
|
|
|
Descriptor::Closure(c) => process_closure(cfg, c),
|
|
|
|
Descriptor::Function(c) => process_function(cfg, c),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_function(cfg: &mut Context, function: &mut Function) {
|
|
|
|
let (args, ret) = extract_anyrefs(&function, 2);
|
|
|
|
if let Some(new) = cfg.table_element_xform(function.shim_idx, &args, ret) {
|
|
|
|
function.shim_idx = new;
|
|
|
|
}
|
|
|
|
process_closure_arguments(cfg, function);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Ensure that the `Closure` is processed in case any of its arguments
|
|
|
|
/// recursively contain `anyref` and such.
|
|
|
|
fn process_closure(cfg: &mut Context, closure: &mut Closure) {
|
|
|
|
let (args, ret) = extract_anyrefs(&closure.function, 2);
|
|
|
|
if let Some(new) = cfg.table_element_xform(closure.shim_idx, &args, ret) {
|
|
|
|
closure.shim_idx = new;
|
|
|
|
}
|
|
|
|
process_closure_arguments(cfg, &mut closure.function);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
fn extract_anyrefs(f: &Function, offset: usize) -> (Vec<(usize, bool)>, bool) {
|
2019-05-31 10:54:03 -07:00
|
|
|
let mut args = Vec::new();
|
2019-06-03 11:36:18 -07:00
|
|
|
let mut cur = offset;
|
2019-05-31 10:54:03 -07:00
|
|
|
if f.ret.abi_returned_through_pointer() {
|
|
|
|
cur += 1;
|
|
|
|
}
|
|
|
|
for arg in f.arguments.iter() {
|
|
|
|
if arg.is_anyref() {
|
|
|
|
args.push((cur, true));
|
|
|
|
} else if arg.is_ref_anyref() {
|
|
|
|
args.push((cur, false));
|
|
|
|
}
|
|
|
|
cur += arg.abi_arg_count();
|
|
|
|
}
|
|
|
|
(args, f.ret.is_anyref())
|
|
|
|
}
|