mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-11-28 14:27:36 +03:00
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:
parent
e49e02cc88
commit
d7a05129ac
@ -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;
|
||||
|
@ -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 {
|
||||
|
50
src/lib.rs
50
src/lib.rs
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user