Skip to content
This repository was archived by the owner on Jul 10, 2023. It is now read-only.

Commit 57031bc

Browse files
committed
Properly support Windows
We use HeapSize with GetProcessHeap() and flags 0, like Rust itself.
1 parent 7913872 commit 57031bc

File tree

2 files changed

+43
-20
lines changed

2 files changed

+43
-20
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@ description = "Infrastructure for measuring the total runtime size of an object
66
license = "MPL-2.0"
77
repository = "https://github.com/servo/heapsize"
88

9+
[dependencies]
10+
kernel32-sys = "0.2.1"
11+
912
[features]
1013
unstable = []

src/lib.rs

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
//! Data structure measurement.
66
7+
#[cfg(target_os = "windows")]
8+
extern crate kernel32;
9+
10+
#[cfg(target_os = "windows")]
11+
use kernel32::{GetProcessHeap, HeapSize, HeapValidate};
712
use std::borrow::Cow;
813
use std::cell::{Cell, RefCell};
914
use std::collections::{BTreeMap, HashMap, LinkedList, VecDeque};
@@ -18,38 +23,53 @@ use std::sync::Arc;
1823
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
1924
use std::rc::Rc;
2025

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.
3629
///
3730
/// `unsafe` because the caller must ensure that the pointer is from jemalloc.
3831
/// FIXME: This probably interacts badly with custom allocators:
3932
/// https://doc.rust-lang.org/book/custom-allocators.html
40-
#[cfg(not(target_os = "windows"))]
4133
pub unsafe fn heap_size_of(ptr: *const c_void) -> usize {
4234
if ptr == 0x01 as *const c_void {
4335
0
4436
} else {
45-
je_malloc_usable_size(ptr)
37+
heap_size_of_impl(ptr)
4638
}
4739
}
4840

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+
5053
#[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
5373
}
5474

5575
// The simplest trait for measuring the size of heap data structures. More complex traits that

0 commit comments

Comments
 (0)