Merge pull request #1065 from alexcrichton/describe-closures

Move closure shims into the descriptor
This commit is contained in:
Alex Crichton 2018-11-29 17:30:58 -06:00 committed by GitHub
commit 91e9495805
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 137 additions and 194 deletions

View File

@ -501,6 +501,7 @@ impl TryToTokens for ast::Export {
&export, &export,
quote! { quote! {
inform(FUNCTION); inform(FUNCTION);
inform(0);
inform(#nargs); inform(#nargs);
#(<#argtys as WasmDescribe>::describe();)* #(<#argtys as WasmDescribe>::describe();)*
#describe_ret #describe_ret
@ -999,6 +1000,7 @@ impl<'a> ToTokens for DescribeImport<'a> {
&f.shim, &f.shim,
quote! { quote! {
inform(FUNCTION); inform(FUNCTION);
inform(0);
inform(#nargs); inform(#nargs);
#(<#argtys as WasmDescribe>::describe();)* #(<#argtys as WasmDescribe>::describe();)*
#inform_ret #inform_ret

View File

@ -70,11 +70,14 @@ pub enum Descriptor {
#[derive(Debug)] #[derive(Debug)]
pub struct Function { pub struct Function {
pub arguments: Vec<Descriptor>, pub arguments: Vec<Descriptor>,
pub shim_idx: u32,
pub ret: Descriptor, pub ret: Descriptor,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Closure { pub struct Closure {
pub shim_idx: u32,
pub dtor_idx: u32,
pub function: Function, pub function: Function,
pub mutable: bool, pub mutable: bool,
} }
@ -293,9 +296,13 @@ fn get(a: &mut &[u32]) -> u32 {
impl Closure { impl Closure {
fn decode(data: &mut &[u32]) -> Closure { fn decode(data: &mut &[u32]) -> Closure {
let shim_idx = get(data);
let dtor_idx = get(data);
let mutable = get(data) == REFMUT; let mutable = get(data) == REFMUT;
assert_eq!(get(data), FUNCTION); assert_eq!(get(data), FUNCTION);
Closure { Closure {
shim_idx,
dtor_idx,
mutable, mutable,
function: Function::decode(data), function: Function::decode(data),
} }
@ -304,11 +311,13 @@ impl Closure {
impl Function { impl Function {
fn decode(data: &mut &[u32]) -> Function { fn decode(data: &mut &[u32]) -> Function {
let shim_idx = get(data);
let arguments = (0..get(data)) let arguments = (0..get(data))
.map(|_| Descriptor::_decode(data)) .map(|_| Descriptor::_decode(data))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Function { Function {
arguments, arguments,
shim_idx,
ret: Descriptor::_decode(data), ret: Descriptor::_decode(data),
} }
} }

View File

@ -47,11 +47,12 @@ pub fn rewrite(input: &mut Context) -> Result<(), Error> {
// If this was an imported function we didn't reorder those, so nothing // If this was an imported function we didn't reorder those, so nothing
// to do. // to do.
if idx < old_num_imports { if idx < old_num_imports {
return idx idx
} } else {
// ... otherwise we're injecting a number of new imports, so offset // ... otherwise we're injecting a number of new imports, so offset
// everything. // everything.
idx + info.code_idx_to_descriptor.len() as u32 idx + info.code_idx_to_descriptor.len() as u32
}
}).remap_module(input.module); }).remap_module(input.module);
info.delete_function_table_entries(input); info.delete_function_table_entries(input);
@ -252,9 +253,9 @@ impl ClosureDescriptors {
input.expose_add_heap_object(); input.expose_add_heap_object();
input.function_table_needed = true; input.function_table_needed = true;
let body = format!( let body = format!(
"function(a, b, fi, di, _ignored) {{ "function(a, b, _ignored) {{
const f = wasm.__wbg_function_table.get(fi); const f = wasm.__wbg_function_table.get({});
const d = wasm.__wbg_function_table.get(di); const d = wasm.__wbg_function_table.get({});
const cb = {}; const cb = {};
cb.a = a; cb.a = a;
cb.cnt = 1; cb.cnt = 1;
@ -262,6 +263,8 @@ impl ClosureDescriptors {
real.original = cb; real.original = cb;
return addHeapObject(real); return addHeapObject(real);
}}", }}",
closure.shim_idx,
closure.dtor_idx,
js, js,
); );
input.export(&import_name, &body, None); input.export(&import_name, &body, None);

View File

@ -256,7 +256,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
self.cx.expose_uint64_cvt_shim() self.cx.expose_uint64_cvt_shim()
}; };
self.cx.expose_uint32_memory(); self.cx.expose_uint32_memory();
self.cx.expose_global_argument_ptr()?;
self.js_arguments.push((name.clone(), "BigInt".to_string())); self.js_arguments.push((name.clone(), "BigInt".to_string()));
self.prelude(&format!( self.prelude(&format!(
" "
@ -374,7 +373,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
self.cx.expose_uint64_cvt_shim() self.cx.expose_uint64_cvt_shim()
}; };
self.cx.expose_uint32_memory(); self.cx.expose_uint32_memory();
self.cx.expose_global_argument_ptr()?;
self.js_arguments.push((name.clone(), "BigInt".to_string())); self.js_arguments.push((name.clone(), "BigInt".to_string()));
self.prelude(&format!( self.prelude(&format!(
" "

View File

@ -459,8 +459,10 @@ impl<'a> Context<'a> {
Ok(String::from("function(idx) { throw takeObject(idx); }")) Ok(String::from("function(idx) { throw takeObject(idx); }"))
})?; })?;
closures::rewrite(self).with_context(|_| {
"failed to generate internal closure shims"
})?;
self.unexport_unused_internal_exports(); self.unexport_unused_internal_exports();
closures::rewrite(self)?;
// Handle the `start` function, if one was specified. If we're in a // Handle the `start` function, if one was specified. If we're in a
// --test mode (such as wasm-bindgen-test-runner) then we skip this // --test mode (such as wasm-bindgen-test-runner) then we skip this
@ -1682,23 +1684,6 @@ impl<'a> Context<'a> {
} }
} }
fn expose_get_global_argument(&mut self) -> Result<(), Error> {
if !self.exposed_globals.insert("get_global_argument") {
return Ok(());
}
self.expose_uint32_memory();
self.expose_global_argument_ptr()?;
self.global(
"
function getGlobalArgument(arg) {
const idx = globalArgumentPtr() / 4 + arg;
return getUint32Memory()[idx];
}
",
);
Ok(())
}
fn expose_global_argument_ptr(&mut self) -> Result<(), Error> { fn expose_global_argument_ptr(&mut self) -> Result<(), Error> {
if !self.exposed_globals.insert("global_argument_ptr") { if !self.exposed_globals.insert("global_argument_ptr") {
return Ok(()); return Ok(());
@ -2337,7 +2322,12 @@ impl<'a, 'b> SubContext<'a, 'b> {
self.generate_enum(e); self.generate_enum(e);
} }
for s in self.program.structs.iter() { for s in self.program.structs.iter() {
self.generate_struct(s)?; self.generate_struct(s).with_context(|_| {
format!(
"failed to generate bindings for Rust struct `{}`",
s.name,
)
})?;
} }
for s in self.program.typescript_custom_sections.iter() { for s in self.program.typescript_custom_sections.iter() {
self.cx.typescript.push_str(s); self.cx.typescript.push_str(s);

View File

@ -252,6 +252,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
} }
if let Some((f, mutable)) = arg.stack_closure() { if let Some((f, mutable)) = arg.stack_closure() {
let arg2 = self.shim_argument();
let (js, _ts, _js_doc) = { let (js, _ts, _js_doc) = {
let mut builder = Js2Rust::new("", self.cx); let mut builder = Js2Rust::new("", self.cx);
if mutable { if mutable {
@ -268,20 +269,19 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
.process(f)? .process(f)?
.finish("function", "this.f") .finish("function", "this.f")
}; };
self.cx.expose_get_global_argument()?;
self.cx.function_table_needed = true; self.cx.function_table_needed = true;
let next_global = self.global_idx();
self.global_idx(); self.global_idx();
self.prelude(&format!( self.prelude(&format!(
"\ "\
let cb{0} = {js};\n\ let cb{0} = {js};\n\
cb{0}.f = wasm.__wbg_function_table.get({0});\n\ cb{0}.f = wasm.__wbg_function_table.get({idx});\n\
cb{0}.a = getGlobalArgument({next_global});\n\ cb{0}.a = {0};\n\
cb{0}.b = getGlobalArgument({next_global} + 1);\n\ cb{0}.b = {1};\n\
", ",
abi, abi,
arg2,
js = js, js = js,
next_global = next_global idx = f.shim_idx,
)); ));
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", abi)); self.finally(&format!("cb{0}.a = cb{0}.b = 0;", abi));
self.js_arguments.push(format!("cb{0}.bind(cb{0})", abi)); self.js_arguments.push(format!("cb{0}.bind(cb{0})", abi));

View File

@ -353,8 +353,6 @@ impl Interpreter {
self.descriptor_table_idx = Some(self.stack.pop().unwrap() as u32); self.descriptor_table_idx = Some(self.stack.pop().unwrap() as u32);
self.stack.pop(); self.stack.pop();
self.stack.pop(); self.stack.pop();
self.stack.pop();
self.stack.pop();
self.stack.push(0); self.stack.push(0);
} else { } else {
self.call(*idx, sections); self.call(*idx, sections);

View File

@ -197,20 +197,16 @@ impl<T> Closure<T>
unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>( unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>(
a: usize, a: usize,
b: usize, b: usize,
invoke: u32,
destroy: u32,
) -> u32 { ) -> u32 {
super::__wbindgen_describe_closure( super::__wbindgen_describe_closure(
a as u32, a as u32,
b as u32, b as u32,
invoke,
destroy,
describe::<T> as u32, describe::<T> as u32,
) )
} }
let idx = unsafe { let idx = unsafe {
breaks_if_inlined::<T>(a, b, T::invoke_fn(), T::destroy_fn()) breaks_if_inlined::<T>(a, b)
}; };
Closure { Closure {
@ -294,9 +290,6 @@ impl<T> Drop for Closure<T>
#[doc(hidden)] #[doc(hidden)]
pub unsafe trait WasmClosure: 'static { pub unsafe trait WasmClosure: 'static {
fn describe(); fn describe();
fn invoke_fn() -> u32;
fn destroy_fn() -> u32;
} }
// The memory safety here in these implementations below is a bit tricky. We // The memory safety here in these implementations below is a bit tricky. We
@ -322,11 +315,6 @@ macro_rules! doit {
R: ReturnWasmAbi + 'static, R: ReturnWasmAbi + 'static,
{ {
fn describe() { fn describe() {
<&Self>::describe();
}
#[inline]
fn invoke_fn() -> u32 {
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
@ -350,12 +338,10 @@ macro_rules! doit {
}; };
ret.return_abi(&mut GlobalStack::new()) ret.return_abi(&mut GlobalStack::new())
} }
invoke::<$($var,)* R> as u32
}
#[inline] inform(invoke::<$($var,)* R> as u32);
fn destroy_fn() -> u32 {
unsafe extern "C" fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
b: usize, b: usize,
) { ) {
@ -364,7 +350,9 @@ macro_rules! doit {
fields: (a, b) fields: (a, b)
}.ptr)); }.ptr));
} }
destroy::<$($var,)* R> as u32 inform(destroy::<$($var,)* R> as u32);
<&Self>::describe();
} }
} }
@ -373,11 +361,6 @@ macro_rules! doit {
R: ReturnWasmAbi + 'static, R: ReturnWasmAbi + 'static,
{ {
fn describe() { fn describe() {
<&mut Self>::describe();
}
#[inline]
fn invoke_fn() -> u32 {
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
@ -402,12 +385,10 @@ macro_rules! doit {
}; };
ret.return_abi(&mut GlobalStack::new()) ret.return_abi(&mut GlobalStack::new())
} }
invoke::<$($var,)* R> as u32
}
#[inline] inform(invoke::<$($var,)* R> as u32);
fn destroy_fn() -> u32 {
unsafe extern "C" fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
b: usize, b: usize,
) { ) {
@ -416,7 +397,9 @@ macro_rules! doit {
fields: (a, b) fields: (a, b)
}.ptr)); }.ptr));
} }
destroy::<$($var,)* R> as u32 inform(destroy::<$($var,)* R> as u32);
<&mut Self>::describe();
} }
} }
)*) )*)

View File

@ -1,19 +1,28 @@
use core::mem; use core::mem;
use convert::{FromWasmAbi, GlobalStack, IntoWasmAbi, ReturnWasmAbi, Stack}; use convert::{FromWasmAbi, GlobalStack, IntoWasmAbi, ReturnWasmAbi, Stack};
use convert::slices::WasmSlice;
use describe::{inform, FUNCTION, WasmDescribe};
use throw_str; use throw_str;
macro_rules! stack_closures { macro_rules! stack_closures {
($( ($($var:ident)*) )*) => ($( ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident)*) )*) => ($(
impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a (Fn($($var),*) -> R + 'b) impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a (Fn($($var),*) -> R + 'b)
where $($var: FromWasmAbi,)* where $($var: FromWasmAbi,)*
R: ReturnWasmAbi R: ReturnWasmAbi
{ {
type Abi = u32; type Abi = WasmSlice;
fn into_abi(self, _extra: &mut Stack) -> WasmSlice {
unsafe {
let (a, b): (usize, usize) = mem::transmute(self);
WasmSlice { ptr: a as u32, len: b as u32 }
}
}
}
fn into_abi(self, extra: &mut Stack) -> u32 {
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
b: usize, b: usize,
$($var: <$var as FromWasmAbi>::Abi),* $($var: <$var as FromWasmAbi>::Abi),*
@ -33,12 +42,17 @@ macro_rules! stack_closures {
}; };
ret.return_abi(&mut GlobalStack::new()) ret.return_abi(&mut GlobalStack::new())
} }
unsafe {
let (a, b): (usize, usize) = mem::transmute(self); impl<'a, $($var,)* R> WasmDescribe for Fn($($var),*) -> R + 'a
extra.push(a as u32); where $($var: FromWasmAbi,)*
extra.push(b as u32); R: ReturnWasmAbi
invoke::<$($var,)* R> as u32 {
} fn describe() {
inform(FUNCTION);
inform($invoke::<$($var,)* R> as u32);
inform($cnt);
$(<$var as WasmDescribe>::describe();)*
<R as WasmDescribe>::describe();
} }
} }
@ -46,11 +60,18 @@ macro_rules! stack_closures {
where $($var: FromWasmAbi,)* where $($var: FromWasmAbi,)*
R: ReturnWasmAbi R: ReturnWasmAbi
{ {
type Abi = u32; type Abi = WasmSlice;
fn into_abi(self, _extra: &mut Stack) -> WasmSlice {
unsafe {
let (a, b): (usize, usize) = mem::transmute(self);
WasmSlice { ptr: a as u32, len: b as u32 }
}
}
}
fn into_abi(self, extra: &mut Stack) -> u32 {
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize, a: usize,
b: usize, b: usize,
$($var: <$var as FromWasmAbi>::Abi),* $($var: <$var as FromWasmAbi>::Abi),*
@ -70,24 +91,29 @@ macro_rules! stack_closures {
}; };
ret.return_abi(&mut GlobalStack::new()) ret.return_abi(&mut GlobalStack::new())
} }
unsafe {
let (a, b): (usize, usize) = mem::transmute(self); impl<'a, $($var,)* R> WasmDescribe for FnMut($($var),*) -> R + 'a
extra.push(a as u32); where $($var: FromWasmAbi,)*
extra.push(b as u32); R: ReturnWasmAbi
invoke::<$($var,)* R> as u32 {
} fn describe() {
inform(FUNCTION);
inform($invoke_mut::<$($var,)* R> as u32);
inform($cnt);
$(<$var as WasmDescribe>::describe();)*
<R as WasmDescribe>::describe();
} }
} }
)*) )*)
} }
stack_closures! { stack_closures! {
() (0 invoke0 invoke0_mut)
(A) (1 invoke1 invoke1_mut A)
(A B) (2 invoke2 invoke2_mut A B)
(A B C) (3 invoke3 invoke3_mut A B C)
(A B C D) (4 invoke4 invoke4_mut A B C D)
(A B C D E) (5 invoke5 invoke5_mut A B C D E)
(A B C D E F) (6 invoke6 invoke6_mut A B C D E F)
(A B C D E F G) (7 invoke7 invoke7_mut A B C D E F G)
} }

View File

@ -133,72 +133,6 @@ if_std! {
} }
} }
macro_rules! cnt {
() => {
0
};
(A) => {
1
};
(A B) => {
2
};
(A B C) => {
3
};
(A B C D) => {
4
};
(A B C D E) => {
5
};
(A B C D E F) => {
6
};
(A B C D E F G) => {
7
};
}
macro_rules! doit {
($( ($($var:ident)*))*) => ($(
impl<'a, $($var,)* R> WasmDescribe for Fn($($var),*) -> R + 'a
where $($var: WasmDescribe,)*
R: WasmDescribe
{
fn describe() {
inform(FUNCTION);
inform(cnt!($($var)*));
$(<$var as WasmDescribe>::describe();)*
<R as WasmDescribe>::describe();
}
}
impl<'a, $($var,)* R> WasmDescribe for FnMut($($var),*) -> R + 'a
where $($var: WasmDescribe,)*
R: WasmDescribe
{
fn describe() {
inform(FUNCTION);
inform(cnt!($($var)*));
$(<$var as WasmDescribe>::describe();)*
<R as WasmDescribe>::describe();
}
}
)*)
}
doit! {
()
(A)
(A B)
(A B C)
(A B C D)
(A B C D E)
(A B C D E F)
(A B C D E F G)
}
impl<T: WasmDescribe> WasmDescribe for Option<T> { impl<T: WasmDescribe> WasmDescribe for Option<T> {
fn describe() { fn describe() {
inform(OPTIONAL); inform(OPTIONAL);

View File

@ -483,7 +483,7 @@ externs! {
fn __wbindgen_cb_forget(idx: u32) -> (); fn __wbindgen_cb_forget(idx: u32) -> ();
fn __wbindgen_describe(v: u32) -> (); fn __wbindgen_describe(v: u32) -> ();
fn __wbindgen_describe_closure(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32; fn __wbindgen_describe_closure(a: u32, b: u32, c: u32) -> u32;
fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32; fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32;
fn __wbindgen_json_serialize(idx: u32, ptr: *mut *mut u8) -> usize; fn __wbindgen_json_serialize(idx: u32, ptr: *mut *mut u8) -> usize;