mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-21 00:36:33 +00:00
cli-support: Skip generating JS shims for imports when unnecessary
After this change, any import that only takes and returns ABI-safe numbers (signed integers less than 64 bits and unrestricted floating point numbers) will be a direct import, and will not have a little JS shim in the middle. We don't have a great mechanism for testing the generated bindings' contents -- as opposed to its behavior -- but I manually verified that everything here does the Right Thing and doesn't have a JS shim: ```rust \#[wasm_bindgen] extern "C" { fn trivial(); fn incoming_i32() -> i32; fn incoming_f32() -> f32; fn incoming_f64() -> f64; fn outgoing_i32(x: i32); fn outgoing_f32(y: f32); fn outgoing_f64(z: f64); fn many(x: i32, y: f32, z: f64) -> i32; } ``` Furthermore, I verified that when our support for emitting native `anyref` is enabled, then we do not have a JS shim for the following import, but if it is disabled, then we do have a JS shim: ```rust \#[wasm_bindgen] extern "C" { fn works_when_anyref_support_is_enabled(v: JsValue) -> JsValue; } ``` Fixes #1636.
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
use crate::descriptor::VectorKind;
|
||||
use crate::intrinsic::Intrinsic;
|
||||
use crate::webidl;
|
||||
use crate::webidl::{AuxEnum, AuxExport, AuxExportKind, AuxImport, AuxStruct};
|
||||
use crate::webidl::{AuxValue, Binding};
|
||||
use crate::webidl::{JsImport, JsImportName, NonstandardWebidlSection, WasmBindgenAux};
|
||||
@ -723,6 +724,15 @@ impl<'a> Context<'a> {
|
||||
self.global("function getObject(idx) { return heap[idx]; }");
|
||||
}
|
||||
|
||||
fn expose_not_defined(&mut self) {
|
||||
if !self.should_write_global("not_defined") {
|
||||
return;
|
||||
}
|
||||
self.global(
|
||||
"function notDefined(what) { return () => { throw new Error(`${what} is not defined`); }; }"
|
||||
);
|
||||
}
|
||||
|
||||
fn expose_assert_num(&mut self) {
|
||||
if !self.should_write_global("assert_num") {
|
||||
return;
|
||||
@ -1971,16 +1981,59 @@ impl<'a> Context<'a> {
|
||||
.types
|
||||
.get::<ast::WebidlFunction>(binding.webidl_ty)
|
||||
.unwrap();
|
||||
let mut builder = binding::Builder::new(self);
|
||||
builder.catch(catch)?;
|
||||
let js = builder.process(&binding, &webidl, false, &None, &mut |cx, prelude, args| {
|
||||
cx.invoke_import(&binding, import, bindings, args, variadic, prelude)
|
||||
})?;
|
||||
let js = format!("function{}", js);
|
||||
let js = match import {
|
||||
AuxImport::Value(AuxValue::Bare(js))
|
||||
if !variadic && !catch && self.import_does_not_require_glue(binding, webidl) =>
|
||||
{
|
||||
self.expose_not_defined();
|
||||
let name = self.import_name(js)?;
|
||||
format!(
|
||||
"typeof {name} == 'function' ? {name} : notDefined('{name}')",
|
||||
name = name,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let mut builder = binding::Builder::new(self);
|
||||
builder.catch(catch)?;
|
||||
let js = builder.process(
|
||||
&binding,
|
||||
&webidl,
|
||||
false,
|
||||
&None,
|
||||
&mut |cx, prelude, args| {
|
||||
cx.invoke_import(&binding, import, bindings, args, variadic, prelude)
|
||||
},
|
||||
)?;
|
||||
format!("function{}", js)
|
||||
}
|
||||
};
|
||||
self.wasm_import_definitions.insert(id, js);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn import_does_not_require_glue(
|
||||
&self,
|
||||
binding: &Binding,
|
||||
webidl: &ast::WebidlFunction,
|
||||
) -> bool {
|
||||
if !self.config.anyref && binding.contains_anyref(self.module) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let wasm_ty = self.module.types.get(binding.wasm_ty);
|
||||
webidl.kind == ast::WebidlFunctionKind::Static
|
||||
&& webidl::outgoing_do_not_require_glue(
|
||||
&binding.outgoing,
|
||||
wasm_ty.params(),
|
||||
&webidl.params,
|
||||
)
|
||||
&& webidl::incoming_do_not_require_glue(
|
||||
&binding.incoming,
|
||||
&webidl.result.into_iter().collect::<Vec<_>>(),
|
||||
wasm_ty.results(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a JS snippet appropriate for invoking `import`.
|
||||
///
|
||||
/// This is generating code for `binding` where `bindings` has more type
|
||||
|
@ -120,6 +120,17 @@ pub struct Binding {
|
||||
pub return_via_outptr: Option<Vec<walrus::ValType>>,
|
||||
}
|
||||
|
||||
impl Binding {
|
||||
/// Does this binding's wasm function signature have any `anyref`s?
|
||||
pub fn contains_anyref(&self, module: &walrus::Module) -> bool {
|
||||
let ty = module.types.get(self.wasm_ty);
|
||||
ty.params()
|
||||
.iter()
|
||||
.chain(ty.results())
|
||||
.any(|ty| *ty == walrus::ValType::Anyref)
|
||||
}
|
||||
}
|
||||
|
||||
/// A synthetic custom section which is not standardized, never will be, and
|
||||
/// cannot be serialized or parsed. This is synthesized from all of the
|
||||
/// compiler-emitted wasm-bindgen sections and then immediately removed to be
|
||||
@ -1428,3 +1439,49 @@ fn concatenate_comments(comments: &[&str]) -> String {
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
/// Do we need to generate JS glue shims for these incoming bindings?
|
||||
pub fn incoming_do_not_require_glue(
|
||||
exprs: &[NonstandardIncoming],
|
||||
from_webidl_tys: &[ast::WebidlTypeRef],
|
||||
to_wasm_tys: &[walrus::ValType],
|
||||
) -> bool {
|
||||
exprs.len() == from_webidl_tys.len()
|
||||
&& exprs.len() == to_wasm_tys.len()
|
||||
&& exprs
|
||||
.iter()
|
||||
.zip(from_webidl_tys)
|
||||
.zip(to_wasm_tys)
|
||||
.enumerate()
|
||||
.all(|(i, ((expr, from_webidl_ty), to_wasm_ty))| match expr {
|
||||
NonstandardIncoming::Standard(e) => e.is_expressible_in_js_without_webidl_bindings(
|
||||
*from_webidl_ty,
|
||||
*to_wasm_ty,
|
||||
i as u32,
|
||||
),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Do we need to generate JS glue shims for these outgoing bindings?
|
||||
pub fn outgoing_do_not_require_glue(
|
||||
exprs: &[NonstandardOutgoing],
|
||||
from_wasm_tys: &[walrus::ValType],
|
||||
to_webidl_tys: &[ast::WebidlTypeRef],
|
||||
) -> bool {
|
||||
exprs.len() == from_wasm_tys.len()
|
||||
&& exprs.len() == to_webidl_tys.len()
|
||||
&& exprs
|
||||
.iter()
|
||||
.zip(from_wasm_tys)
|
||||
.zip(to_webidl_tys)
|
||||
.enumerate()
|
||||
.all(|(i, ((expr, from_wasm_ty), to_webidl_ty))| match expr {
|
||||
NonstandardOutgoing::Standard(e) => e.is_expressible_in_js_without_webidl_bindings(
|
||||
*from_wasm_ty,
|
||||
*to_webidl_ty,
|
||||
i as u32,
|
||||
),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
@ -200,8 +200,12 @@ impl OutgoingBuilder<'_> {
|
||||
Descriptor::U16 => self.standard_as(ValType::I32, ast::WebidlScalarType::UnsignedShort),
|
||||
Descriptor::I32 => self.standard_as(ValType::I32, ast::WebidlScalarType::Long),
|
||||
Descriptor::U32 => self.standard_as(ValType::I32, ast::WebidlScalarType::UnsignedLong),
|
||||
Descriptor::F32 => self.standard_as(ValType::F32, ast::WebidlScalarType::Float),
|
||||
Descriptor::F64 => self.standard_as(ValType::F64, ast::WebidlScalarType::Double),
|
||||
Descriptor::F32 => {
|
||||
self.standard_as(ValType::F32, ast::WebidlScalarType::UnrestrictedFloat)
|
||||
}
|
||||
Descriptor::F64 => {
|
||||
self.standard_as(ValType::F64, ast::WebidlScalarType::UnrestrictedDouble)
|
||||
}
|
||||
Descriptor::Enum { .. } => self.standard_as(ValType::I32, ast::WebidlScalarType::Long),
|
||||
|
||||
Descriptor::Char => {
|
||||
|
Reference in New Issue
Block a user