Skip to content

Commit 65acc3b

Browse files
committed
Tighten up codegen with JsStatic a bit
This requires some `unsafe` as we have knowledge that LLVM doesn't, but shouldn't be too harmful.
1 parent 4436c0e commit 65acc3b

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

src/lib.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,29 @@ impl<T: FromWasmAbi + 'static> Deref for JsStatic<T> {
317317
type Target = T;
318318
fn deref(&self) -> &T {
319319
unsafe {
320-
(*self.__inner.get()).get_or_insert_with(|| {
321-
(self.__init)()
322-
})
320+
// Ideally we want to use `get_or_insert_with` here but
321+
// unfortunately that has subpar codegen for now.
322+
//
323+
// If we get past the `Some` branch here LLVM statically
324+
// knows that we're `None`, but the after the call to the `__init`
325+
// function LLVM can no longer know this because `__init` could
326+
// recursively call this function again (aka if JS came back to Rust
327+
// and Rust referenced this static).
328+
//
329+
// We know, however, that cannot happen. As a result we can
330+
// conclude that even after the call to `__init` our `ptr` still
331+
// points to `None` (and a debug assertion to this effect). Then
332+
// using `ptr::write` should tell rustc to not run destuctors
333+
// (as one isn't there) and this should tighten up codegen for
334+
// `JsStatic` a bit as well.
335+
let ptr = self.__inner.get();
336+
if let Some(ref t) = *ptr {
337+
return t
338+
}
339+
let init = Some((self.__init)());
340+
debug_assert!((*ptr).is_none());
341+
ptr::write(ptr, init);
342+
(*ptr).as_ref().unwrap()
323343
}
324344
}
325345
}

0 commit comments

Comments
 (0)