From 6a088b6804d76e51359977101fa27c26ad1a58ac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 13 Sep 2017 16:06:55 +1000 Subject: [PATCH] Support MallocSizeOf for [T] and Box<[T]>. This requires tweaking things a bit to handle dynamically-sized types. --- components/malloc_size_of/lib.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index 7cb04b6e634..5ecd29d794a 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -103,13 +103,20 @@ impl MallocSizeOfOps { /// Check if an allocation is empty. This relies on knowledge of how Rust /// handles empty allocations, which may change in the future. - fn is_empty(ptr: *const T) -> bool { - return ptr as usize <= ::std::mem::align_of::(); + fn is_empty(ptr: *const T) -> bool { + // The correct condition is this: + // `ptr as usize <= ::std::mem::align_of::()` + // But we can't call align_of() on a ?Sized T. So we approximate it + // with the following. 256 is large enough that it should always be + // larger than the required alignment, but small enough that it is + // always in the first page of memory and therefore not a legitimate + // address. + return ptr as *const usize as usize <= 256 } /// Call `size_of_op` on `ptr`, first checking that the allocation isn't /// empty, because some types (such as `Vec`) utilize empty allocations. - pub unsafe fn malloc_size_of(&self, ptr: *const T) -> usize { + pub unsafe fn malloc_size_of(&self, ptr: *const T) -> usize { if MallocSizeOfOps::is_empty(ptr) { 0 } else { @@ -179,13 +186,13 @@ pub trait MallocConditionalShallowSizeOf { fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize; } -impl MallocShallowSizeOf for Box { +impl MallocShallowSizeOf for Box { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { unsafe { ops.malloc_size_of(&**self) } } } -impl MallocSizeOf for Box { +impl MallocSizeOf for Box { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { self.shallow_size_of(ops) + (**self).size_of(ops) } @@ -207,6 +214,16 @@ impl MallocSizeOf for Option { } } +impl MallocSizeOf for [T] { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = 0; + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + impl MallocShallowSizeOf for Vec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { unsafe { ops.malloc_size_of(self.as_ptr()) }