Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions src/ast/e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2662,9 +2662,8 @@ mod json_tape_tests {
self.0
}
/// `Parser::tape_mut` — a fresh reborrow of the root pointer per call.
#[allow(clippy::mut_from_ref)]
fn get(&self) -> &mut JsonTape {
// SAFETY: sole owner; each call hands out one short-lived borrow.
fn get(&mut self) -> &mut JsonTape {
// SAFETY: sole owner; `&mut self` makes the reborrow exclusive.
unsafe { &mut *self.0.as_ptr() }
}
}
Expand All @@ -2682,7 +2681,7 @@ mod json_tape_tests {
/// the inner node must survive, because `properties()` is read afterwards.
#[test]
fn object_json_survives_later_tape_writes() {
let tape = TapeOwner::new();
let mut tape = TapeOwner::new();

// Inner `{"b": null}`.
let kb = tape.get().alloc_str(b"b");
Expand All @@ -2707,7 +2706,7 @@ mod json_tape_tests {

#[test]
fn array_json_survives_later_tape_writes() {
let tape = TapeOwner::new();
let mut tape = TapeOwner::new();

let (first, count) = tape.get().append_items(&[JsonValue::Null], &[]);
// SAFETY: the tape's own pointer, as `Parser` passes it.
Expand Down Expand Up @@ -2741,7 +2740,7 @@ mod json_tape_tests {
/// later strings spill into new chunks.
#[test]
fn alloc_str_chunks_never_move() {
let tape = TapeOwner::new();
let mut tape = TapeOwner::new();
let a = tape.get().alloc_str(b"first");
// Force a fresh chunk: bigger than what is left in the current one.
let big = vec![b'x'; JsonTape::STR_CHUNK + 1];
Expand Down
38 changes: 19 additions & 19 deletions src/bun_alloc/BufferFallbackAllocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ impl<'a> BufferFallbackAllocator<'a> {
}
}

pub fn allocator(&mut self) -> StdAllocator {
pub fn allocator(&self) -> StdAllocator {
StdAllocator {
ptr: std::ptr::from_mut::<Self>(self).cast::<c_void>(),
ptr: std::ptr::from_ref::<Self>(self).cast_mut().cast::<c_void>(),
vtable: &VTABLE,
}
}

pub fn reset(&mut self) {
pub fn reset(&self) {
self.fixed.reset();
}
}
Expand All @@ -39,10 +39,11 @@ static VTABLE: AllocatorVTable = AllocatorVTable {
};

unsafe fn alloc(ctx: *mut c_void, len: usize, alignment: Alignment, ra: usize) -> *mut u8 {
// SAFETY: ctx was set to `&mut BufferFallbackAllocator` in `allocator()`.
let self_: &mut BufferFallbackAllocator =
unsafe { &mut *ctx.cast::<BufferFallbackAllocator>() };
FixedBufferAllocator::alloc(&mut self_.fixed, len, alignment, ra)
// SAFETY: ctx was set to `&BufferFallbackAllocator` in `allocator()`.
let self_: &BufferFallbackAllocator = unsafe { &*ctx.cast::<BufferFallbackAllocator>() };
self_
.fixed
.alloc(len, alignment, ra)
.or_else(|| self_.fallback.raw_alloc(len, alignment, ra))
.unwrap_or(core::ptr::null_mut())
}
Expand All @@ -54,11 +55,10 @@ unsafe fn resize(
new_len: usize,
ra: usize,
) -> bool {
// SAFETY: ctx was set to `&mut BufferFallbackAllocator` in `allocator()`.
let self_: &mut BufferFallbackAllocator =
unsafe { &mut *ctx.cast::<BufferFallbackAllocator>() };
// SAFETY: ctx was set to `&BufferFallbackAllocator` in `allocator()`.
let self_: &BufferFallbackAllocator = unsafe { &*ctx.cast::<BufferFallbackAllocator>() };
if self_.fixed.owns_ptr(buf.as_ptr()) {
return FixedBufferAllocator::resize(&mut self_.fixed, buf, alignment, new_len, ra);
return self_.fixed.resize(buf, alignment, new_len, ra);
}
self_.fallback.raw_resize(buf, alignment, new_len, ra)
}
Expand All @@ -70,11 +70,12 @@ unsafe fn remap(
new_len: usize,
ra: usize,
) -> *mut u8 {
// SAFETY: ctx was set to `&mut BufferFallbackAllocator` in `allocator()`.
let self_: &mut BufferFallbackAllocator =
unsafe { &mut *ctx.cast::<BufferFallbackAllocator>() };
// SAFETY: ctx was set to `&BufferFallbackAllocator` in `allocator()`.
let self_: &BufferFallbackAllocator = unsafe { &*ctx.cast::<BufferFallbackAllocator>() };
if self_.fixed.owns_ptr(memory.as_ptr()) {
return FixedBufferAllocator::remap(&mut self_.fixed, memory, alignment, new_len, ra)
return self_
.fixed
.remap(memory, alignment, new_len, ra)
.unwrap_or(core::ptr::null_mut());
}
self_
Expand All @@ -84,11 +85,10 @@ unsafe fn remap(
}

unsafe fn free(ctx: *mut c_void, buf: &mut [u8], alignment: Alignment, ra: usize) {
// SAFETY: ctx was set to `&mut BufferFallbackAllocator` in `allocator()`.
let self_: &mut BufferFallbackAllocator =
unsafe { &mut *ctx.cast::<BufferFallbackAllocator>() };
// SAFETY: ctx was set to `&BufferFallbackAllocator` in `allocator()`.
let self_: &BufferFallbackAllocator = unsafe { &*ctx.cast::<BufferFallbackAllocator>() };
if self_.fixed.owns_ptr(buf.as_ptr()) {
return FixedBufferAllocator::free(&mut self_.fixed, buf, alignment, ra);
return self_.fixed.free(buf, alignment, ra);
}
self_.fallback.raw_free(buf, alignment, ra)
}
69 changes: 42 additions & 27 deletions src/bun_alloc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// Used for the per-allocation hot-path TLS in `ast_alloc::AST_ALLOC`.
#![feature(thread_local)]

use core::cell::{Cell, UnsafeCell};
use core::fmt::Write as _;
use core::mem::{MaybeUninit, size_of};
use core::ptr::{NonNull, addr_of_mut};
Expand Down Expand Up @@ -183,51 +184,65 @@ impl StdAllocator {

/// Bump allocator over a caller-owned buffer.
pub struct FixedBufferAllocator<'a> {
end: usize,
buffer: &'a mut [u8],
/// `Cell` + `UnsafeCell` so every method takes `&self`: the vtable thunks in
/// `BufferFallbackAllocator` only ever get a shared ref out of their `ctx`,
/// and `alloc` hands out `*mut u8` into `buffer`.
end: Cell<usize>,
buffer: &'a UnsafeCell<[u8]>,
}
impl<'a> FixedBufferAllocator<'a> {
#[inline]
pub fn init(buffer: &'a mut [u8]) -> Self {
Self { end: 0, buffer }
Self {
end: Cell::new(0),
buffer: UnsafeCell::from_mut(buffer),
}
}
#[inline]
pub fn reset(&mut self) {
self.end = 0;
fn base(&self) -> *mut u8 {
self.buffer.get().cast::<u8>()
}
#[inline]
fn capacity(&self) -> usize {
self.buffer.get().len()
}
#[inline]
pub fn reset(&self) {
self.end.set(0);
}
#[inline]
pub fn owns_ptr(&self, p: *const u8) -> bool {
let base = self.buffer.as_ptr() as usize;
let q = p as usize;
q >= base && q < base + self.buffer.len()
}
pub fn alloc(&mut self, len: usize, alignment: Alignment, _ra: usize) -> Option<*mut u8> {
let base = self.buffer.as_mut_ptr() as usize;
let aligned =
(base + self.end + alignment.to_byte_units() - 1) & !(alignment.to_byte_units() - 1);
let new_end = (aligned - base).checked_add(len)?;
if new_end > self.buffer.len() {
let base = self.base().addr();
let q = p.addr();
q >= base && q < base + self.capacity()
}
pub fn alloc(&self, len: usize, alignment: Alignment, _ra: usize) -> Option<*mut u8> {
let base = self.base();
let aligned = (base.addr() + self.end.get() + alignment.to_byte_units() - 1)
& !(alignment.to_byte_units() - 1);
let new_end = (aligned - base.addr()).checked_add(len)?;
if new_end > self.capacity() {
return None;
}
self.end = new_end;
Some(aligned as *mut u8)
self.end.set(new_end);
Some(base.with_addr(aligned))
}
pub fn resize(&mut self, buf: &mut [u8], _a: Alignment, new_len: usize, _ra: usize) -> bool {
pub fn resize(&self, buf: &mut [u8], _a: Alignment, new_len: usize, _ra: usize) -> bool {
// Only the last allocation can grow; shrinks always succeed.
let buf_end = buf.as_ptr() as usize - self.buffer.as_ptr() as usize + buf.len();
if buf_end != self.end {
let buf_end = buf.as_ptr().addr() - self.base().addr() + buf.len();
if buf_end != self.end.get() {
return new_len <= buf.len();
}
let new_end = buf_end - buf.len() + new_len;
if new_end > self.buffer.len() {
if new_end > self.capacity() {
return false;
}
self.end = new_end;
self.end.set(new_end);
true
}
#[inline]
pub fn remap(
&mut self,
&self,
buf: &mut [u8],
a: Alignment,
new_len: usize,
Expand All @@ -240,11 +255,11 @@ impl<'a> FixedBufferAllocator<'a> {
}
}
#[inline]
pub fn free(&mut self, buf: &mut [u8], _a: Alignment, _ra: usize) {
pub fn free(&self, buf: &mut [u8], _a: Alignment, _ra: usize) {
// Only the last allocation can be freed.
let buf_end = buf.as_ptr() as usize - self.buffer.as_ptr() as usize + buf.len();
if buf_end == self.end {
self.end -= buf.len();
let buf_end = buf.as_ptr().addr() - self.base().addr() + buf.len();
if buf_end == self.end.get() {
self.end.set(self.end.get() - buf.len());
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/bundler/BundleThread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,7 @@ impl<C: CompletionStruct> BundleThread<C> {
// `completion` can be borrowed again below.
let transpiler_ptr: *mut Transpiler<'_> = transpiler;
let run = completion.init_and_run(
// SAFETY: `transpiler` lives in `bump` for the duration of `heap`.
unsafe { &mut *transpiler_ptr },
transpiler,
bump,
// `WorkPool::get()` returns `&'static ThreadPool`; pass as raw so
// the impl can hand it to `BundleV2::init` (which stores `*mut`).
Expand Down
Loading
Loading