Skip to content
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
1 change: 1 addition & 0 deletions crates/oxc_allocator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod from_raw_parts;
pub mod hash_map;
pub mod string;
mod vec;
mod vec2;

pub use address::{Address, GetAddress};
pub use allocator::Allocator;
Expand Down
7 changes: 4 additions & 3 deletions crates/oxc_allocator/src/vec2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@
clippy::undocumented_unsafe_blocks
)]

use super::raw_vec::RawVec;
use crate::Bump;
use crate::collections::CollectionAllocErr;
use bumpalo::{Bump, collections::CollectionAllocErr};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt;
Expand All @@ -128,6 +126,9 @@ use core::slice;
// #[cfg(feature = "std")]
// use std::io;

mod raw_vec;
use raw_vec::RawVec;

unsafe fn arith_offset<T>(p: *const T, offset: isize) -> *const T {
p.offset(offset)
}
Expand Down
113 changes: 99 additions & 14 deletions crates/oxc_allocator/src/vec2/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@
#![allow(unstable_name_collisions)]
#![allow(dead_code)]

use crate::Bump;
use allocator_api2::alloc::{AllocError, Allocator};
use bumpalo::Bump;

pub use core::alloc::Layout;
use core::cmp;
use core::mem;
use core::ptr::{self, NonNull};

use crate::alloc::{Alloc, Layout, UnstableLayoutMethods, handle_alloc_error};
use crate::collections::CollectionAllocErr;
use crate::collections::CollectionAllocErr::*;
use bumpalo::collections::CollectionAllocErr::{self, AllocErr, CapacityOverflow};

// use boxed::Box;

/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
Expand Down Expand Up @@ -103,8 +104,7 @@ impl<'a, T> RawVec<'a, T> {
} else {
let align = mem::align_of::<T>();
let layout = Layout::from_size_align(alloc_size, align).unwrap();
let result =
if zeroed { a.alloc_zeroed(layout) } else { Alloc::alloc(&mut a, layout) };
let result = if zeroed { a.allocate_zeroed(layout) } else { a.allocate(layout) };
match result {
Ok(ptr) => ptr.cast(),
Err(_) => handle_alloc_error(layout),
Expand Down Expand Up @@ -533,7 +533,7 @@ impl<'a, T> RawVec<'a, T> {
let new_size = elem_size * amount;
let align = mem::align_of::<T>();
let old_layout = Layout::from_size_align_unchecked(old_size, align);
match self.a.realloc(self.ptr.cast(), old_layout, new_size) {
match realloc(self.a, self.ptr.cast(), old_layout, new_size) {
Ok(p) => self.ptr = p.cast(),
Err(_) => {
handle_alloc_error(Layout::from_size_align_unchecked(new_size, align))
Expand Down Expand Up @@ -656,8 +656,6 @@ impl<'a, T> RawVec<'a, T> {
strategy: ReserveStrategy,
) -> Result<(), CollectionAllocErr> {
unsafe {
use crate::AllocErr;

// NOTE: we don't early branch on ZSTs here because we want this
// to actually catch "asking for more than usize::MAX" in that case.
// If we make it past the first branch then we are guaranteed to
Expand All @@ -675,16 +673,16 @@ impl<'a, T> RawVec<'a, T> {
let res = match self.current_layout() {
Some(layout) => {
debug_assert!(new_layout.align() == layout.align());
self.a.realloc(self.ptr.cast(), layout, new_layout.size())
realloc(self.a, self.ptr.cast(), layout, new_layout.size())
}
None => Alloc::alloc(&mut self.a, new_layout),
None => self.a.allocate(new_layout),
};

if let (Err(AllocErr), Infallible) = (&res, fallibility) {
if let (Err(AllocError), Infallible) = (&res, fallibility) {
handle_alloc_error(new_layout);
}

self.ptr = res?.cast();
self.ptr = res.map_err(|_| AllocErr)?.cast();
self.cap = new_cap;

Ok(())
Expand All @@ -698,7 +696,7 @@ impl<'a, T> RawVec<'a, T> {
let elem_size = mem::size_of::<T>();
if elem_size != 0 {
if let Some(layout) = self.current_layout() {
self.a.dealloc(self.ptr.cast(), layout);
self.a.deallocate(self.ptr.cast(), layout);
}
}
}
Expand Down Expand Up @@ -738,6 +736,93 @@ fn capacity_overflow() -> ! {
panic!("capacity overflow")
}

// Copied from https://github.com/fitzgen/bumpalo/blob/1d2fbea9e3d0c2be56367b9ad5382ff33852a188/src/alloc.rs#L29-L31
fn handle_alloc_error(layout: Layout) -> ! {
panic!("encountered allocation error: {:?}", layout)
}

// Copied from https://github.com/fitzgen/bumpalo/blob/1d2fbea9e3d0c2be56367b9ad5382ff33852a188/src/lib.rs#L482-L486
/// Wrapper around `Layout::from_size_align` that adds debug assertions.
#[inline]
fn layout_from_size_align(size: usize, align: usize) -> Result<Layout, AllocError> {
Layout::from_size_align(size, align).map_err(|_| AllocError)
}

// Code copied from https://github.com/fitzgen/bumpalo/blob/1d2fbea9e3d0c2be56367b9ad5382ff33852a188/src/lib.rs#L1917-L1936
// Doc comment from https://github.com/fitzgen/bumpalo/blob/1d2fbea9e3d0c2be56367b9ad5382ff33852a188/src/alloc.rs#L322-L402
//
/// Returns a pointer suitable for holding data described by
/// a new layout with `layout`’s alignment and a size given
/// by `new_size`. To
/// accomplish this, this may extend or shrink the allocation
/// referenced by `ptr` to fit the new layout.
///
/// If this returns `Ok`, then ownership of the memory block
/// referenced by `ptr` has been transferred to this
/// allocator. The memory may or may not have been freed, and
/// should be considered unusable (unless of course it was
/// transferred back to the caller again via the return value of
/// this method).
///
/// If this method returns `Err`, then ownership of the memory
/// block has not been transferred to this allocator, and the
/// contents of the memory block are unaltered.
///
/// # Safety
///
/// This function is unsafe because undefined behavior can result
/// if the caller does not ensure all of the following:
///
/// * `ptr` must be currently allocated via this allocator,
///
/// * `layout` must *fit* the `ptr` (see above). (The `new_size`
/// argument need not fit it.)
///
/// * `new_size` must be greater than zero.
///
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
/// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
///
/// (Extension subtraits might provide more specific bounds on
/// behavior, e.g. guarantee a sentinel address or a null pointer
/// in response to a zero-size allocation request.)
///
/// # Errors
///
/// Returns `Err` only if the new layout
/// does not meet the allocator's size
/// and alignment constraints of the allocator, or if reallocation
/// otherwise fails.
///
/// Implementations are encouraged to return `Err` on memory
/// exhaustion rather than panicking or aborting, but this is not
/// a strict requirement. (Specifically: it is *legal* to
/// implement this trait atop an underlying native allocation
/// library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to a
/// reallocation error are encouraged to call the [`handle_alloc_error`] function,
/// rather than directly invoking `panic!` or similar.
unsafe fn realloc(
bump: &Bump,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize,
) -> Result<NonNull<[u8]>, AllocError> {
let old_size = layout.size();

if old_size == 0 {
return bump.allocate(layout);
}

let new_layout = layout_from_size_align(new_size, layout.align())?;
if new_size <= old_size {
bump.shrink(ptr, layout, new_layout)
} else {
bump.grow(ptr, layout, new_layout)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading