Skip to content
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

feat(allocator): Introduce scoped allocator #9230

Draft
wants to merge 65 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
c4c497e
boxed
kdy1 Jul 12, 2024
e88decf
doc
kdy1 Jul 12, 2024
3a0d765
Dep
kdy1 Jul 12, 2024
f253661
cargo lockfiel
kdy1 Jul 12, 2024
0ee7893
alloc::ALLOC
kdy1 Jul 12, 2024
580d0b1
doc
kdy1 Jul 12, 2024
663726d
Dep
kdy1 Jul 12, 2024
4252d5e
cargo lockfile
kdy1 Jul 12, 2024
6567db1
SwcAlloc
kdy1 Jul 12, 2024
e4f3140
traits
kdy1 Jul 12, 2024
565012e
`with_allocator`
kdy1 Jul 12, 2024
8de8088
SwcAlloc
kdy1 Jul 12, 2024
074b470
`SwcAlloc`
kdy1 Jul 12, 2024
b22e6b5
WIP
kdy1 Jul 12, 2024
2574bec
Box<T>
kdy1 Jul 12, 2024
c4e08c1
more traits
kdy1 Jul 12, 2024
6ac0023
scope
kdy1 Jul 12, 2024
b53d2d6
Dep
kdy1 Jul 12, 2024
5b0c3ea
cargo lockfile
kdy1 Jul 12, 2024
86af131
AST
kdy1 Jul 12, 2024
73b2582
`Vec`
kdy1 Jul 12, 2024
d31747c
Dep serde
kdy1 Jul 12, 2024
09e4a42
dep
kdy1 Jul 12, 2024
e2de2f7
cargo lockfile
kdy1 Jul 12, 2024
0d27464
More work for allocator
kdy1 Jul 12, 2024
fff6b2b
more work
kdy1 Jul 12, 2024
2e010b6
Dep
kdy1 Jul 12, 2024
856cff9
cargo lockfile
kdy1 Jul 12, 2024
970bb22
rkyv
kdy1 Jul 12, 2024
f61905d
dep
kdy1 Jul 12, 2024
7b4dcdb
cargo lockfile
kdy1 Jul 12, 2024
71b2af9
More work
kdy1 Jul 12, 2024
c8b7799
from impl
kdy1 Jul 12, 2024
42626cf
dep
kdy1 Jul 12, 2024
301b060
cargo lockfile
kdy1 Jul 12, 2024
b6204bb
rkyv & serde
kdy1 Jul 13, 2024
d34c783
Fix more
kdy1 Jul 13, 2024
a29beda
WIP
kdy1 Jul 13, 2024
3511d58
Dep version
kdy1 Jul 13, 2024
053edf1
cargo lockfile
kdy1 Jul 13, 2024
94500f0
as_ref()
kdy1 Jul 13, 2024
fd1de5e
Take
kdy1 Jul 13, 2024
5dd8489
Spanned
kdy1 Jul 13, 2024
e19c20b
`Default`
kdy1 Jul 13, 2024
6720faf
Move vec
kdy1 Jul 13, 2024
9605763
Fix swc_common
kdy1 Jul 13, 2024
d8f4880
Update import
kdy1 Jul 13, 2024
32b9ace
Fix deref
kdy1 Jul 13, 2024
b366925
iteratr0o
kdy1 Jul 13, 2024
caed2b1
FromIter
kdy1 Jul 13, 2024
a723791
More AST fix
kdy1 Jul 13, 2024
13fc660
Vec::new()
kdy1 Jul 13, 2024
9200ca2
fix more AST
kdy1 Jul 13, 2024
812cf9e
fix more
kdy1 Jul 13, 2024
445142f
AsMut
kdy1 Jul 13, 2024
ab3c63e
impl<T> From<T> for Box<T>
kdy1 Jul 13, 2024
7477b73
More ast work
kdy1 Jul 13, 2024
583c2ed
More AST work
kdy1 Jul 13, 2024
ad7e3c4
boxed()
kdy1 Jul 13, 2024
c69accc
Fix AST
kdy1 Jul 13, 2024
1f29c75
More AST work
kdy1 Jul 13, 2024
8d7bd13
Rename
kdy1 Jul 14, 2024
71403bc
SwcAlloc
kdy1 Jul 14, 2024
04dfd41
Some work
kdy1 Jul 14, 2024
8a4fbef
allcator trait
kdy1 Jul 14, 2024
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
28 changes: 24 additions & 4 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ resolver = "2"

Inflector = "0.11.4"
ahash = "0.8.8"
allocator-api2 = "0.2.18"
ansi_term = "0.12.1"
anyhow = "1.0.81"
arbitrary = "1"
Expand Down Expand Up @@ -95,6 +96,7 @@ resolver = "2"
phf = "0.11.2"
pretty_assertions = "1.3"
proc-macro2 = "1.0.24"
ptr_meta = "0.1.4"
quote = "1.0.7"
rayon = "1.7.0"
regex = "1.5.4"
Expand Down
12 changes: 11 additions & 1 deletion crates/swc_allocator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ repository = { workspace = true }
version = "0.1.1"

[dependencies]
bumpalo = { workspace = true, features = ["boxed", "collections"] }
allocator-api2 = { workspace = true, features = ["serde"] }
bumpalo = { workspace = true, features = [
"allocator-api2",
"boxed",
"collections",
] }
ptr_meta = { workspace = true }
rkyv = { workspace = true }
scoped-tls = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
153 changes: 153 additions & 0 deletions crates/swc_allocator/src/alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use std::{alloc::Layout, ptr::NonNull};

use allocator_api2::alloc::Global;
use scoped_tls::scoped_thread_local;

use crate::Allocator;

scoped_thread_local!(pub(crate) static ALLOC: Allocator);

#[derive(Debug, Clone, Copy, Default)]
pub struct SwcAlloc;

impl SwcAlloc {
/// `true` is passed to `f` if the box is allocated with a custom allocator.
fn with_allocator<T>(
&self,
f: impl FnOnce(&dyn allocator_api2::alloc::Allocator, bool) -> T,
) -> T {
if ALLOC.is_set() {
ALLOC.with(|a| {
//
f(&&**a as &dyn allocator_api2::alloc::Allocator, true)
})
} else {
f(&allocator_api2::alloc::Global, false)
}
}
}

/// Set the last bit to 1
fn mark_ptr_as_arena_mode(ptr: NonNull<[u8]>) -> NonNull<[u8]> {
let ptr = ptr.as_ptr() as *mut () as usize | 1;
unsafe { NonNull::new_unchecked(ptr as *mut [u8]) }
}

fn is_ptr_in_arena_mode(ptr: NonNull<u8>) -> bool {
let ptr = ptr.as_ptr() as usize;
ptr & 1 == 1
}

unsafe impl allocator_api2::alloc::Allocator for SwcAlloc {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
self.with_allocator(|a, is_arena_mode| {
let ptr = a.allocate(layout)?;

if is_arena_mode {
Ok(mark_ptr_as_arena_mode(ptr))
} else {
Ok(ptr)
}
})
}

fn allocate_zeroed(
&self,
layout: Layout,
) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
self.with_allocator(|a, is_arena_mode| {
let ptr = a.allocate_zeroed(layout)?;

if is_arena_mode {
Ok(mark_ptr_as_arena_mode(ptr))
} else {
Ok(ptr)
}
})
}

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if is_ptr_in_arena_mode(ptr) {
debug_assert!(
ALLOC.is_set(),
"Deallocating a pointer allocated with arena mode with a non-arena mode allocator"
);

ALLOC.with(|alloc| {
unsafe {
// Safety: We are in unsafe fn
(&**alloc).deallocate(ptr, layout)
}
})
} else {
Global.deallocate(ptr, layout)
}
}

unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
if is_ptr_in_arena_mode(ptr) {
debug_assert!(
ALLOC.is_set(),
"Growing a pointer allocated with arena mode with a non-arena mode allocator"
);

ALLOC.with(|alloc| {
return (&**alloc).grow(ptr, old_layout, new_layout);
})
} else {
Global.grow(ptr, old_layout, new_layout)
}
}

unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
if is_ptr_in_arena_mode(ptr) {
debug_assert!(
ALLOC.is_set(),
"Growing a pointer allocated with arena mode with a non-arena mode allocator"
);

ALLOC.with(|alloc| {
return (&**alloc).grow_zeroed(ptr, old_layout, new_layout);
})
} else {
Global.grow_zeroed(ptr, old_layout, new_layout)
}
}

unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
if is_ptr_in_arena_mode(ptr) {
debug_assert!(
ALLOC.is_set(),
"Shrinking a pointer allocated with arena mode with a non-arena mode allocator"
);

ALLOC.with(|alloc| {
return (&**alloc).shrink(ptr, old_layout, new_layout);
})
} else {
Global.shrink(ptr, old_layout, new_layout)
}
}

fn by_ref(&self) -> &Self
where
Self: Sized,
{
self
}
}
93 changes: 93 additions & 0 deletions crates/swc_allocator/src/boxed/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::ops::{Deref, DerefMut};

use crate::alloc::SwcAlloc;

mod rkyv;
mod serde;

/// A special `Box` which has size of [`std::boxed::Box`] but **may** be
/// allocated with a custom allocator.
///
///
/// # Representation
///
/// The last bit is 1 if the box is allocated with a custom allocator.
#[repr(transparent)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Box<T: ?Sized>(pub(crate) allocator_api2::boxed::Box<T, SwcAlloc>);

impl<T> From<T> for Box<T> {
#[inline(always)]
fn from(v: T) -> Self {
Box::new(v)
}
}

pub trait IntoBox<T>: Sized {
fn boxed(self) -> Box<T>;
}

impl<T, V> IntoBox<T> for V
where
V: Into<T>,
{
#[inline(always)]
fn boxed(self) -> Box<T> {
Box::new(self.into())
}
}

impl<T> Default for Box<T>
where
T: Default,
{
fn default() -> Self {
Box::new(Default::default())
}
}

impl<T> Box<T> {
#[inline(always)]
pub fn new(value: T) -> Self {
Self(allocator_api2::boxed::Box::new_in(value, SwcAlloc))
}

pub fn unbox(self) -> T {
allocator_api2::boxed::Box::into_inner(self.0)
}
}

impl<T: ?Sized> Box<T> {
pub unsafe fn from_raw(raw: *mut T) -> Self {
Self(allocator_api2::boxed::Box::from_raw_in(
raw,
SwcAlloc::default(),
))
}
}

impl<T: ?Sized> AsRef<T> for Box<T> {
fn as_ref(&self) -> &T {
&self.0
}
}

impl<T: ?Sized> AsMut<T> for Box<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}

impl<T: ?Sized> Deref for Box<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}

impl<T: ?Sized> DerefMut for Box<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
Loading
Loading