Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for emitting a Wasm Interface Types section #1725

Merged
merged 1 commit into from
Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions crates/cli-support/src/anyref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use walrus::Module;
use wasm_bindgen_anyref_xform::Context;
use wasm_webidl_bindings::ast;

pub fn process(module: &mut Module) -> Result<(), Error> {
pub fn process(module: &mut Module, wasm_interface_types: bool) -> Result<(), Error> {
let mut cfg = Context::default();
cfg.prepare(module)?;
let bindings = module
Expand Down Expand Up @@ -45,18 +45,24 @@ pub fn process(module: &mut Module) -> Result<(), Error> {

cfg.run(module)?;

// Make sure to export the `anyref` table for the JS bindings since it
// will need to be initialized. If it doesn't exist though then the
// module must not use it, so we skip it.
let table = module.tables.iter().find(|t| match t.kind {
walrus::TableKind::Anyref(_) => true,
_ => false,
});
let table = match table {
Some(t) => t.id(),
None => return Ok(()),
};
module.exports.add("__wbg_anyref_table", table);
// If our output is using WebAssembly interface types then our bindings will
// never use this table, so no need to export it. Otherwise it's highly
// likely in web/JS embeddings this will be used, so make sure we export it
// to avoid it getting gc'd accidentally.
if !wasm_interface_types {
// Make sure to export the `anyref` table for the JS bindings since it
// will need to be initialized. If it doesn't exist though then the
// module must not use it, so we skip it.
let table = module.tables.iter().find(|t| match t.kind {
walrus::TableKind::Anyref(_) => true,
_ => false,
});
let table = match table {
Some(t) => t.id(),
None => return Ok(()),
};
module.exports.add("__wbg_anyref_table", table);
}

// Clean up now-unused intrinsics and shims and such
walrus::passes::gc::run(module);
Expand Down
9 changes: 9 additions & 0 deletions crates/cli-support/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ macro_rules! intrinsics {
)*
}
}

/// Returns the symbol name of this intrinsic
pub fn name(&self) -> &'static str {
match self {
$(
Intrinsic::$name => $sym,
)*
}
}
}
};
}
Expand Down
2 changes: 2 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2081,11 +2081,13 @@ impl<'a> Context<'a> {
&binding.outgoing,
wasm_ty.params(),
&webidl.params,
self.config.wasm_interface_types,
)
&& webidl::incoming_do_not_require_glue(
&binding.incoming,
&webidl.result.into_iter().collect::<Vec<_>>(),
wasm_ty.results(),
self.config.wasm_interface_types,
)
}

Expand Down
43 changes: 32 additions & 11 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct Bindgen {
// "ready to be instantiated on any thread"
threads: wasm_bindgen_threads_xform::Config,
anyref: bool,
wasm_interface_types: bool,
encode_into: EncodeInto,
}

Expand All @@ -49,6 +50,7 @@ pub struct Output {
snippets: HashMap<String, Vec<String>>,
local_modules: HashMap<String, String>,
npm_dependencies: HashMap<String, (PathBuf, String)>,
wasm_interface_types: bool,
}

#[derive(Clone)]
Expand All @@ -73,6 +75,8 @@ pub enum EncodeInto {

impl Bindgen {
pub fn new() -> Bindgen {
let anyref = env::var("WASM_BINDGEN_ANYREF").is_ok();
let wasm_interface_types = env::var("WASM_INTERFACE_TYPES").is_ok();
Bindgen {
input: Input::None,
out_name: None,
Expand All @@ -88,7 +92,8 @@ impl Bindgen {
emit_start: true,
weak_refs: env::var("WASM_BINDGEN_WEAKREF").is_ok(),
threads: threads_config(),
anyref: env::var("WASM_BINDGEN_ANYREF").is_ok(),
anyref: anyref || wasm_interface_types,
wasm_interface_types,
encode_into: EncodeInto::Test,
}
}
Expand Down Expand Up @@ -315,15 +320,15 @@ impl Bindgen {
// the webidl bindings proposal) as well as an auxiliary section for all
// sorts of miscellaneous information and features #[wasm_bindgen]
// supports that aren't covered by WebIDL bindings.
webidl::process(&mut module, self.anyref, self.emit_start)?;
webidl::process(&mut module, self.anyref, self.wasm_interface_types, self.emit_start)?;

// Now that we've got type information from the webidl processing pass,
// touch up the output of rustc to insert anyref shims where necessary.
// This is only done if the anyref pass is enabled, which it's
// currently off-by-default since `anyref` is still in development in
// engines.
if self.anyref {
anyref::process(&mut module)?;
anyref::process(&mut module, self.wasm_interface_types)?;
}

let aux = module
Expand All @@ -344,6 +349,11 @@ impl Bindgen {
(npm_dependencies, cx.finalize(stem)?)
};

if self.wasm_interface_types {
webidl::standard::add_section(&mut module, &aux, &bindings)
.with_context(|_| "failed to generate a standard wasm bindings custom section")?;
}

Ok(Output {
module,
stem: stem.to_string(),
Expand All @@ -354,6 +364,7 @@ impl Bindgen {
ts,
mode: self.mode.clone(),
typescript: self.typescript,
wasm_interface_types: self.wasm_interface_types,
})
}

Expand Down Expand Up @@ -506,6 +517,7 @@ fn unexported_unused_lld_things(module: &mut Module) {

impl Output {
pub fn js(&self) -> &str {
assert!(!self.wasm_interface_types);
&self.js
}

Expand All @@ -518,6 +530,23 @@ impl Output {
}

fn _emit(&self, out_dir: &Path) -> Result<(), Error> {
let wasm_name = if self.wasm_interface_types {
self.stem.clone()
} else {
format!("{}_bg", self.stem)
};
let wasm_path = out_dir
.join(wasm_name)
.with_extension("wasm");
fs::create_dir_all(out_dir)?;
let wasm_bytes = self.module.emit_wasm()?;
fs::write(&wasm_path, wasm_bytes)
.with_context(|_| format!("failed to write `{}`", wasm_path.display()))?;

if self.wasm_interface_types {
return Ok(())
}

// Write out all local JS snippets to the final destination now that
// we've collected them from all the programs.
for (identifier, list) in self.snippets.iter() {
Expand Down Expand Up @@ -554,7 +583,6 @@ impl Output {
} else {
"js"
};
fs::create_dir_all(out_dir)?;
let js_path = out_dir.join(&self.stem).with_extension(extension);
fs::write(&js_path, reset_indentation(&self.js))
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
Expand All @@ -565,10 +593,6 @@ impl Output {
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
}

let wasm_path = out_dir
.join(format!("{}_bg", self.stem))
.with_extension("wasm");

if self.mode.nodejs() {
let js_path = wasm_path.with_extension(extension);
let shim = self.generate_node_wasm_import(&self.module, &wasm_path);
Expand All @@ -583,9 +607,6 @@ impl Output {
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
}

let wasm_bytes = self.module.emit_wasm()?;
fs::write(&wasm_path, wasm_bytes)
.with_context(|_| format!("failed to write `{}`", wasm_path.display()))?;
Ok(())
}

Expand Down
Loading