Skip to content

Commit 65d02b2

Browse files
committed
Add impl of Alloc for the global rust heap.
Alpha-renamed `HeapAllocator` to `HeapAlloc`. `<HeapAlloc as Alloc>::alloc_zeroed` is hooked up to `heap::allocate_zeroed`. `HeapAlloc::realloc` falls back on alloc+copy+realloc on align mismatch.
1 parent 1d3bc4e commit 65d02b2

File tree

1 file changed

+78
-1
lines changed

1 file changed

+78
-1
lines changed

src/liballoc/heap.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
tracing garbage collector",
1616
issue = "27700")]
1717

18-
use core::{isize, usize};
18+
use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout};
19+
use core::{isize, usize, cmp, ptr};
1920
use core::intrinsics::{min_align_of_val, size_of_val};
2021

2122
#[allow(improper_ctypes)]
@@ -44,6 +45,82 @@ fn check_size_and_alignment(size: usize, align: usize) {
4445
align);
4546
}
4647

48+
#[derive(Copy, Clone, Default, Debug)]
49+
pub struct HeapAlloc;
50+
51+
unsafe impl Alloc for HeapAlloc {
52+
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
53+
let addr = allocate(layout.size(), layout.align());
54+
if addr.is_null() {
55+
Err(AllocErr::Exhausted { request: layout })
56+
} else {
57+
Ok(addr)
58+
}
59+
}
60+
61+
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
62+
let addr = allocate_zeroed(layout.size(), layout.align());
63+
if addr.is_null() {
64+
Err(AllocErr::Exhausted { request: layout })
65+
} else {
66+
Ok(addr)
67+
}
68+
}
69+
70+
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
71+
deallocate(ptr, layout.size(), layout.align());
72+
}
73+
74+
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
75+
(layout.size(), usable_size(layout.size(), layout.align()))
76+
}
77+
78+
unsafe fn realloc(&mut self,
79+
ptr: *mut u8,
80+
layout: Layout,
81+
new_layout: Layout)
82+
-> Result<*mut u8, AllocErr>
83+
{
84+
let old_size = layout.size();
85+
let new_size = new_layout.size();
86+
if layout.align() == new_layout.align() {
87+
let new_ptr = reallocate(ptr, old_size, new_size, layout.align());
88+
if new_ptr.is_null() {
89+
// We assume `reallocate` already tried alloc + copy +
90+
// dealloc fallback; thus pointless to repeat effort
91+
Err(AllocErr::Exhausted { request: new_layout })
92+
} else {
93+
Ok(new_ptr)
94+
}
95+
} else {
96+
// if alignments don't match, fall back on alloc + copy + dealloc
97+
let result = self.alloc(new_layout);
98+
if let Ok(new_ptr) = result {
99+
ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size));
100+
self.dealloc(ptr, layout);
101+
}
102+
result
103+
}
104+
}
105+
106+
unsafe fn grow_in_place(&mut self,
107+
ptr: *mut u8,
108+
layout: Layout,
109+
new_layout: Layout)
110+
-> Result<(), CannotReallocInPlace>
111+
{
112+
// grow_in_place spec requires this, and the spec for reallocate_inplace
113+
// makes it hard to detect failure if it does not hold.
114+
debug_assert!(new_layout.size() >= layout.size());
115+
116+
if layout.align() != new_layout.align() { // reallocate_inplace requires this.
117+
return Err(CannotReallocInPlace);
118+
}
119+
let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align());
120+
if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) }
121+
}
122+
}
123+
47124
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
48125

49126
/// Return a pointer to `size` bytes of memory aligned to `align`.

0 commit comments

Comments
 (0)