I'm implementing GlobalAlloc to always align allocations on 4096-byte boundaries, and for sizes to be a multiple of 64 bytes. This will provide better interoperability with OpenCL, specifically zero-copy-buffers with Intel graphics.
The documentation and source of AllocRef (implemented by System) says the return value for alloc in System is Result<NonNull<u8>, AllocErr>. However, the compiler complains about mismatched types. Pretending that alloc indeed returns *mut u8 and programming as such compiles, but now the IDE (IntelliJ) complains.
Because I'm using the nightly build of Rust, and am very new to Rust, I can't tell if this is simply due to outdated documentation and installed source, a bug in the IDE, or something else that i don't understand.
#![feature(allocator_api)]
use std::alloc::System;
use std::alloc::{handle_alloc_error, AllocRef, GlobalAlloc, Layout};
use std::ptr::NonNull;
struct OpenCLConsideringAlloc;
unsafe impl GlobalAlloc for OpenCLConsideringAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
match System.alloc(to_ocl_considering_layout(layout)) {
Ok(v) => v.as_ptr(),
Err(e) => match System.alloc(layout) {
Ok(ptr) => ptr.as_ptr(),
Err(e) => handle_alloc_error(layout),
},
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
System.dealloc(
NonNull::new_unchecked(ptr),
to_ocl_considering_layout(layout),
);
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
match System.alloc_zeroed(to_ocl_considering_layout(layout)) {
Ok(ptr) => ptr.as_ptr(),
Err(e) => match System.alloc_zeroed(layout) {
Ok(ptr) => ptr.as_ptr(),
Err(e) => handle_alloc_error(layout),
},
}
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
match System.realloc(
NonNull::new_unchecked(ptr),
to_ocl_considering_layout(layout),
new_size,
) {
Ok(ptr) => ptr.as_ptr(),
Err(e) => match System.realloc(NonNull::new_unchecked(ptr), layout, new_size) {
Ok(ptr) => ptr.as_ptr(),
Err(e) => handle_alloc_error(layout),
},
}
}
}
//Attempts to round-up size up to a multiple of 64, forces 4096-byte alignment for large
//allocations, 64-byte alignment for intermediate sizes, default for small allocations.
#[inline]
fn to_ocl_considering_layout(any_layout: Layout) -> Layout {
let alignment: usize = match any_layout.size() {
0..=1024 => any_layout.align(),
1025..=65536 => 64,
_ => 4096
};
match Layout::from_size_align(
((any_layout.size() as i64 + 63_i64) & -64_i64) as usize,
alignment
) {
Ok(layout) => layout,
Err(e) => any_layout,
}
}
#[global_allocator]
static GLOBAL: OpenCLConsideringAlloc = OpenCLConsideringAlloc;
Compiler error:
error[E0308]: mismatched types
--> src/lib.rs:12:13
|
11 | match System.alloc(to_ocl_considering_layout(layout)) {
| ----------------------------------------------- this expression has type `*mut u8`
12 | Ok(v) => v.as_ptr(),
| ^^^^^ expected *-ptr, found enum `std::result::Result`
|
= note: expected raw pointer `*mut u8`
found enum `std::result::Result<_, _>`
The implementation of System::alloc:
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
}
Output of rustup show:
Default host: x86_64-pc-windows-gnu
rustup home: C:\Users\username\.rustup
nightly-x86_64-pc-windows-gnu (default)
rustc 1.43.0-nightly (6d0e58bff 2020-02-23)