Casting, GEPs, partial LLVM backend
This commit is contained in:
+82
-49
@@ -5,69 +5,102 @@ use std::{alloc::Layout, sync::Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ArenaAllocator {
|
||||
bump: Bump,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
bump: Bump,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for ArenaAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = self.bump.alloc_layout(layout).as_ptr();
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = self.bump.alloc_layout(layout).as_ptr();
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn alloc_uninit(&self, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
let ptr = self.bump.alloc_layout(layout).as_ptr();
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ArenaAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry { ptr, drop_fn, .. } in std::mem::take(&mut self.allocations) {
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry {
|
||||
ptr,
|
||||
drop_fn,
|
||||
layout,
|
||||
} in std::mem::take(&mut self.allocations)
|
||||
{
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SyncArenaAllocator {
|
||||
bump: Mutex<Bump>,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
bump: Mutex<Bump>,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for SyncArenaAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = {
|
||||
let bump = self.bump.lock().unwrap();
|
||||
bump.alloc_layout(layout).as_ptr()
|
||||
};
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = {
|
||||
let bump = self.bump.lock().unwrap();
|
||||
bump.alloc_layout(layout).as_ptr()
|
||||
};
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn alloc_uninit(&self, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
let ptr = {
|
||||
let bump = self.bump.lock().unwrap();
|
||||
bump.alloc_layout(layout).as_ptr()
|
||||
};
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SyncArenaAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry { ptr, drop_fn, .. } in std::mem::take(&mut self.allocations) {
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry {
|
||||
ptr,
|
||||
drop_fn,
|
||||
layout,
|
||||
} in std::mem::take(&mut self.allocations)
|
||||
{
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-28
@@ -4,38 +4,50 @@ use std::alloc::Layout;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GlobalAllocator {
|
||||
allocations: Vec<AllocationEntry>,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for GlobalAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = std::alloc::alloc(layout);
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = std::alloc::alloc(layout);
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn alloc_uninit(&self, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = std::alloc::alloc(layout);
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlobalAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
} in std::mem::take(&mut self.allocations)
|
||||
{
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
std::alloc::dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
} in std::mem::take(&mut self.allocations)
|
||||
{
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr, layout);
|
||||
}
|
||||
std::alloc::dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-2
@@ -5,7 +5,7 @@ pub use arena::*;
|
||||
pub use global::*;
|
||||
use std::{alloc::Layout, mem::MaybeUninit};
|
||||
|
||||
pub type DropFn = Option<unsafe fn(*mut u8)>;
|
||||
pub type DropFn = Option<unsafe fn(*mut u8, Layout)>;
|
||||
|
||||
pub struct AllocationEntry {
|
||||
ptr: *mut u8,
|
||||
@@ -17,6 +17,7 @@ unsafe impl Send for AllocationEntry {}
|
||||
unsafe impl Sync for AllocationEntry {}
|
||||
|
||||
pub trait Allocator {
|
||||
unsafe fn alloc_uninit(&self, layout: Layout, drop: DropFn) -> *mut u8;
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop: DropFn) -> *mut u8;
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ impl<'l> dyn Allocator + 'l {
|
||||
let layout = Layout::new::<T>();
|
||||
let drop: DropFn = match std::mem::needs_drop::<T>() {
|
||||
false => None,
|
||||
true => Some(|ptr: *mut u8| std::ptr::drop_in_place(ptr as *mut T)),
|
||||
true => Some(|ptr, _| std::ptr::drop_in_place(ptr as *mut T)),
|
||||
};
|
||||
&mut *(self.alloc_unsafe(data, layout, drop) as *mut T)
|
||||
}
|
||||
@@ -47,6 +48,29 @@ impl<'l> dyn Allocator + 'l {
|
||||
std::str::from_utf8_unchecked(slice)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_slice<T>(&'l self, iter: impl Iterator<Item = T> + ExactSizeIterator) -> &'l [T] {
|
||||
unsafe {
|
||||
let len = iter.len();
|
||||
let layout = Layout::array::<T>(len).unwrap();
|
||||
let ptr = self.alloc_uninit(
|
||||
layout,
|
||||
match std::mem::needs_drop::<T>() {
|
||||
false => None,
|
||||
true => Some(|ptr, layout| {
|
||||
let len = layout.size() / size_of::<T>();
|
||||
let slice = std::slice::from_raw_parts_mut(ptr as *mut T, len);
|
||||
std::ptr::drop_in_place(slice);
|
||||
}),
|
||||
},
|
||||
) as *mut MaybeUninit<T>;
|
||||
let slice = std::slice::from_raw_parts_mut(ptr, len);
|
||||
for (dst, val) in slice.iter_mut().zip(iter) {
|
||||
dst.write(val);
|
||||
}
|
||||
slice.assume_init_ref()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> dyn SyncAllocator + 'l {
|
||||
@@ -57,4 +81,8 @@ impl<'l> dyn SyncAllocator + 'l {
|
||||
pub fn alloc_str(&'l self, value: &str) -> &'l str {
|
||||
<dyn Allocator>::alloc_str(self, value)
|
||||
}
|
||||
|
||||
pub fn alloc_slice<T>(&'l self, iter: impl Iterator<Item = T> + ExactSizeIterator) -> &'l [T] {
|
||||
<dyn Allocator>::alloc_slice(self, iter)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user