Skip to content

Commit ef4fd41

Browse files
authored
Integrate gc_arena to aiscript own crates (#18)
* Integrate gc_arena to aiscript own crates * Cargo clippy --fix
1 parent 649b1a0 commit ef4fd41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4275
-65
lines changed

Cargo.lock

Lines changed: 57 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ members = [
33
"aiscript",
44
"aiscript-cli",
55
"aiscript-lexer",
6+
"aiscript-arena",
7+
"aiscript-derived",
68
"aiscript-directive",
79
"aiscript-runtime",
810
"aiscript-vm",

aiscript-arena/Cargo.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "aiscript-arena"
3+
description = "safe, incrementally garbage collected arenas"
4+
version = "0.1.0"
5+
authors.workspace = true
6+
edition.workspace = true
7+
license.workspace = true
8+
readme.workspace = true
9+
repository.workspace = true
10+
11+
[features]
12+
default = ["std"]
13+
std = []
14+
tracing = ["dep:tracing"]
15+
allocator-api2 = ["dep:allocator-api2", "hashbrown?/allocator-api2"]
16+
17+
[dependencies]
18+
allocator-api2 = { version = "0.2", optional = true, default-features = false, features = [
19+
"alloc",
20+
] }
21+
aiscript-derived = { path = "../aiscript-derived", version = "0.1.0" }
22+
hashbrown = { version = "0.14", optional = true, default-features = false }
23+
sptr = "0.3.2"
24+
tracing = { version = "0.1.37", optional = true, default-features = false }
25+
26+
[dev-dependencies]
27+
rand = "0.8"
28+
trybuild = "1.0"
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use std::{alloc::Layout, marker::PhantomData, ptr::NonNull};
2+
3+
use allocator_api2::{
4+
alloc::{AllocError, Allocator, Global},
5+
boxed, vec,
6+
};
7+
8+
use crate::{
9+
collect::Collect,
10+
context::{Collection, Mutation},
11+
metrics::Metrics,
12+
types::Invariant,
13+
};
14+
15+
#[derive(Clone)]
16+
pub struct MetricsAlloc<'gc, A = Global> {
17+
metrics: Metrics,
18+
allocator: A,
19+
_marker: Invariant<'gc>,
20+
}
21+
22+
impl<'gc> MetricsAlloc<'gc> {
23+
#[inline]
24+
pub fn new(mc: &Mutation<'gc>) -> Self {
25+
Self::new_in(mc, Global)
26+
}
27+
28+
/// `MetricsAlloc` is normally branded with the `'gc` branding lifetime to ensure that it is not
29+
/// placed in the wrong arena or used outside of the enclosing arena.
30+
///
31+
/// This is actually completely artificial and only used as a lint: `aiscript_arena::metrics::Metrics`
32+
/// has no lifetime at all. Therefore, we can safely provide a method that returns a
33+
/// `MetricsAlloc` with an arbitrary lifetime.
34+
///
35+
/// NOTE: Use `MetricsAlloc::new` if at all possible, because it is harder to misuse.
36+
#[inline]
37+
pub fn from_metrics(metrics: Metrics) -> Self {
38+
Self::from_metrics_in(metrics, Global)
39+
}
40+
}
41+
42+
impl<'gc, A> MetricsAlloc<'gc, A> {
43+
#[inline]
44+
pub fn new_in(mc: &Mutation<'gc>, allocator: A) -> Self {
45+
Self {
46+
metrics: mc.metrics().clone(),
47+
allocator,
48+
_marker: PhantomData,
49+
}
50+
}
51+
52+
#[inline]
53+
pub fn from_metrics_in(metrics: Metrics, allocator: A) -> Self {
54+
Self {
55+
metrics,
56+
allocator,
57+
_marker: PhantomData,
58+
}
59+
}
60+
}
61+
62+
unsafe impl<A: Allocator> Allocator for MetricsAlloc<'_, A> {
63+
#[inline]
64+
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
65+
let ptr = self.allocator.allocate(layout)?;
66+
self.metrics.mark_external_allocation(layout.size());
67+
Ok(ptr)
68+
}
69+
70+
#[inline]
71+
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe {
72+
self.metrics.mark_external_deallocation(layout.size());
73+
self.allocator.deallocate(ptr, layout);
74+
}}
75+
76+
#[inline]
77+
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
78+
let ptr = self.allocator.allocate_zeroed(layout)?;
79+
self.metrics.mark_external_allocation(layout.size());
80+
Ok(ptr)
81+
}
82+
83+
#[inline]
84+
unsafe fn grow(
85+
&self,
86+
ptr: NonNull<u8>,
87+
old_layout: Layout,
88+
new_layout: Layout,
89+
) -> Result<NonNull<[u8]>, AllocError> { unsafe {
90+
let ptr = self.allocator.grow(ptr, old_layout, new_layout)?;
91+
self.metrics
92+
.mark_external_allocation(new_layout.size() - old_layout.size());
93+
Ok(ptr)
94+
}}
95+
96+
#[inline]
97+
unsafe fn grow_zeroed(
98+
&self,
99+
ptr: NonNull<u8>,
100+
old_layout: Layout,
101+
new_layout: Layout,
102+
) -> Result<NonNull<[u8]>, AllocError> { unsafe {
103+
let ptr = self.allocator.grow_zeroed(ptr, old_layout, new_layout)?;
104+
self.metrics
105+
.mark_external_allocation(new_layout.size() - old_layout.size());
106+
Ok(ptr)
107+
}}
108+
109+
#[inline]
110+
unsafe fn shrink(
111+
&self,
112+
ptr: NonNull<u8>,
113+
old_layout: Layout,
114+
new_layout: Layout,
115+
) -> Result<NonNull<[u8]>, AllocError> { unsafe {
116+
let ptr = self.allocator.shrink(ptr, old_layout, new_layout)?;
117+
self.metrics
118+
.mark_external_deallocation(old_layout.size() - new_layout.size());
119+
Ok(ptr)
120+
}}
121+
}
122+
123+
unsafe impl<A: 'static> Collect for MetricsAlloc<'_, A> {
124+
#[inline]
125+
fn needs_trace() -> bool {
126+
false
127+
}
128+
}
129+
130+
unsafe impl Collect for Global {
131+
#[inline]
132+
fn needs_trace() -> bool {
133+
false
134+
}
135+
}
136+
137+
unsafe impl<T: Collect + ?Sized, A: Collect + Allocator> Collect for boxed::Box<T, A> {
138+
#[inline]
139+
fn trace(&self, cc: &Collection) {
140+
boxed::Box::allocator(self).trace(cc);
141+
(**self).trace(cc)
142+
}
143+
}
144+
145+
unsafe impl<T: Collect, A: Collect + Allocator> Collect for vec::Vec<T, A> {
146+
#[inline]
147+
fn needs_trace() -> bool {
148+
T::needs_trace() || A::needs_trace()
149+
}
150+
151+
#[inline]
152+
fn trace(&self, cc: &Collection) {
153+
self.allocator().trace(cc);
154+
for v in self {
155+
v.trace(cc);
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)