Reimplement anyref processing and passes

This commit reimplements the `anyref` transformation pass tasked with
taking raw rustc output and enhancing the module to use `anyref`. This
was disabled in the previous commits during refactoring, and now the
pass is re-enabled in the manner originally intended.

Instead of being tangled up in the `js/mod.rs` pass, the anyref
transformation now happens locally within one module,
`cli-support/src/anyref.rs`, which exclusively uses the output of the
`webidl` module which produces a WebIDL bindings section as well as an
auxiliary wasm-bindgen specific section. This makes the anyref transform
much more straightforward and local, ensuring that it doesn't propagate
elsewhere and can be a largely local concern during the transformation.

The main addition needed to support this pass was detailed knowledge of
the ABI of a `Descriptor`. This knowledge is already implicitly
hardcoded in `js2rust.rs` and `rust2js.rs` through the ABI shims
generated. This was previously used for the anyref transformation to
piggy-back what was already there, but as a separate pass we are unable
to reuse the knowledge in the binding generator.

Instead `Descriptor` now has two dedicated methods describing the
various ABI properties of a type. This is then asserted to be correct
(all the time) when processing bindings, ensuring that the two are kept
in sync.
This commit is contained in:
Alex Crichton 2019-05-31 10:54:03 -07:00
parent 55fc5367a5
commit b51df39bc9
7 changed files with 264 additions and 193 deletions

View File

@ -20,6 +20,7 @@ use std::cmp;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::mem;
use walrus::ir::*;
use walrus::{ExportId, ImportId};
use walrus::{FunctionId, GlobalId, InitExpr, Module, TableId, ValType};
// must be kept in sync with src/lib.rs and ANYREF_HEAP_START
@ -32,8 +33,8 @@ pub struct Context {
// Functions within the module that we're gonna be wrapping, organized by
// type. The `Function` contains information about what arguments/return
// values in the function signature should turn into anyref.
imports: HashMap<String, HashMap<String, Function>>,
exports: HashMap<String, Function>,
imports: HashMap<ImportId, Function>,
exports: HashMap<ExportId, Function>,
elements: BTreeMap<u32, (u32, Function)>,
// When wrapping closures with new shims, this is the index of the next
@ -42,9 +43,6 @@ pub struct Context {
// The anyref table we'll be using, injected after construction
table: Option<TableId>,
// Whether or not the transformation will actually be run at the end
pub enabled: bool,
}
struct Transform<'a> {
@ -68,7 +66,6 @@ struct Transform<'a> {
}
struct Function {
name: String,
// A map of argument index to whether it's an owned or borrowed anyref
// (owned = true)
args: HashMap<usize, bool>,
@ -87,10 +84,6 @@ impl Context {
/// large the function table is so we know what indexes to hand out when
/// we're appending entries.
pub fn prepare(&mut self, module: &mut Module) -> Result<(), Error> {
if !self.enabled {
return Ok(());
}
// Figure out what the maximum index of functions pointers are. We'll
// be adding new entries to the function table later (maybe) so
// precalculate this ahead of time.
@ -118,19 +111,13 @@ impl Context {
/// transformed. The actual transformation happens later during `run`.
pub fn import_xform(
&mut self,
module: &str,
name: &str,
id: ImportId,
anyref: &[(usize, bool)],
ret_anyref: bool,
) -> &mut Self {
if !self.enabled {
return self;
if let Some(f) = self.function(anyref, ret_anyref) {
self.imports.insert(id, f);
}
let f = self.function(name, anyref, ret_anyref);
self.imports
.entry(module.to_string())
.or_insert_with(Default::default)
.insert(name.to_string(), f);
self
}
@ -138,15 +125,13 @@ impl Context {
/// transformed. The actual transformation happens later during `run`.
pub fn export_xform(
&mut self,
name: &str,
id: ExportId,
anyref: &[(usize, bool)],
ret_anyref: bool,
) -> &mut Self {
if !self.enabled {
return self;
if let Some(f) = self.function(anyref, ret_anyref) {
self.exports.insert(id, f);
}
let f = self.function(name, anyref, ret_anyref);
self.exports.insert(name.to_string(), f);
self
}
@ -158,34 +143,26 @@ impl Context {
idx: u32,
anyref: &[(usize, bool)],
ret_anyref: bool,
) -> u32 {
if !self.enabled {
return idx;
}
let name = format!("closure{}", idx);
let f = self.function(&name, anyref, ret_anyref);
let ret = self.next_element;
self.next_element += 1;
self.elements.insert(ret, (idx, f));
ret
) -> Option<u32> {
self.function(anyref, ret_anyref).map(|f| {
let ret = self.next_element;
self.next_element += 1;
self.elements.insert(ret, (idx, f));
ret
})
}
fn function(&self, name: &str, anyref: &[(usize, bool)], ret_anyref: bool) -> Function {
Function {
name: name.to_string(),
fn function(&self, anyref: &[(usize, bool)], ret_anyref: bool) -> Option<Function> {
if !ret_anyref && anyref.len() == 0 {
return None;
}
Some(Function {
args: anyref.iter().cloned().collect(),
ret_anyref,
}
}
pub fn anyref_table_id(&self) -> TableId {
self.table.unwrap()
})
}
pub fn run(&mut self, module: &mut Module) -> Result<(), Error> {
if !self.enabled {
return Ok(());
}
let table = self.table.unwrap();
// Inject a stack pointer global which will be used for managing the
@ -261,9 +238,7 @@ impl Transform<'_> {
// Perform transformations of imports, exports, and function pointers.
self.process_imports(module);
for m in self.cx.imports.values() {
assert!(m.is_empty());
}
assert!(self.cx.imports.is_empty());
self.process_exports(module);
assert!(self.cx.exports.is_empty());
self.process_elements(module)?;
@ -333,20 +308,15 @@ impl Transform<'_> {
walrus::ImportKind::Function(f) => f,
_ => continue,
};
let import = {
let entries = match self.cx.imports.get_mut(&import.module) {
Some(s) => s,
None => continue,
};
match entries.remove(&import.name) {
Some(s) => s,
None => continue,
}
let func = match self.cx.imports.remove(&import.id()) {
Some(s) => s,
None => continue,
};
let shim = self.append_shim(
f,
import,
&import.name,
func,
&mut module.types,
&mut module.funcs,
&mut module.locals,
@ -356,29 +326,25 @@ impl Transform<'_> {
}
fn process_exports(&mut self, module: &mut Module) {
let mut new_exports = Vec::new();
for export in module.exports.iter() {
// let mut new_exports = Vec::new();
for export in module.exports.iter_mut() {
let f = match export.item {
walrus::ExportItem::Function(f) => f,
_ => continue,
};
let function = match self.cx.exports.remove(&export.name) {
let function = match self.cx.exports.remove(&export.id()) {
Some(s) => s,
None => continue,
};
let shim = self.append_shim(
f,
&export.name,
function,
&mut module.types,
&mut module.funcs,
&mut module.locals,
);
new_exports.push((export.name.to_string(), shim, export.id()));
}
for (name, shim, old_id) in new_exports {
module.exports.add(&name, shim);
module.exports.delete(old_id);
export.item = shim.into();
}
}
@ -402,6 +368,7 @@ impl Transform<'_> {
let target = kind.elements[idx as usize].unwrap();
let shim = self.append_shim(
target,
&format!("closure{}", idx),
function,
&mut module.types,
&mut module.funcs,
@ -422,6 +389,7 @@ impl Transform<'_> {
fn append_shim(
&mut self,
shim_target: FunctionId,
name: &str,
mut func: Function,
types: &mut walrus::ModuleTypes,
funcs: &mut walrus::ModuleFunctions,
@ -625,7 +593,7 @@ impl Transform<'_> {
// nice name for debugging and then we're good to go!
let expr = builder.with_side_effects(before, result, after);
let id = builder.finish_parts(shim_ty, params, vec![expr], types, funcs);
let name = format!("{}_anyref_shim", func.name);
let name = format!("{}_anyref_shim", name);
funcs.get_mut(id).name = Some(name);
self.shims.insert(id);
return id;

View File

@ -0,0 +1,87 @@
use crate::descriptor::Function;
use crate::webidl::{ImportBinding, WasmBindgenAux, WebidlCustomSection, AuxImport};
use failure::Error;
use std::collections::HashSet;
use walrus::Module;
pub fn process(module: &mut Module) -> Result<(), Error> {
let mut cfg = wasm_bindgen_anyref_xform::Context::default();
cfg.prepare(module)?;
let bindings = module
.customs
.get_typed::<WebidlCustomSection>()
.expect("webidl custom section should exist");
for (export, binding) in bindings.exports.iter() {
let (args, ret) = extract_anyrefs(binding);
cfg.export_xform(*export, &args, ret);
}
for (import, kind) in bindings.imports.iter() {
let binding = match kind {
ImportBinding::Function(f) => f,
ImportBinding::Constructor(f) => f,
ImportBinding::Method(f) => f,
};
let (args, ret) = extract_anyrefs(binding);
cfg.import_xform(*import, &args, ret);
}
let aux = module
.customs
.get_typed_mut::<WasmBindgenAux>()
.expect("webidl custom section should exist");
for import in aux.import_map.values_mut() {
let closure = match import {
AuxImport::Closure(f) => f,
_ => continue,
};
let (args, ret) = extract_anyrefs(&closure.function);
if let Some(new) = cfg.table_element_xform(closure.shim_idx, &args, ret) {
closure.shim_idx = new;
}
}
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(())
}
fn extract_anyrefs(f: &Function) -> (Vec<(usize, bool)>, bool) {
let mut args = Vec::new();
let mut cur = 0;
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())
}

View File

@ -292,6 +292,83 @@ impl Descriptor {
_ => false,
}
}
pub fn abi_returned_through_pointer(&self) -> bool {
if self.vector_kind().is_some() {
return true;
}
if self.get_64().is_some() {
return true;
}
match self {
Descriptor::Option(inner) => match &**inner {
Descriptor::Anyref
| Descriptor::RustStruct(_)
| Descriptor::Enum { .. }
| Descriptor::Char
| Descriptor::Boolean
| Descriptor::I8
| Descriptor::U8
| Descriptor::I16
| Descriptor::U16 => false,
_ => true,
},
_ => false,
}
}
pub fn abi_arg_count(&self) -> usize {
if let Descriptor::Option(inner) = self {
if inner.get_64().is_some() {
return 4;
}
if let Descriptor::Ref(inner) = &**inner {
match &**inner {
Descriptor::Anyref => return 1,
_ => {}
}
}
}
if self.stack_closure().is_some() {
return 2;
}
if self.abi_returned_through_pointer() {
2
} else {
1
}
}
pub fn assert_abi_return_correct(&self, before: usize, after: usize) {
if before != after {
assert_eq!(
before + 1,
after,
"abi_returned_through_pointer wrong for {:?}",
self,
);
assert!(
self.abi_returned_through_pointer(),
"abi_returned_through_pointer wrong for {:?}",
self,
);
} else {
assert!(
!self.abi_returned_through_pointer(),
"abi_returned_through_pointer wrong for {:?}",
self,
);
}
}
pub fn assert_abi_arg_correct(&self, before: usize, after: usize) {
assert_eq!(
before + self.abi_arg_count(),
after,
"abi_arg_count wrong for {:?}",
self,
);
}
}
fn get(a: &mut &[u32]) -> u32 {

View File

@ -68,15 +68,6 @@ pub struct Js2Rust<'a, 'b: 'a> {
/// The string value here is the class that this should be a constructor
/// for.
constructor: Option<String>,
/// metadata for anyref transformations
anyref_args: Vec<(usize, bool)>,
ret_anyref: bool,
}
pub enum ExportedShim<'a> {
Named(&'a str),
TableElement(&'a mut u32),
}
impl<'a, 'b> Js2Rust<'a, 'b> {
@ -92,8 +83,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
ret_ty: String::new(),
ret_expr: String::new(),
constructor: None,
anyref_args: Vec::new(),
ret_anyref: false,
}
}
@ -104,17 +93,26 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
function: &Function,
opt_arg_names: &Option<Vec<String>>,
) -> Result<&mut Self, Error> {
if let Some(arg_names) = opt_arg_names {
assert_eq!(arg_names.len(), function.arguments.len());
for (arg, arg_name) in function.arguments.iter().zip(arg_names) {
self.argument(arg, arg_name.as_str())?;
}
} else {
for arg in function.arguments.iter() {
self.argument(arg, None)?;
}
let arg_names = match opt_arg_names {
Some(arg_names) => arg_names.iter().map(|s| Some(s.as_str())).collect(),
None => vec![None; function.arguments.len()],
};
assert_eq!(arg_names.len(), function.arguments.len());
for (arg, arg_name) in function.arguments.iter().zip(arg_names) {
// Process the function argument and assert that the metadata about
// the number of arguments on the Rust side required is correct.
let before = self.rust_arguments.len();
self.argument(arg, arg_name)?;
arg.assert_abi_arg_correct(before, self.rust_arguments.len());
}
// Process the return argument, and assert that the metadata returned
// about the descriptor is indeed correct.
let before = self.rust_arguments.len();
self.ret(&function.ret)?;
function
.ret
.assert_abi_return_correct(before, self.rust_arguments.len());
Ok(self)
}
@ -181,12 +179,9 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
ret
}
pub fn argument<'c, I>(&mut self, arg: &Descriptor, opt_arg_name: I) -> Result<&mut Self, Error>
where
I: Into<Option<&'c str>>,
{
fn argument(&mut self, arg: &Descriptor, arg_name: Option<&str>) -> Result<&mut Self, Error> {
let i = self.arg_idx;
let name = self.abi_arg(opt_arg_name.into());
let name = self.abi_arg(arg_name);
let (arg, optional) = match arg {
Descriptor::Option(t) => (&**t, true),
@ -252,7 +247,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
self.rust_arguments
.push(format!("isLikeNone({0}) ? 0 : addToAnyrefTable({0})", name));
} else {
self.anyref_args.push((self.rust_arguments.len(), true));
self.rust_arguments.push(name);
}
} else {
@ -449,7 +443,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
self.js_arguments
.push(JsArgument::required(name.clone(), "any".to_string()));
if self.cx.config.anyref {
self.anyref_args.push((self.rust_arguments.len(), false));
self.rust_arguments.push(name);
} else {
// the "stack-ful" nature means that we're always popping from the
@ -492,7 +485,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
Ok(self)
}
pub fn ret(&mut self, ty: &Descriptor) -> Result<&mut Self, Error> {
fn ret(&mut self, ty: &Descriptor) -> Result<&mut Self, Error> {
if let Some(name) = ty.rust_struct() {
match &self.constructor {
Some(class) if class == name => {
@ -566,7 +559,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
if ty.is_anyref() {
self.ret_ty = "any".to_string();
self.ret_expr = format!("return {};", self.cx.take_object("RET"));
self.ret_anyref = true;
return Ok(self);
}
@ -784,12 +776,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
/// Returns two strings, the first of which is the JS expression for the
/// generated function shim and the second is a TypeScript signature of the
/// JS expression.
pub fn finish(
&mut self,
prefix: &str,
invoc: &str,
exported_shim: ExportedShim,
) -> (String, String, String) {
pub fn finish(&mut self, prefix: &str, invoc: &str) -> (String, String, String) {
let js_args = self
.js_arguments
.iter()
@ -854,23 +841,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
}
ts.push(';');
if self.ret_anyref || self.anyref_args.len() > 0 {
match exported_shim {
ExportedShim::Named(name) => {
self.cx
.anyref
.export_xform(name, &self.anyref_args, self.ret_anyref);
}
ExportedShim::TableElement(idx) => {
*idx = self.cx.anyref.table_element_xform(
*idx,
&self.anyref_args,
self.ret_anyref,
);
}
}
}
(js, ts, self.js_doc_comments())
}

View File

@ -2,7 +2,7 @@ mod js2rust;
mod rust2js;
use crate::descriptor::VectorKind;
use crate::js::js2rust::{ExportedShim, Js2Rust};
use crate::js::js2rust::Js2Rust;
use crate::js::rust2js::Rust2Js;
use crate::webidl::{AuxEnum, AuxExport, AuxExportKind, AuxImport, AuxStruct};
use crate::webidl::{JsImport, JsImportName, WasmBindgenAux, WebidlCustomSection};
@ -47,8 +47,6 @@ pub struct Context<'a> {
/// A map of the name of npm dependencies we've loaded so far to the path
/// they're defined in as well as their version specification.
pub npm_dependencies: HashMap<String, (PathBuf, String)>,
pub anyref: wasm_bindgen_anyref_xform::Context,
}
#[derive(Default)]
@ -99,7 +97,6 @@ impl<'a> Context<'a> {
module,
function_table_needed: false,
memory,
anyref: Default::default(),
npm_dependencies: Default::default(),
})
}
@ -192,13 +189,6 @@ impl<'a> Context<'a> {
// `__wrap` and such.
self.write_classes()?;
// And now that we're almost ready, run the final "anyref" pass. This is
// where we transform a wasm module which doesn't actually use `anyref`
// anywhere to using the type internally. The transformation here is
// based off all the previous data we've collected so far for each
// import/export listed.
// self.anyref.run(self.module)?;
// We're almost done here, so we can delete any internal exports (like
// `__wbindgen_malloc`) if none of our JS glue actually needed it.
self.unexport_unused_internal_exports();
@ -1794,9 +1784,17 @@ impl<'a> Context<'a> {
if !self.should_write_global("anyref_table") {
return;
}
self.module
.exports
.add("__wbg_anyref_table", self.anyref.anyref_table_id());
let table = self
.module
.tables
.iter()
.find(|t| match t.kind {
walrus::TableKind::Anyref(_) => true,
_ => false,
})
.expect("failed to find anyref table in module")
.id();
self.module.exports.add("__wbg_anyref_table", table);
}
fn expose_add_to_anyref_table(&mut self) -> Result<(), Error> {
@ -1878,11 +1876,7 @@ impl<'a> Context<'a> {
AuxExportKind::Function(name) => {
let (js, ts, js_doc) = Js2Rust::new(&name, self)
.process(&descriptor, &export.arg_names)?
.finish(
"function",
&format!("wasm.{}", wasm_name),
ExportedShim::Named(&wasm_name),
);
.finish("function", &format!("wasm.{}", wasm_name));
self.export(
&name,
&js,
@ -1897,11 +1891,7 @@ impl<'a> Context<'a> {
let (js, ts, raw_docs) = Js2Rust::new("constructor", self)
.constructor(Some(&class))
.process(&descriptor, &export.arg_names)?
.finish(
"",
&format!("wasm.{}", wasm_name),
ExportedShim::Named(&wasm_name),
);
.finish("", &format!("wasm.{}", wasm_name));
let exported = require_class(&mut self.exported_classes, class);
if exported.has_constructor {
bail!("found duplicate constructor for class `{}`", class);
@ -1924,11 +1914,9 @@ impl<'a> Context<'a> {
j2r.method(false);
}
}
let (js, ts, raw_docs) = j2r.process(&descriptor, &export.arg_names)?.finish(
"",
&format!("wasm.{}", wasm_name),
ExportedShim::Named(&wasm_name),
);
let (js, ts, raw_docs) = j2r
.process(&descriptor, &export.arg_names)?
.finish("", &format!("wasm.{}", wasm_name));
let ret_ty = j2r.ret_ty.clone();
let exported = require_class(&mut self.exported_classes, class);
let docs = format_doc_comments(&export.comments, Some(raw_docs));

View File

@ -1,6 +1,5 @@
use crate::descriptor::Descriptor;
use crate::intrinsic::Intrinsic;
use crate::js::js2rust::ExportedShim;
use crate::js::{Context, Js2Rust};
use crate::webidl::{AuxImport, AuxValue, ImportBinding};
use failure::{bail, Error};
@ -119,9 +118,19 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
}
};
for arg in function.arguments.iter() {
// Process the function argument and assert that the metadata about
// the number of arguments on the Rust side required is correct.
let before = self.shim_arguments.len();
self.argument(arg)?;
arg.assert_abi_arg_correct(before, self.shim_arguments.len());
}
// Process the return argument, and assert that the metadata returned
// about the descriptor is indeed correct.
let before = self.shim_arguments.len();
self.ret(&function.ret)?;
function
.ret
.assert_abi_return_correct(before, self.shim_arguments.len());
Ok(self)
}
@ -308,7 +317,6 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
if let Some((f, mutable)) = arg.stack_closure() {
let arg2 = self.shim_argument();
let mut shim = f.shim_idx;
let (js, _ts, _js_doc) = {
let mut builder = Js2Rust::new("", self.cx);
if mutable {
@ -320,11 +328,10 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
} else {
builder.rust_argument("this.a");
}
builder.rust_argument("this.b").process(f, &None)?.finish(
"function",
"this.f",
ExportedShim::TableElement(&mut shim),
)
builder
.rust_argument("this.b")
.process(f, &None)?
.finish("function", "this.f")
};
self.cx.function_table_needed = true;
self.global_idx();
@ -338,7 +345,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
abi,
arg2,
js = js,
idx = shim,
idx = f.shim_idx,
));
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", abi));
self.js_arguments.push(format!("cb{0}.bind(cb{0})", abi));
@ -676,7 +683,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
format!("new {}({})", js, variadic_args(&self.js_arguments)?)
}
Style::Method => {
let descriptor = |anchor: &str, extra: &str, field: &str, which:&str| {
let descriptor = |anchor: &str, extra: &str, field: &str, which: &str| {
format!(
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').{}",
anchor, extra, field, which
@ -741,7 +748,6 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
assert!(self.style == Style::Function);
assert!(!variadic);
assert_eq!(self.js_arguments.len(), 3);
let mut shim = closure.shim_idx;
let (js, _ts, _js_doc) = {
let mut builder = Js2Rust::new("", self.cx);
@ -777,11 +783,9 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
.finally("this.a = 0;")
.finally("}");
}
builder.process(&closure.function, &None)?.finish(
"function",
"f",
ExportedShim::TableElement(&mut shim),
)
builder
.process(&closure.function, &None)?
.finish("function", "f")
};
self.cx.function_table_needed = true;
let body = format!(
@ -795,7 +799,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
let real = cb.bind(cb);
real.original = cb;
",
shim,
closure.shim_idx,
closure.dtor_idx,
&self.js_arguments[1],
js,
@ -978,32 +982,6 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
ret.push_str(&invoc);
ret.push_str("\n}\n");
// if self.ret_anyref || self.anyref_args.len() > 0 {
// // Some return values go at the the beginning of the argument list
// // (they force a return pointer). Handle that here by offsetting all
// // our arg indices by one, but throw in some sanity checks for if
// // this ever changes.
// if let Some(start) = self.shim_arguments.get(0) {
// if start == "ret" {
// assert!(!self.ret_anyref);
// if let Some(next) = self.shim_arguments.get(1) {
// assert_eq!(next, "arg0");
// }
// for (idx, _) in self.anyref_args.iter_mut() {
// *idx += 1;
// }
// } else {
// assert_eq!(start, "arg0");
// }
// }
// self.cx.anyref.import_xform(
// "__wbindgen_placeholder__",
// shim,
// &self.anyref_args,
// self.ret_anyref,
// );
// }
Ok(ret)
}

View File

@ -9,6 +9,7 @@ use std::path::{Path, PathBuf};
use std::str;
use walrus::Module;
mod anyref;
mod decode;
mod intrinsic;
mod descriptor;
@ -316,6 +317,10 @@ impl Bindgen {
// supports that aren't covered by WebIDL bindings.
webidl::process(&mut module)?;
if self.anyref {
anyref::process(&mut module)?;
}
// If we're in a testing mode then remove the start function since we
// shouldn't execute it.
if !self.emit_start {
@ -326,8 +331,6 @@ impl Bindgen {
// shim generation which will actually generate JS for all this.
let (js, ts) = {
let mut cx = js::Context::new(&mut module, self)?;
cx.anyref.enabled = self.anyref;
cx.anyref.prepare(cx.module)?;
let aux = cx.module.customs.delete_typed::<webidl::WasmBindgenAux>()
.expect("aux section should be present");