From a729a404945de10f99e2530a5c28952996532b29 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 21 Jan 2015 00:46:02 +1300 Subject: [PATCH 1/3] Use assume to inform the optimiser about refcount invariants The reference count can never be 0, unless we're about to drop the data completely. Using the `assume` intrinsic allows us to inform LLVM about that invariant, meaning it can avoid unnecessary drops. --- src/liballoc/rc.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 7191a7af346b0..0f2a11cc1dbac 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -160,6 +160,7 @@ use core::option::Option::{Some, None}; use core::ptr::{self, PtrExt}; use core::result::Result; use core::result::Result::{Ok, Err}; +use core::intrinsics::assume; use heap::deallocate; @@ -905,10 +906,20 @@ trait RcBoxPtr { fn strong(&self) -> uint { self.inner().strong.get() } #[inline] - fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + fn inc_strong(&self) { + let strong = self.strong(); + // The reference count is always at least one unless we're about to drop the type + unsafe { assume(strong > 0); } + self.inner().strong.set(strong + 1); + } #[inline] - fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } + fn dec_strong(&self) { + let strong = self.strong(); + // The reference count is always at least one unless we're about to drop the type + unsafe { assume(strong > 0); } + self.inner().strong.set(strong - 1); + } #[inline] fn weak(&self) -> uint { self.inner().weak.get() } From 9bbfd681c9fa47f462a89e8f5eedd3fa2a5de2e7 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 21 Jan 2015 09:35:24 +1300 Subject: [PATCH 2/3] Add assumptions that the pointer is non-null --- src/liballoc/rc.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 0f2a11cc1dbac..837d709e88209 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -933,12 +933,26 @@ trait RcBoxPtr { impl RcBoxPtr for Rc { #[inline(always)] - fn inner(&self) -> &RcBox { unsafe { &(**self._ptr) } } + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway + assume(!self._ptr.is_null()); + &(**self._ptr) + } + } } impl RcBoxPtr for Weak { #[inline(always)] - fn inner(&self) -> &RcBox { unsafe { &(**self._ptr) } } + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway + assume(!self._ptr.is_null()); + &(**self._ptr) + } + } } #[cfg(test)] From a7525bc4c8eb8507a5c248d29286e77133217cf3 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 21 Jan 2015 09:56:59 +1300 Subject: [PATCH 3/3] Add more explanation for why the assumes are there --- src/liballoc/rc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 837d709e88209..e651e375e3d5c 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -909,6 +909,8 @@ trait RcBoxPtr { fn inc_strong(&self) { let strong = self.strong(); // The reference count is always at least one unless we're about to drop the type + // This allows the bulk of the destructor to be omitted in cases where we know that + // the reference count must be > 0. unsafe { assume(strong > 0); } self.inner().strong.set(strong + 1); } @@ -917,6 +919,8 @@ trait RcBoxPtr { fn dec_strong(&self) { let strong = self.strong(); // The reference count is always at least one unless we're about to drop the type + // This allows the bulk of the destructor to be omitted in cases where we know that + // the reference count must be > 0 unsafe { assume(strong > 0); } self.inner().strong.set(strong - 1); } @@ -936,7 +940,9 @@ impl RcBoxPtr for Rc { fn inner(&self) -> &RcBox { unsafe { // Safe to assume this here, as if it weren't true, we'd be breaking - // the contract anyway + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. assume(!self._ptr.is_null()); &(**self._ptr) } @@ -949,6 +955,8 @@ impl RcBoxPtr for Weak { unsafe { // Safe to assume this here, as if it weren't true, we'd be breaking // the contract anyway + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. assume(!self._ptr.is_null()); &(**self._ptr) }