Casting, GEPs, partial LLVM backend

This commit is contained in:
Mia
2026-03-06 15:21:44 +01:00
parent 0b4f169c6f
commit bd0b619127
27 changed files with 1260 additions and 947 deletions
+82 -49
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
}