diff --git a/src/gc-arena-derive/src/lib.rs b/src/gc-arena-derive/src/lib.rs index c91494c2..1e02fd22 100644 --- a/src/gc-arena-derive/src/lib.rs +++ b/src/gc-arena-derive/src/lib.rs @@ -162,7 +162,8 @@ fn collect_derive(mut s: synstructure::Structure) -> TokenStream { let ty = &b.ast().ty; quote_spanned!(b.ast().span()=> || <#ty as gc_arena::Collect>::needs_trace() - ).to_tokens(&mut needs_trace_body); + ) + .to_tokens(&mut needs_trace_body); } } // Likewise, this will skip any fields that have `#[collect(require_static)]` diff --git a/src/gc-arena/src/collect_impl.rs b/src/gc-arena/src/collect_impl.rs index 3e1da6d3..349bbe2e 100644 --- a/src/gc-arena/src/collect_impl.rs +++ b/src/gc-arena/src/collect_impl.rs @@ -1,14 +1,14 @@ use alloc::boxed::Box; +use alloc::collections::VecDeque; use alloc::collections::{BTreeMap, BTreeSet}; use alloc::rc::Rc; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; -use alloc::collections::VecDeque; use core::cell::{Cell, RefCell}; -use core::marker::PhantomData; #[cfg(feature = "std")] use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; #[cfg(feature = "std")] use std::collections::{HashMap, HashSet}; @@ -271,8 +271,7 @@ where } // SAFETY: `PhantomData` is a ZST, and therefore doesn't store anything -unsafe impl Collect for PhantomData -{ +unsafe impl Collect for PhantomData { #[inline] fn needs_trace() -> bool { false diff --git a/src/gc-arena/src/context.rs b/src/gc-arena/src/context.rs index 3a3d9505..419c2ecb 100644 --- a/src/gc-arena/src/context.rs +++ b/src/gc-arena/src/context.rs @@ -264,13 +264,20 @@ impl Context { ); } - let gc_box = GcBox { - flags: GcFlags::new(), - next: Cell::new(self.all.get()), - value: UnsafeCell::new(t), - }; - gc_box.flags.set_needs_trace(T::needs_trace()); - let ptr = NonNull::new_unchecked(Box::into_raw(Box::new(gc_box))); + let flags = GcFlags::new(); + flags.set_needs_trace(T::needs_trace()); + + let mut uninitialized = Box::new(mem::MaybeUninit::>::uninit()); + + core::ptr::write(&mut (*uninitialized.as_mut_ptr()).flags, flags); + core::ptr::write( + &mut (*uninitialized.as_mut_ptr()).next, + Cell::new(self.all.get()), + ); + core::ptr::write(&mut (*uninitialized.as_mut_ptr()).value, UnsafeCell::new(t)); + + let ptr = NonNull::new_unchecked(Box::into_raw(uninitialized) as *mut GcBox); + self.all.set(Some(static_gc_box(ptr))); if self.phase.get() == Phase::Sweep && self.sweep_prev.get().is_none() { self.sweep_prev.set(self.all.get()); @@ -317,6 +324,7 @@ enum Phase { Sleep, } +#[inline] unsafe fn static_gc_box<'gc>( ptr: NonNull>, ) -> NonNull> { diff --git a/src/gc-arena/src/types.rs b/src/gc-arena/src/types.rs index 1ccf2906..c8157ff1 100644 --- a/src/gc-arena/src/types.rs +++ b/src/gc-arena/src/types.rs @@ -20,10 +20,12 @@ pub(crate) struct GcBox { pub(crate) struct GcFlags(Cell); impl GcFlags { + #[inline] pub(crate) fn new() -> GcFlags { GcFlags(Cell::new(0)) } + #[inline] pub(crate) fn color(&self) -> GcColor { match self.0.get() & 0x3 { 0x0 => GcColor::White, @@ -33,6 +35,7 @@ impl GcFlags { } } + #[inline] pub(crate) fn set_color(&self, color: GcColor) { self.0.set( (self.0.get() & !0x3) @@ -44,10 +47,12 @@ impl GcFlags { ) } + #[inline] pub(crate) fn needs_trace(&self) -> bool { self.0.get() & 0x4 != 0x0 } + #[inline] pub(crate) fn set_needs_trace(&self, needs_trace: bool) { self.0 .set((self.0.get() & !0x4) | if needs_trace { 0x4 } else { 0x0 });