Skip to content

Commit 2b651cd

Browse files
Co-allocating functions for GlobalAlloc
1 parent 97799ab commit 2b651cd

File tree

2 files changed

+135
-6
lines changed

2 files changed

+135
-6
lines changed

library/core/src/alloc/global.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::alloc::GlobalCoAllocMeta;
66
#[unstable(feature = "global_co_alloc_meta", issue = "none")]
77
#[allow(missing_debug_implementations)]
88
/// Used for parameters and results (to/from `GlobalCoAllocator`'s functions, where applicable).
9-
pub struct PtrAndMeta {
9+
pub struct RawAndMeta {
1010
pub ptr: *mut u8,
1111
pub meta: GlobalCoAllocMeta,
1212
}
@@ -166,7 +166,7 @@ pub unsafe trait GlobalAlloc {
166166
unsafe fn alloc(&self, layout: Layout) -> *mut u8;
167167

168168
#[unstable(feature = "global_co_alloc", issue = "none")]
169-
unsafe fn co_alloc(&self, _layout: Layout, mut _result: &mut PtrAndMeta) {panic!("TODO")}
169+
unsafe fn co_alloc(&self, _layout: Layout, mut _result: &mut RawAndMeta) {panic!("TODO")}
170170

171171
/// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
172172
///
@@ -184,7 +184,7 @@ pub unsafe trait GlobalAlloc {
184184
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
185185

186186
#[unstable(feature = "global_co_alloc", issue = "none")]
187-
unsafe fn co_dealloc(&self, _ptr_and_meta: PtrAndMeta, _layout: Layout) {panic!("TODO")}
187+
unsafe fn co_dealloc(&self, _ptr_and_meta: RawAndMeta, _layout: Layout) {panic!("TODO")}
188188

189189
/// Behaves like `alloc`, but also ensures that the contents
190190
/// are set to zero before being returned.
@@ -219,7 +219,7 @@ pub unsafe trait GlobalAlloc {
219219
}
220220

221221
#[unstable(feature = "global_co_alloc", issue = "none")]
222-
unsafe fn co_alloc_zeroed(&self, layout: Layout, mut result: &mut PtrAndMeta) {
222+
unsafe fn co_alloc_zeroed(&self, layout: Layout, mut result: &mut RawAndMeta) {
223223
let size = layout.size();
224224
// SAFETY: the safety contract for `alloc` must be upheld by the caller.
225225
unsafe { self.co_alloc(layout, &mut result) };
@@ -305,10 +305,10 @@ pub unsafe trait GlobalAlloc {
305305
#[unstable(feature = "global_co_alloc", issue = "none")]
306306
unsafe fn co_realloc(
307307
&self,
308-
ptr_and_meta: PtrAndMeta,
308+
ptr_and_meta: RawAndMeta,
309309
layout: Layout,
310310
new_size: usize,
311-
mut result: &mut PtrAndMeta
311+
mut result: &mut RawAndMeta
312312
) {
313313
// SAFETY: the caller must ensure that the `new_size` does not overflow.
314314
// `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.

library/core/src/alloc/mod.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,25 @@ impl fmt::Display for AllocError {
5959
}
6060
}
6161

62+
#[unstable(feature = "global_co_alloc_meta", issue = "none")]
63+
#[allow(missing_debug_implementations)]
64+
pub struct PtrAndMeta {
65+
pub ptr: NonNull<u8>,
66+
pub meta: GlobalCoAllocMeta,
67+
}
68+
69+
#[unstable(feature = "global_co_alloc_meta", issue = "none")]
70+
#[allow(missing_debug_implementations)]
71+
/// Used for results (from `CoAllocator`'s functions, where applicable).
72+
pub struct SliceAndMeta {
73+
pub slice: NonNull<[u8]>,
74+
pub meta: GlobalCoAllocMeta,
75+
}
76+
77+
#[unstable(feature = "global_co_alloc_meta", issue = "none")]
78+
#[allow(missing_debug_implementations)]
79+
pub type SliceAndMetaResult = Result<SliceAndMeta, AllocError>;
80+
6281
/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
6382
/// data described via [`Layout`][].
6483
///
@@ -140,6 +159,8 @@ pub unsafe trait Allocator {
140159
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
141160
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
142161

162+
fn co_allocate(&self, _layout: Layout, _result: &mut SliceAndMetaResult) {panic!("TODO")}
163+
143164
/// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
144165
///
145166
/// # Errors
@@ -162,6 +183,19 @@ pub unsafe trait Allocator {
162183
Ok(ptr)
163184
}
164185

186+
fn co_allocate_zeroed(&self, layout: Layout, mut result: &mut SliceAndMetaResult) {
187+
self.co_allocate(layout, &mut result);
188+
if let Ok(SliceAndMeta{slice, ..}) = result {
189+
// SAFETY: `alloc` returns a valid memory block
190+
unsafe {
191+
slice
192+
.as_non_null_ptr()
193+
.as_ptr()
194+
.write_bytes(0, slice.len())
195+
}
196+
}
197+
}
198+
165199
/// Deallocates the memory referenced by `ptr`.
166200
///
167201
/// # Safety
@@ -173,6 +207,8 @@ pub unsafe trait Allocator {
173207
/// [*fit*]: #memory-fitting
174208
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
175209

210+
unsafe fn co_deallocate(&self, _ptr_and_meta: PtrAndMeta, _layout: Layout) {panic!("TODO")}
211+
176212
/// Attempts to extend the memory block.
177213
///
178214
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
@@ -237,6 +273,37 @@ pub unsafe trait Allocator {
237273
Ok(new_ptr)
238274
}
239275

276+
unsafe fn co_grow(
277+
&self,
278+
ptr_and_meta: PtrAndMeta,
279+
old_layout: Layout,
280+
new_layout: Layout,
281+
mut result: &mut SliceAndMetaResult
282+
) {
283+
debug_assert!(
284+
new_layout.size() >= old_layout.size(),
285+
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
286+
);
287+
288+
self.co_allocate(new_layout, &mut result);
289+
290+
if let Ok(SliceAndMeta {slice, ..}) = result {
291+
// SAFETY: because `new_layout.size()` must be greater than or equal to
292+
// `old_layout.size()`, both the old and new memory allocation are valid for reads and
293+
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
294+
// deallocated, it cannot overlap `new_slice_and_meta.slice`. Thus, the call to `copy_nonoverlapping` is
295+
// safe. The safety contract for `dealloc` must be upheld by the caller.
296+
unsafe {
297+
ptr::copy_nonoverlapping(
298+
ptr_and_meta.ptr.as_ptr(),
299+
slice.as_mut_ptr(),
300+
old_layout.size(),
301+
);
302+
self.co_deallocate(ptr_and_meta, old_layout);
303+
}
304+
}
305+
}
306+
240307
/// Behaves like `grow`, but also ensures that the new contents are set to zero before being
241308
/// returned.
242309
///
@@ -300,6 +367,37 @@ pub unsafe trait Allocator {
300367
Ok(new_ptr)
301368
}
302369

370+
unsafe fn co_grow_zeroed(
371+
&self,
372+
ptr_and_meta: PtrAndMeta,
373+
old_layout: Layout,
374+
new_layout: Layout,
375+
mut result: &mut SliceAndMetaResult
376+
) {
377+
debug_assert!(
378+
new_layout.size() >= old_layout.size(),
379+
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
380+
);
381+
382+
self.co_allocate_zeroed(new_layout, &mut result);
383+
384+
if let Ok(SliceAndMeta{ slice, ..}) = result {
385+
// SAFETY: because `new_layout.size()` must be greater than or equal to
386+
// `old_layout.size()`, both the old and new memory allocation are valid for reads and
387+
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
388+
// deallocated, it cannot overlap `new_slice_and_meta.slice`. Thus, the call to `copy_nonoverlapping` is
389+
// safe. The safety contract for `dealloc` must be upheld by the caller.
390+
unsafe {
391+
ptr::copy_nonoverlapping(
392+
ptr_and_meta.ptr.as_ptr(),
393+
slice.as_mut_ptr(),
394+
old_layout.size(),
395+
);
396+
self.co_deallocate(ptr_and_meta, old_layout);
397+
}
398+
}
399+
}
400+
303401
/// Attempts to shrink the memory block.
304402
///
305403
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
@@ -364,6 +462,37 @@ pub unsafe trait Allocator {
364462
Ok(new_ptr)
365463
}
366464

465+
unsafe fn co_shrink(
466+
&self,
467+
ptr_and_meta: PtrAndMeta,
468+
old_layout: Layout,
469+
new_layout: Layout,
470+
mut result: &mut SliceAndMetaResult
471+
) {
472+
debug_assert!(
473+
new_layout.size() <= old_layout.size(),
474+
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
475+
);
476+
477+
self.co_allocate(new_layout, &mut result);
478+
479+
if let Ok(SliceAndMeta{ slice, ..}) = result {
480+
// SAFETY: because `new_layout.size()` must be lower than or equal to
481+
// `old_layout.size()`, both the old and new memory allocation are valid for reads and
482+
// writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
483+
// deallocated, it cannot overlap `new_slice_and_meta.slice`. Thus, the call to `copy_nonoverlapping` is
484+
// safe. The safety contract for `dealloc` must be upheld by the caller.
485+
unsafe {
486+
ptr::copy_nonoverlapping(
487+
ptr_and_meta.ptr.as_ptr(),
488+
slice.as_mut_ptr(),
489+
new_layout.size(),
490+
);
491+
self.co_deallocate(ptr_and_meta, old_layout);
492+
}
493+
}
494+
}
495+
367496
/// Creates a "by reference" adapter for this instance of `Allocator`.
368497
///
369498
/// The returned adapter also implements `Allocator` and will simply borrow this.

0 commit comments

Comments
 (0)