Improve documentation around link_this_library (#471)

I've started noticing this in non-LTO builds and initially tried to remove it. I
was unsuccessful but decided to better document my adventures to hopefully
improve future onlookers!
This commit is contained in:
Alex Crichton 2018-07-14 11:04:47 -05:00 committed by GitHub
parent e49e02cc88
commit d7a05129ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 6 deletions

View File

@ -452,7 +452,8 @@ impl ToTokens for ast::Export {
#[allow(non_snake_case)]
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub extern fn #generated_name(#(#args),*) #ret_ty {
::wasm_bindgen::__rt::link_this_library();
// See definition of `link_mem_intrinsics` for what this is doing
::wasm_bindgen::__rt::link_mem_intrinsics();
let #ret = {
let mut __stack = unsafe {
::wasm_bindgen::convert::GlobalStack::new()
@ -794,7 +795,8 @@ impl ToTokens for ast::ImportFunction {
#[allow(bad_style)]
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
#vis fn #rust_name(#me #(#arguments),*) #ret {
::wasm_bindgen::__rt::link_this_library();
// See definition of `link_mem_intrinsics` for what this is doing
::wasm_bindgen::__rt::link_mem_intrinsics();
#[wasm_import_module = "__wbindgen_placeholder__"]
extern {
fn #import_name(#(#abi_arguments),*) -> #abi_ret;

View File

@ -447,7 +447,13 @@ pub struct GlobalStack {
}
const GLOBAL_STACK_CAP: usize = 16;
static mut GLOBAL_STACK: [u32; GLOBAL_STACK_CAP] = [0; GLOBAL_STACK_CAP];
// Increase the alignment to 8 here because this can be used as a
// BigUint64Array pointer base which requires alignment 8
#[repr(align(8))]
struct GlobalData([u32; GLOBAL_STACK_CAP]);
static mut GLOBAL_STACK: GlobalData = GlobalData([0; GLOBAL_STACK_CAP]);
impl GlobalStack {
#[inline]
@ -461,7 +467,7 @@ impl Stack for GlobalStack {
fn push(&mut self, val: u32) {
unsafe {
assert!(self.next < GLOBAL_STACK_CAP);
GLOBAL_STACK[self.next] = val;
GLOBAL_STACK.0[self.next] = val;
self.next += 1;
}
}
@ -470,7 +476,7 @@ impl Stack for GlobalStack {
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __wbindgen_global_argument_ptr() -> *mut u32 {
GLOBAL_STACK.as_mut_ptr()
GLOBAL_STACK.0.as_mut_ptr()
}
macro_rules! stack_closures {

View File

@ -687,5 +687,53 @@ pub mod __rt {
}
}
pub fn link_this_library() {}
/// This is a curious function necessary to get wasm-bindgen working today,
/// and it's a bit of an unfortunate hack.
///
/// The general problem is that somehow we need the above two symbols to
/// exist in the final output binary (__wbindgen_malloc and
/// __wbindgen_free). These symbols may be called by JS for various
/// bindings, so we for sure need to make sure they're exported.
///
/// The problem arises, though, when what if no Rust code uses the symbols?
/// For all intents and purposes it looks to LLVM and the linker like the
/// above two symbols are dead code, so they're completely discarded!
///
/// Specifically what happens is this:
///
/// * The above two symbols are generated into some object file inside of
/// libwasm_bindgen.rlib
/// * The linker, LLD, will not load this object file unless *some* symbol
/// is loaded from the object. In this case, if the Rust code never calls
/// __wbindgen_malloc or __wbindgen_free then the symbols never get linked
/// in.
/// * Later when `wasm-bindgen` attempts to use the symbols they don't
/// exist, causing an error.
///
/// This function is a weird hack for this problem. We inject a call to this
/// function in all generated code. Usage of this function should then
/// ensure that the above two intrinsics are translated.
///
/// Due to how rustc creates object files this function (and anything inside
/// it) will be placed into the same object file as the two intrinsics
/// 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);
}
}