Improve link_mem_intrinsics hack

Previously the `link_mem_intrinsics` hack actually had a runtime
overhead by storing a value into a global location, but it turns out we
can actually use a non-inlined function call as part of the *descriptor*
which requires this to be in the final binary, but we'll end up snip'ing
the value at the end.

All in all this should mean that it's not a zero-overhead solution for
linking these intrinsics! The `#[wasm_bindgen]` attribute already has
other problems if the descriptors don't show up, so that's the least of
our issues!
This commit is contained in:
Alex Crichton 2018-09-24 15:39:55 -07:00
parent d10ca579e4
commit b256b98e38
3 changed files with 5 additions and 25 deletions

View File

@ -451,9 +451,6 @@ impl TryToTokens for ast::Export {
#[allow(non_snake_case)]
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub extern fn #generated_name(#(#args),*) #ret_ty {
// See definition of `link_mem_intrinsics` for what this is doing
::wasm_bindgen::__rt::link_mem_intrinsics();
// Scope all local variables to be destroyed after we call the
// function to ensure that `#convert_ret`, if it panics, doesn't
// leak anything.
@ -887,8 +884,6 @@ impl TryToTokens for ast::ImportFunction {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
#[doc = #doc_comment]
#vis fn #rust_name(#me #(#arguments),*) #ret {
// See definition of `link_mem_intrinsics` for what this is doing
::wasm_bindgen::__rt::link_mem_intrinsics();
#[link(wasm_import_module = "__wbindgen_placeholder__")]
extern {
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
@ -1256,6 +1251,8 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub extern fn #name() {
use wasm_bindgen::describe::*;
// See definition of `link_mem_intrinsics` for what this is doing
::wasm_bindgen::__rt::link_mem_intrinsics();
#inner
}
}).to_tokens(tokens);

View File

@ -15,11 +15,11 @@ Currently this code...
{{#include ../../../examples/add/src/lib.rs}}
```
generates a 723 byte wasm binary:
generates a 710 byte wasm binary:
```
$ ls -l add_bg.wasm
-rw-rw-r-- 1 alex alex 723 Sep 19 17:32 add_bg.wasm
-rw-rw-r-- 1 alex alex 710 Sep 19 17:32 add_bg.wasm
```
If you run [wasm-opt], a C++ tool for optimize WebAssembly, you can make it
@ -28,7 +28,7 @@ even smaller too!
```
$ wasm-opt -Os add_bg.wasm -o add.wasm
$ ls -l add.wasm
-rw-rw-r-- 1 alex alex 182 Sep 19 17:33 add.wasm
-rw-rw-r-- 1 alex alex 172 Sep 19 17:33 add.wasm
```
And sure enough, using the [wasm2wat] tool it's quite small!
@ -38,9 +38,6 @@ $ wasm2wat add.wasm
(module
(type (;0;) (func (param i32 i32) (result i32)))
(func (;0;) (type 0) (param i32 i32) (result i32)
i32.const 1048640
i32.const 0
i32.store
get_local 1
get_local 0
i32.add)

View File

@ -846,21 +846,7 @@ pub mod __rt {
/// above. That means if this function is called and referenced we'll pull
/// in the object file and link the intrinsics.
///
/// Note that this is an `#[inline]` function to remove the function call
/// overhead we inject in functions, but right now it's unclear how to do
/// this in a zero-cost fashion. The lowest cost seems to be generating a
/// store that can't be optimized away (to a global), which is listed below.
///
/// Ideas for how to improve this are most welcome!
#[inline]
pub fn link_mem_intrinsics() {
// the above symbols only exist with the `std` feature enabled.
if !cfg!(feature = "std") {
return
}
use core::sync::atomic::*;
static FOO: AtomicUsize = ATOMIC_USIZE_INIT;
FOO.store(0, Ordering::SeqCst);
}
}