@@ -6,6 +6,7 @@ use crate::ptr;
66use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
77use crate :: sys:: c;
88use crate :: sys:: common:: alloc:: { realloc_fallback, MIN_ALIGN } ;
9+ use core:: mem:: MaybeUninit ;
910
1011#[ cfg( test) ]
1112mod tests;
@@ -94,29 +95,30 @@ static HEAP: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
9495// a non-null handle returned by `GetProcessHeap`.
9596#[ inline]
9697fn init_or_get_process_heap ( ) -> c:: HANDLE {
97- let heap = HEAP . load ( Ordering :: Relaxed ) ;
98- if core:: intrinsics:: unlikely ( heap. is_null ( ) ) {
99- // `HEAP` has not yet been successfully initialized
100- let heap = unsafe { GetProcessHeap ( ) } ;
101- if !heap. is_null ( ) {
102- // SAFETY: No locking is needed because within the same process,
103- // successful calls to `GetProcessHeap` will always return the same value, even on different threads.
104- HEAP . store ( heap, Ordering :: Release ) ;
105-
106- // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap`
107- heap
108- } else {
109- // Could not get the current process heap.
110- ptr:: null_mut ( )
111- }
112- } else {
98+ // `HEAP` has not yet been successfully initialized
99+ let heap = unsafe { GetProcessHeap ( ) } ;
100+ if !heap. is_null ( ) {
101+ // SAFETY: No locking is needed because within the same process,
102+ // successful calls to `GetProcessHeap` will always return the same value, even on different threads.
103+ HEAP . store ( heap, Ordering :: Release ) ;
104+
113105 // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap`
114106 heap
107+ } else {
108+ // Could not get the current process heap.
109+ ptr:: null_mut ( )
115110 }
116111}
117112
113+ /// This is outlined from `process_heap_alloc` so that `process_heap_alloc`
114+ /// does not need any stack allocations.
118115#[ inline( never) ]
119- fn process_heap_alloc ( flags : c:: DWORD , dwBytes : c:: SIZE_T ) -> c:: LPVOID {
116+ #[ cold]
117+ extern "C" fn process_heap_init_and_alloc (
118+ _heap : MaybeUninit < c:: HANDLE > , // We pass this argument to match the ABI of `HeapAlloc`
119+ flags : c:: DWORD ,
120+ dwBytes : c:: SIZE_T ,
121+ ) -> c:: LPVOID {
120122 let heap = init_or_get_process_heap ( ) ;
121123 if core:: intrinsics:: unlikely ( heap. is_null ( ) ) {
122124 return ptr:: null_mut ( ) ;
@@ -125,6 +127,21 @@ fn process_heap_alloc(flags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID {
125127 unsafe { HeapAlloc ( heap, flags, dwBytes) }
126128}
127129
130+ #[ inline( never) ]
131+ fn process_heap_alloc (
132+ _heap : MaybeUninit < c:: HANDLE > , // We pass this argument to match the ABI of `HeapAlloc`,
133+ flags : c:: DWORD ,
134+ dwBytes : c:: SIZE_T ,
135+ ) -> c:: LPVOID {
136+ let heap = HEAP . load ( Ordering :: Relaxed ) ;
137+ if core:: intrinsics:: likely ( !heap. is_null ( ) ) {
138+ // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
139+ unsafe { HeapAlloc ( heap, flags, dwBytes) }
140+ } else {
141+ process_heap_init_and_alloc ( MaybeUninit :: uninit ( ) , flags, dwBytes)
142+ }
143+ }
144+
128145// Get a non-null handle to the default heap of the current process.
129146// SAFETY: `HEAP` must have been successfully initialized.
130147#[ inline]
@@ -148,12 +165,12 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 {
148165
149166 if layout. align ( ) <= MIN_ALIGN {
150167 // The returned pointer points to the start of an allocated block.
151- process_heap_alloc ( flags, layout. size ( ) ) as * mut u8
168+ process_heap_alloc ( MaybeUninit :: uninit ( ) , flags, layout. size ( ) ) as * mut u8
152169 } else {
153170 // Allocate extra padding in order to be able to satisfy the alignment.
154171 let total = layout. align ( ) + layout. size ( ) ;
155172
156- let ptr = process_heap_alloc ( flags, total) as * mut u8 ;
173+ let ptr = process_heap_alloc ( MaybeUninit :: uninit ( ) , flags, total) as * mut u8 ;
157174 if ptr. is_null ( ) {
158175 // Allocation has failed.
159176 return ptr:: null_mut ( ) ;
0 commit comments