Skip to content

Commit e03e404

Browse files
authored
Merge pull request #955 from alexcrichton/non-send
Ensure that `JsValue` isn't considered `Send`
2 parents 41d3a08 + e46537e commit e03e404

File tree

4 files changed

+46
-56
lines changed

4 files changed

+46
-56
lines changed

crates/backend/src/codegen.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,11 +1042,9 @@ impl ToTokens for ast::ImportStatic {
10421042
fn init() -> #ty {
10431043
panic!("cannot access imported statics on non-wasm targets")
10441044
}
1045-
static mut _VAL: ::wasm_bindgen::__rt::core::cell::UnsafeCell<Option<#ty>> =
1046-
::wasm_bindgen::__rt::core::cell::UnsafeCell::new(None);
1045+
thread_local!(static _VAL: #ty = init(););
10471046
::wasm_bindgen::JsStatic {
1048-
__inner: unsafe { &_VAL },
1049-
__init: init,
1047+
__inner: &_VAL,
10501048
}
10511049
};
10521050
}).to_tokens(into);

src/closure.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ impl<T> Closure<T>
214214
};
215215

216216
Closure {
217-
js: ManuallyDrop::new(JsValue { idx }),
217+
js: ManuallyDrop::new(JsValue::_new(idx)),
218218
data: ManuallyDrop::new(data),
219219
}
220220
}

src/convert/impls.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ impl FromWasmAbi for JsValue {
337337

338338
#[inline]
339339
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> JsValue {
340-
JsValue { idx: js }
340+
JsValue::_new(js)
341341
}
342342
}
343343

@@ -356,7 +356,7 @@ impl RefFromWasmAbi for JsValue {
356356

357357
#[inline]
358358
unsafe fn ref_from_abi(js: u32, _extra: &mut Stack) -> Self::Anchor {
359-
ManuallyDrop::new(JsValue { idx: js })
359+
ManuallyDrop::new(JsValue::_new(js))
360360
}
361361
}
362362

src/lib.rs

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ extern crate serde_json;
1616

1717
extern crate wasm_bindgen_macro;
1818

19-
use core::cell::UnsafeCell;
2019
use core::fmt;
20+
use core::marker;
2121
use core::mem;
2222
use core::ops::{Deref, DerefMut};
2323
use core::ptr;
@@ -64,6 +64,7 @@ if_std! {
6464
/// but for now it may be slightly slow.
6565
pub struct JsValue {
6666
idx: u32,
67+
_marker: marker::PhantomData<*mut u8>, // not at all threadsafe
6768
}
6869

6970
const JSIDX_UNDEFINED: u32 = 0;
@@ -74,18 +75,36 @@ const JSIDX_RESERVED: u32 = 8;
7475

7576
impl JsValue {
7677
/// The `null` JS value constant.
77-
pub const NULL: JsValue = JsValue { idx: JSIDX_NULL };
78+
pub const NULL: JsValue = JsValue {
79+
idx: JSIDX_NULL,
80+
_marker: marker::PhantomData,
81+
};
7882

7983
/// The `undefined` JS value constant.
8084
pub const UNDEFINED: JsValue = JsValue {
8185
idx: JSIDX_UNDEFINED,
86+
_marker: marker::PhantomData,
8287
};
8388

89+
8490
/// The `true` JS value constant.
85-
pub const TRUE: JsValue = JsValue { idx: JSIDX_TRUE };
91+
pub const TRUE: JsValue = JsValue {
92+
idx: JSIDX_TRUE,
93+
_marker: marker::PhantomData,
94+
};
8695

8796
/// The `false` JS value constant.
88-
pub const FALSE: JsValue = JsValue { idx: JSIDX_FALSE };
97+
pub const FALSE: JsValue = JsValue {
98+
idx: JSIDX_FALSE,
99+
_marker: marker::PhantomData,
100+
};
101+
102+
fn _new(idx: u32) -> JsValue {
103+
JsValue {
104+
idx,
105+
_marker: marker::PhantomData,
106+
}
107+
}
89108

90109
/// Creates a new JS value which is a string.
91110
///
@@ -94,9 +113,7 @@ impl JsValue {
94113
#[inline]
95114
pub fn from_str(s: &str) -> JsValue {
96115
unsafe {
97-
JsValue {
98-
idx: __wbindgen_string_new(s.as_ptr(), s.len()),
99-
}
116+
JsValue::_new(__wbindgen_string_new(s.as_ptr(), s.len()))
100117
}
101118
}
102119

@@ -107,9 +124,7 @@ impl JsValue {
107124
#[inline]
108125
pub fn from_f64(n: f64) -> JsValue {
109126
unsafe {
110-
JsValue {
111-
idx: __wbindgen_number_new(n),
112-
}
127+
JsValue::_new(__wbindgen_number_new(n))
113128
}
114129
}
115130

@@ -142,9 +157,7 @@ impl JsValue {
142157
unsafe {
143158
let ptr = description.map(|s| s.as_ptr()).unwrap_or(ptr::null());
144159
let len = description.map(|s| s.len()).unwrap_or(0);
145-
JsValue {
146-
idx: __wbindgen_symbol_new(ptr, len),
147-
}
160+
JsValue::_new(__wbindgen_symbol_new(ptr, len))
148161
}
149162
}
150163

@@ -170,9 +183,7 @@ impl JsValue {
170183
{
171184
let s = serde_json::to_string(t)?;
172185
unsafe {
173-
Ok(JsValue {
174-
idx: __wbindgen_json_parse(s.as_ptr(), s.len()),
175-
})
186+
Ok(JsValue::_new(__wbindgen_json_parse(s.as_ptr(), s.len())))
176187
}
177188
}
178189

@@ -486,7 +497,7 @@ impl Clone for JsValue {
486497
fn clone(&self) -> JsValue {
487498
unsafe {
488499
let idx = __wbindgen_object_clone_ref(self.idx);
489-
JsValue { idx }
500+
JsValue::_new(idx)
490501
}
491502
}
492503
}
@@ -552,43 +563,26 @@ impl Drop for JsValue {
552563
///
553564
/// This type implements `Deref` to the inner type so it's typically used as if
554565
/// it were `&T`.
566+
#[cfg(feature = "std")]
555567
pub struct JsStatic<T: 'static> {
556568
#[doc(hidden)]
557-
pub __inner: &'static UnsafeCell<Option<T>>,
558-
#[doc(hidden)]
559-
pub __init: fn() -> T,
569+
pub __inner: &'static std::thread::LocalKey<T>,
560570
}
561571

562-
unsafe impl<T: Sync> Sync for JsStatic<T> {}
563-
unsafe impl<T: Send> Send for JsStatic<T> {}
564-
572+
#[cfg(feature = "std")]
565573
impl<T: FromWasmAbi + 'static> Deref for JsStatic<T> {
566574
type Target = T;
567575
fn deref(&self) -> &T {
576+
// We know that our tls key is never overwritten after initialization,
577+
// so it should be safe (on that axis at least) to hand out a reference
578+
// that lives longer than the closure below.
579+
//
580+
// FIXME: this is not sound if we ever implement thread exit hooks on
581+
// wasm, as the pointer will eventually be invalidated but you can get
582+
// `&'static T` from this interface. We... probably need to deprecate
583+
// and/or remove this interface nowadays.
568584
unsafe {
569-
// Ideally we want to use `get_or_insert_with` here but
570-
// unfortunately that has subpar codegen for now.
571-
//
572-
// If we get past the `Some` branch here LLVM statically
573-
// knows that we're `None`, but the after the call to the `__init`
574-
// function LLVM can no longer know this because `__init` could
575-
// recursively call this function again (aka if JS came back to Rust
576-
// and Rust referenced this static).
577-
//
578-
// We know, however, that cannot happen. As a result we can
579-
// conclude that even after the call to `__init` our `ptr` still
580-
// points to `None` (and a debug assertion to this effect). Then
581-
// using `ptr::write` should tell rustc to not run destuctors
582-
// (as one isn't there) and this should tighten up codegen for
583-
// `JsStatic` a bit as well.
584-
let ptr = self.__inner.get();
585-
if let Some(ref t) = *ptr {
586-
return t;
587-
}
588-
let init = Some((self.__init)());
589-
debug_assert!((*ptr).is_none());
590-
ptr::write(ptr, init);
591-
(*ptr).as_ref().unwrap()
585+
self.__inner.with(|ptr| &*(ptr as *const T))
592586
}
593587
}
594588
}
@@ -642,9 +636,7 @@ pub fn throw_val(s: JsValue) -> ! {
642636
/// Returns a handle to this wasm instance's `WebAssembly.Memory`
643637
pub fn memory() -> JsValue {
644638
unsafe {
645-
JsValue {
646-
idx: __wbindgen_memory(),
647-
}
639+
JsValue::_new(__wbindgen_memory())
648640
}
649641
}
650642

0 commit comments

Comments
 (0)