Skip to content

Commit 229243c

Browse files
committedJan 21, 2015
rollup merge of rust-lang#21418: Aatch/assume-refcount
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. --- Before and after IR: https://gist.github.com/Aatch/3786d20df2edaad6a0e8 Generated from the example in rust-lang#13018 Fixes rust-lang#13018
2 parents a6780d8 + a7525bc commit 229243c

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed
 

‎src/liballoc/rc.rs

+37-4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ use core::option::Option::{Some, None};
160160
use core::ptr::{self, PtrExt};
161161
use core::result::Result;
162162
use core::result::Result::{Ok, Err};
163+
use core::intrinsics::assume;
163164

164165
use heap::deallocate;
165166

@@ -905,10 +906,24 @@ trait RcBoxPtr<T> {
905906
fn strong(&self) -> uint { self.inner().strong.get() }
906907

907908
#[inline]
908-
fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }
909+
fn inc_strong(&self) {
910+
let strong = self.strong();
911+
// The reference count is always at least one unless we're about to drop the type
912+
// This allows the bulk of the destructor to be omitted in cases where we know that
913+
// the reference count must be > 0.
914+
unsafe { assume(strong > 0); }
915+
self.inner().strong.set(strong + 1);
916+
}
909917

910918
#[inline]
911-
fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
919+
fn dec_strong(&self) {
920+
let strong = self.strong();
921+
// The reference count is always at least one unless we're about to drop the type
922+
// This allows the bulk of the destructor to be omitted in cases where we know that
923+
// the reference count must be > 0
924+
unsafe { assume(strong > 0); }
925+
self.inner().strong.set(strong - 1);
926+
}
912927

913928
#[inline]
914929
fn weak(&self) -> uint { self.inner().weak.get() }
@@ -922,12 +937,30 @@ trait RcBoxPtr<T> {
922937

923938
impl<T> RcBoxPtr<T> for Rc<T> {
924939
#[inline(always)]
925-
fn inner(&self) -> &RcBox<T> { unsafe { &(**self._ptr) } }
940+
fn inner(&self) -> &RcBox<T> {
941+
unsafe {
942+
// Safe to assume this here, as if it weren't true, we'd be breaking
943+
// the contract anyway.
944+
// This allows the null check to be elided in the destructor if we
945+
// manipulated the reference count in the same function.
946+
assume(!self._ptr.is_null());
947+
&(**self._ptr)
948+
}
949+
}
926950
}
927951

928952
impl<T> RcBoxPtr<T> for Weak<T> {
929953
#[inline(always)]
930-
fn inner(&self) -> &RcBox<T> { unsafe { &(**self._ptr) } }
954+
fn inner(&self) -> &RcBox<T> {
955+
unsafe {
956+
// Safe to assume this here, as if it weren't true, we'd be breaking
957+
// the contract anyway
958+
// This allows the null check to be elided in the destructor if we
959+
// manipulated the reference count in the same function.
960+
assume(!self._ptr.is_null());
961+
&(**self._ptr)
962+
}
963+
}
931964
}
932965

933966
#[cfg(test)]

0 commit comments

Comments
 (0)