4
4
5
5
//! Data structure measurement.
6
6
7
+ #[ cfg( target_os = "windows" ) ]
8
+ extern crate kernel32;
9
+
10
+ #[ cfg( target_os = "windows" ) ]
11
+ use kernel32:: { GetProcessHeap , HeapSize , HeapValidate } ;
7
12
use std:: borrow:: Cow ;
8
13
use std:: cell:: { Cell , RefCell } ;
9
14
use std:: collections:: { BTreeMap , HashMap , LinkedList , VecDeque } ;
@@ -18,38 +23,53 @@ use std::sync::Arc;
18
23
use std:: sync:: atomic:: { AtomicBool , AtomicIsize , AtomicUsize } ;
19
24
use std:: rc:: Rc ;
20
25
21
- #[ cfg( not( target_os = "windows" ) ) ]
22
- extern {
23
- // Get the size of a heap block.
24
- //
25
- // Ideally Rust would expose a function like this in std::rt::heap, which would avoid the
26
- // jemalloc dependence.
27
- //
28
- // The C prototype is `je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)`. On some
29
- // platforms `JEMALLOC_USABLE_SIZE_CONST` is `const` and on some it is empty. But in practice
30
- // this function doesn't modify the contents of the block that `ptr` points to, so we use
31
- // `*const c_void` here.
32
- fn je_malloc_usable_size ( ptr : * const c_void ) -> usize ;
33
- }
34
-
35
- /// A wrapper for je_malloc_usable_size that handles `EMPTY` and returns `usize`.
26
+ /// Get the size of a heap block.
27
+ ///
28
+ /// Ideally Rust would expose a function like this in std::rt::heap.
36
29
///
37
30
/// `unsafe` because the caller must ensure that the pointer is from jemalloc.
38
31
/// FIXME: This probably interacts badly with custom allocators:
39
32
/// https://doc.rust-lang.org/book/custom-allocators.html
40
- #[ cfg( not( target_os = "windows" ) ) ]
41
33
pub unsafe fn heap_size_of ( ptr : * const c_void ) -> usize {
42
34
if ptr == 0x01 as * const c_void {
43
35
0
44
36
} else {
45
- je_malloc_usable_size ( ptr)
37
+ heap_size_of_impl ( ptr)
46
38
}
47
39
}
48
40
49
- /// FIXME: Need to implement heap size support on Windows.
41
+ #[ cfg( not( target_os = "windows" ) ) ]
42
+ unsafe fn heap_size_of_impl ( ptr : * const c_void ) -> usize {
43
+ // The C prototype is `je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)`. On some
44
+ // platforms `JEMALLOC_USABLE_SIZE_CONST` is `const` and on some it is empty. But in practice
45
+ // this function doesn't modify the contents of the block that `ptr` points to, so we use
46
+ // `*const c_void` here.
47
+ extern "C" {
48
+ fn je_malloc_usable_size ( ptr : * const c_void ) -> usize ;
49
+ }
50
+ je_malloc_usable_size ( ptr)
51
+ }
52
+
50
53
#[ cfg( target_os = "windows" ) ]
51
- pub unsafe fn heap_size_of ( ptr : * const c_void ) -> usize {
52
- 0
54
+ pub unsafe fn heap_size_of_impl ( mut ptr : * const c_void ) -> usize {
55
+ // Copied from Rust's liballoc_system.
56
+ #[ cfg( all( any( target_arch = "x86" ,
57
+ target_arch = "arm" ,
58
+ target_arch = "mips" ,
59
+ target_arch = "mipsel" ,
60
+ target_arch = "powerpc" ) ) ) ]
61
+ const MIN_ALIGN : usize = 8 ;
62
+ #[ cfg( all( any( target_arch = "x86_64" ,
63
+ target_arch = "aarch64" ) ) ) ]
64
+ const MIN_ALIGN : usize = 16 ;
65
+
66
+ let heap = GetProcessHeap ( ) ;
67
+
68
+ if HeapValidate ( heap, 0 , ptr) == 0 {
69
+ ptr = * ( ptr as * const * const c_void ) . offset ( -1 ) ;
70
+ }
71
+
72
+ HeapSize ( heap, 0 , ptr) as usize
53
73
}
54
74
55
75
// The simplest trait for measuring the size of heap data structures. More complex traits that
0 commit comments