From 7fd85a520f2c41f3262871b640c0bf5ba46467b8 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Tue, 16 Jan 2024 09:06:07 +0100 Subject: [PATCH] feat: try to use boa gc --- Cargo.lock | 88 +++++++++++---- bindings/jsonnet/src/import.rs | 2 +- crates/jrsonnet-evaluator/Cargo.toml | 2 +- crates/jrsonnet-evaluator/src/arr/mod.rs | 14 +-- crates/jrsonnet-evaluator/src/arr/spec.rs | 47 ++++---- crates/jrsonnet-evaluator/src/async_import.rs | 2 +- crates/jrsonnet-evaluator/src/ctx.rs | 14 +-- crates/jrsonnet-evaluator/src/dynamic.rs | 61 ++++++++--- crates/jrsonnet-evaluator/src/error.rs | 12 +- .../src/evaluate/destructure.rs | 20 ++-- crates/jrsonnet-evaluator/src/evaluate/mod.rs | 21 ++-- .../src/function/arglike.rs | 7 +- .../src/function/builtin.rs | 20 ++-- crates/jrsonnet-evaluator/src/function/mod.rs | 19 ++-- .../jrsonnet-evaluator/src/function/parse.rs | 7 +- crates/jrsonnet-evaluator/src/gc.rs | 93 +--------------- crates/jrsonnet-evaluator/src/import.rs | 19 +++- crates/jrsonnet-evaluator/src/lib.rs | 80 ++++++++------ crates/jrsonnet-evaluator/src/map.rs | 15 ++- crates/jrsonnet-evaluator/src/obj.rs | 103 ++++++++++-------- .../jrsonnet-evaluator/src/stdlib/format.rs | 4 +- crates/jrsonnet-evaluator/src/trace/mod.rs | 10 +- .../src/typed/conversions.rs | 16 +-- crates/jrsonnet-evaluator/src/typed/mod.rs | 16 +-- crates/jrsonnet-evaluator/src/val.rs | 53 ++++----- crates/jrsonnet-interner/Cargo.toml | 2 +- crates/jrsonnet-interner/src/lib.rs | 18 +-- crates/jrsonnet-macros/src/lib.rs | 6 +- crates/jrsonnet-parser/Cargo.toml | 2 +- crates/jrsonnet-parser/src/expr.rs | 77 ++++++++----- crates/jrsonnet-parser/src/source.rs | 41 ++----- crates/jrsonnet-stdlib/Cargo.toml | 2 +- crates/jrsonnet-stdlib/src/lib.rs | 20 ++-- crates/jrsonnet-stdlib/src/misc.rs | 7 +- crates/jrsonnet-types/Cargo.toml | 2 +- crates/jrsonnet-types/src/lib.rs | 9 +- flake.lock | 18 +-- flake.nix | 2 +- nix/jrsonnet.nix | 4 + 39 files changed, 498 insertions(+), 457 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24f86ed6..266e9649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,6 +192,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "boa_gc" +version = "0.17.0" +source = "git+https://github.com/boa-dev/boa#ee4d6495ab405fe6d19b7166ef428361a6eff855" +dependencies = [ + "boa_macros", + "boa_profiler", + "hashbrown 0.14.3", +] + +[[package]] +name = "boa_macros" +version = "0.17.0" +source = "git+https://github.com/boa-dev/boa#ee4d6495ab405fe6d19b7166ef428361a6eff855" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", + "synstructure", +] + +[[package]] +name = "boa_profiler" +version = "0.17.0" +source = "git+https://github.com/boa-dev/boa#ee4d6495ab405fe6d19b7166ef428361a6eff855" + [[package]] name = "bumpalo" version = "3.14.0" @@ -253,7 +279,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -297,9 +323,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" dependencies = [ "cfg-if", "crossbeam-utils", @@ -307,9 +333,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -606,9 +632,9 @@ dependencies = [ "annotate-snippets", "anyhow", "bincode", + "boa_gc", "derivative", "hashbrown 0.14.3", - "jrsonnet-gcmodule", "jrsonnet-interner", "jrsonnet-macros", "jrsonnet-parser", @@ -661,8 +687,8 @@ dependencies = [ name = "jrsonnet-interner" version = "0.5.0-pre95" dependencies = [ + "boa_gc", "hashbrown 0.14.3", - "jrsonnet-gcmodule", "rustc-hash", "serde", "structdump", @@ -687,14 +713,14 @@ version = "0.5.0-pre95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] name = "jrsonnet-parser" version = "0.5.0-pre95" dependencies = [ - "jrsonnet-gcmodule", + "boa_gc", "jrsonnet-interner", "peg", "serde", @@ -723,8 +749,8 @@ version = "0.5.0-pre95" dependencies = [ "base64", "bincode", + "boa_gc", "jrsonnet-evaluator", - "jrsonnet-gcmodule", "jrsonnet-macros", "jrsonnet-parser", "lru", @@ -745,7 +771,7 @@ dependencies = [ name = "jrsonnet-types" version = "0.5.0-pre95" dependencies = [ - "jrsonnet-gcmodule", + "boa_gc", "peg", ] @@ -915,7 +941,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1294,7 +1320,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1316,7 +1342,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1456,15 +1482,27 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.8.1" @@ -1532,7 +1570,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1595,6 +1633,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "url" version = "2.5.0" @@ -1899,20 +1943,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] diff --git a/bindings/jsonnet/src/import.rs b/bindings/jsonnet/src/import.rs index 72bd3e7a..e0c3ab71 100644 --- a/bindings/jsonnet/src/import.rs +++ b/bindings/jsonnet/src/import.rs @@ -17,7 +17,7 @@ use jrsonnet_evaluator::{ error::{ErrorKind::*, Result}, FileImportResolver, ImportResolver, }; -use jrsonnet_gcmodule::Trace; +use boa_gc::Trace; use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath}; use crate::VM; diff --git a/crates/jrsonnet-evaluator/Cargo.toml b/crates/jrsonnet-evaluator/Cargo.toml index 9c350b07..0fde9a7d 100644 --- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -35,7 +35,6 @@ jrsonnet-interner.workspace = true jrsonnet-parser.workspace = true jrsonnet-types.workspace = true jrsonnet-macros.workspace = true -jrsonnet-gcmodule.workspace = true pathdiff.workspace = true hashbrown.workspace = true @@ -57,3 +56,4 @@ annotate-snippets = { workspace = true, features = ["color"], optional = true } # Bigint num-bigint = { workspace = true, features = ["serde"], optional = true } derivative.workspace = true +boa_gc = { git = "https://github.com/boa-dev/boa", version = "0.17.0" } diff --git a/crates/jrsonnet-evaluator/src/arr/mod.rs b/crates/jrsonnet-evaluator/src/arr/mod.rs index 0c685d7a..fa004c00 100644 --- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -1,20 +1,20 @@ use std::any::Any; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Gc, Trace, Finalize, GcBox}; use jrsonnet_interner::IBytes; use jrsonnet_parser::LocExpr; -use crate::{function::FuncVal, gc::TraceBox, tb, Context, Result, Thunk, Val}; +use crate::{DynGcBox, dyn_gc_box}; +use crate::{function::FuncVal, Context, Result, Thunk, Val}; mod spec; pub use spec::ArrayLike; pub(crate) use spec::*; /// Represents a Jsonnet array value. -#[derive(Debug, Clone, Trace)] +#[derive(Debug, Clone, Trace, Finalize)] // may contrain other ArrValue -#[trace(tracking(force))] -pub struct ArrValue(Cc>); +pub struct ArrValue(DynGcBox); pub trait ArrayLikeIter: Iterator + DoubleEndedIterator + ExactSizeIterator {} impl ArrayLikeIter for I where @@ -24,7 +24,7 @@ impl ArrayLikeIter for I where impl ArrValue { pub fn new(v: impl ArrayLike) -> Self { - Self(Cc::new(tb!(v))) + Self(dyn_gc_box!(v)) } pub fn empty() -> Self { Self::new(RangeArray::empty()) @@ -177,7 +177,7 @@ impl ArrValue { } pub fn ptr_eq(a: &Self, b: &Self) -> bool { - Cc::ptr_eq(&a.0, &b.0) + Gc::ptr_eq(&a.0, &b.0) } /// Is this vec supports `.get_cheap()?` diff --git a/crates/jrsonnet-evaluator/src/arr/spec.rs b/crates/jrsonnet-evaluator/src/arr/spec.rs index 6b367d6c..a43a8437 100644 --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -1,6 +1,6 @@ use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace}; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Finalize, Gc, GcRefCell, Trace}; use jrsonnet_interner::{IBytes, IStr}; use jrsonnet_parser::LocExpr; @@ -22,7 +22,7 @@ pub trait ArrayLike: Any + Trace + Debug { fn is_cheap(&self) -> bool; } -#[derive(Debug, Trace)] +#[derive(Debug, Trace, Finalize)] pub struct SliceArray { pub(crate) inner: ArrValue, pub(crate) from: u32, @@ -81,7 +81,7 @@ impl ArrayLike for SliceArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct CharArray(pub Vec); impl ArrayLike for CharArray { fn len(&self) -> usize { @@ -104,7 +104,7 @@ impl ArrayLike for CharArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct BytesArray(pub IBytes); impl ArrayLike for BytesArray { fn len(&self) -> usize { @@ -127,7 +127,8 @@ impl ArrayLike for BytesArray { } } -#[derive(Debug, Trace, Clone)] +#[derive(Debug, Trace, Clone, Finalize)] +#[boa_gc(unsafe_no_drop)] enum ArrayThunk { Computed(Val), Errored(Error), @@ -135,18 +136,16 @@ enum ArrayThunk { Pending, } -#[derive(Debug, Trace, Clone)] +#[derive(Debug, Trace, Finalize, Clone)] pub struct ExprArray { ctx: Context, - cached: Cc>>>, + cached: GcRefCell>>, } impl ExprArray { pub fn new(ctx: Context, items: impl IntoIterator) -> Self { Self { ctx, - cached: Cc::new(RefCell::new( - items.into_iter().map(ArrayThunk::Waiting).collect(), - )), + cached: GcRefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()), } } } @@ -182,7 +181,8 @@ impl ArrayLike for ExprArray { Ok(Some(new_value)) } fn get_lazy(&self, index: usize) -> Option> { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct ArrayElement { arr_thunk: ExprArray, index: usize, @@ -221,7 +221,7 @@ impl ArrayLike for ExprArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct ExtendedArray { pub a: ArrValue, pub b: ArrValue, @@ -309,7 +309,7 @@ impl ArrayLike for ExtendedArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct LazyArray(pub Vec>); impl ArrayLike for LazyArray { fn len(&self) -> usize { @@ -332,7 +332,7 @@ impl ArrayLike for LazyArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct EagerArray(pub Vec); impl ArrayLike for EagerArray { fn len(&self) -> usize { @@ -356,7 +356,7 @@ impl ArrayLike for EagerArray { } /// Inclusive range type -#[derive(Debug, Trace, PartialEq, Eq)] +#[derive(Debug, Trace, Finalize, PartialEq, Eq)] pub struct RangeArray { start: i32, end: i32, @@ -406,7 +406,7 @@ impl ArrayLike for RangeArray { } } -#[derive(Debug, Trace)] +#[derive(Debug, Trace, Finalize)] pub struct ReverseArray(pub ArrValue); impl ArrayLike for ReverseArray { fn len(&self) -> usize { @@ -429,10 +429,10 @@ impl ArrayLike for ReverseArray { } } -#[derive(Trace, Debug, Clone)] +#[derive(Trace, Finalize, Debug, Clone)] pub struct MappedArray { inner: ArrValue, - cached: Cc>>>, + cached: GcRefCell>>, mapper: FuncVal, } impl MappedArray { @@ -440,7 +440,7 @@ impl MappedArray { let len = inner.len(); Self { inner, - cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])), + cached: GcRefCell::new(vec![ArrayThunk::Waiting(()); len]), mapper, } } @@ -485,7 +485,8 @@ impl ArrayLike for MappedArray { Ok(Some(new_value)) } fn get_lazy(&self, index: usize) -> Option> { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct ArrayElement { arr_thunk: MappedArray, index: usize, @@ -525,7 +526,7 @@ impl ArrayLike for MappedArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct RepeatedArray { data: ArrValue, repeats: usize, @@ -572,7 +573,7 @@ impl ArrayLike for RepeatedArray { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct PickObjectValues { obj: ObjValue, keys: Vec, @@ -612,7 +613,7 @@ impl ArrayLike for PickObjectValues { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] pub struct PickObjectKeyValues { obj: ObjValue, keys: Vec, diff --git a/crates/jrsonnet-evaluator/src/async_import.rs b/crates/jrsonnet-evaluator/src/async_import.rs index d12dc4fb..615b8fab 100644 --- a/crates/jrsonnet-evaluator/src/async_import.rs +++ b/crates/jrsonnet-evaluator/src/async_import.rs @@ -250,7 +250,7 @@ pub trait AsyncImportResolver { ) -> impl Future, Self::Error>>; } -#[derive(Trace)] +#[derive(Trace, Finalize)] struct ResolvedImportResolver { resolved: RefCell>, } diff --git a/crates/jrsonnet-evaluator/src/ctx.rs b/crates/jrsonnet-evaluator/src/ctx.rs index ab4b81cd..29615157 100644 --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Gc, Trace, Finalize}; use jrsonnet_interner::IStr; use crate::{ @@ -8,7 +8,7 @@ use crate::{ Thunk, Val, }; -#[derive(Trace)] +#[derive(Trace, Finalize)] struct ContextInternals { state: Option, dollar: Option, @@ -25,8 +25,8 @@ impl Debug for ContextInternals { /// Context keeps information about current lexical code location /// /// This information includes local variables, top-level object (`$`), current object (`this`), and super object (`super`) -#[derive(Debug, Clone, Trace)] -pub struct Context(Cc); +#[derive(Debug, Clone, Trace, Finalize)] +pub struct Context(Gc); impl Context { pub fn new_future() -> Pending { Pending::new() @@ -110,7 +110,7 @@ impl Context { } else { ctx.bindings.clone().extend(new_bindings) }; - Self(Cc::new(ContextInternals { + Self(Gc::new(ContextInternals { state: ctx.state.clone(), dollar, sup, @@ -122,7 +122,7 @@ impl Context { impl PartialEq for Context { fn eq(&self, other: &Self) -> bool { - Cc::ptr_eq(&self.0, &other.0) + Gc::ptr_eq(&self.0, &other.0) } } @@ -171,7 +171,7 @@ impl ContextBuilder { // TODO: replace self.extend with Result, and remove `state` field parent.extend(self.bindings, None, None, None) } else { - Context(Cc::new(ContextInternals { + Context(Gc::new(ContextInternals { state: self.state, bindings: LayeredHashMap::new(self.bindings), dollar: None, diff --git a/crates/jrsonnet-evaluator/src/dynamic.rs b/crates/jrsonnet-evaluator/src/dynamic.rs index 641fc8d9..39ef8cf8 100644 --- a/crates/jrsonnet-evaluator/src/dynamic.rs +++ b/crates/jrsonnet-evaluator/src/dynamic.rs @@ -1,38 +1,35 @@ -use std::cell::OnceCell; +use std::{cell::OnceCell, ops::Deref}; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Finalize, Gc, GcRefCell, Trace}; +use derivative::Derivative; use crate::{bail, error::ErrorKind::InfiniteRecursionDetected, val::ThunkValue, Result}; -// TODO: Replace with OnceCell once in std -#[derive(Clone, Trace)] -pub struct Pending(pub Cc>); +// TODO: Replace with OnceCell +#[derive(Clone, Trace, Finalize)] +pub struct Pending(pub Gc>>); impl Pending { pub fn new() -> Self { - Self(Cc::new(OnceCell::new())) + Self(Gc::new(GcRefCell::new(None))) } pub fn new_filled(v: T) -> Self { - let cell = OnceCell::new(); - let _ = cell.set(v); - Self(Cc::new(cell)) + Self(Gc::new(GcRefCell::new(Some(v)))) } /// # Panics /// If wrapper is filled already pub fn fill(self, value: T) { - self.0 - .set(value) - .map_err(|_| ()) - .expect("wrapper is filled already"); + // TODO: Panic if set + *self.0.borrow_mut() = Some(value); } } impl Pending { /// # Panics /// If wrapper is not yet filled pub fn unwrap(&self) -> T { - self.0.get().cloned().expect("pending was not filled") + self.0.borrow().clone().expect("pending was not filled") } pub fn try_get(&self) -> Option { - self.0.get().cloned() + self.0.borrow().clone() } } @@ -40,7 +37,8 @@ impl ThunkValue for Pending { type Output = T; fn get(self: Box) -> Result { - let Some(value) = self.0.get() else { + let v = self.0.borrow(); + let Some(value) = &*v else { bail!(InfiniteRecursionDetected); }; Ok(value.clone()) @@ -52,3 +50,34 @@ impl Default for Pending { Self::new() } } + +#[derive(Trace, Finalize, Derivative)] +#[derivative(Debug)] +pub struct DynGcBox(Gc>); +impl DynGcBox { + #[doc(hidden)] + pub fn wrap(v: Gc>) -> Self { + Self(v) + } + pub fn value(&self) -> &T { + &self.0 + } +} +impl Clone for DynGcBox { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +#[macro_export] +macro_rules! dyn_gc_box { + ($t:expr) => { + $crate::dynamic::DynGcBox::wrap(boa_gc::Gc::new(Box::new($t))) + }; +} + +impl Deref for DynGcBox { + type Target = Gc>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/crates/jrsonnet-evaluator/src/error.rs b/crates/jrsonnet-evaluator/src/error.rs index 50ee1cf0..ecea337d 100644 --- a/crates/jrsonnet-evaluator/src/error.rs +++ b/crates/jrsonnet-evaluator/src/error.rs @@ -4,7 +4,7 @@ use std::{ path::PathBuf, }; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use jrsonnet_interner::IStr; use jrsonnet_parser::{BinaryOpType, ExprLocation, LocExpr, Source, SourcePath, UnaryOpType}; use jrsonnet_types::ValType; @@ -92,8 +92,9 @@ type FunctionSignature = Vec<(Option, bool)>; /// Possible errors #[allow(missing_docs)] -#[derive(Error, Debug, Clone, Trace)] +#[derive(Error, Debug, Clone, Trace, Finalize)] #[non_exhaustive] +#[boa_gc(unsafe_empty_trace)] pub enum ErrorKind { #[error("intrinsic not found: {0}")] IntrinsicNotFound(IStr), @@ -194,7 +195,6 @@ pub enum ErrorKind { )] ImportSyntaxError { path: Source, - #[trace(skip)] error: Box, }, @@ -250,7 +250,7 @@ impl From for Error { } /// Single stack trace frame -#[derive(Clone, Debug, Trace)] +#[derive(Clone, Debug, Trace, Finalize)] pub struct StackTraceElement { /// Source of this frame /// Some frames only act as description, without attached source @@ -258,10 +258,10 @@ pub struct StackTraceElement { /// Frame description pub desc: String, } -#[derive(Debug, Clone, Trace)] +#[derive(Debug, Clone, Trace, Finalize)] pub struct StackTrace(pub Vec); -#[derive(Clone, Trace)] +#[derive(Clone, Trace, Finalize)] pub struct Error(Box<(ErrorKind, StackTrace)>); impl Error { pub fn new(e: ErrorKind) -> Self { diff --git a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs index f3e90db0..df998dbb 100644 --- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs @@ -1,4 +1,4 @@ -use jrsonnet_gcmodule::Trace; +use boa_gc::{Finalize, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{BindSpec, Destruct, LocExpr, ParamsDesc}; @@ -34,7 +34,7 @@ pub fn destruct( use crate::arr::ArrValue; - #[derive(Trace)] + #[derive(Trace, Finalize)] struct DataThunk { parent: Thunk, min_len: usize, @@ -70,7 +70,7 @@ pub fn destruct( }); { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct BaseThunk { full: Thunk, index: usize, @@ -98,7 +98,7 @@ pub fn destruct( match rest { Some(DestructRest::Keep(v)) => { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct RestThunk { full: Thunk, start: usize, @@ -132,7 +132,7 @@ pub fn destruct( } { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct EndThunk { full: Thunk, index: usize, @@ -166,7 +166,7 @@ pub fn destruct( Destruct::Object { fields, rest } => { use crate::obj::ObjValue; - #[derive(Trace)] + #[derive(Trace, Finalize)] struct DataThunk { parent: Thunk, field_names: Vec, @@ -206,7 +206,7 @@ pub fn destruct( }); for (field, d, default) in fields { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct FieldThunk { full: Thunk, field: IStr, @@ -253,7 +253,8 @@ pub fn evaluate_dest( ) -> Result<()> { match d { BindSpec::Field { into, value } => { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct EvaluateThunkValue { name: Option, fctx: Pending, @@ -280,7 +281,8 @@ pub fn evaluate_dest( params, value, } => { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct MethodThunk { fctx: Pending, name: IStr, diff --git a/crates/jrsonnet-evaluator/src/evaluate/mod.rs b/crates/jrsonnet-evaluator/src/evaluate/mod.rs index cddb00ba..d8e6ef42 100644 --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Finalize, Gc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, FieldMember, FieldName, ForSpecData, @@ -58,7 +58,7 @@ pub fn evaluate_trivial(expr: &LocExpr) -> Option { } pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val { - Val::Func(FuncVal::Normal(Cc::new(FuncDesc { + Val::Func(FuncVal::Normal(Gc::new(FuncDesc { name, ctx, params, @@ -117,7 +117,7 @@ pub fn evaluate_comp( #[cfg(feature = "exp-preserve-order")] false, ) { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct ObjectFieldThunk { obj: ObjValue, field: IStr, @@ -163,9 +163,10 @@ fn evaluate_object_locals( fctx: Pending, locals: Rc>, ) -> impl CloneableUnbound { - #[derive(Trace, Clone)] + #[derive(Trace, Finalize, Clone)] struct UnboundLocals { fctx: Pending, + #[unsafe_ignore_trace] locals: Rc>, } impl Unbound for UnboundLocals { @@ -212,7 +213,7 @@ pub fn evaluate_field_member + Clone>( value, .. } => { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct UnboundValue { uctx: B, value: LocExpr, @@ -242,7 +243,7 @@ pub fn evaluate_field_member + Clone>( value, .. } => { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct UnboundMethod { uctx: B, value: LocExpr, @@ -300,7 +301,7 @@ pub fn evaluate_member_list_object(ctx: Context, members: &[Member]) -> Result { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct ObjectAssert { uctx: B, assert: AssertStmt, @@ -574,7 +575,8 @@ pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result { if items.is_empty() { Val::Arr(ArrValue::empty()) } else if items.len() == 1 { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct ArrayElement { ctx: Context, item: LocExpr, @@ -596,7 +598,8 @@ pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result { ArrComp(expr, comp_specs) => { let mut out = Vec::new(); evaluate_comp(ctx, comp_specs, &mut |ctx| { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct EvaluateThunk { ctx: Context, expr: LocExpr, diff --git a/crates/jrsonnet-evaluator/src/function/arglike.rs b/crates/jrsonnet-evaluator/src/function/arglike.rs index a102169d..e7b7dc32 100644 --- a/crates/jrsonnet-evaluator/src/function/arglike.rs +++ b/crates/jrsonnet-evaluator/src/function/arglike.rs @@ -1,5 +1,5 @@ use hashbrown::HashMap; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, LocExpr}; @@ -8,7 +8,8 @@ use crate::{evaluate, gc::GcHashMap, typed::Typed, val::ThunkValue, Context, Res /// Marker for arguments, which can be evaluated with context set to None pub trait OptionalContext {} -#[derive(Trace)] +#[derive(Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] struct EvaluateThunk { ctx: Context, expr: LocExpr, @@ -51,7 +52,7 @@ where } impl OptionalContext for T where T: Typed + Clone {} -#[derive(Clone, Trace)] +#[derive(Clone, Trace, Finalize)] pub enum TlaArg { String(IStr), Code(LocExpr), diff --git a/crates/jrsonnet-evaluator/src/function/builtin.rs b/crates/jrsonnet-evaluator/src/function/builtin.rs index 3656e7c3..3cbdd1f3 100644 --- a/crates/jrsonnet-evaluator/src/function/builtin.rs +++ b/crates/jrsonnet-evaluator/src/function/builtin.rs @@ -1,15 +1,15 @@ use std::{any::Any, borrow::Cow}; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Finalize, GcBox, Trace}; use jrsonnet_interner::IStr; use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation}; -use crate::{gc::TraceBox, tb, Context, Result, Val}; +use crate::{dyn_gc_box, Context, DynGcBox, Result, Val}; /// Can't have str | IStr, because constant BuiltinParam causes /// E0492: constant functions cannot refer to interior mutable data -#[derive(Clone, Trace)] -pub struct ParamName(Option>); +#[derive(Clone, Trace, Finalize)] +pub struct ParamName(#[unsafe_ignore_trace] Option>); impl ParamName { pub const ANONYMOUS: Self = Self(None); pub const fn new_static(name: &'static str) -> Self { @@ -34,7 +34,7 @@ impl PartialEq for ParamName { } } -#[derive(Clone, Trace)] +#[derive(Clone, Trace, Finalize)] pub struct BuiltinParam { name: ParamName, has_default: bool, @@ -56,7 +56,7 @@ impl BuiltinParam { /// Description of function defined by native code /// /// Prefer to use #[builtin] macro, instead of manual implementation of this trait -pub trait Builtin: Trace { +pub trait Builtin: Trace + 'static { /// Function name to be used in stack traces fn name(&self) -> &str; /// Parameter names for named calls @@ -75,10 +75,10 @@ where // const INST: &'static Self; } -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct NativeCallback { pub(crate) params: Vec, - handler: TraceBox, + handler: DynGcBox, } impl NativeCallback { #[deprecated = "prefer using builtins directly, use this interface only for bindings"] @@ -91,7 +91,7 @@ impl NativeCallback { has_default: false, }) .collect(), - handler: tb!(handler), + handler: dyn_gc_box!(handler), } } } @@ -122,6 +122,6 @@ impl Builtin for NativeCallback { } } -pub trait NativeCallbackHandler: Trace { +pub trait NativeCallbackHandler: Trace + 'static { fn call(&self, args: &[Val]) -> Result; } diff --git a/crates/jrsonnet-evaluator/src/function/mod.rs b/crates/jrsonnet-evaluator/src/function/mod.rs index 1a8732e5..dc31d9ae 100644 --- a/crates/jrsonnet-evaluator/src/function/mod.rs +++ b/crates/jrsonnet-evaluator/src/function/mod.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; pub use arglike::{ArgLike, ArgsLike, TlaArg}; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Finalize, Gc, GcBox, Trace}; use jrsonnet_interner::IStr; pub use jrsonnet_macros::builtin; use jrsonnet_parser::{Destruct, Expr, ExprLocation, LocExpr, ParamsDesc}; @@ -12,7 +12,9 @@ use self::{ native::NativeDesc, parse::{parse_default_function_call, parse_function_call}, }; -use crate::{evaluate, evaluate_trivial, gc::TraceBox, tb, Context, ContextBuilder, Result, Val}; +use crate::{ + dyn_gc_box, evaluate, evaluate_trivial, Context, ContextBuilder, DynGcBox, Result, Val, +}; pub mod arglike; pub mod builtin; @@ -37,7 +39,7 @@ impl CallLocation<'static> { } /// Represents Jsonnet function defined in code. -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct FuncDesc { /// # Example /// @@ -88,16 +90,17 @@ impl FuncDesc { /// Represents a Jsonnet function value, including plain functions and user-provided builtins. #[allow(clippy::module_name_repetitions)] -#[derive(Trace, Clone)] +#[derive(Trace, Clone, Finalize)] +#[boa_gc(unsafe_no_drop)] pub enum FuncVal { /// Identity function, kept this way for comparsions. Id, /// Plain function implemented in jsonnet. - Normal(Cc), + Normal(Gc), /// Standard library function. - StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin), + StaticBuiltin(#[boa_gc(unsafe_ignore_trace)] &'static dyn StaticBuiltin), /// User-provided function. - Builtin(Cc>), + Builtin(DynGcBox), } impl Debug for FuncVal { @@ -122,7 +125,7 @@ static ID: &builtin_id = &builtin_id {}; impl FuncVal { pub fn builtin(builtin: impl Builtin) -> Self { - Self::Builtin(Cc::new(tb!(builtin))) + Self::Builtin(dyn_gc_box!(builtin)) } pub fn static_builtin(static_builtin: &'static dyn StaticBuiltin) -> Self { Self::StaticBuiltin(static_builtin) diff --git a/crates/jrsonnet-evaluator/src/function/parse.rs b/crates/jrsonnet-evaluator/src/function/parse.rs index 86e297d2..bf1800e4 100644 --- a/crates/jrsonnet-evaluator/src/function/parse.rs +++ b/crates/jrsonnet-evaluator/src/function/parse.rs @@ -1,6 +1,6 @@ use std::mem::replace; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Finalize, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{LocExpr, ParamsDesc}; @@ -15,7 +15,8 @@ use crate::{ Context, Pending, Thunk, Val, }; -#[derive(Trace)] +#[derive(Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] struct EvaluateNamedThunk { ctx: Pending, name: IStr, @@ -225,7 +226,7 @@ pub fn parse_builtin_call( /// Creates Context, which has all argument default values applied /// and with unbound values causing error to be returned pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Result { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct DependsOnUnbound(IStr, ParamsDesc); impl ThunkValue for DependsOnUnbound { type Output = Val; diff --git a/crates/jrsonnet-evaluator/src/gc.rs b/crates/jrsonnet-evaluator/src/gc.rs index 9f949087..7d9e1045 100644 --- a/crates/jrsonnet-evaluator/src/gc.rs +++ b/crates/jrsonnet-evaluator/src/gc.rs @@ -6,76 +6,11 @@ use std::{ ops::{Deref, DerefMut}, }; +use boa_gc::{Finalize, Trace, Tracer}; use hashbrown::HashMap; -use jrsonnet_gcmodule::{Trace, Tracer}; use rustc_hash::{FxHashSet, FxHasher}; -/// Replacement for box, which assumes that the underlying type is [`Trace`] -/// Used in places, where `Cc` should be used instead, but it can't, because `CoerceUnsiced` is not stable -#[derive(Debug, Clone)] -pub struct TraceBox(pub Box); -#[macro_export] -macro_rules! tb { - ($v:expr) => { - $crate::gc::TraceBox(Box::new($v)) - }; -} - -impl Trace for TraceBox { - fn trace(&self, tracer: &mut Tracer<'_>) { - self.0.trace(tracer); - } - - fn is_type_tracked() -> bool { - true - } -} - -// TODO: Replace with CoerceUnsized -impl From> for TraceBox { - fn from(inner: Box) -> Self { - Self(inner) - } -} - -impl Deref for TraceBox { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for TraceBox { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Borrow for TraceBox { - fn borrow(&self) -> &T { - &self.0 - } -} - -impl BorrowMut for TraceBox { - fn borrow_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -impl AsRef for TraceBox { - fn as_ref(&self) -> &T { - &self.0 - } -} - -impl AsMut for TraceBox { - fn as_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -#[derive(Clone)] +#[derive(Clone, Trace, Finalize)] pub struct GcHashSet(pub FxHashSet); impl GcHashSet { pub fn new() -> Self { @@ -88,16 +23,6 @@ impl GcHashSet { )) } } -impl Trace for GcHashSet -where - V: Trace, -{ - fn trace(&self, tracer: &mut Tracer<'_>) { - for v in &self.0 { - v.trace(tracer); - } - } -} impl Deref for GcHashSet { type Target = FxHashSet; @@ -116,7 +41,7 @@ impl Default for GcHashSet { } } -#[derive(Debug)] +#[derive(Debug, Trace, Finalize)] pub struct GcHashMap(pub HashMap>); impl GcHashMap { pub fn new() -> Self { @@ -129,18 +54,6 @@ impl GcHashMap { )) } } -impl Trace for GcHashMap -where - K: Trace, - V: Trace, -{ - fn trace(&self, tracer: &mut Tracer<'_>) { - for (k, v) in &self.0 { - k.trace(tracer); - v.trace(tracer); - } - } -} impl Deref for GcHashMap { type Target = HashMap>; diff --git a/crates/jrsonnet-evaluator/src/import.rs b/crates/jrsonnet-evaluator/src/import.rs index ce95fa21..039a8c43 100644 --- a/crates/jrsonnet-evaluator/src/import.rs +++ b/crates/jrsonnet-evaluator/src/import.rs @@ -7,17 +7,18 @@ use std::{ path::{Path, PathBuf}, }; +use boa_gc::{Finalize, Trace}; use fs::File; -use jrsonnet_gcmodule::Trace; use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath}; use crate::{ bail, error::{ErrorKind::*, Result}, + DynGcBox, }; /// Implements file resolution logic for `import` and `importStr` -pub trait ImportResolver: Trace { +pub trait ImportResolver: Trace + 'static { /// Resolves file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet` /// where `${vendor}` is a library path. @@ -43,9 +44,18 @@ pub trait ImportResolver: Trace { /// For downcasts fn as_any(&self) -> &dyn Any; } +impl ImportResolver for DynGcBox { + fn load_file_contents(&self, resolved: &SourcePath) -> Result> { + self.value().load_file_contents(resolved) + } + + fn as_any(&self) -> &dyn Any { + self.value().as_any() + } +} /// Dummy resolver, can't resolve/load any file -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct DummyImportResolver; impl ImportResolver for DummyImportResolver { fn load_file_contents(&self, _resolved: &SourcePath) -> Result> { @@ -64,10 +74,11 @@ impl Default for Box { } /// File resolver, can load file from both FS and library paths -#[derive(Default, Trace)] +#[derive(Default, Trace, Finalize)] pub struct FileImportResolver { /// Library directories to search for file. /// Referred to as `jpath` in original jsonnet implementation. + #[unsafe_ignore_trace] library_paths: RefCell>, } impl FileImportResolver { diff --git a/crates/jrsonnet-evaluator/src/lib.rs b/crates/jrsonnet-evaluator/src/lib.rs index ce0692fa..2f3a283a 100644 --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -54,7 +54,7 @@ mod arr; #[cfg(feature = "async-import")] pub mod async_import; mod ctx; -mod dynamic; +pub mod dynamic; pub mod error; mod evaluate; pub mod function; @@ -78,15 +78,15 @@ use std::{ path::Path, }; +use boa_gc::{Finalize, Gc, GcBox, GcRef, GcRefCell, GcRefMut, Trace}; pub use ctx::*; pub use dynamic::*; pub use error::{Error, ErrorKind::*, Result, ResultExt}; pub use evaluate::*; use function::CallLocation; -use gc::{GcHashMap, TraceBox}; +use gc::GcHashMap; use hashbrown::hash_map::RawEntryMut; pub use import::*; -use jrsonnet_gcmodule::{Cc, Trace}; pub use jrsonnet_interner::{IBytes, IStr}; #[doc(hidden)] pub use jrsonnet_macros; @@ -99,7 +99,7 @@ pub use val::{Thunk, Val}; /// Thunk without bound `super`/`this` /// object inheritance may be overriden multiple times, and will be fixed only on field read -pub trait Unbound: Trace { +pub trait Unbound: Trace + 'static { /// Type of value after object context is bound type Bound; /// Create value bound to specified object context @@ -108,10 +108,10 @@ pub trait Unbound: Trace { /// Object fields may, or may not depend on `this`/`super`, this enum allows cheaper reuse of object-independent fields for native code /// Standard jsonnet fields are always unbound -#[derive(Clone, Trace)] +#[derive(Clone, Trace, Finalize)] pub enum MaybeUnbound { /// Value needs to be bound to `this`/`super` - Unbound(Cc>>), + Unbound(DynGcBox>), /// Value is object-independent Bound(Thunk), } @@ -133,7 +133,7 @@ impl MaybeUnbound { /// During import, this trait will be called to create initial context for file. /// It may initialize global variables, stdlib for example. -pub trait ContextInitializer: Trace { +pub trait ContextInitializer: Trace + 'static { /// For which size the builder should be preallocated fn reserve_vars(&self) -> usize { 0 @@ -154,6 +154,16 @@ pub trait ContextInitializer: Trace { fn as_any(&self) -> &dyn Any; } +impl ContextInitializer for DynGcBox { + fn populate(&self, for_file: Source, builder: &mut ContextBuilder) { + self.value().populate(for_file, builder) + } + + fn as_any(&self) -> &dyn Any { + self.value().as_any() + } +} + /// Context initializer which adds nothing. impl ContextInitializer for () { fn populate(&self, _for_file: Source, _builder: &mut ContextBuilder) {} @@ -194,24 +204,24 @@ impl_context_initializer! { } /// Dynamically reconfigurable evaluation settings -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct EvaluationSettings { /// Context initializer, which will be used for imports and everything /// [`NoopContextInitializer`] is used by default, most likely you want to have `jrsonnet-stdlib` - pub context_initializer: TraceBox, + pub context_initializer: DynGcBox, /// Used to resolve file locations/contents - pub import_resolver: TraceBox, + pub import_resolver: DynGcBox, } impl Default for EvaluationSettings { fn default() -> Self { Self { - context_initializer: tb!(()), - import_resolver: tb!(DummyImportResolver), + context_initializer: dyn_gc_box!(()), + import_resolver: dyn_gc_box!(DummyImportResolver), } } } -#[derive(Trace)] +#[derive(Trace, Finalize)] struct FileData { string: Option, bytes: Option, @@ -253,17 +263,17 @@ impl FileData { } } -#[derive(Default, Trace)] +#[derive(Default, Trace, Finalize)] pub struct EvaluationStateInternals { /// Internal state - file_cache: RefCell>, + file_cache: GcRefCell>, /// Settings, safe to change at runtime - settings: RefCell, + settings: GcRefCell, } /// Maintains stack trace and import resolution -#[derive(Default, Clone, Trace)] -pub struct State(Cc); +#[derive(Default, Clone, Trace, Finalize)] +pub struct State(Gc); impl State { /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise @@ -452,20 +462,20 @@ impl State { /// Internals impl State { - fn file_cache(&self) -> RefMut<'_, GcHashMap> { + fn file_cache(&self) -> GcRefMut<'_, GcHashMap> { self.0.file_cache.borrow_mut() } - pub fn settings(&self) -> Ref<'_, EvaluationSettings> { + pub fn settings(&self) -> GcRef<'_, EvaluationSettings> { self.0.settings.borrow() } - pub fn settings_mut(&self) -> RefMut<'_, EvaluationSettings> { + pub fn settings_mut(&self) -> GcRefMut<'_, EvaluationSettings> { self.0.settings.borrow_mut() } pub fn add_global(&self, name: IStr, value: Thunk) { - #[derive(Trace)] + #[derive(Trace, Finalize)] struct GlobalsCtx { - globals: RefCell>>, - inner: TraceBox, + globals: GcRefCell>>, + inner: DynGcBox, } impl ContextInitializer for GlobalsCtx { fn reserve_vars(&self) -> usize { @@ -487,20 +497,20 @@ impl State { if let Some(global) = initializer.as_any().downcast_ref::() { global.globals.borrow_mut().insert(name, value); } else { - let inner = std::mem::replace(&mut settings.context_initializer, tb!(())); - settings.context_initializer = tb!(GlobalsCtx { + let inner = std::mem::replace(&mut settings.context_initializer, dyn_gc_box!(())); + settings.context_initializer = dyn_gc_box!(GlobalsCtx { globals: { let mut out = GcHashMap::with_capacity(1); out.insert(name, value); - RefCell::new(out) + GcRefCell::new(out) }, - inner + inner, }); } } } -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct InitialUnderscore(pub Thunk); impl ContextInitializer for InitialUnderscore { fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) { @@ -569,16 +579,16 @@ impl State { pub fn resolve(&self, path: impl AsRef) -> Result { self.import_resolver().resolve(path.as_ref()) } - pub fn import_resolver(&self) -> Ref<'_, dyn ImportResolver> { - Ref::map(self.settings(), |s| &*s.import_resolver) + pub fn import_resolver(&self) -> GcRef<'_, dyn ImportResolver> { + GcRef::map(self.settings(), |s| &***s.import_resolver) } pub fn set_import_resolver(&self, resolver: impl ImportResolver) { - self.settings_mut().import_resolver = tb!(resolver); + self.settings_mut().import_resolver = dyn_gc_box!(resolver); } - pub fn context_initializer(&self) -> Ref<'_, dyn ContextInitializer> { - Ref::map(self.settings(), |s| &*s.context_initializer) + pub fn context_initializer(&self) -> GcRef<'_, dyn ContextInitializer> { + GcRef::map(self.settings(), |s| &***s.context_initializer) } pub fn set_context_initializer(&self, initializer: impl ContextInitializer) { - self.settings_mut().context_initializer = tb!(initializer); + self.settings_mut().context_initializer = dyn_gc_box!(initializer); } } diff --git a/crates/jrsonnet-evaluator/src/map.rs b/crates/jrsonnet-evaluator/src/map.rs index 3ed58139..f95f52f9 100644 --- a/crates/jrsonnet-evaluator/src/map.rs +++ b/crates/jrsonnet-evaluator/src/map.rs @@ -1,17 +1,16 @@ -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Gc, Trace, Finalize}; use jrsonnet_interner::IStr; use crate::{GcHashMap, Thunk, Val}; -#[derive(Trace)] -#[trace(tracking(force))] +#[derive(Trace, Finalize)] pub struct LayeredHashMapInternals { parent: Option, current: GcHashMap>, } -#[derive(Trace)] -pub struct LayeredHashMap(Cc); +#[derive(Trace, Finalize)] +pub struct LayeredHashMap(Gc); impl LayeredHashMap { pub fn iter_keys(self, mut handler: impl FnMut(IStr)) { @@ -24,14 +23,14 @@ impl LayeredHashMap { } pub(crate) fn new(layer: GcHashMap>) -> Self { - Self(Cc::new(LayeredHashMapInternals { + Self(Gc::new(LayeredHashMapInternals { parent: None, current: layer, })) } pub fn extend(self, new_layer: GcHashMap>) -> Self { - Self(Cc::new(LayeredHashMapInternals { + Self(Gc::new(LayeredHashMapInternals { parent: Some(self), current: new_layer, })) @@ -62,7 +61,7 @@ impl Clone for LayeredHashMap { impl Default for LayeredHashMap { fn default() -> Self { - Self(Cc::new(LayeredHashMapInternals { + Self(Gc::new(LayeredHashMapInternals { parent: None, current: GcHashMap::new(), })) diff --git a/crates/jrsonnet-evaluator/src/obj.rs b/crates/jrsonnet-evaluator/src/obj.rs index a47ab1ab..0f8dbd52 100644 --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -6,21 +6,20 @@ use std::{ ptr::addr_of, }; -use jrsonnet_gcmodule::{Cc, Trace, Weak}; +use boa_gc::{Finalize, Gc, GcBox, GcRefCell, Trace, WeakGc}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ExprLocation, Visibility}; use rustc_hash::FxHashMap; use crate::{ arr::{PickObjectKeyValues, PickObjectValues}, - bail, + bail, dyn_gc_box, error::{suggest_object_fields, Error, ErrorKind::*}, function::{CallLocation, FuncVal}, - gc::{GcHashMap, GcHashSet, TraceBox}, + gc::{GcHashMap, GcHashSet}, operator::evaluate_add_op, - tb, val::{ArrValue, ThunkValue}, - MaybeUnbound, Result, State, Thunk, Unbound, Val, + DynGcBox, MaybeUnbound, Result, State, Thunk, Unbound, Val, }; #[cfg(not(feature = "exp-preserve-order"))] @@ -30,9 +29,10 @@ mod ordering { clippy::unused_self, )] - use jrsonnet_gcmodule::Trace; + use boa_gc::{Finalize, Trace}; - #[derive(Clone, Copy, Default, Debug, Trace)] + #[derive(Clone, Copy, Default, Debug, Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] pub struct FieldIndex(()); impl FieldIndex { pub const fn next(self) -> Self { @@ -40,7 +40,8 @@ mod ordering { } } - #[derive(Clone, Copy, Default, Debug, Trace)] + #[derive(Clone, Default, Debug, Trace, Finalize, Copy)] + #[boa_gc(unsafe_no_drop)] pub struct SuperDepth(()); impl SuperDepth { pub const fn deeper(self) -> Self { @@ -63,7 +64,8 @@ mod ordering { use jrsonnet_gcmodule::Trace; - #[derive(Clone, Copy, Default, Debug, Trace, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Clone, Copy, Default, Debug, Trace, Finalize, PartialEq, Eq, PartialOrd, Ord)] + #[boa_gc(unsafe_no_drop)] pub struct FieldIndex(u32); impl FieldIndex { pub fn next(self) -> Self { @@ -72,6 +74,7 @@ mod ordering { } #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug)] + #[boa_gc(unsafe_no_drop)] pub struct SuperDepth(u32); impl SuperDepth { pub fn deeper(self) -> Self { @@ -129,9 +132,10 @@ impl Debug for ObjFieldFlags { } #[allow(clippy::module_name_repetitions)] -#[derive(Debug, Trace)] +#[derive(Debug, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] pub struct ObjMember { - #[trace(skip)] + #[unsafe_ignore_trace] flags: ObjFieldFlags, original_index: FieldIndex, pub invoke: MaybeUnbound, @@ -144,7 +148,7 @@ pub trait ObjectAssertion: Trace { // Field => This -#[derive(Trace)] +#[derive(Trace, Finalize, Debug)] enum CacheValue { Cached(Val), NotFound, @@ -153,15 +157,14 @@ enum CacheValue { } #[allow(clippy::module_name_repetitions)] -#[derive(Trace)] -#[trace(tracking(force))] +#[derive(Trace, Finalize)] pub struct OopObject { sup: Option, // this: Option, - assertions: Cc>>, - assertions_ran: RefCell>, - this_entries: Cc>, - value_cache: RefCell), CacheValue>>, + assertions: Gc>>, + assertions_ran: GcRefCell>, + this_entries: Gc>, + value_cache: GcRefCell), CacheValue>>, } impl Debug for OopObject { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -201,29 +204,34 @@ pub trait ObjectLike: Trace + Any + Debug { fn run_assertions_raw(&self, this: ObjValue) -> Result<()>; } -#[derive(Clone, Trace)] -pub struct WeakObjValue(#[trace(skip)] pub(crate) Weak>); +#[derive(Clone, Trace, Finalize)] +pub struct WeakObjValue(u32, pub(crate) WeakGc>); + +impl Debug for WeakObjValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("WeakObjValue").field(&self.1).finish() + } +} impl PartialEq for WeakObjValue { fn eq(&self, other: &Self) -> bool { - Weak::ptr_eq(&self.0, &other.0) + // PartialEq is implemented as ptr equality for WeakGc. + self.1 == other.1 } } impl Eq for WeakObjValue {} impl Hash for WeakObjValue { fn hash(&self, hasher: &mut H) { - // Safety: usize is POD - let addr = unsafe { *std::ptr::addr_of!(self.0).cast() }; - hasher.write_usize(addr); + hasher.write_u32(self.0) } } #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Trace, Debug)] -pub struct ObjValue(pub(crate) Cc>); +#[derive(Clone, Trace, Finalize, Debug)] +pub struct ObjValue(pub(crate) DynGcBox); -#[derive(Debug, Trace)] +#[derive(Debug, Trace, Finalize)] struct EmptyObject; impl ObjectLike for EmptyObject { fn extend_from(&self, sup: ObjValue) -> ObjValue { @@ -271,7 +279,7 @@ impl ObjectLike for EmptyObject { } } -#[derive(Trace, Debug)] +#[derive(Trace, Finalize, Debug)] struct ThisOverride { inner: ObjValue, this: ObjValue, @@ -331,7 +339,7 @@ impl ObjectLike for ThisOverride { impl ObjValue { pub fn new(v: impl ObjectLike) -> Self { - Self(Cc::new(tb!(v))) + Self(dyn_gc_box!(v)) } pub fn new_empty() -> Self { Self::new(EmptyObject) @@ -443,7 +451,8 @@ impl ObjValue { }) } pub fn get_lazy(&self, key: IStr) -> Option> { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct ThunkGet { obj: ObjValue, key: IStr, @@ -465,7 +474,8 @@ impl ObjValue { })) } pub fn get_lazy_or_bail(&self, key: IStr) -> Thunk { - #[derive(Trace)] + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] struct ThunkGet { obj: ObjValue, key: IStr, @@ -484,10 +494,10 @@ impl ObjValue { }) } pub fn ptr_eq(a: &Self, b: &Self) -> bool { - Cc::ptr_eq(&a.0, &b.0) + Gc::ptr_eq(&a.0, &b.0) } pub fn downgrade(self) -> WeakObjValue { - WeakObjValue(self.0.downgrade()) + WeakObjValue(addr_of!(**Gc::as_ref(&self.0)).cast::<()>() as usize as u32, WeakGc::new(&self.0)) } fn fields_visibility(&self) -> FxHashMap { let mut out = FxHashMap::default(); @@ -610,16 +620,16 @@ impl ObjValue { impl OopObject { pub fn new( sup: Option, - this_entries: Cc>, - assertions: Cc>>, + this_entries: Gc>, + assertions: Gc>>, ) -> Self { Self { sup, // this: None, assertions, - assertions_ran: RefCell::new(GcHashSet::new()), + assertions_ran: GcRefCell::new(GcHashSet::new()), this_entries, - value_cache: RefCell::new(GcHashMap::new()), + value_cache: GcRefCell::new(GcHashMap::new()), } } @@ -805,14 +815,15 @@ impl ObjectLike for OopObject { impl PartialEq for ObjValue { fn eq(&self, other: &Self) -> bool { - Cc::ptr_eq(&self.0, &other.0) + Gc::ptr_eq(&self.0, &other.0) } } impl Eq for ObjValue {} impl Hash for ObjValue { fn hash(&self, hasher: &mut H) { - hasher.write_usize(addr_of!(*self.0) as usize); + let hash = addr_of!(**Gc::as_ref(&self.0)).cast::<()>() as usize as u32; + hasher.write_u32(hash); } } @@ -820,7 +831,7 @@ impl Hash for ObjValue { pub struct ObjValueBuilder { sup: Option, map: GcHashMap, - assertions: Vec>, + assertions: Vec>, next_field_index: FieldIndex, } impl ObjValueBuilder { @@ -845,7 +856,7 @@ impl ObjValueBuilder { } pub fn assert(&mut self, assertion: impl ObjectAssertion + 'static) -> &mut Self { - self.assertions.push(tb!(assertion)); + self.assertions.push(Box::new(assertion)); self } pub fn field(&mut self, name: impl Into) -> ObjMemberBuilder> { @@ -876,8 +887,8 @@ impl ObjValueBuilder { } ObjValue::new(OopObject::new( self.sup, - Cc::new(self.map), - Cc::new(self.assertions), + Gc::new(self.map), + Gc::new(self.assertions), )) } } @@ -961,7 +972,7 @@ impl ObjMemberBuilder> { self.binding(MaybeUnbound::Bound(value.into())) } pub fn bindable(self, bindable: impl Unbound) -> Result<()> { - self.binding(MaybeUnbound::Unbound(Cc::new(tb!(bindable)))) + self.binding(MaybeUnbound::Unbound(dyn_gc_box!(bindable))) } pub fn binding(self, binding: MaybeUnbound) -> Result<()> { let (receiver, name, member) = self.build_member(binding); @@ -983,8 +994,8 @@ impl ObjMemberBuilder> { pub fn value(self, value: impl Into) { self.binding(MaybeUnbound::Bound(Thunk::evaluated(value.into()))); } - pub fn bindable(self, bindable: TraceBox>) { - self.binding(MaybeUnbound::Unbound(Cc::new(bindable))); + pub fn bindable(self, bindable: impl Unbound) { + self.binding(MaybeUnbound::Unbound(dyn_gc_box!(bindable))); } pub fn binding(self, binding: MaybeUnbound) { let (receiver, name, member) = self.build_member(binding); diff --git a/crates/jrsonnet-evaluator/src/stdlib/format.rs b/crates/jrsonnet-evaluator/src/stdlib/format.rs index 59e085ca..b37cca45 100644 --- a/crates/jrsonnet-evaluator/src/stdlib/format.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs @@ -1,7 +1,7 @@ //! faster std.format impl #![allow(clippy::too_many_arguments)] -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use jrsonnet_interner::IStr; use jrsonnet_types::ValType; use thiserror::Error; @@ -13,7 +13,7 @@ use crate::{ Error, ObjValue, Result, Val, }; -#[derive(Debug, Clone, Error, Trace)] +#[derive(Debug, Clone, Error, Trace, Finalize)] pub enum FormatError { #[error("truncated format code")] TruncatedFormatCode, diff --git a/crates/jrsonnet-evaluator/src/trace/mod.rs b/crates/jrsonnet-evaluator/src/trace/mod.rs index 5a1f9925..2f20cc1a 100644 --- a/crates/jrsonnet-evaluator/src/trace/mod.rs +++ b/crates/jrsonnet-evaluator/src/trace/mod.rs @@ -3,13 +3,13 @@ use std::{ path::{Path, PathBuf}, }; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use jrsonnet_parser::{CodeLocation, Source}; use crate::{error::ErrorKind, Error}; /// The way paths should be displayed -#[derive(Clone, Trace)] +#[derive(Clone, Trace, Finalize)] pub enum PathResolver { /// Only filename FileName, @@ -87,7 +87,7 @@ fn print_code_location( } /// vanilla-like jsonnet formatting -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct CompactFormat { pub resolver: PathResolver, pub max_trace: usize, @@ -196,7 +196,7 @@ impl TraceFormat for CompactFormat { } } -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct JsFormat { pub max_trace: usize, } @@ -240,7 +240,7 @@ impl TraceFormat for JsFormat { /// rustc-like trace displaying #[cfg(feature = "explaining-traces")] -#[derive(Trace)] +#[derive(Trace, Finalize)] pub struct ExplainingFormat { pub resolver: PathResolver, pub max_trace: usize, diff --git a/crates/jrsonnet-evaluator/src/typed/conversions.rs b/crates/jrsonnet-evaluator/src/typed/conversions.rs index 1579d4cd..8275ea35 100644 --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -1,6 +1,6 @@ use std::{collections::BTreeMap, marker::PhantomData, ops::Deref}; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Gc, Trace, Finalize}; use jrsonnet_interner::{IBytes, IStr}; pub use jrsonnet_macros::Typed; use jrsonnet_types::{ComplexValType, ValType}; @@ -14,11 +14,11 @@ use crate::{ ObjValue, ObjValueBuilder, Result, Thunk, Val, }; -#[derive(Trace)] -struct FromUntyped(PhantomData K>); +#[derive(Trace, Finalize)] +struct FromUntyped(PhantomData K>); impl ThunkMapper for FromUntyped where - K: Typed + Trace, + K: Typed + Trace + 'static, { type Output = K; @@ -91,11 +91,11 @@ where } fn into_lazy_untyped(inner: Self) -> Thunk { - #[derive(Trace)] - struct IntoUntyped(PhantomData K>); + #[derive(Trace, Finalize)] + struct IntoUntyped(PhantomData K>); impl ThunkMapper for IntoUntyped where - K: Typed + Trace, + K: Typed + Trace + 'static, { type Output = Val; @@ -571,7 +571,7 @@ impl Typed for FuncVal { } } -impl Typed for Cc { +impl Typed for Gc { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); fn into_untyped(value: Self) -> Result { diff --git a/crates/jrsonnet-evaluator/src/typed/mod.rs b/crates/jrsonnet-evaluator/src/typed/mod.rs index 7423f4d0..64c15235 100644 --- a/crates/jrsonnet-evaluator/src/typed/mod.rs +++ b/crates/jrsonnet-evaluator/src/typed/mod.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, rc::Rc}; mod conversions; pub use conversions::*; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; pub use jrsonnet_types::{ComplexValType, ValType}; use thiserror::Error; @@ -11,12 +11,12 @@ use crate::{ State, Val, }; -#[derive(Debug, Error, Clone, Trace)] +#[derive(Debug, Error, Clone, Trace, Finalize)] pub enum TypeError { #[error("expected {0}, got {1}")] ExpectedGot(ComplexValType, ValType), #[error("missing property {0} from {1}")] - MissingProperty(#[trace(skip)] Rc, ComplexValType), + MissingProperty(#[boa_gc(unsafe_ignore_trace)] Rc, ComplexValType), #[error("every failed from {0}:\n{1}")] UnionFailed(ComplexValType, TypeLocErrorList), #[error( @@ -32,7 +32,7 @@ impl From for Error { } } -#[derive(Debug, Clone, Trace)] +#[derive(Debug, Clone, Trace, Finalize)] pub struct TypeLocError(Box, ValuePathStack); impl From for TypeLocError { fn from(e: TypeError) -> Self { @@ -54,7 +54,7 @@ impl Display for TypeLocError { } } -#[derive(Debug, Clone, Trace)] +#[derive(Debug, Clone, Trace, Finalize)] pub struct TypeLocErrorList(Vec); impl Display for TypeLocErrorList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -116,9 +116,9 @@ impl CheckType for ValType { } } -#[derive(Clone, Debug, Trace)] +#[derive(Clone, Debug, Trace, Finalize)] enum ValuePathItem { - Field(#[trace(skip)] Rc), + Field(#[boa_gc(unsafe_ignore_trace)] Rc), Index(u64), } impl Display for ValuePathItem { @@ -131,7 +131,7 @@ impl Display for ValuePathItem { } } -#[derive(Clone, Debug, Trace)] +#[derive(Clone, Debug, Trace, Finalize)] struct ValuePathStack(Vec); impl Display for ValuePathStack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/jrsonnet-evaluator/src/val.rs b/crates/jrsonnet-evaluator/src/val.rs index e622f93c..c985ad0d 100644 --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -5,7 +5,7 @@ use std::{ rc::Rc, }; -use jrsonnet_gcmodule::{Cc, Trace}; +use boa_gc::{Finalize, Gc, GcBox, GcRefCell, Trace}; use jrsonnet_interner::IStr; use jrsonnet_types::ValType; @@ -14,40 +14,40 @@ use crate::{ bail, error::{Error, ErrorKind::*}, function::FuncVal, - gc::{GcHashMap, TraceBox}, + gc::GcHashMap, manifest::{ManifestFormat, ToStringFormat}, - tb, typed::BoundedUsize, ObjValue, Result, Unbound, WeakObjValue, }; -pub trait ThunkValue: Trace { +pub trait ThunkValue: Trace + 'static { type Output; fn get(self: Box) -> Result; } -#[derive(Trace)] -enum ThunkInner { +#[derive(Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +enum ThunkInner { Computed(T), Errored(Error), - Waiting(TraceBox>), + Waiting(Box>), Pending, } /// Lazily evaluated value #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Trace)] -pub struct Thunk(Cc>>); +#[derive(Clone, Trace, Finalize)] +pub struct Thunk(Gc>>); impl Thunk { pub fn evaluated(val: T) -> Self { - Self(Cc::new(RefCell::new(ThunkInner::Computed(val)))) + Self(Gc::new(GcRefCell::new(ThunkInner::Computed(val)))) } pub fn new(f: impl ThunkValue + 'static) -> Self { - Self(Cc::new(RefCell::new(ThunkInner::Waiting(tb!(f))))) + Self(Gc::new(GcRefCell::new(ThunkInner::Waiting(Box::new(f))))) } pub fn errored(e: Error) -> Self { - Self(Cc::new(RefCell::new(ThunkInner::Errored(e)))) + Self(Gc::new(GcRefCell::new(ThunkInner::Errored(e)))) } pub fn result(res: Result) -> Self { match res { @@ -83,7 +83,7 @@ where else { unreachable!(); }; - let new_value = match value.0.get() { + let new_value = match value.get() { Ok(v) => v, Err(e) => { *self.0.borrow_mut() = ThunkInner::Errored(e.clone()); @@ -95,7 +95,7 @@ where } } -pub trait ThunkMapper: Trace { +pub trait ThunkMapper: Trace + 'static { type Output; fn map(self, from: Input) -> Result; } @@ -108,15 +108,16 @@ where M: ThunkMapper, M::Output: Trace, { - #[derive(Trace)] - struct Mapped { + #[derive(Trace, Finalize)] + #[boa_gc(unsafe_no_drop)] + struct Mapped { inner: Thunk, mapper: Mapper, } impl ThunkValue for Mapped where - Input: Trace + Clone, - Mapper: ThunkMapper, + Input: Trace + Clone + 'static, + Mapper: ThunkMapper + 'static, { type Output = Mapper::Output; @@ -159,19 +160,19 @@ impl Default for Thunk { type CacheKey = (Option, Option); -#[derive(Trace, Clone)] +#[derive(Trace, Clone, Finalize)] pub struct CachedUnbound where I: Unbound, - T: Trace, + T: Trace + 'static, { - cache: Cc>>, + cache: Gc>>, value: I, } impl, T: Trace> CachedUnbound { pub fn new(value: I) -> Self { Self { - cache: Cc::new(RefCell::new(GcHashMap::new())), + cache: Gc::new(GcRefCell::new(GcHashMap::new())), value, } } @@ -206,7 +207,7 @@ impl Debug for Thunk { } impl PartialEq for Thunk { fn eq(&self, other: &Self) -> bool { - Cc::ptr_eq(&self.0, &other.0) + Gc::ptr_eq(&self.0, &other.0) } } @@ -276,7 +277,8 @@ impl IndexableVal { } } -#[derive(Debug, Clone, Trace)] +#[derive(Debug, Clone, Trace, Finalize)] +#[boa_gc(unsafe_empty_trace)] pub enum StrValue { Flat(IStr), Tree(Rc<(StrValue, StrValue, usize)>), @@ -372,7 +374,8 @@ impl Ord for StrValue { } /// Represents any valid Jsonnet value. -#[derive(Debug, Clone, Trace, Default)] +#[derive(Debug, Clone, Trace, Finalize, Default)] +#[boa_gc(unsafe_no_drop)] pub enum Val { /// Represents a Jsonnet boolean. Bool(bool), diff --git a/crates/jrsonnet-interner/Cargo.toml b/crates/jrsonnet-interner/Cargo.toml index 35592ac7..646b5b17 100644 --- a/crates/jrsonnet-interner/Cargo.toml +++ b/crates/jrsonnet-interner/Cargo.toml @@ -17,10 +17,10 @@ structdump = ["dep:structdump"] serde = ["dep:serde"] [dependencies] -jrsonnet-gcmodule.workspace = true serde = { workspace = true, optional = true } structdump = { workspace = true, optional = true } rustc-hash.workspace = true hashbrown = { workspace = true, features = ["inline-more"] } +boa_gc = { git = "https://github.com/boa-dev/boa", version = "0.17.0" } diff --git a/crates/jrsonnet-interner/src/lib.rs b/crates/jrsonnet-interner/src/lib.rs index bee01dca..7cacdeeb 100644 --- a/crates/jrsonnet-interner/src/lib.rs +++ b/crates/jrsonnet-interner/src/lib.rs @@ -15,7 +15,7 @@ use std::{ }; use hashbrown::HashMap; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use rustc_hash::FxHasher; mod inner; @@ -24,13 +24,9 @@ use inner::Inner; /// Interned string /// /// Provides O(1) comparsions and hashing, cheap copy, and cheap conversion to [`IBytes`] -#[derive(Clone, PartialOrd, Ord, Eq)] +#[derive(Clone, PartialOrd, Ord, Eq, Trace, Finalize)] +#[boa_gc(unsafe_empty_trace)] pub struct IStr(Inner); -impl Trace for IStr { - fn is_type_tracked() -> bool { - false - } -} impl IStr { #[must_use] @@ -107,13 +103,9 @@ impl Display for IStr { } /// Interned byte array -#[derive(Clone, PartialOrd, Ord, Eq)] +#[derive(Clone, PartialOrd, Ord, Eq, Trace, Finalize)] +#[boa_gc(unsafe_empty_trace)] pub struct IBytes(Inner); -impl Trace for IBytes { - fn is_type_tracked() -> bool { - false - } -} impl IBytes { #[must_use] diff --git a/crates/jrsonnet-macros/src/lib.rs b/crates/jrsonnet-macros/src/lib.rs index 90951b0e..b82a5500 100644 --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -338,7 +338,9 @@ fn builtin_inner( quote! {} }; let static_derive_copy = if attr.fields.is_empty() { - quote! {, Copy} + // FIXME: Make possible to implement Copy on type with no destructor + // in boa_gc + quote! {} } else { quote! {} }; @@ -348,7 +350,7 @@ fn builtin_inner( #[doc(hidden)] #[allow(non_camel_case_types)] - #[derive(Clone, jrsonnet_gcmodule::Trace #static_derive_copy)] + #[derive(Clone, boa_gc::Trace, boa_gc::Finalize #static_derive_copy)] #vis struct #name { #(#fields)* } diff --git a/crates/jrsonnet-parser/Cargo.toml b/crates/jrsonnet-parser/Cargo.toml index d0c2c40a..248a025a 100644 --- a/crates/jrsonnet-parser/Cargo.toml +++ b/crates/jrsonnet-parser/Cargo.toml @@ -29,7 +29,6 @@ serde = ["dep:serde"] [dependencies] jrsonnet-interner.workspace = true -jrsonnet-gcmodule.workspace = true static_assertions.workspace = true @@ -37,3 +36,4 @@ peg.workspace = true serde = { workspace = true, features = ["derive", "rc"], optional = true } structdump = { workspace = true, features = ["derive"], optional = true } +boa_gc = { git = "https://github.com/boa-dev/boa", version = "0.17.0" } diff --git a/crates/jrsonnet-parser/src/expr.rs b/crates/jrsonnet-parser/src/expr.rs index 110f9d71..5ae1dd6f 100644 --- a/crates/jrsonnet-parser/src/expr.rs +++ b/crates/jrsonnet-parser/src/expr.rs @@ -4,7 +4,7 @@ use std::{ rc::Rc, }; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; use jrsonnet_interner::IStr; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -15,7 +15,7 @@ use crate::source::Source; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "structdump", derive(Codegen))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub enum FieldName { /// {fixed: 2} Fixed(IStr), @@ -25,7 +25,9 @@ pub enum FieldName { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] #[repr(u8)] pub enum Visibility { /// : @@ -44,12 +46,16 @@ impl Visibility { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, Debug, PartialEq, Trace)] +#[derive(Clone, Debug, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct AssertStmt(pub LocExpr, pub Option); #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct FieldMember { pub name: FieldName, pub plus: bool, @@ -60,7 +66,9 @@ pub struct FieldMember { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum Member { Field(FieldMember), BindStmt(BindSpec), @@ -69,7 +77,9 @@ pub enum Member { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum UnaryOpType { Plus, Minus, @@ -95,7 +105,9 @@ impl Display for UnaryOpType { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum BinaryOpType { Mul, Div, @@ -166,13 +178,15 @@ impl Display for BinaryOpType { /// name, default value #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct Param(pub Destruct, pub Option); /// Defined function parameters #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, PartialEq, Trace)] +#[derive(Debug, Clone, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct ParamsDesc(pub Rc>); impl Deref for ParamsDesc { @@ -184,7 +198,9 @@ impl Deref for ParamsDesc { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct ArgsDesc { pub unnamed: Vec, pub named: Vec<(IStr, LocExpr)>, @@ -197,7 +213,9 @@ impl ArgsDesc { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, PartialEq, Eq, Trace)] +#[derive(Debug, Clone, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum DestructRest { /// ...rest Keep(IStr), @@ -207,7 +225,9 @@ pub enum DestructRest { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, PartialEq, Trace)] +#[derive(Debug, Clone, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum Destruct { Full(IStr), #[cfg(feature = "exp-destruct")] @@ -270,7 +290,7 @@ impl Destruct { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, PartialEq, Trace)] +#[derive(Debug, Clone, PartialEq, Trace, Finalize)] pub enum BindSpec { Field { into: Destruct, @@ -293,17 +313,17 @@ impl BindSpec { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct IfSpecData(pub LocExpr); #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct ForSpecData(pub Destruct, pub LocExpr); #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub enum CompSpec { IfSpec(IfSpecData), ForSpec(ForSpecData), @@ -311,7 +331,7 @@ pub enum CompSpec { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct ObjComp { pub pre_locals: Vec, pub field: FieldMember, @@ -321,7 +341,7 @@ pub struct ObjComp { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub enum ObjBody { MemberList(Vec), ObjComp(ObjComp), @@ -329,7 +349,9 @@ pub enum ObjBody { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub enum LiteralType { This, Super, @@ -341,7 +363,7 @@ pub enum LiteralType { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct SliceDesc { pub start: Option, pub end: Option, @@ -351,7 +373,7 @@ pub struct SliceDesc { /// Syntax base #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub enum Expr { Literal(LiteralType), @@ -422,7 +444,7 @@ pub enum Expr { #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, PartialEq, Trace)] +#[derive(Debug, PartialEq, Trace, Finalize)] pub struct IndexPart { pub value: LocExpr, #[cfg(feature = "exp-null-coaelse")] @@ -432,8 +454,9 @@ pub struct IndexPart { /// file, begin offset, end offset #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, PartialEq, Eq, Trace)] -#[trace(skip)] +#[derive(Clone, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] #[repr(C)] pub struct ExprLocation(pub Source, pub u32, pub u32); impl ExprLocation { @@ -454,7 +477,9 @@ impl Debug for ExprLocation { /// Holds AST expression and its location in source file #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "structdump", derive(Codegen))] -#[derive(Clone, PartialEq, Trace)] +#[derive(Clone, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct LocExpr(pub Rc, pub ExprLocation); #[cfg(target_pointer_width = "64")] diff --git a/crates/jrsonnet-parser/src/source.rs b/crates/jrsonnet-parser/src/source.rs index bf1f2404..88b545f4 100644 --- a/crates/jrsonnet-parser/src/source.rs +++ b/crates/jrsonnet-parser/src/source.rs @@ -6,7 +6,7 @@ use std::{ rc::Rc, }; -use jrsonnet_gcmodule::{Trace, Tracer}; +use boa_gc::{Trace, Finalize}; use jrsonnet_interner::IStr; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -82,13 +82,14 @@ any_ext!(SourcePathT); /// search location is applicable /// /// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files -#[derive(Eq, Debug, Clone)] +#[derive(Eq, Debug, Clone, Trace, Finalize)] +#[boa_gc(unsafe_empty_trace)] pub struct SourcePath(Rc); impl SourcePath { - pub fn new(inner: impl SourcePathT) -> Self { + pub fn new(inner: impl SourcePathT + 'static) -> Self { Self(Rc::new(inner)) } - pub fn downcast_ref(&self) -> Option<&T> { + pub fn downcast_ref(&self) -> Option<&T> { self.0.as_any().downcast_ref() } pub fn is_default(&self) -> bool { @@ -109,18 +110,6 @@ impl PartialEq for SourcePath { &*self.0 == &*other.0 } } -impl Trace for SourcePath { - fn trace(&self, tracer: &mut Tracer) { - (*self.0).trace(tracer) - } - - fn is_type_tracked() -> bool - where - Self: Sized, - { - true - } -} impl Display for SourcePath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) @@ -157,7 +146,7 @@ impl Codegen for SourcePath { } } -#[derive(Trace, Hash, PartialEq, Eq, Debug)] +#[derive(Trace, Finalize, Hash, PartialEq, Eq, Debug)] struct SourceDefault; impl Display for SourceDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -179,7 +168,7 @@ impl SourcePathT for SourceDefault { /// /// When `file` is being resolved from `SourceFile(a/b/c)`, it should be resolved to `SourceFile(a/b/file)`, /// however if it is being resolved from `SourceDirectory(a/b/c)`, then it should be resolved to `SourceDirectory(a/b/c/file)` -#[derive(Trace, Hash, PartialEq, Eq, Debug)] +#[derive(Trace, Finalize, Hash, PartialEq, Eq, Debug)] pub struct SourceFile(PathBuf); impl SourceFile { pub fn new(path: PathBuf) -> Self { @@ -207,7 +196,7 @@ impl SourcePathT for SourceFile { /// Represents path to the directory on the disk /// /// See also [`SourceFile`] -#[derive(Trace, Hash, PartialEq, Eq, Debug)] +#[derive(Trace, Finalize, Hash, PartialEq, Eq, Debug)] pub struct SourceDirectory(PathBuf); impl SourceDirectory { pub fn new(path: PathBuf) -> Self { @@ -237,7 +226,7 @@ impl SourcePathT for SourceDirectory { /// It is used for --ext-code=.../--tla-code=.../standard library source code by default, /// and user can construct arbitrary values by hand, without asking import resolver #[cfg_attr(feature = "structdump", derive(Codegen))] -#[derive(Trace, Hash, PartialEq, Eq, Debug, Clone)] +#[derive(Trace, Finalize, Hash, PartialEq, Eq, Debug, Clone)] pub struct SourceVirtual(pub IStr); impl Display for SourceVirtual { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -258,17 +247,11 @@ impl SourcePathT for SourceVirtual { /// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +#[boa_gc(unsafe_empty_trace)] pub struct Source(pub Rc<(SourcePath, IStr)>); -impl Trace for Source { - fn trace(&self, _tracer: &mut Tracer) {} - - fn is_type_tracked() -> bool { - false - } -} - impl Source { pub fn new(path: SourcePath, code: IStr) -> Self { Self(Rc::new((path, code))) diff --git a/crates/jrsonnet-stdlib/Cargo.toml b/crates/jrsonnet-stdlib/Cargo.toml index cebe4b14..a39195dc 100644 --- a/crates/jrsonnet-stdlib/Cargo.toml +++ b/crates/jrsonnet-stdlib/Cargo.toml @@ -27,7 +27,7 @@ exp-regex = ["regex", "lru", "rustc-hash"] jrsonnet-evaluator.workspace = true jrsonnet-macros.workspace = true jrsonnet-parser.workspace = true -jrsonnet-gcmodule.workspace = true +boa_gc = { git = "https://github.com/boa-dev/boa", version = "0.17.0" } # Used for stdlib AST serialization bincode = { workspace = true, optional = true } diff --git a/crates/jrsonnet-stdlib/src/lib.rs b/crates/jrsonnet-stdlib/src/lib.rs index 6d19c193..08cfd099 100644 --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -4,14 +4,14 @@ use std::{ rc::Rc, }; +use boa_gc::{Finalize, Gc, GcRefCell, Trace, GcRef, GcRefMut}; use jrsonnet_evaluator::{ + dyn_gc_box, error::{ErrorKind::*, Result}, function::{CallLocation, FuncVal, TlaArg}, - tb, trace::PathResolver, ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val, }; -use jrsonnet_gcmodule::Trace; use jrsonnet_parser::Source; mod expr; @@ -48,7 +48,7 @@ mod regex; #[cfg(feature = "exp-regex")] pub use crate::regex::*; -pub fn stdlib_uncached(settings: Rc>) -> ObjValue { +pub fn stdlib_uncached(settings: Gc>) -> ObjValue { let mut builder = ObjValueBuilder::new(); let expr = expr::stdlib_expr(); @@ -279,12 +279,14 @@ impl TracePrinter for StdTracePrinter { } } +#[derive(Trace, Finalize)] pub struct Settings { /// Used for `std.extVar` pub ext_vars: HashMap, /// Used for `std.native` pub ext_natives: HashMap, /// Used for `std.trace` + #[unsafe_ignore_trace] pub trace_printer: Box, /// Used for `std.thisFile` pub path_resolver: PathResolver, @@ -295,7 +297,7 @@ fn extvar_source(name: &str, code: impl Into) -> Source { Source::new_virtual(source_name.into(), code.into()) } -#[derive(Trace, Clone)] +#[derive(Trace, Finalize, Clone)] pub struct ContextInitializer { /// When we don't need to support legacy-this-file, we can reuse same context for all files #[cfg(not(feature = "legacy-this-file"))] @@ -306,7 +308,7 @@ pub struct ContextInitializer { /// Otherwise, we can only keep first stdlib layer, and then stack thisFile on top of it #[cfg(feature = "legacy-this-file")] stdlib_obj: ObjValue, - settings: Rc>, + settings: Gc>, } impl ContextInitializer { pub fn new(_s: State, resolver: PathResolver) -> Self { @@ -316,7 +318,7 @@ impl ContextInitializer { trace_printer: Box::new(StdTracePrinter::new(resolver.clone())), path_resolver: resolver, }; - let settings = Rc::new(RefCell::new(settings)); + let settings = Gc::new(GcRefCell::new(settings)); let stdlib_obj = stdlib_uncached(settings.clone()); #[cfg(not(feature = "legacy-this-file"))] let stdlib_thunk = Thunk::evaluated(Val::Obj(stdlib_obj)); @@ -334,10 +336,10 @@ impl ContextInitializer { settings, } } - pub fn settings(&self) -> Ref { + pub fn settings(&self) -> GcRef { self.settings.borrow() } - pub fn settings_mut(&self) -> RefMut { + pub fn settings_mut(&self) -> GcRefMut { self.settings.borrow_mut() } pub fn add_ext_var(&self, name: IStr, value: Val) { @@ -416,6 +418,6 @@ pub trait StateExt { impl StateExt for State { fn with_stdlib(&self) { let initializer = ContextInitializer::new(self.clone(), PathResolver::new_cwd_fallback()); - self.settings_mut().context_initializer = tb!(initializer) + self.settings_mut().context_initializer = dyn_gc_box!(initializer) } } diff --git a/crates/jrsonnet-stdlib/src/misc.rs b/crates/jrsonnet-stdlib/src/misc.rs index 8bb3d76a..59cd56e7 100644 --- a/crates/jrsonnet-stdlib/src/misc.rs +++ b/crates/jrsonnet-stdlib/src/misc.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, rc::Rc}; +use boa_gc::{Gc, GcRefCell}; use jrsonnet_evaluator::{ bail, error::{ErrorKind::*, Result}, @@ -24,7 +25,7 @@ pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> usize { } #[builtin(fields( - settings: Rc>, + settings: Gc>, ))] pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result { let ctx = ctx.state().create_default_context(extvar_source(&x, "")); @@ -39,7 +40,7 @@ pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result< } #[builtin(fields( - settings: Rc>, + settings: Gc>, ))] pub fn builtin_native(this: &builtin_native, x: IStr) -> Val { this.settings @@ -51,7 +52,7 @@ pub fn builtin_native(this: &builtin_native, x: IStr) -> Val { } #[builtin(fields( - settings: Rc>, + settings: Gc>, ))] pub fn builtin_trace( this: &builtin_trace, diff --git a/crates/jrsonnet-types/Cargo.toml b/crates/jrsonnet-types/Cargo.toml index 57d3ac1e..674aecfe 100644 --- a/crates/jrsonnet-types/Cargo.toml +++ b/crates/jrsonnet-types/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" edition = "2021" [dependencies] -jrsonnet-gcmodule.workspace = true +boa_gc = { git = "https://github.com/boa-dev/boa", version = "0.17.0" } peg.workspace = true diff --git a/crates/jrsonnet-types/src/lib.rs b/crates/jrsonnet-types/src/lib.rs index 0518ce5a..a9bccc3a 100644 --- a/crates/jrsonnet-types/src/lib.rs +++ b/crates/jrsonnet-types/src/lib.rs @@ -2,7 +2,7 @@ use std::fmt::Display; -use jrsonnet_gcmodule::Trace; +use boa_gc::{Trace, Finalize}; #[macro_export] macro_rules! ty { @@ -82,7 +82,8 @@ fn test() { ); } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] pub enum ValType { Bool, Null, @@ -118,8 +119,8 @@ impl Display for ValType { } } -#[derive(Debug, Clone, PartialEq, Trace)] -#[trace(skip)] +#[derive(Debug, Clone, PartialEq, Trace, Finalize)] +#[boa_gc(unsafe_empty_trace)] pub enum ComplexValType { Any, Char, diff --git a/flake.lock b/flake.lock index 7228a9c4..97c13236 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701376520, - "narHash": "sha256-U3iGiOZqgu7wvVzgfoQzGGFMqNsDj/q/6zPIjCy7ajg=", + "lastModified": 1705161857, + "narHash": "sha256-z2xxWJJS3ZA9BVSMdZ4bLmZqC2qH89HWD+G8vA/o1MI=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c74cc3c3db2ed5e68895953d75c397797d499133", + "rev": "580e976836beaa493ee3d22be40fb43be632f37a", "type": "github" }, "original": { @@ -50,11 +50,11 @@ ] }, "locked": { - "lastModified": 1701310566, - "narHash": "sha256-CL9J3xUR2Ejni4LysrEGX0IdO+Y4BXCiH/By0lmF3eQ=", + "lastModified": 1705112162, + "narHash": "sha256-IAM0+Uijh/fwlfoeDrOwau9MxcZW3zeDoUHc6Z3xfqM=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "6d3c6e185198b8bf7ad639f22404a75aa9a09bff", + "rev": "9e0af26ffe52bf955ad5575888f093e41fba0104", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index fcecd0e0..9262c70d 100644 --- a/flake.nix +++ b/flake.nix @@ -25,7 +25,7 @@ lib = pkgs.lib; rust = (pkgs.rustChannelOf { - date = "2023-10-28"; + date = "2024-01-12"; channel = "nightly"; }) .default diff --git a/nix/jrsonnet.nix b/nix/jrsonnet.nix index ddea5d59..d1a9b293 100644 --- a/nix/jrsonnet.nix +++ b/nix/jrsonnet.nix @@ -41,5 +41,9 @@ rustPlatform.buildRustPackage rec { cargoLock = { lockFile = ../Cargo.lock; + outputHashes = { + "ass-stroke-0.1.0" = "sha256-muCxjyvgtbK6QDePRQlq29Ey7A22vvCaCMoZH+OUr6U="; + "boa_gc-0.17.0" = "sha256-4h5nLLdSYgDZNo9g3jx5XUpDBqWhmJ74OgyE4tXdKg8="; + }; }; }