diff --git a/core/engine/src/builtins/function/arguments.rs b/core/engine/src/builtins/function/arguments.rs index 0341f83b8b4..81fe3f10043 100644 --- a/core/engine/src/builtins/function/arguments.rs +++ b/core/engine/src/builtins/function/arguments.rs @@ -83,7 +83,7 @@ impl UnmappedArguments { pub(crate) struct MappedArguments { #[unsafe_ignore_trace] binding_indices: Vec>, - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, } impl JsData for MappedArguments { @@ -215,7 +215,7 @@ impl MappedArguments { func: &JsObject, binding_indices: &[Option], arguments_list: &[JsValue], - env: &Gc, + env: &Gc<'static, DeclarativeEnvironment>, context: &Context, ) -> JsObject { // 1. Assert: formals does not contain a rest parameter, any binding patterns, or any initializers. diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index bb04263a469..d7585a76994 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -166,7 +166,7 @@ unsafe impl Trace for ClassFieldDefinition { #[derive(Debug, Trace, Finalize)] pub struct OrdinaryFunction { /// The code block containing the compiled function. - pub(crate) code: Gc, + pub(crate) code: Gc<'static, CodeBlock>, /// The `[[Environment]]` internal slot. pub(crate) environments: EnvironmentStack, @@ -210,7 +210,7 @@ impl JsData for OrdinaryFunction { impl OrdinaryFunction { pub(crate) fn new( - code: Gc, + code: Gc<'static, CodeBlock>, environments: EnvironmentStack, script_or_module: Option, realm: Realm, @@ -233,7 +233,10 @@ impl OrdinaryFunction { } /// Push a private environment to the function. - pub(crate) fn push_private_environment(&mut self, environment: Gc) { + pub(crate) fn push_private_environment( + &mut self, + environment: Gc<'static, PrivateEnvironment>, + ) { self.environments.push_private(environment); } diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index 3893ce8eeaa..6024b5b44a3 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -646,7 +646,7 @@ impl Promise { #[unsafe_ignore_trace] already_called: Rc>, index: usize, - values: Gc>>, + values: Gc<'static, GcRefCell>>, capability_resolve: JsFunction, #[unsafe_ignore_trace] remaining_elements_count: Rc>, @@ -861,7 +861,7 @@ impl Promise { #[unsafe_ignore_trace] already_called: Rc>, index: usize, - values: Gc>>, + values: Gc<'static, GcRefCell>>, capability: JsFunction, #[unsafe_ignore_trace] remaining_elements: Rc>, @@ -1222,7 +1222,7 @@ impl Promise { variant: KeyedVariant, #[unsafe_ignore_trace] keys: Rc>>, - values: Gc>>, + values: Gc<'static, GcRefCell>>, capability: JsFunction, #[unsafe_ignore_trace] remaining_elements: Rc>, @@ -1538,7 +1538,7 @@ impl Promise { #[unsafe_ignore_trace] already_called: Rc>, index: usize, - errors: Gc>>, + errors: Gc<'static, GcRefCell>>, capability_reject: JsFunction, #[unsafe_ignore_trace] remaining_elements_count: Rc>, diff --git a/core/engine/src/bytecompiler/class.rs b/core/engine/src/bytecompiler/class.rs index 9e7a00190f2..18a0ee32ccf 100644 --- a/core/engine/src/bytecompiler/class.rs +++ b/core/engine/src/bytecompiler/class.rs @@ -20,11 +20,11 @@ use thin_vec::ThinVec; // Static class elements that are initialized at a later time in the class creation. enum StaticElement { // A static class block with it's function code. - StaticBlock(Gc), + StaticBlock(Gc<'static, CodeBlock>), // A static class field with it's function code, an optional name index and the information if the function is an anonymous function. StaticField { - code: Gc, + code: Gc<'static, CodeBlock>, name_index: StaticFieldName, is_anonymous_function: bool, }, diff --git a/core/engine/src/bytecompiler/function.rs b/core/engine/src/bytecompiler/function.rs index 9316e28ae6b..4aa4bbbe8a2 100644 --- a/core/engine/src/bytecompiler/function.rs +++ b/core/engine/src/bytecompiler/function.rs @@ -122,7 +122,7 @@ impl FunctionCompiler { scopes: &FunctionScopes, contains_direct_eval: bool, interner: &mut Interner, - ) -> Gc { + ) -> Gc<'static, CodeBlock> { self.strict = self.strict || body.strict(); let length = parameters.length(); diff --git a/core/engine/src/bytecompiler/mod.rs b/core/engine/src/bytecompiler/mod.rs index b093f3c0008..839b40c98fc 100644 --- a/core/engine/src/bytecompiler/mod.rs +++ b/core/engine/src/bytecompiler/mod.rs @@ -812,7 +812,7 @@ impl<'ctx> ByteCompiler<'ctx> { #[inline] #[must_use] - pub(crate) fn push_function_to_constants(&mut self, function: Gc) -> u32 { + pub(crate) fn push_function_to_constants(&mut self, function: Gc<'static, CodeBlock>) -> u32 { let index = self.constants.len() as u32; self.constants.push(Constant::Function(function)); index diff --git a/core/engine/src/environments/runtime/mod.rs b/core/engine/src/environments/runtime/mod.rs index ac2ece5276c..e2f9afe879c 100644 --- a/core/engine/src/environments/runtime/mod.rs +++ b/core/engine/src/environments/runtime/mod.rs @@ -27,7 +27,7 @@ pub(crate) use self::{ #[derive(Clone, Debug, Trace, Finalize)] pub(crate) struct EnvironmentNode { env: Environment, - parent: Option>, + parent: Option>, } /// The environment stack holds all environments at runtime. @@ -42,32 +42,32 @@ pub(crate) struct EnvironmentNode { #[derive(Clone, Debug, Trace, Finalize)] pub(crate) struct EnvironmentStack { /// The tip (most recently pushed) environment in the chain. - tip: Option>, + tip: Option>, /// Number of environments in the chain (not counting global). #[unsafe_ignore_trace] depth: u32, - private_stack: ThinVec>, + private_stack: ThinVec>, } /// Saved environment state for `pop_to_global` / `restore_from_saved`. /// Used by indirect `eval` and `Function.prototype.toString` recompilation. pub(crate) struct SavedEnvironments { - tip: Option>, + tip: Option>, depth: u32, } /// A runtime environment. #[derive(Clone, Debug, Trace, Finalize)] pub(crate) enum Environment { - Declarative(Gc), + Declarative(Gc<'static, DeclarativeEnvironment>), Object(JsObject), } impl Environment { /// Returns the declarative environment if it is one. - pub(crate) const fn as_declarative(&self) -> Option<&Gc> { + pub(crate) const fn as_declarative(&self) -> Option<&Gc<'static, DeclarativeEnvironment>> { match self { Self::Declarative(env) => Some(env), Self::Object(_) => None, @@ -86,7 +86,9 @@ impl EnvironmentStack { } /// Gets the next outer function environment. - pub(crate) fn outer_function_environment(&self) -> Option<(Gc, Scope)> { + pub(crate) fn outer_function_environment( + &self, + ) -> Option<(Gc<'static, DeclarativeEnvironment>, Scope)> { for (env, _) in self.iter_from_tip() { if let Some(decl) = env.as_declarative() && let Some(function_env) = decl.kind().as_function() @@ -170,7 +172,7 @@ impl EnvironmentStack { /// [spec]: https://tc39.es/ecma262/#sec-getthisenvironment pub(crate) fn get_this_environment<'a>( &'a self, - global: &'a Gc, + global: &'a Gc<'static, DeclarativeEnvironment>, ) -> &'a DeclarativeEnvironmentKind { for (env, _) in self.iter_from_tip() { if let Some(decl) = env.as_declarative().filter(|decl| decl.has_this_binding()) { @@ -211,7 +213,7 @@ impl EnvironmentStack { pub(crate) fn push_lexical( &mut self, bindings_count: u32, - global: &Gc, + global: &Gc<'static, DeclarativeEnvironment>, ) -> u32 { let (poisoned, with) = self.compute_poisoned_with(global); @@ -233,7 +235,7 @@ impl EnvironmentStack { &mut self, scope: Scope, function_slots: FunctionSlots, - global: &Gc, + global: &Gc<'static, DeclarativeEnvironment>, ) { let num_bindings = scope.num_bindings_non_local(); @@ -278,8 +280,8 @@ impl EnvironmentStack { /// Get the most outer environment. pub(crate) fn current_declarative_ref<'a>( &'a self, - global: &'a Gc, - ) -> Option<&'a Gc> { + global: &'a Gc<'static, DeclarativeEnvironment>, + ) -> Option<&'a Gc<'static, DeclarativeEnvironment>> { if let Some(env) = self.last() { env.as_declarative() } else { @@ -289,7 +291,10 @@ impl EnvironmentStack { /// Mark that there may be added bindings from the current environment to the next function /// environment. - pub(crate) fn poison_until_last_function(&mut self, global: &Gc) { + pub(crate) fn poison_until_last_function( + &mut self, + global: &Gc<'static, DeclarativeEnvironment>, + ) { for (env, _) in self.iter_from_tip() { if let Some(decl) = env.as_declarative() { decl.poison(); @@ -312,7 +317,7 @@ impl EnvironmentStack { environment: BindingLocatorScope, binding_index: u32, value: JsValue, - global: &Gc, + global: &Gc<'static, DeclarativeEnvironment>, ) { let env = match environment { BindingLocatorScope::GlobalObject | BindingLocatorScope::GlobalDeclarative => global, @@ -335,7 +340,7 @@ impl EnvironmentStack { environment: BindingLocatorScope, binding_index: u32, value: JsValue, - global: &Gc, + global: &Gc<'static, DeclarativeEnvironment>, ) { let env = match environment { BindingLocatorScope::GlobalObject | BindingLocatorScope::GlobalDeclarative => global, @@ -350,7 +355,7 @@ impl EnvironmentStack { } /// Push a private environment to the private environment stack. - pub(crate) fn push_private(&mut self, environment: Gc) { + pub(crate) fn push_private(&mut self, environment: Gc<'static, PrivateEnvironment>) { self.private_stack.push(environment); } @@ -413,7 +418,7 @@ impl EnvironmentStack { } /// Compute the `(poisoned, with)` flags for a new environment. - fn compute_poisoned_with(&self, global: &Gc) -> (bool, bool) { + fn compute_poisoned_with(&self, global: &Gc<'static, DeclarativeEnvironment>) -> (bool, bool) { let with = if let Some(env) = self.last() { env.as_declarative().is_none() } else { diff --git a/core/engine/src/module/mod.rs b/core/engine/src/module/mod.rs index af74f3c1a09..3d798eddb10 100644 --- a/core/engine/src/module/mod.rs +++ b/core/engine/src/module/mod.rs @@ -170,7 +170,7 @@ impl ModuleRequest { /// [spec]: https://tc39.es/ecma262/#sec-abstract-module-records #[derive(Clone, Trace, Finalize)] pub struct Module { - inner: Gc, + inner: Gc<'static, ModuleRepr>, } impl std::fmt::Debug for Module { @@ -382,7 +382,7 @@ impl Module { } /// Gets the declarative environment of this `Module`. - pub(crate) fn environment(&self) -> Option> { + pub(crate) fn environment(&self) -> Option> { match self.kind() { ModuleKind::SourceText(src) => src.environment(), ModuleKind::Synthetic(syn) => syn.environment(), @@ -808,7 +808,7 @@ fn into_js_module() { use std::cell::RefCell; use std::rc::Rc; - type ResultType = Gc>; + type ResultType = Gc<'static, GcRefCell>; let loader = Rc::new(MapModuleLoader::default()); let mut context = Context::builder() diff --git a/core/engine/src/module/source.rs b/core/engine/src/module/source.rs index f19bdf175ad..a234c28c180 100644 --- a/core/engine/src/module/source.rs +++ b/core/engine/src/module/source.rs @@ -68,17 +68,17 @@ enum ModuleStatus { ancestor_index: usize, }, PreLinked { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, context: SourceTextContext, ancestor_index: usize, }, Linked { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, context: SourceTextContext, ancestor_index: usize, }, Evaluating { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, context: SourceTextContext, top_level_capability: Option, cycle_root: Module, @@ -86,7 +86,7 @@ enum ModuleStatus { async_evaluation_order: Option, }, EvaluatingAsync { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, context: SourceTextContext, top_level_capability: Option, cycle_root: Module, @@ -94,7 +94,7 @@ enum ModuleStatus { pending_async_dependencies: usize, }, Evaluated { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, top_level_capability: Option, cycle_root: Module, error: Option, @@ -196,7 +196,7 @@ impl ModuleStatus { } /// Gets the declarative environment from the module status. - fn environment(&self) -> Option> { + fn environment(&self) -> Option> { match self { ModuleStatus::Unlinked { .. } | ModuleStatus::Linking { .. } => None, ModuleStatus::PreLinked { environment, .. } @@ -231,7 +231,7 @@ impl ModuleStatus { #[derive(Clone, Trace, Finalize)] #[boa_gc(unsafe_no_drop)] struct SourceTextContext { - codeblock: Gc, + codeblock: Gc<'static, CodeBlock>, environments: EnvironmentStack, realm: Realm, } @@ -2031,7 +2031,7 @@ impl SourceTextModule { } /// Gets the declarative environment of this module. - pub(crate) fn environment(&self) -> Option> { + pub(crate) fn environment(&self) -> Option> { self.status.borrow().environment() } } diff --git a/core/engine/src/module/synthetic.rs b/core/engine/src/module/synthetic.rs index 3dd783fb21a..374088dfadb 100644 --- a/core/engine/src/module/synthetic.rs +++ b/core/engine/src/module/synthetic.rs @@ -53,7 +53,7 @@ where /// **Undefined Behaviour**. #[derive(Clone, Trace, Finalize)] pub struct SyntheticModuleInitializer { - inner: Gc, + inner: Gc<'static, dyn TraceableCallback>, } impl std::fmt::Debug for SyntheticModuleInitializer { @@ -147,11 +147,11 @@ enum ModuleStatus { #[default] Unlinked, Linked { - environment: Gc, - eval_context: (EnvironmentStack, Gc), + environment: Gc<'static, DeclarativeEnvironment>, + eval_context: (EnvironmentStack, Gc<'static, CodeBlock>), }, Evaluated { - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, promise: JsPromise, }, } @@ -450,7 +450,7 @@ impl SyntheticModule { Ok(promise) } - pub(crate) fn environment(&self) -> Option> { + pub(crate) fn environment(&self) -> Option> { match &*self.state.borrow() { ModuleStatus::Unlinked => None, ModuleStatus::Linked { environment, .. } diff --git a/core/engine/src/native_function/continuation.rs b/core/engine/src/native_function/continuation.rs index 921d1e69ed1..44b3bd0299a 100644 --- a/core/engine/src/native_function/continuation.rs +++ b/core/engine/src/native_function/continuation.rs @@ -72,7 +72,7 @@ where /// **Undefined Behaviour**. #[derive(Clone, Trace, Finalize)] pub(crate) struct NativeCoroutine { - inner: Gc, + inner: Gc<'static, dyn TraceableCoroutine>, } impl std::fmt::Debug for NativeCoroutine { diff --git a/core/engine/src/native_function/mod.rs b/core/engine/src/native_function/mod.rs index da480f914dc..a09beefd8a5 100644 --- a/core/engine/src/native_function/mod.rs +++ b/core/engine/src/native_function/mod.rs @@ -134,7 +134,7 @@ pub struct NativeFunction { #[derive(Clone)] enum Inner { PointerFn(NativeFunctionPointer), - Closure(Gc), + Closure(Gc<'static, dyn TraceableClosure>), } // Manual implementation because deriving `Trace` triggers the `single_use_lifetimes` lint. diff --git a/core/engine/src/object/builtins/jspromise.rs b/core/engine/src/object/builtins/jspromise.rs index a2ed16760ea..649469318bb 100644 --- a/core/engine/src/object/builtins/jspromise.rs +++ b/core/engine/src/object/builtins/jspromise.rs @@ -1427,7 +1427,7 @@ impl TryIntoJs for JsPromise { /// /// The only way to construct an instance of `JsFuture` is by calling [`JsPromise::into_js_future`]. pub struct JsFuture { - inner: Gc>, + inner: Gc<'static, GcRefCell>, } impl std::fmt::Debug for JsFuture { diff --git a/core/engine/src/object/datatypes.rs b/core/engine/src/object/datatypes.rs index 31ff76f55b9..9d62f28b99a 100644 --- a/core/engine/src/object/datatypes.rs +++ b/core/engine/src/object/datatypes.rs @@ -201,7 +201,7 @@ impl JsData for Cell> {} #[cfg(feature = "intl")] default_impls!(icu_locale::Locale); -impl JsData for Gc {} +impl JsData for Gc<'static, T> {} impl JsData for WeakGc {} diff --git a/core/engine/src/object/jsobject.rs b/core/engine/src/object/jsobject.rs index d755236d11f..f971bf67812 100644 --- a/core/engine/src/object/jsobject.rs +++ b/core/engine/src/object/jsobject.rs @@ -60,7 +60,7 @@ impl JsData for ErasedObjectData {} #[derive(Trace, Finalize)] #[boa_gc(unsafe_no_drop)] pub struct JsObject { - inner: Gc>, + inner: Gc<'static, VTableObject>, } impl Clone for JsObject { @@ -1038,11 +1038,11 @@ impl JsObject { self.inner.vtable } - pub(crate) fn inner(&self) -> &Gc> { + pub(crate) fn inner(&self) -> &Gc<'static, VTableObject> { &self.inner } - pub(crate) fn from_inner(inner: Gc>) -> Self { + pub(crate) fn from_inner(inner: Gc<'static, VTableObject>) -> Self { Self { inner } } @@ -1158,9 +1158,9 @@ impl AsRef>> for JsObject { } } -impl From>> for JsObject { +impl From>> for JsObject { #[inline] - fn from(inner: Gc>) -> Self { + fn from(inner: Gc<'static, VTableObject>) -> Self { Self { inner } } } diff --git a/core/engine/src/object/shape/shared_shape/forward_transition.rs b/core/engine/src/object/shape/shared_shape/forward_transition.rs index ccaf53995de..3d4292eba59 100644 --- a/core/engine/src/object/shape/shared_shape/forward_transition.rs +++ b/core/engine/src/object/shape/shared_shape/forward_transition.rs @@ -54,7 +54,11 @@ pub(super) struct ForwardTransition { impl ForwardTransition { /// Insert a property transition. - pub(super) fn insert_property(&self, key: TransitionKey, value: &Gc) { + pub(super) fn insert_property( + &self, + key: TransitionKey, + value: &Gc<'static, SharedShapeInner>, + ) { let mut this = self.inner.borrow_mut(); let properties = this.properties.get_or_insert_with(Box::default); @@ -66,7 +70,7 @@ impl ForwardTransition { } /// Insert a prototype transition. - pub(super) fn insert_prototype(&self, key: JsPrototype, value: &Gc) { + pub(super) fn insert_prototype(&self, key: JsPrototype, value: &Gc<'static, SharedShapeInner>) { let mut this = self.inner.borrow_mut(); let prototypes = this.prototypes.get_or_insert_with(Box::default); diff --git a/core/engine/src/object/shape/shared_shape/mod.rs b/core/engine/src/object/shape/shared_shape/mod.rs index 13ed5de88b4..bb04e33a561 100644 --- a/core/engine/src/object/shape/shared_shape/mod.rs +++ b/core/engine/src/object/shape/shared_shape/mod.rs @@ -110,7 +110,7 @@ struct Inner { /// Represents a shared object shape. #[derive(Debug, Trace, Finalize, Clone)] pub struct SharedShape { - inner: Gc, + inner: Gc<'static, Inner>, } impl SharedShape { diff --git a/core/engine/src/object/shape/unique_shape.rs b/core/engine/src/object/shape/unique_shape.rs index 915f278fbfb..bfac600e7d2 100644 --- a/core/engine/src/object/shape/unique_shape.rs +++ b/core/engine/src/object/shape/unique_shape.rs @@ -30,7 +30,7 @@ struct Inner { /// Cloning this does a shallow clone. #[derive(Default, Debug, Clone, Trace, Finalize)] pub(crate) struct UniqueShape { - inner: Gc, + inner: Gc<'static, Inner>, } impl UniqueShape { diff --git a/core/engine/src/realm.rs b/core/engine/src/realm.rs index 13e9b7a6c67..dcf03f71fec 100644 --- a/core/engine/src/realm.rs +++ b/core/engine/src/realm.rs @@ -30,7 +30,7 @@ use rustc_hash::FxHashMap; /// In the specification these are called Realm Records. #[derive(Clone, Trace, Finalize)] pub struct Realm { - inner: Gc, + inner: Gc<'static, Inner>, } impl Eq for Realm {} @@ -57,7 +57,7 @@ struct Inner { intrinsics: Intrinsics, /// The global declarative environment of this realm. - environment: Gc, + environment: Gc<'static, DeclarativeEnvironment>, /// The global scope of this realm. /// This is directly related to the global declarative environment. @@ -162,7 +162,7 @@ impl Realm { .cloned() } - pub(crate) fn environment(&self) -> &Gc { + pub(crate) fn environment(&self) -> &Gc<'static, DeclarativeEnvironment> { &self.inner.environment } diff --git a/core/engine/src/script.rs b/core/engine/src/script.rs index ceba9c24a9a..63ccffb0c35 100644 --- a/core/engine/src/script.rs +++ b/core/engine/src/script.rs @@ -30,7 +30,7 @@ use crate::{ /// [spec]: https://tc39.es/ecma262/#sec-script-records #[derive(Clone, Trace, Finalize)] pub struct Script { - inner: Gc, + inner: Gc<'static, Inner>, } impl std::fmt::Debug for Script { @@ -46,7 +46,7 @@ impl std::fmt::Debug for Script { #[derive(Trace, Debug, Finalize)] enum ScriptPhase { Ast(#[unsafe_ignore_trace] boa_ast::Script), - Codeblock(Gc), + Codeblock(Gc<'static, CodeBlock>), } #[derive(Trace, Finalize)] @@ -118,7 +118,7 @@ impl Script { /// Compiles the codeblock of this script. /// /// This is a no-op if this has been called previously. - pub fn codeblock(&self, context: &mut Context) -> JsResult> { + pub fn codeblock(&self, context: &mut Context) -> JsResult> { let cb = { let phase = self.inner.phase.borrow(); let source = match &*phase { diff --git a/core/engine/src/vm/call_frame/mod.rs b/core/engine/src/vm/call_frame/mod.rs index cd560f18594..3b50f88875e 100644 --- a/core/engine/src/vm/call_frame/mod.rs +++ b/core/engine/src/vm/call_frame/mod.rs @@ -46,7 +46,7 @@ pub struct CallFrameLocation { /// A `CallFrame` holds the state of a function call. #[derive(Clone, Debug, Finalize, Trace)] pub struct CallFrame { - pub(crate) code_block: Gc, + pub(crate) code_block: Gc<'static, CodeBlock>, pub(crate) pc: u32, /// The frame pointer, points to the start of this frame's data in the stack /// (i.e., the `this` value position). @@ -87,7 +87,7 @@ impl CallFrame { /// Retrieves the [`CodeBlock`] of this call frame. #[inline] #[must_use] - pub const fn code_block(&self) -> &Gc { + pub const fn code_block(&self) -> &Gc<'static, CodeBlock> { &self.code_block } @@ -136,7 +136,7 @@ impl CallFrame { /// Creates a new `CallFrame` with the provided `CodeBlock`. pub(crate) fn new( - code_block: Gc, + code_block: Gc<'static, CodeBlock>, active_runnable: Option, environments: EnvironmentStack, realm: Realm, diff --git a/core/engine/src/vm/code_block.rs b/core/engine/src/vm/code_block.rs index 8d98737fef2..fb494a0a972 100644 --- a/core/engine/src/vm/code_block.rs +++ b/core/engine/src/vm/code_block.rs @@ -100,7 +100,7 @@ impl Handler { pub(crate) enum Constant { /// Property field names and private names `[[description]]`s. String(JsString), - Function(Gc), + Function(Gc<'static, CodeBlock>), BigInt(#[unsafe_ignore_trace] JsBigInt), /// Declarative or function scope. @@ -324,13 +324,13 @@ impl CodeBlock { panic!("expected string constant at index {index}") } - /// Get the function ([`Gc`]) constant from the [`CodeBlock`]. + /// Get the function ([`Gc<'static, CodeBlock>`]) constant from the [`CodeBlock`]. /// /// # Panics /// /// If the type of the [`Constant`] is not [`Constant::Function`]. /// Or `index` is greater or equal to length of `constants`. - pub(crate) fn constant_function(&self, index: usize) -> Gc { + pub(crate) fn constant_function(&self, index: usize) -> Gc<'static, Self> { if let Some(Constant::Function(value)) = self.constants.get(index) { return value.clone(); } @@ -1092,7 +1092,7 @@ impl Display for CodeBlock { /// /// This is slower than direct object template construction that is done in [`create_function_object_fast`]. pub(crate) fn create_function_object( - code: Gc, + code: Gc<'static, CodeBlock>, prototype: JsObject, context: &mut Context, ) -> JsObject { @@ -1163,7 +1163,10 @@ pub(crate) fn create_function_object( /// This is preferred over [`create_function_object`] if prototype is [`None`], /// because it constructs the function from a pre-initialized object template, /// with all the properties and prototype set. -pub(crate) fn create_function_object_fast(code: Gc, context: &mut Context) -> JsObject { +pub(crate) fn create_function_object_fast( + code: Gc<'static, CodeBlock>, + context: &mut Context, +) -> JsObject { let name: JsValue = code.name().clone().into(); let length: JsValue = code.length.into(); diff --git a/core/engine/src/vm/inline_cache/tests.rs b/core/engine/src/vm/inline_cache/tests.rs index 1f93754b4b3..7e893b5dabc 100644 --- a/core/engine/src/vm/inline_cache/tests.rs +++ b/core/engine/src/vm/inline_cache/tests.rs @@ -316,7 +316,7 @@ fn set_internal_method() { assert_eq!(context.slot().index, slot.index); } -fn get_codeblock(value: &JsValue) -> Option<(JsObject, Gc)> { +fn get_codeblock(value: &JsValue) -> Option<(JsObject, Gc<'static, CodeBlock>)> { let object = value.as_object()?.clone(); let code = object.downcast_ref::()?.code.clone(); diff --git a/core/gc/src/boa_allocator.rs b/core/gc/src/boa_allocator.rs index 0d426c924d0..2a34abf4a60 100644 --- a/core/gc/src/boa_allocator.rs +++ b/core/gc/src/boa_allocator.rs @@ -1,4 +1,7 @@ -use super::*; +use super::{ + Cell, EphemeronBox, ErasedEphemeronBox, ErasedWeakMapBox, Gc, GcBox, GcRefCell, NonNull, + NonTraceable, RawWeakMap, RefCell, Trace, Tracer, WeakGc, WeakMap, WeakMapBox, mem, +}; pub(crate) type GcErasedPointer = NonNull>; pub(crate) type EphemeronPointer = NonNull; diff --git a/core/gc/src/internals/ephemeron_box.rs b/core/gc/src/internals/ephemeron_box.rs index f88e9989cff..edce794da3b 100644 --- a/core/gc/src/internals/ephemeron_box.rs +++ b/core/gc/src/internals/ephemeron_box.rs @@ -16,7 +16,7 @@ struct Data { impl EphemeronBox { /// Creates a new `EphemeronBox` that tracks `key` and has `value` as its inner data. - pub(crate) fn new(key: &Gc, value: V) -> Self { + pub(crate) fn new(key: &Gc<'_, K>, value: V) -> Self { Self { header: GcHeader::new(), data: UnsafeCell::new(Some(Data { @@ -88,7 +88,7 @@ impl EphemeronBox { /// /// The caller must ensure there are no live mutable references to the ephemeron box's data /// before calling this method. - pub(crate) unsafe fn set(&self, key: &Gc, value: V) { + pub(crate) unsafe fn set(&self, key: &Gc<'_, K>, value: V) { // SAFETY: The caller must ensure setting the key and value of the ephemeron box is safe. unsafe { *self.data.get() = Some(Data { diff --git a/core/gc/src/pointers/ephemeron.rs b/core/gc/src/pointers/ephemeron.rs index 519381c9593..0fccf5a5404 100644 --- a/core/gc/src/pointers/ephemeron.rs +++ b/core/gc/src/pointers/ephemeron.rs @@ -15,7 +15,7 @@ use std::{ops::Deref, ptr::NonNull}; #[derive(Debug)] pub struct EphemeronValueRef<'a, K: Trace + ?Sized + 'static, V> { // Only required to maintain the reference `&V` alive. - _key: Gc, + _key: Gc<'a, K>, value: &'a V, } @@ -45,7 +45,7 @@ pub struct Ephemeron { impl Ephemeron { /// Creates a new `Ephemeron`. #[must_use] - pub fn new(key: &Gc, value: V) -> Self { + pub fn new(key: &Gc<'_, K>, value: V) -> Self { let inner_ptr = Allocator::alloc_ephemeron(EphemeronBox::new(key, value)); Self { inner_ptr } } @@ -53,7 +53,7 @@ impl Ephemeron { /// Gets the stored key of this `Ephemeron`, or `None` if the key was already garbage collected. #[inline] #[must_use] - pub fn key(&self) -> Option> { + pub fn key(&self) -> Option> { // SAFETY: this is safe because `Ephemeron` is tracked to always point to a valid pointer // `inner_ptr`. let key_ptr = unsafe { self.inner_ptr.as_ref().key_ptr() }?; diff --git a/core/gc/src/pointers/gc.rs b/core/gc/src/pointers/gc.rs index 988a62f7dfc..8c2ebecc50d 100644 --- a/core/gc/src/pointers/gc.rs +++ b/core/gc/src/pointers/gc.rs @@ -49,15 +49,15 @@ impl Drop for NonTraceable { /// A type erased [`Gc`] pointer type. #[repr(transparent)] -pub struct GcErased { - inner: Gc, +pub struct GcErased<'gc> { + inner: Gc<'gc, NonTraceable>, } -impl GcErased { +impl<'gc> GcErased<'gc> { /// Convert a [`Gc`] into a type erased [`GcErased`]. #[inline] #[must_use] - pub fn new(gc: Gc) -> Self { + pub fn new(gc: Gc<'gc, T>) -> Self { let inner_ptr = gc.inner_ptr; std::mem::forget(gc); @@ -79,21 +79,25 @@ impl GcErased { #[inline] #[must_use] pub fn type_id(&self) -> TypeId { - Gc::type_id(&self.inner) + self.inner.vtable().type_id() } /// Returns true if the inner type is the same as `T`. #[inline] #[must_use] pub fn is(&self) -> bool { - Gc::is::(&self.inner) + self.type_id() == TypeId::of::() } - /// Returns [`Some`] `Gc` if it is of type `T`, or [`None`] if it isn’t. + /// Returns [`Some`] `Gc` if it is of type `T`, or [`None`] if it isn't. #[inline] #[must_use] - pub fn downcast(self) -> Option> { - Gc::downcast::(self.inner) + pub fn downcast(self) -> Option> { + if !self.is::() { + return None; + } + // SAFETY: verified the type above + Some(unsafe { Gc::cast_unchecked::(self.inner) }) } /// Downcast the inner value of type `T`. @@ -103,7 +107,7 @@ impl GcErased { /// The caller must ensure that the cast is valid. #[inline] #[must_use] - pub unsafe fn downcast_unchecked(self) -> Gc { + pub unsafe fn downcast_unchecked(self) -> Gc<'gc, T> { // SAFETY: It's the callers responsibility to make sure this is valid. unsafe { Gc::cast_unchecked::(self.inner) } } @@ -115,13 +119,13 @@ impl GcErased { /// The caller must ensure that the cast is valid. #[inline] #[must_use] - pub unsafe fn downcast_ref_unchecked(&self) -> &Gc { + pub unsafe fn downcast_ref_unchecked(&self) -> &Gc<'gc, T> { // SAFETY: It's the callers responsibility to make sure this is valid. unsafe { Gc::cast_ref_unchecked::(&self.inner) } } } -impl Debug for GcErased { +impl Debug for GcErased<'_> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("GcErased") @@ -130,19 +134,19 @@ impl Debug for GcErased { } } -impl Finalize for GcErased { +impl Finalize for GcErased<'_> { fn finalize(&self) {} } // SAFETY: We only have one transparent field in GcErased that needs trace, // so this is safe. -unsafe impl Trace for GcErased { +unsafe impl Trace for GcErased<'_> { custom_trace!(this, mark, { mark(&this.inner); }); } -impl Clone for GcErased { +impl Clone for GcErased<'_> { #[inline] fn clone(&self) -> Self { Self { @@ -152,12 +156,14 @@ impl Clone for GcErased { } /// A garbage-collected pointer type over an immutable value. -pub struct Gc { +pub struct Gc<'gc, T: Trace + ?Sized + 'static> { pub(crate) inner_ptr: NonNull>, - pub(crate) marker: PhantomData>, + // `Rc` makes `Gc` invariant over `T` and non-`Send`/non-`Sync`, + // `&'gc ()` brands the pointer to a specific gc arena lifetime + pub(crate) marker: PhantomData<(Rc, PhantomData<&'gc ()>)>, } -impl Gc { +impl<'gc, T: Trace + ?Sized + 'static> Gc<'gc, T> { /// Constructs a new `Gc` with the given value. #[must_use] pub fn new(value: T) -> Self @@ -217,7 +223,7 @@ impl Gc { /// Returns `true` if the two `Gc`s point to the same allocation. #[must_use] - pub fn ptr_eq(this: &Self, other: &Gc) -> bool { + pub fn ptr_eq(this: &Self, other: &Gc<'_, U>) -> bool { std::ptr::addr_eq(this.inner(), other.inner()) } @@ -259,7 +265,7 @@ impl Gc { /// Returns [`Some`] reference to the inner value if it is of type `T`, or [`None`] if it isn’t. #[inline] #[must_use] - pub fn downcast(this: Self) -> Option> { + pub fn downcast(this: Self) -> Option> { if !Gc::is::(&this) { return None; } @@ -275,7 +281,7 @@ impl Gc { /// The caller must ensure that the cast is valid. #[inline] #[must_use] - pub unsafe fn cast_unchecked(this: Self) -> Gc { + pub unsafe fn cast_unchecked(this: Self) -> Gc<'gc, U> { let inner_ptr = this.inner_ptr.cast::(); core::mem::forget(this); // Prevents double free. Gc { @@ -291,14 +297,14 @@ impl Gc { /// The caller must ensure that the cast is valid. #[inline] #[must_use] - pub unsafe fn cast_ref_unchecked(this: &Self) -> &Gc { + pub unsafe fn cast_ref_unchecked(this: &Self) -> &Gc<'gc, U> { // SAFETY: Casting a Gc to a Gc of any type is safe, as long as you don’t actually access it as a U. // The correct functions for T will still be called during tracing, finalization, and dropping. - unsafe { &(*(&raw const *this).cast::>()) } + unsafe { &(*(&raw const *this).cast::>()) } } } -impl Gc { +impl Gc<'_, T> { pub(crate) fn vtable(&self) -> &'static VTable { // SAFETY: The inner pointer is valid at all times. unsafe { self.inner_ptr.as_ref() }.vtable @@ -317,7 +323,7 @@ impl Gc { } } -impl Finalize for Gc { +impl Finalize for Gc<'_, T> { fn finalize(&self) { // SAFETY: inner_ptr should be alive when calling finalize. // We don't call inner_ptr() to avoid overhead of calling finalizer_safe(). @@ -329,7 +335,7 @@ impl Finalize for Gc { // SAFETY: `Gc` maintains it's own rootedness and implements all methods of // Trace. It is not possible to root an already rooted `Gc` and vice versa. -unsafe impl Trace for Gc { +unsafe impl Trace for Gc<'_, T> { unsafe fn trace(&self, tracer: &mut Tracer) { tracer.enqueue(self.as_erased_pointer()); } @@ -343,7 +349,7 @@ unsafe impl Trace for Gc { } } -impl Clone for Gc { +impl Clone for Gc<'_, T> { fn clone(&self) -> Self { let ptr = self.inner_ptr(); // SAFETY: though `ptr` doesn't come from a `into_raw` call, it essentially does the same, @@ -356,7 +362,7 @@ impl Clone for Gc { } } -impl Deref for Gc { +impl Deref for Gc<'_, T> { type Target = T; fn deref(&self) -> &T { @@ -364,7 +370,7 @@ impl Deref for Gc { } } -impl Drop for Gc { +impl Drop for Gc<'_, T> { fn drop(&mut self) { if finalizer_safe() { Finalize::finalize(self); @@ -372,24 +378,24 @@ impl Drop for Gc { } } -impl Default for Gc { +impl Default for Gc<'_, T> { fn default() -> Self { Self::new(Default::default()) } } #[allow(clippy::inline_always)] -impl PartialEq for Gc { +impl PartialEq for Gc<'_, T> { #[inline(always)] fn eq(&self, other: &Self) -> bool { **self == **other } } -impl Eq for Gc {} +impl Eq for Gc<'_, T> {} #[allow(clippy::inline_always)] -impl PartialOrd for Gc { +impl PartialOrd for Gc<'_, T> { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { (**self).partial_cmp(&**other) @@ -416,43 +422,43 @@ impl PartialOrd for Gc { } } -impl Ord for Gc { +impl Ord for Gc<'_, T> { fn cmp(&self, other: &Self) -> Ordering { (**self).cmp(&**other) } } -impl Hash for Gc { +impl Hash for Gc<'_, T> { fn hash(&self, state: &mut H) { (**self).hash(state); } } -impl Display for Gc { +impl Display for Gc<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&**self, f) } } -impl Debug for Gc { +impl Debug for Gc<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&**self, f) } } -impl fmt::Pointer for Gc { +impl fmt::Pointer for Gc<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&self.inner(), f) } } -impl std::borrow::Borrow for Gc { +impl std::borrow::Borrow for Gc<'_, T> { fn borrow(&self) -> &T { self } } -impl AsRef for Gc { +impl AsRef for Gc<'_, T> { fn as_ref(&self) -> &T { self } diff --git a/core/gc/src/pointers/weak.rs b/core/gc/src/pointers/weak.rs index 4cd38a8f489..0649af2be54 100644 --- a/core/gc/src/pointers/weak.rs +++ b/core/gc/src/pointers/weak.rs @@ -15,7 +15,7 @@ impl WeakGc { /// Creates a new weak pointer for a garbage collected value. #[inline] #[must_use] - pub fn new(value: &Gc) -> Self { + pub fn new(value: &Gc<'_, T>) -> Self { Self { inner: Ephemeron::new(value, ()), } @@ -25,7 +25,7 @@ impl WeakGc { /// if the value was already garbage collected. #[inline] #[must_use] - pub fn upgrade(&self) -> Option> { + pub fn upgrade(&self) -> Option> { self.inner.key() } diff --git a/core/gc/src/pointers/weak_map.rs b/core/gc/src/pointers/weak_map.rs index 5d13b35ae59..12a7eb4dd75 100644 --- a/core/gc/src/pointers/weak_map.rs +++ b/core/gc/src/pointers/weak_map.rs @@ -12,7 +12,7 @@ use std::{fmt, hash::BuildHasher, marker::PhantomData}; /// A map that holds weak references to its keys and is traced by the garbage collector. #[derive(Clone, Debug, Default, Finalize)] pub struct WeakMap { - pub(crate) inner: Gc>>, + pub(crate) inner: Gc<'static, GcRefCell>>, } unsafe impl Trace for WeakMap { @@ -21,7 +21,7 @@ unsafe impl Trace for WeakMap WeakMap { +impl WeakMap { /// Creates a new `WeakMap`. #[must_use] #[inline] @@ -31,28 +31,28 @@ impl WeakMap { /// Inserts a key-value pair into the map. #[inline] - pub fn insert(&mut self, key: &Gc, value: V) { + pub fn insert(&mut self, key: &Gc<'_, K>, value: V) { self.inner.borrow_mut().insert(key, value); } /// Removes a key from the map, returning `true` if the key was previously in /// the map. #[inline] - pub fn remove(&mut self, key: &Gc) -> bool { + pub fn remove(&mut self, key: &Gc<'_, K>) -> bool { self.inner.borrow_mut().remove(key) } /// Returns `true` if the map contains a value for the specified key. #[must_use] #[inline] - pub fn contains_key(&self, key: &Gc) -> bool { + pub fn contains_key(&self, key: &Gc<'_, K>) -> bool { self.inner.borrow().contains_key(key) } /// Returns a reference to the ephemeron corresponding to the key. #[must_use] #[inline] - pub fn get<'a>(&'a self, key: &Gc) -> Option>> { + pub fn get<'a>(&'a self, key: &Gc<'_, K>) -> Option>> { GcRef::try_map(self.inner.borrow(), |inner| inner.get(key)) } } @@ -277,7 +277,7 @@ where } /// Returns the ephemeron corresponding to the supplied key. - pub(crate) fn get(&self, k: &Gc) -> Option<&Ephemeron> { + pub(crate) fn get(&self, k: &Gc<'_, K>) -> Option<&Ephemeron> { if self.table.is_empty() { None } else { @@ -287,7 +287,7 @@ where } /// Returns `true` if the map contains a value for the specified key. - pub(crate) fn contains_key(&self, k: &Gc) -> bool { + pub(crate) fn contains_key(&self, k: &Gc<'_, K>) -> bool { self.get(k).is_some() } @@ -297,7 +297,7 @@ where /// /// If the map did have this key present, the value is updated, and the old /// value is returned. The key is not updated. - pub(crate) fn insert(&mut self, k: &Gc, v: V) -> Option> { + pub(crate) fn insert(&mut self, k: &Gc<'_, K>, v: V) -> Option> { let hash = make_hash_from_gc(&self.hash_builder, k); let hasher = make_hasher(&self.hash_builder); let entry = self.table.entry(hash, equivalent_key(k), hasher); @@ -315,7 +315,7 @@ where /// Removes a key from the map, returning `true` if the key /// was previously in the map. Keeps the allocated memory for reuse. - pub(crate) fn remove(&mut self, k: &Gc) -> bool { + pub(crate) fn remove(&mut self, k: &Gc<'_, K>) -> bool { let hash = make_hash_from_gc(&self.hash_builder, k); if let Ok(entry) = self.table.find_entry(hash, equivalent_key(k)) { entry.remove(); @@ -424,7 +424,7 @@ where state.finish() } -fn make_hash_from_gc(hash_builder: &S, gc: &Gc) -> u64 +fn make_hash_from_gc(hash_builder: &S, gc: &Gc<'_, K>) -> u64 where S: BuildHasher, K: Trace + ?Sized + 'static, @@ -435,7 +435,7 @@ where state.finish() } -fn equivalent_key(k: &Gc) -> impl Fn(&Ephemeron) -> bool + '_ +fn equivalent_key<'a, K, V>(k: &'a Gc<'a, K>) -> impl Fn(&Ephemeron) -> bool + 'a where K: Trace + ?Sized + 'static, V: Trace + 'static, diff --git a/core/gc/src/test/allocation.rs b/core/gc/src/test/allocation.rs index e31d699c8d9..12c7c5e0f04 100644 --- a/core/gc/src/test/allocation.rs +++ b/core/gc/src/test/allocation.rs @@ -41,7 +41,7 @@ mod miri { #[derive(Debug, Finalize, Trace)] struct S { i: usize, - next: Option>, + next: Option>, } const SIZE: usize = size_of::>(); diff --git a/core/gc/src/test/erased.rs b/core/gc/src/test/erased.rs index 41451e5624a..95b34f9d5be 100644 --- a/core/gc/src/test/erased.rs +++ b/core/gc/src/test/erased.rs @@ -33,7 +33,7 @@ mod miri { #[derive(Debug, Trace, Finalize)] struct List { value: i32, - next: Option, + next: Option>, } run_test(|| { diff --git a/core/gc/src/test/weak.rs b/core/gc/src/test/weak.rs index 6b8613747d5..9ac4a248815 100644 --- a/core/gc/src/test/weak.rs +++ b/core/gc/src/test/weak.rs @@ -148,7 +148,7 @@ mod miri { } #[derive(Trace, Finalize, Clone)] struct TestCell { - inner: Gc, + inner: Gc<'static, InnerCell>, } run_test(|| { let root = TestCell { @@ -182,7 +182,7 @@ mod miri { fn eph_self_referential_chain() { #[derive(Trace, Finalize, Clone)] struct TestCell { - inner: Gc>>>, + inner: Gc<'static, GcRefCell>>>, } run_test(|| { let root = Gc::new(GcRefCell::new(None)); @@ -301,7 +301,7 @@ mod miri { type Inner = GcRefCell<(Option, Option)>; #[derive(Trace, Finalize, Clone)] struct TestCell { - inner: Gc, + inner: Gc<'static, Inner>, } run_test(|| { let root = TestCell { diff --git a/core/runtime/src/console/tests.rs b/core/runtime/src/console/tests.rs index 6ff1de47430..a536e02138a 100644 --- a/core/runtime/src/console/tests.rs +++ b/core/runtime/src/console/tests.rs @@ -116,7 +116,7 @@ fn console_log_cyclic() { /// A logger that records all log messages. #[derive(Clone, Debug, Default, boa_engine::Trace, boa_engine::Finalize)] pub(crate) struct RecordingLogger { - pub log: Gc>, + pub log: Gc<'static, GcRefCell>, } impl Logger for RecordingLogger { diff --git a/tests/macros/tests/gcd_callback.rs b/tests/macros/tests/gcd_callback.rs index 645413a8dd8..0aa45890b30 100644 --- a/tests/macros/tests/gcd_callback.rs +++ b/tests/macros/tests/gcd_callback.rs @@ -8,7 +8,7 @@ use boa_gc::Gc; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; -fn callback_from_js(ContextData(r): ContextData>, result: usize) { +fn callback_from_js(ContextData(r): ContextData>, result: usize) { r.store(result, Ordering::Relaxed); } diff --git a/tests/wpt/src/logger/mod.rs b/tests/wpt/src/logger/mod.rs index 2b885b6343a..f0c7f27526c 100644 --- a/tests/wpt/src/logger/mod.rs +++ b/tests/wpt/src/logger/mod.rs @@ -35,7 +35,7 @@ struct RecordingLoggerInner { #[derive(Clone, Trace, Finalize, JsData)] pub(crate) struct RecordingLogger { /// Also send logs to this logger. - tee: Gc>, + tee: Gc<'static, Box>, #[unsafe_ignore_trace] inner: Rc>,