Skip to content

Rework the class system #373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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