Skip to content

Commit

Permalink
Merge pull request #373 from DelSkayn/change-class-registration
Browse files Browse the repository at this point in the history
Rework the class system
  • Loading branch information
DelSkayn authored Oct 31, 2024
2 parents 1cff949 + 80ecb11 commit 3444ac2
Show file tree
Hide file tree
Showing 43 changed files with 1,459 additions and 984 deletions.
18 changes: 7 additions & 11 deletions core/src/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ mod rust;

pub use rust::RustAllocator;

/// Raw memory pointer
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "allocator")))]
pub type RawMemPtr = *mut u8;

/// The allocator interface
///
/// # Safety
Expand All @@ -26,28 +22,28 @@ pub unsafe trait Allocator {
/// Allocate new memory
///
///
fn alloc(&mut self, size: usize) -> RawMemPtr;
fn alloc(&mut self, size: usize) -> *mut u8;

/// De-allocate previously allocated memory
///
/// # Safety
/// Caller must ensure that the pointer that is being deallocated was allocated by the same
/// Allocator instance.
unsafe fn dealloc(&mut self, ptr: RawMemPtr);
unsafe fn dealloc(&mut self, ptr: *mut u8);

/// Re-allocate previously allocated memory
///
/// # Safety
/// Caller must ensure that the pointer points to an allocation that was allocated by the same
/// Allocator instance.
unsafe fn realloc(&mut self, ptr: RawMemPtr, new_size: usize) -> RawMemPtr;
unsafe fn realloc(&mut self, ptr: *mut u8, new_size: usize) -> *mut u8;

/// Get usable size of allocated memory region
///
/// # Safety
/// Caller must ensure that the pointer handed to this function points to an allocation
/// allocated by the same allocator instance.
unsafe fn usable_size(ptr: RawMemPtr) -> usize
unsafe fn usable_size(ptr: *mut u8) -> usize
where
Self: Sized;
}
Expand Down Expand Up @@ -140,7 +136,7 @@ impl AllocatorHolder {
let state = &mut *state;
state.malloc_count -= 1;

let size = A::usable_size(ptr as RawMemPtr);
let size = A::usable_size(ptr as *mut u8);

let allocator = &mut *(state.opaque as *mut DynAllocator);
allocator.dealloc(ptr as _);
Expand All @@ -167,7 +163,7 @@ impl AllocatorHolder {
return ptr::null_mut();
}

let old_size = Self::size_t(A::usable_size(ptr as RawMemPtr));
let old_size = Self::size_t(A::usable_size(ptr as *mut u8));

let new_malloc_size = state_ref.malloc_size - old_size + size;
if new_malloc_size > state_ref.malloc_limit {
Expand All @@ -181,7 +177,7 @@ impl AllocatorHolder {
return ptr::null_mut();
}

let actual_size = Self::size_t(A::usable_size(ptr as RawMemPtr));
let actual_size = Self::size_t(A::usable_size(ptr as *mut u8));

state_ref.malloc_size -= old_size;
state_ref.malloc_size += actual_size;
Expand Down
90 changes: 36 additions & 54 deletions core/src/allocator/rust.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::{
alloc::{alloc, dealloc, realloc, Layout},
mem::size_of,
ptr::null_mut,
alloc::{self, Layout},
mem, ptr,
};

use super::{Allocator, RawMemPtr};
use super::Allocator;

/// The largest value QuickJS will allocate is a u64;
/// So all allocated memory must have the same alignment is this largest size.
const ALLOC_ALIGN: usize = std::mem::align_of::<u64>();
const ALLOC_ALIGN: usize = mem::align_of::<u64>();

#[derive(Copy, Clone)]
#[repr(transparent)]
Expand All @@ -25,83 +24,70 @@ const fn max(a: usize, b: usize) -> usize {
}

/// Head needs to be at least alloc aligned so all that values after the header are aligned.
const HEADER_SIZE: usize = max(size_of::<Header>(), ALLOC_ALIGN);
const HEADER_SIZE: usize = max(mem::size_of::<Header>(), ALLOC_ALIGN);

#[inline]
fn round_size(size: usize) -> usize {
// this will be optimized by the compiler
// to something like (size + <off>) & <mask>
(size + ALLOC_ALIGN - 1) / ALLOC_ALIGN * ALLOC_ALIGN
}

/// The allocator which uses Rust global allocator
pub struct RustAllocator;

unsafe impl Allocator for RustAllocator {
fn alloc(&mut self, size: usize) -> RawMemPtr {
fn alloc(&mut self, size: usize) -> *mut u8 {
let size = round_size(size);
let alloc_size = size + HEADER_SIZE;

let layout = if let Ok(layout) = Layout::from_size_align(alloc_size, ALLOC_ALIGN) {
layout
} else {
return null_mut();
return ptr::null_mut();
};

let ptr = unsafe { alloc(layout) };
let ptr = unsafe { alloc::alloc(layout) };

if ptr.is_null() {
return null_mut();
}
{
let header = unsafe { &mut *(ptr as *mut Header) };
header.size = size;
return ptr::null_mut();
}

unsafe { ptr.add(HEADER_SIZE) }
unsafe {
ptr.cast::<Header>().write(Header { size });
ptr.add(HEADER_SIZE)
}
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
unsafe fn dealloc(&mut self, ptr: RawMemPtr) {
let ptr = unsafe { ptr.sub(HEADER_SIZE) };
let alloc_size = {
let header = unsafe { &*(ptr as *const Header) };
header.size + HEADER_SIZE
};
let layout = unsafe { Layout::from_size_align_unchecked(alloc_size, ALLOC_ALIGN) };
unsafe fn dealloc(&mut self, ptr: *mut u8) {
let ptr = ptr.sub(HEADER_SIZE);
let alloc_size = ptr.cast::<Header>().read().size + HEADER_SIZE;
let layout = Layout::from_size_align_unchecked(alloc_size, ALLOC_ALIGN);

unsafe { dealloc(ptr, layout) };
alloc::dealloc(ptr, layout);
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
unsafe fn realloc(&mut self, ptr: RawMemPtr, new_size: usize) -> RawMemPtr {
unsafe fn realloc(&mut self, ptr: *mut u8, new_size: usize) -> *mut u8 {
let new_size = round_size(new_size);
let ptr = unsafe { ptr.sub(HEADER_SIZE) };
let alloc_size = {
let header = unsafe { &*(ptr as *const Header) };
header.size + HEADER_SIZE
};
let layout = unsafe { Layout::from_size_align_unchecked(alloc_size, ALLOC_ALIGN) };

let ptr = ptr.sub(HEADER_SIZE);
let alloc_size = ptr.cast::<Header>().read().size;

let layout = Layout::from_size_align_unchecked(alloc_size, ALLOC_ALIGN);

let new_alloc_size = new_size + HEADER_SIZE;

let ptr = unsafe { realloc(ptr, layout, new_alloc_size) };
let ptr = alloc::realloc(ptr, layout, new_alloc_size);

if ptr.is_null() {
return null_mut();
}
{
let header = unsafe { &mut *(ptr as *mut Header) };
header.size = new_size;
return ptr::null_mut();
}

unsafe { ptr.add(HEADER_SIZE) }
ptr.cast::<Header>().write(Header { size: new_size });
ptr.add(HEADER_SIZE)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
unsafe fn usable_size(ptr: RawMemPtr) -> usize {
let ptr = unsafe { ptr.sub(HEADER_SIZE) };
let header = unsafe { &*(ptr as *const Header) };
header.size
unsafe fn usable_size(ptr: *mut u8) -> usize {
let ptr = ptr.sub(HEADER_SIZE);
ptr.cast::<Header>().read().size
}
}

Expand All @@ -116,24 +102,20 @@ mod test {
struct TestAllocator;

unsafe impl Allocator for TestAllocator {
fn alloc(&mut self, size: usize) -> crate::allocator::RawMemPtr {
fn alloc(&mut self, size: usize) -> *mut u8 {
unsafe {
let res = RustAllocator.alloc(size);
ALLOC_SIZE.fetch_add(RustAllocator::usable_size(res), Ordering::AcqRel);
res
}
}

unsafe fn dealloc(&mut self, ptr: crate::allocator::RawMemPtr) {
unsafe fn dealloc(&mut self, ptr: *mut u8) {
ALLOC_SIZE.fetch_sub(RustAllocator::usable_size(ptr), Ordering::AcqRel);
RustAllocator.dealloc(ptr);
}

unsafe fn realloc(
&mut self,
ptr: crate::allocator::RawMemPtr,
new_size: usize,
) -> crate::allocator::RawMemPtr {
unsafe fn realloc(&mut self, ptr: *mut u8, new_size: usize) -> *mut u8 {
if !ptr.is_null() {
ALLOC_SIZE.fetch_sub(RustAllocator::usable_size(ptr), Ordering::AcqRel);
}
Expand All @@ -145,7 +127,7 @@ mod test {
res
}

unsafe fn usable_size(ptr: crate::allocator::RawMemPtr) -> usize
unsafe fn usable_size(ptr: *mut u8) -> usize
where
Self: Sized,
{
Expand Down
Loading

0 comments on commit 3444ac2

Please sign in to comment.