From 65acc3b69246613ee1d62bb7bfa3a4902cd6fc33 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 21 Apr 2018 13:52:28 -0700 Subject: [PATCH] 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. --- src/lib.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb3321cc..6ed4e9a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -317,9 +317,29 @@ impl Deref for JsStatic { type Target = T; fn deref(&self) -> &T { unsafe { - (*self.__inner.get()).get_or_insert_with(|| { - (self.__init)() - }) + // Ideally we want to use `get_or_insert_with` here but + // unfortunately that has subpar codegen for now. + // + // If we get past the `Some` branch here LLVM statically + // knows that we're `None`, but the after the call to the `__init` + // function LLVM can no longer know this because `__init` could + // recursively call this function again (aka if JS came back to Rust + // and Rust referenced this static). + // + // We know, however, that cannot happen. As a result we can + // conclude that even after the call to `__init` our `ptr` still + // points to `None` (and a debug assertion to this effect). Then + // using `ptr::write` should tell rustc to not run destuctors + // (as one isn't there) and this should tighten up codegen for + // `JsStatic` a bit as well. + let ptr = self.__inner.get(); + if let Some(ref t) = *ptr { + return t + } + let init = Some((self.__init)()); + debug_assert!((*ptr).is_none()); + ptr::write(ptr, init); + (*ptr).as_ref().unwrap() } } }