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,54 @@ 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, which would avoid the
29
+ /// jemalloc dependence.
36
30
///
37
31
/// `unsafe` because the caller must ensure that the pointer is from jemalloc.
38
32
/// FIXME: This probably interacts badly with custom allocators:
39
33
/// https://doc.rust-lang.org/book/custom-allocators.html
40
- #[ cfg( not( target_os = "windows" ) ) ]
41
34
pub unsafe fn heap_size_of ( ptr : * const c_void ) -> usize {
42
35
if ptr == 0x01 as * const c_void {
43
36
0
44
37
} else {
45
- je_malloc_usable_size ( ptr)
38
+ heap_size_of_impl ( ptr)
46
39
}
47
40
}
48
41
49
- /// FIXME: Need to implement heap size support on Windows.
42
+ #[ cfg( not( target_os = "windows" ) ) ]
43
+ unsafe fn heap_size_of_impl ( ptr : * const c_void ) -> usize {
44
+ // The C prototype is `je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)`. On some
45
+ // platforms `JEMALLOC_USABLE_SIZE_CONST` is `const` and on some it is empty. But in practice
46
+ // this function doesn't modify the contents of the block that `ptr` points to, so we use
47
+ // `*const c_void` here.
48
+ extern "C" {
49
+ fn je_malloc_usable_size ( ptr : * const c_void ) -> usize ;
50
+ }
51
+ je_malloc_usable_size ( ptr)
52
+ }
53
+
50
54
#[ cfg( target_os = "windows" ) ]
51
- pub unsafe fn heap_size_of ( ptr : * const c_void ) -> usize {
52
- 0
55
+ pub unsafe fn heap_size_of_impl ( mut ptr : * const c_void ) -> usize {
56
+ // Copied from Rust's liballoc_system.
57
+ #[ cfg( all( any( target_arch = "x86" ,
58
+ target_arch = "arm" ,
59
+ target_arch = "mips" ,
60
+ target_arch = "mipsel" ,
61
+ target_arch = "powerpc" ) ) ) ]
62
+ const MIN_ALIGN : usize = 8 ;
63
+ #[ cfg( all( any( target_arch = "x86_64" ,
64
+ target_arch = "aarch64" ) ) ) ]
65
+ const MIN_ALIGN : usize = 16 ;
66
+
67
+ let heap = GetProcessHeap ( ) ;
68
+
69
+ if ptr as usize % ( MIN_ALIGN * 2 ) != 0 && HeapValidate ( heap, 0 , ptr) == 0 {
70
+ ptr = * ( ptr as * const * const c_void ) . offset ( -1 ) ;
71
+ }
72
+
73
+ HeapSize ( heap, 0 , ptr) as usize
53
74
}
54
75
55
76
// The simplest trait for measuring the size of heap data structures. More complex traits that
0 commit comments