diff --git a/core/engine/src/builtins/eval/mod.rs b/core/engine/src/builtins/eval/mod.rs index f8fc8f458f0..7b0f9246640 100644 --- a/core/engine/src/builtins/eval/mod.rs +++ b/core/engine/src/builtins/eval/mod.rs @@ -320,7 +320,10 @@ impl Eval { compiler.compile_statement_list(body.statements(), true, false); - let code_block = Gc::new(compiler.finish()); + let code_block = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ); // Strict calls don't need extensions, since all strict eval calls push a new // function environment before evaluating. diff --git a/core/engine/src/builtins/finalization_registry/mod.rs b/core/engine/src/builtins/finalization_registry/mod.rs index ad41948e4f0..4ec7ba0c0f3 100644 --- a/core/engine/src/builtins/finalization_registry/mod.rs +++ b/core/engine/src/builtins/finalization_registry/mod.rs @@ -158,7 +158,10 @@ impl BuiltInConstructor for FinalizationRegistry { }, ); - let weak_registry = WeakGc::new(registry.inner()); + let weak_registry = WeakGc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + registry.inner(), + ); { async fn inner_cleanup( @@ -170,7 +173,10 @@ impl BuiltInConstructor for FinalizationRegistry { return Ok(JsValue::undefined()); }; - let Some(registry) = weak_registry.upgrade().map(JsObject::from_inner) else { + let Some(registry) = weak_registry + .upgrade(&unsafe { boa_gc::MutationContext::dummy() }) + .map(JsObject::from_inner) + else { return Ok(JsValue::undefined()); }; @@ -251,7 +257,10 @@ impl FinalizationRegistry { // // TODO: support Symbols let unregister_token = match unregister_token.variant() { - JsVariant::Object(obj) => Some(WeakGc::new(obj.inner())), + JsVariant::Object(obj) => Some(WeakGc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + obj.inner(), + )), // b. Set unregisterToken to empty. JsVariant::Undefined => None, // a. If unregisterToken is not undefined, throw a TypeError exception. @@ -266,6 +275,7 @@ impl FinalizationRegistry { // 6. Let cell be the Record { [[WeakRefTarget]]: target, [[HeldValue]]: heldValue, [[UnregisterToken]]: unregisterToken }. let cell = RegistryCell { target: Ephemeron::new( + &unsafe { boa_gc::MutationContext::dummy() }, target_obj.inner(), CleanupSignaler(Cell::new(Some( registry.cleanup_notifier.clone().downgrade(), @@ -328,15 +338,20 @@ impl FinalizationRegistry { // a. If cell.[[UnregisterToken]] is not empty and SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then if let Some(tok) = cell.unregister_token.as_ref() - && let Some(tok) = tok.upgrade() + && let Some(tok) = tok.upgrade(&unsafe { boa_gc::MutationContext::dummy() }) && Gc::ptr_eq(&tok, unregister_token) { // i. Remove cell from finalizationRegistry.[[Cells]]. let cell = registry.cells.swap_remove(i); - let _key = cell.target.key(); + let _key = cell + .target + .key(&unsafe { boa_gc::MutationContext::dummy() }); + // TODO: it might be better to add a special ref for the value that // also preserves the original key instead. - cell.target.value().and_then(|v| v.0.take()); + cell.target + .value(&unsafe { boa_gc::MutationContext::dummy() }) + .and_then(|v| v.0.take()); // ii. Set removed to true. removed = true; diff --git a/core/engine/src/builtins/json/mod.rs b/core/engine/src/builtins/json/mod.rs index 514f7afbf1b..be01ebb234b 100644 --- a/core/engine/src/builtins/json/mod.rs +++ b/core/engine/src/builtins/json/mod.rs @@ -307,7 +307,10 @@ impl Json { SourcePath::Json, ); compiler.compile_statement_list(script.statements(), true, false); - Gc::new(compiler.finish()) + Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ) }; let realm = context.realm().clone(); diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index 6024b5b44a3..e79b52fc256 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -243,10 +243,13 @@ impl PromiseCapability { // 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 27.2.3.1). // 3. Let promiseCapability be the PromiseCapability Record { [[Promise]]: undefined, [[Resolve]]: undefined, [[Reject]]: undefined }. - let promise_capability = Gc::new(GcRefCell::new(RejectResolve { - reject: JsValue::undefined(), - resolve: JsValue::undefined(), - })); + let promise_capability = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(RejectResolve { + reject: JsValue::undefined(), + resolve: JsValue::undefined(), + }), + ); // 4. Let executorClosure be a new Abstract Closure with parameters (resolve, reject) that captures promiseCapability and performs the following steps when called: // 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »). @@ -653,7 +656,10 @@ impl Promise { } // 1. Let values be a new empty List. - let values = Gc::new(GcRefCell::new(Vec::new())); + let values = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(Vec::new()), + ); // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }. let remaining_elements_count = Rc::new(Cell::new(1)); @@ -868,7 +874,10 @@ impl Promise { } // 1. Let values be a new empty List. - let values = Gc::new(GcRefCell::new(Vec::new())); + let values = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(Vec::new()), + ); // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }. let remaining_elements_count = Rc::new(Cell::new(1)); @@ -1235,7 +1244,10 @@ impl Promise { let keys = Rc::new(RefCell::new(Vec::new())); // 3. Let values be a new empty List. - let values = Gc::new(GcRefCell::new(Vec::new())); + let values = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(Vec::new()), + ); // 4. Let remainingElementsCount be the Record { [[Value]]: 1 }. let remaining_elements_count = Rc::new(Cell::new(1)); @@ -1545,7 +1557,10 @@ impl Promise { } // 1. Let errors be a new empty List. - let errors = Gc::new(GcRefCell::new(Vec::new())); + let errors = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(Vec::new()), + ); // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }. let remaining_elements_count = Rc::new(Cell::new(1)); @@ -2445,7 +2460,10 @@ impl Promise { // 1. Let alreadyResolved be the Record { [[Value]]: false }. // 5. Set resolve.[[Promise]] to promise. // 6. Set resolve.[[AlreadyResolved]] to alreadyResolved. - let promise = Gc::new(Cell::new(Some(promise.clone()))); + let promise = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Cell::new(Some(promise.clone())), + ); // 2. Let stepsResolve be the algorithm steps defined in Promise Resolve Functions. // 3. Let lengthResolve be the number of non-optional parameters of the function definition in Promise Resolve Functions. diff --git a/core/engine/src/builtins/weak/weak_ref.rs b/core/engine/src/builtins/weak/weak_ref.rs index a2bd0c4cde2..77f136812ac 100644 --- a/core/engine/src/builtins/weak/weak_ref.rs +++ b/core/engine/src/builtins/weak/weak_ref.rs @@ -87,7 +87,7 @@ impl BuiltInConstructor for WeakRef { let weak_ref = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - WeakGc::new(target.inner()), + WeakGc::new(&unsafe { boa_gc::MutationContext::dummy() }, target.inner()), ); // 4. Perform AddToKeptObjects(target). @@ -124,7 +124,7 @@ impl WeakRef { // https://tc39.es/ecma262/multipage/managing-memory.html#sec-weakrefderef // 1. Let target be weakRef.[[WeakRefTarget]]. // 2. If target is not empty, then - if let Some(object) = weak_ref.upgrade() { + if let Some(object) = weak_ref.upgrade(&unsafe { boa_gc::MutationContext::dummy() }) { let object = JsObject::from(object); // a. Perform AddToKeptObjects(target). diff --git a/core/engine/src/builtins/weak_map/mod.rs b/core/engine/src/builtins/weak_map/mod.rs index 5ef5abc8c83..adff36ecbfc 100644 --- a/core/engine/src/builtins/weak_map/mod.rs +++ b/core/engine/src/builtins/weak_map/mod.rs @@ -97,7 +97,7 @@ impl BuiltInConstructor for WeakMap { let map = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - NativeWeakMap::new(), + NativeWeakMap::new(&unsafe { boa_gc::MutationContext::dummy() }), ) .upcast(); @@ -194,7 +194,7 @@ impl WeakMap { // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. // 6. Return undefined. if let Some(entry) = map.get(key.inner()) - && let Some(val) = entry.value() + && let Some(val) = entry.value(&unsafe { boa_gc::MutationContext::dummy() }) { Ok(val.clone()) } else { @@ -325,7 +325,7 @@ impl WeakMap { // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]] if let Some(existing) = map.borrow().data().get(key.inner()) - && let Some(value) = existing.value() + && let Some(value) = existing.value(&unsafe { boa_gc::MutationContext::dummy() }) { // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. return Ok(value.clone()); @@ -387,7 +387,7 @@ impl WeakMap { // 5. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]] if let Some(existing) = map.borrow().data().get(key_obj.inner()) - && let Some(value) = existing.value() + && let Some(value) = existing.value(&unsafe { boa_gc::MutationContext::dummy() }) { // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. return Ok(value.clone()); diff --git a/core/engine/src/builtins/weak_set/mod.rs b/core/engine/src/builtins/weak_set/mod.rs index 7e9575f802f..50647b16881 100644 --- a/core/engine/src/builtins/weak_set/mod.rs +++ b/core/engine/src/builtins/weak_set/mod.rs @@ -86,7 +86,7 @@ impl BuiltInConstructor for WeakSet { let weak_set = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - NativeWeakSet::new(), + NativeWeakSet::new(&unsafe { boa_gc::MutationContext::dummy() }), ) .upcast(); diff --git a/core/engine/src/bytecompiler/class.rs b/core/engine/src/bytecompiler/class.rs index 18a0ee32ccf..a876cc80403 100644 --- a/core/engine/src/bytecompiler/class.rs +++ b/core/engine/src/bytecompiler/class.rs @@ -156,7 +156,10 @@ impl ByteCompiler<'_> { class.super_ref.is_some(), ); - let code = Gc::new(compiler.finish()); + let code = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ); let index = self.push_function_to_constants(code); let class_register = self.register_allocator.alloc(); @@ -440,7 +443,10 @@ impl ByteCompiler<'_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; - let code = Gc::new(field_compiler.finish()); + let code = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + field_compiler.finish(), + ); let index = self.push_function_to_constants(code); let dst = self.register_allocator.alloc(); @@ -486,7 +492,10 @@ impl ByteCompiler<'_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; - let code = Gc::new(field_compiler.finish()); + let code = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + field_compiler.finish(), + ); let index = self.push_function_to_constants(code); let dst = self.register_allocator.alloc(); self.emit_get_function(&dst, index); @@ -542,7 +551,7 @@ impl ByteCompiler<'_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; let code = field_compiler.finish(); - let code = Gc::new(code); + let code = Gc::new(&unsafe { boa_gc::MutationContext::dummy() }, code); static_elements.push(StaticElement::StaticField { code, @@ -586,7 +595,7 @@ impl ByteCompiler<'_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; let code = field_compiler.finish(); - let code = Gc::new(code); + let code = Gc::new(&unsafe { boa_gc::MutationContext::dummy() }, code); static_elements.push(StaticElement::StaticField { code, @@ -629,7 +638,10 @@ impl ByteCompiler<'_> { ); } - let code = Gc::new(compiler.finish()); + let code = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ); static_elements.push(StaticElement::StaticBlock(code)); } } diff --git a/core/engine/src/bytecompiler/function.rs b/core/engine/src/bytecompiler/function.rs index 4aa4bbbe8a2..b862326fc7b 100644 --- a/core/engine/src/bytecompiler/function.rs +++ b/core/engine/src/bytecompiler/function.rs @@ -227,6 +227,6 @@ impl FunctionCompiler { let code = compiler.finish(); - Gc::new(code) + Gc::new(&unsafe { boa_gc::MutationContext::dummy() }, code) } } diff --git a/core/engine/src/environments/runtime/mod.rs b/core/engine/src/environments/runtime/mod.rs index e2f9afe879c..8f7b2dd26c6 100644 --- a/core/engine/src/environments/runtime/mod.rs +++ b/core/engine/src/environments/runtime/mod.rs @@ -220,6 +220,7 @@ impl EnvironmentStack { let index = self.depth; self.push_env(Environment::Declarative(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, DeclarativeEnvironment::new( DeclarativeEnvironmentKind::Lexical(LexicalEnvironment::new(bindings_count)), poisoned, @@ -242,6 +243,7 @@ impl EnvironmentStack { let (poisoned, with) = self.compute_poisoned_with(global); self.push_env(Environment::Declarative(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, DeclarativeEnvironment::new( DeclarativeEnvironmentKind::Function(FunctionEnvironment::new( num_bindings, @@ -258,6 +260,7 @@ impl EnvironmentStack { pub(crate) fn push_module(&mut self, scope: Scope) { let num_bindings = scope.num_bindings_non_local(); self.push_env(Environment::Declarative(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, DeclarativeEnvironment::new( DeclarativeEnvironmentKind::Module(ModuleEnvironment::new(num_bindings, scope)), false, @@ -410,10 +413,13 @@ impl EnvironmentStack { /// Push an environment onto the chain. fn push_env(&mut self, env: Environment) { - self.tip = Some(Gc::new(EnvironmentNode { - env, - parent: self.tip.take(), - })); + self.tip = Some(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + EnvironmentNode { + env, + parent: self.tip.take(), + }, + )); self.depth += 1; } diff --git a/core/engine/src/module/mod.rs b/core/engine/src/module/mod.rs index 3d798eddb10..e34f8a8329d 100644 --- a/core/engine/src/module/mod.rs +++ b/core/engine/src/module/mod.rs @@ -286,13 +286,16 @@ impl Module { let src = SourceTextModule::new(module, context.interner(), source_text, path.clone()); Ok(Self { - inner: Gc::new(ModuleRepr { - realm, - namespace: GcRefCell::default(), - kind: ModuleKind::SourceText(Box::new(src)), - host_defined: HostDefined::default(), - path, - }), + inner: Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + ModuleRepr { + realm, + namespace: GcRefCell::default(), + kind: ModuleKind::SourceText(Box::new(src)), + host_defined: HostDefined::default(), + path, + }, + ), }) } @@ -315,13 +318,16 @@ impl Module { let synth = SyntheticModule::new(names, evaluation_steps); Self { - inner: Gc::new(ModuleRepr { - realm, - namespace: GcRefCell::default(), - kind: ModuleKind::Synthetic(Box::new(synth)), - host_defined: HostDefined::default(), - path, - }), + inner: Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + ModuleRepr { + realm, + namespace: GcRefCell::default(), + kind: ModuleKind::Synthetic(Box::new(synth)), + host_defined: HostDefined::default(), + path, + }, + ), } } @@ -820,7 +826,10 @@ fn into_js_module() { let bar_count = Rc::new(RefCell::new(0)); let dad_count = Rc::new(RefCell::new(0)); - context.insert_data(Gc::new(GcRefCell::new(JsValue::undefined()))); + context.insert_data(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(JsValue::undefined()), + )); let module = unsafe { vec![ diff --git a/core/engine/src/module/source.rs b/core/engine/src/module/source.rs index a234c28c180..80fe607c6d6 100644 --- a/core/engine/src/module/source.rs +++ b/core/engine/src/module/source.rs @@ -1823,7 +1823,13 @@ impl SourceTextModule { compiler.compile_module_item_list(source.items()); - (Gc::new(compiler.finish()), functions) + ( + Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ), + functions, + ) }; // 8. Let moduleContext be a new ECMAScript code execution context. diff --git a/core/engine/src/module/synthetic.rs b/core/engine/src/module/synthetic.rs index 374088dfadb..613561c9558 100644 --- a/core/engine/src/module/synthetic.rs +++ b/core/engine/src/module/synthetic.rs @@ -119,10 +119,13 @@ impl SyntheticModuleInitializer { { // Hopefully, this unsafe operation will be replaced by the `CoerceUnsized` API in the // future: https://github.com/rust-lang/rust/issues/18598 - let ptr = Gc::into_raw(Gc::new(Callback { - f: closure, - captures, - })); + let ptr = Gc::into_raw(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Callback { + f: closure, + captures, + }, + )); // SAFETY: The pointer returned by `into_raw` is only used to coerce to a trait object, // meaning this is safe. @@ -335,7 +338,10 @@ impl SyntheticModule { module_scope.escape_all_bindings(); - let cb = Gc::new(compiler.finish()); + let cb = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ); let mut envs = EnvironmentStack::new(); envs.push_module(module_scope); diff --git a/core/engine/src/native_function/continuation.rs b/core/engine/src/native_function/continuation.rs index 44b3bd0299a..c18fa9e0327 100644 --- a/core/engine/src/native_function/continuation.rs +++ b/core/engine/src/native_function/continuation.rs @@ -107,10 +107,13 @@ impl NativeCoroutine { { // Hopefully, this unsafe operation will be replaced by the `CoerceUnsized` API in the // future: https://github.com/rust-lang/rust/issues/18598 - let ptr = Gc::into_raw(Gc::new(Coroutine { - f: closure, - captures, - })); + let ptr = Gc::into_raw(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Coroutine { + f: closure, + captures, + }, + )); // SAFETY: The pointer returned by `into_raw` is only used to coerce to a trait object, // meaning this is safe. unsafe { diff --git a/core/engine/src/native_function/mod.rs b/core/engine/src/native_function/mod.rs index a09beefd8a5..22d661a3b38 100644 --- a/core/engine/src/native_function/mod.rs +++ b/core/engine/src/native_function/mod.rs @@ -278,10 +278,13 @@ impl NativeFunction { { // Hopefully, this unsafe operation will be replaced by the `CoerceUnsized` API in the // future: https://github.com/rust-lang/rust/issues/18598 - let ptr = Gc::into_raw(Gc::new(Closure { - f: closure, - captures, - })); + let ptr = Gc::into_raw(Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Closure { + f: closure, + captures, + }, + )); // SAFETY: The pointer returned by `into_raw` is only used to coerce to a trait object, // meaning this is safe. unsafe { diff --git a/core/engine/src/object/builtins/jspromise.rs b/core/engine/src/object/builtins/jspromise.rs index 649469318bb..85aa1b26b2b 100644 --- a/core/engine/src/object/builtins/jspromise.rs +++ b/core/engine/src/object/builtins/jspromise.rs @@ -1093,10 +1093,13 @@ impl JsPromise { } } - let state = Gc::new(GcRefCell::new(Inner { - result: None, - task: None, - })); + let state = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(Inner { + result: None, + task: None, + }), + ); let resolve = { let state = state.clone(); diff --git a/core/engine/src/object/builtins/jsweakmap.rs b/core/engine/src/object/builtins/jsweakmap.rs index fe2d42d8cb7..e752f696b95 100644 --- a/core/engine/src/object/builtins/jsweakmap.rs +++ b/core/engine/src/object/builtins/jsweakmap.rs @@ -30,7 +30,7 @@ impl JsWeakMap { inner: JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), context.intrinsics().constructors().weak_map().prototype(), - NativeWeakMap::new(), + NativeWeakMap::new(&unsafe { boa_gc::MutationContext::dummy() }), ) .upcast(), } diff --git a/core/engine/src/object/builtins/jsweakset.rs b/core/engine/src/object/builtins/jsweakset.rs index 1409a81edb8..13d14095cc8 100644 --- a/core/engine/src/object/builtins/jsweakset.rs +++ b/core/engine/src/object/builtins/jsweakset.rs @@ -30,7 +30,7 @@ impl JsWeakSet { inner: JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), context.intrinsics().constructors().weak_set().prototype(), - NativeWeakSet::new(), + NativeWeakSet::new(&unsafe { boa_gc::MutationContext::dummy() }), ) .upcast(), } diff --git a/core/engine/src/object/jsobject.rs b/core/engine/src/object/jsobject.rs index f971bf67812..cd30c5dceb4 100644 --- a/core/engine/src/object/jsobject.rs +++ b/core/engine/src/object/jsobject.rs @@ -127,10 +127,13 @@ impl JsObject { object: Object, vtable: &'static InternalObjectMethods, ) -> Self { - let inner = Gc::new(VTableObject { - object: GcRefCell::new(object), - vtable, - }); + let inner = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + VTableObject { + object: GcRefCell::new(object), + vtable, + }, + ); JsObject { inner }.upcast() } @@ -213,15 +216,18 @@ impl JsObject { data: T, ) -> Self { let internal_methods = data.internal_methods(); - let inner = Gc::new(VTableObject { - object: GcRefCell::new(Object { - data: ObjectData::new(data), - properties: PropertyMap::from_prototype_unique_shape(prototype.into()), - extensible: true, - private_elements: ThinVec::new(), - }), - vtable: internal_methods, - }); + let inner = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + VTableObject { + object: GcRefCell::new(Object { + data: ObjectData::new(data), + properties: PropertyMap::from_prototype_unique_shape(prototype.into()), + extensible: true, + private_elements: ThinVec::new(), + }), + vtable: internal_methods, + }, + ); JsObject { inner }.upcast() } @@ -239,18 +245,21 @@ impl JsObject { data: T, ) -> JsObject { let internal_methods = data.internal_methods(); - let inner = Gc::new(VTableObject { - object: GcRefCell::new(Object { - data: ObjectData::new(data), - properties: PropertyMap::from_prototype_with_shared_shape( - root_shape, - prototype.into(), - ), - extensible: true, - private_elements: ThinVec::new(), - }), - vtable: internal_methods, - }); + let inner = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + VTableObject { + object: GcRefCell::new(Object { + data: ObjectData::new(data), + properties: PropertyMap::from_prototype_with_shared_shape( + root_shape, + prototype.into(), + ), + extensible: true, + private_elements: ThinVec::new(), + }), + vtable: internal_methods, + }, + ); JsObject { inner } } @@ -1078,18 +1087,21 @@ impl JsObject { /// ``` pub fn new>>(root_shape: &RootShape, prototype: O, data: T) -> Self { let internal_methods = data.internal_methods(); - let inner = Gc::new(VTableObject { - object: GcRefCell::new(Object { - data: ObjectData::new(data), - properties: PropertyMap::from_prototype_with_shared_shape( - root_shape, - prototype.into(), - ), - extensible: true, - private_elements: ThinVec::new(), - }), - vtable: internal_methods, - }); + let inner = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + VTableObject { + object: GcRefCell::new(Object { + data: ObjectData::new(data), + properties: PropertyMap::from_prototype_with_shared_shape( + root_shape, + prototype.into(), + ), + extensible: true, + private_elements: ThinVec::new(), + }), + vtable: internal_methods, + }, + ); Self { inner } } @@ -1113,15 +1125,18 @@ impl JsObject { /// ``` pub fn new_unique>>(prototype: O, data: T) -> Self { let internal_methods = data.internal_methods(); - let inner = Gc::new(VTableObject { - object: GcRefCell::new(Object { - data: ObjectData::new(data), - properties: PropertyMap::from_prototype_unique_shape(prototype.into()), - extensible: true, - private_elements: ThinVec::new(), - }), - vtable: internal_methods, - }); + let inner = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + VTableObject { + object: GcRefCell::new(Object { + data: ObjectData::new(data), + properties: PropertyMap::from_prototype_unique_shape(prototype.into()), + extensible: true, + private_elements: ThinVec::new(), + }), + vtable: internal_methods, + }, + ); 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 3d4292eba59..11934d51b79 100644 --- a/core/engine/src/object/shape/shared_shape/forward_transition.rs +++ b/core/engine/src/object/shape/shared_shape/forward_transition.rs @@ -66,7 +66,10 @@ impl ForwardTransition { properties.map.retain(|_, v| v.is_upgradable()); } - properties.map.insert(key, WeakGc::new(value)); + properties.map.insert( + key, + WeakGc::new(&unsafe { boa_gc::MutationContext::dummy() }, value), + ); } /// Insert a prototype transition. @@ -78,7 +81,10 @@ impl ForwardTransition { prototypes.map.retain(|_, v| v.is_upgradable()); } - prototypes.map.insert(key, WeakGc::new(value)); + prototypes.map.insert( + key, + WeakGc::new(&unsafe { boa_gc::MutationContext::dummy() }, value), + ); } /// Get a property transition, return [`None`] otherwise. diff --git a/core/engine/src/object/shape/shared_shape/mod.rs b/core/engine/src/object/shape/shared_shape/mod.rs index bb04e33a561..0a1609fd55a 100644 --- a/core/engine/src/object/shape/shared_shape/mod.rs +++ b/core/engine/src/object/shape/shared_shape/mod.rs @@ -166,7 +166,7 @@ impl SharedShape { /// Create a new [`SharedShape`]. fn new(inner: Inner) -> Self { Self { - inner: Gc::new(inner), + inner: Gc::new(&unsafe { boa_gc::MutationContext::dummy() }, inner), } } @@ -188,7 +188,7 @@ impl SharedShape { /// Create a [`SharedShape`] change prototype transition. pub(crate) fn change_prototype_transition(&self, prototype: JsPrototype) -> Self { if let Some(shape) = self.forward_transitions().get_prototype(&prototype) { - if let Some(inner) = shape.upgrade() { + if let Some(inner) = shape.upgrade(&unsafe { boa_gc::MutationContext::dummy() }) { return Self { inner }; } @@ -215,7 +215,7 @@ impl SharedShape { pub(crate) fn insert_property_transition(&self, key: TransitionKey) -> Self { // Check if we have already created such a transition, if so use it! if let Some(shape) = self.forward_transitions().get_property(&key) { - if let Some(inner) = shape.upgrade() { + if let Some(inner) = shape.upgrade(&unsafe { boa_gc::MutationContext::dummy() }) { return Self { inner }; } @@ -253,7 +253,7 @@ impl SharedShape { // Check if we have already created such a transition, if so use it! if let Some(shape) = self.forward_transitions().get_property(&key) { - if let Some(inner) = shape.upgrade() { + if let Some(inner) = shape.upgrade(&unsafe { boa_gc::MutationContext::dummy() }) { let action = if slot.attributes.width_match(key.attributes) { ChangeTransitionAction::Nothing } else if slot.attributes.is_accessor_descriptor() { @@ -486,7 +486,9 @@ impl WeakSharedShape { #[must_use] pub(crate) fn upgrade(&self) -> Option { Some(SharedShape { - inner: self.inner.upgrade()?, + inner: self + .inner + .upgrade(&unsafe { boa_gc::MutationContext::dummy() })?, }) } } @@ -494,7 +496,7 @@ impl WeakSharedShape { impl From<&SharedShape> for WeakSharedShape { fn from(value: &SharedShape) -> Self { WeakSharedShape { - inner: WeakGc::new(&value.inner), + inner: WeakGc::new(&unsafe { boa_gc::MutationContext::dummy() }, &value.inner), } } } diff --git a/core/engine/src/object/shape/unique_shape.rs b/core/engine/src/object/shape/unique_shape.rs index bfac600e7d2..6947489a526 100644 --- a/core/engine/src/object/shape/unique_shape.rs +++ b/core/engine/src/object/shape/unique_shape.rs @@ -37,10 +37,13 @@ impl UniqueShape { /// Create a new [`UniqueShape`]. pub(crate) fn new(prototype: JsPrototype, property_table: PropertyTableInner) -> Self { Self { - inner: Gc::new(Inner { - property_table: RefCell::new(property_table), - prototype: GcRefCell::new(prototype), - }), + inner: Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Inner { + property_table: RefCell::new(property_table), + prototype: GcRefCell::new(prototype), + }, + ), } } @@ -253,7 +256,9 @@ impl WeakUniqueShape { #[must_use] pub(crate) fn upgrade(&self) -> Option { Some(UniqueShape { - inner: self.inner.upgrade()?, + inner: self + .inner + .upgrade(&unsafe { boa_gc::MutationContext::dummy() })?, }) } } @@ -261,7 +266,7 @@ impl WeakUniqueShape { impl From<&UniqueShape> for WeakUniqueShape { fn from(value: &UniqueShape) -> Self { WeakUniqueShape { - inner: WeakGc::new(&value.inner), + inner: WeakGc::new(&unsafe { boa_gc::MutationContext::dummy() }, &value.inner), } } } diff --git a/core/engine/src/realm.rs b/core/engine/src/realm.rs index dcf03f71fec..84bf5c39cf2 100644 --- a/core/engine/src/realm.rs +++ b/core/engine/src/realm.rs @@ -86,21 +86,27 @@ impl Realm { let global_this = hooks .create_global_this(&intrinsics) .unwrap_or_else(|| global_object.clone()); - let environment = Gc::new(DeclarativeEnvironment::global()); + let environment = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + DeclarativeEnvironment::global(), + ); let scope = Scope::new_global(); let realm = Self { - inner: Gc::new(Inner { - intrinsics, - environment, - scope, - global_object, - global_this, - template_map: GcRefCell::default(), - loaded_modules: GcRefCell::default(), - host_classes: GcRefCell::default(), - host_defined: GcRefCell::default(), - }), + inner: Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Inner { + intrinsics, + environment, + scope, + global_object, + global_this, + template_map: GcRefCell::default(), + loaded_modules: GcRefCell::default(), + host_classes: GcRefCell::default(), + host_defined: GcRefCell::default(), + }, + ), }; realm.initialize(); diff --git a/core/engine/src/script.rs b/core/engine/src/script.rs index 63ccffb0c35..f11dbc61168 100644 --- a/core/engine/src/script.rs +++ b/core/engine/src/script.rs @@ -104,14 +104,17 @@ impl Script { let source_text = SourceText::new(source); Ok(Self { - inner: Gc::new(Inner { - realm: realm.unwrap_or_else(|| context.realm().clone()), - phase: GcRefCell::new(ScriptPhase::Ast(code)), - source_text, - loaded_modules: GcRefCell::default(), - host_defined: HostDefined::default(), - path, - }), + inner: Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Inner { + realm: realm.unwrap_or_else(|| context.realm().clone()), + phase: GcRefCell::new(ScriptPhase::Ast(code)), + source_text, + loaded_modules: GcRefCell::default(), + host_defined: HostDefined::default(), + path, + }, + ), }) } @@ -159,7 +162,10 @@ impl Script { compiler.global_declaration_instantiation(source); compiler.compile_statement_list(source.statements(), true, false); - Gc::new(compiler.finish()) + Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + compiler.finish(), + ) }; *self.inner.phase.borrow_mut() = ScriptPhase::Codeblock(cb.clone()); diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index dc6b1dca985..b7da166b5c9 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -407,7 +407,10 @@ impl Vm { pub(crate) fn new(realm: Realm) -> Self { let mut frames = Vec::with_capacity(16); frames.push(CallFrame::new( - Gc::new(CodeBlock::new(JsString::default(), 0, true)), + Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + CodeBlock::new(JsString::default(), 0, true), + ), None, EnvironmentStack::new(), realm, diff --git a/core/engine/src/vm/opcode/await/mod.rs b/core/engine/src/vm/opcode/await/mod.rs index 69d925281c6..ad2c5fcbd54 100644 --- a/core/engine/src/vm/opcode/await/mod.rs +++ b/core/engine/src/vm/opcode/await/mod.rs @@ -56,7 +56,10 @@ impl Await { let r#gen = GeneratorContext::from_current(context, None); - let captures = Gc::new(Cell::new(Some(r#gen))); + let captures = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + Cell::new(Some(r#gen)), + ); // 3. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures asyncContext and performs the following steps when called: // 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »). diff --git a/core/engine/src/vm/opcode/push/environment.rs b/core/engine/src/vm/opcode/push/environment.rs index debccae3991..8f49f65b2c6 100644 --- a/core/engine/src/vm/opcode/push/environment.rs +++ b/core/engine/src/vm/opcode/push/environment.rs @@ -81,7 +81,10 @@ impl PushPrivateEnvironment { } let ptr: *const _ = class.as_ref(); - let environment = Gc::new(PrivateEnvironment::new(ptr.cast::<()>() as usize, names)); + let environment = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + PrivateEnvironment::new(ptr.cast::<()>() as usize, names), + ); class .downcast_mut::() diff --git a/core/gc/src/boa_allocator.rs b/core/gc/src/boa_allocator.rs index 2a34abf4a60..1a86a0c7606 100644 --- a/core/gc/src/boa_allocator.rs +++ b/core/gc/src/boa_allocator.rs @@ -132,9 +132,12 @@ impl Allocator { pub(crate) fn alloc_weak_map() -> WeakMap { let weak_map = WeakMap { - inner: Gc::new(GcRefCell::new(RawWeakMap::new())), + inner: Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(RawWeakMap::new()), + ), }; - let weak = WeakGc::new(&weak_map.inner); + let weak = WeakGc::new(&unsafe { crate::MutationContext::dummy() }, &weak_map.inner); BOA_GC.with(|st| { let mut gc = st.borrow_mut(); diff --git a/core/gc/src/internals/weak_map_box.rs b/core/gc/src/internals/weak_map_box.rs index d85ba92e221..254fb06bc45 100644 --- a/core/gc/src/internals/weak_map_box.rs +++ b/core/gc/src/internals/weak_map_box.rs @@ -19,7 +19,9 @@ pub(crate) trait ErasedWeakMapBox { impl ErasedWeakMapBox for WeakMapBox { fn clear_dead_entries(&self) { - if let Some(map) = self.map.upgrade() + if let Some(map) = self + .map + .upgrade(&unsafe { crate::MutationContext::dummy() }) && let Ok(mut map) = map.try_borrow_mut() { map.clear_expired(); @@ -27,11 +29,17 @@ impl ErasedWeakMapBox for WeakMapBox { } fn is_live(&self) -> bool { - self.map.upgrade().is_some() + self.map + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .is_some() } unsafe fn trace(&self, tracer: &mut Tracer) { - if self.map.upgrade().is_some() { + if self + .map + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .is_some() + { // SAFETY: When the weak map is live, the weak reference should be traced. unsafe { self.map.trace(tracer) } } diff --git a/core/gc/src/lib.rs b/core/gc/src/lib.rs index fc5a447a667..dec09a9c077 100644 --- a/core/gc/src/lib.rs +++ b/core/gc/src/lib.rs @@ -46,7 +46,7 @@ pub use cell::{GcRef, GcRefCell, GcRefMut}; #[cfg(not(feature = "oscars_backend"))] pub use internals::GcBox; #[cfg(not(feature = "oscars_backend"))] -pub use pointers::{Ephemeron, Gc, GcErased, WeakGc, WeakMap}; +pub use pointers::{Ephemeron, Gc, GcErased, MutationContext, WeakGc, WeakMap}; #[cfg(feature = "oscars_backend")] pub use oscars::null_collector_branded::{ diff --git a/core/gc/src/pointers/ephemeron.rs b/core/gc/src/pointers/ephemeron.rs index 0fccf5a5404..3fc56cadc42 100644 --- a/core/gc/src/pointers/ephemeron.rs +++ b/core/gc/src/pointers/ephemeron.rs @@ -45,7 +45,7 @@ pub struct Ephemeron { impl Ephemeron { /// Creates a new `Ephemeron`. #[must_use] - pub fn new(key: &Gc<'_, K>, value: V) -> Self { + pub fn new(_mc: &crate::MutationContext<'_, '_>, 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<'gc>(&self, _mc: &crate::MutationContext<'gc, '_>) -> 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() }?; @@ -69,8 +69,11 @@ impl Ephemeron { /// Gets the stored value of this `Ephemeron`, or `None` if the key was already garbage collected. #[must_use] - pub fn value(&self) -> Option> { - let key = self.key()?; + pub fn value<'gc>( + &self, + _mc: &crate::MutationContext<'gc, '_>, + ) -> Option> { + let key = self.key(&unsafe { crate::MutationContext::dummy() })?; // SAFETY: this is safe because `Ephemeron` is tracked to always point to a valid pointer // `inner_ptr`. diff --git a/core/gc/src/pointers/gc.rs b/core/gc/src/pointers/gc.rs index 8c2ebecc50d..3ef43301f5f 100644 --- a/core/gc/src/pointers/gc.rs +++ b/core/gc/src/pointers/gc.rs @@ -166,7 +166,7 @@ pub struct Gc<'gc, T: Trace + ?Sized + 'static> { 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 + pub fn new(_mc: &crate::MutationContext<'gc, '_>, value: T) -> Self where T: Sized, { @@ -188,7 +188,7 @@ impl<'gc, T: Trace + ?Sized + 'static> Gc<'gc, T> { /// [`upgrade`][WeakGc::upgrade] on the weak reference inside the closure will fail and result /// in a `None` value. #[must_use] - pub fn new_cyclic(data_fn: F) -> Self + pub fn new_cyclic(_mc: &crate::MutationContext<'gc, '_>, data_fn: F) -> Self where F: FnOnce(&WeakGc) -> T, T: Sized, @@ -199,7 +199,7 @@ impl<'gc, T: Trace + ?Sized + 'static> Gc<'gc, T> { Ephemeron::from_raw(Allocator::alloc_ephemeron(EphemeronBox::new_empty())).into() }; - let gc = Self::new(data_fn(&weak)); + let gc = Self::new(&unsafe { crate::MutationContext::dummy() }, data_fn(&weak)); // SAFETY: // - `as_mut`: `weak` is properly initialized by `alloc_ephemeron` and cannot escape the @@ -380,7 +380,10 @@ impl Drop for Gc<'_, T> { impl Default for Gc<'_, T> { fn default() -> Self { - Self::new(Default::default()) + Self::new( + &unsafe { crate::MutationContext::dummy() }, + Default::default(), + ) } } diff --git a/core/gc/src/pointers/mod.rs b/core/gc/src/pointers/mod.rs index 20e317010f9..bc00093f2bb 100644 --- a/core/gc/src/pointers/mod.rs +++ b/core/gc/src/pointers/mod.rs @@ -2,6 +2,8 @@ mod ephemeron; mod gc; +mod mutation_context; +pub use mutation_context::MutationContext; mod weak; mod weak_map; diff --git a/core/gc/src/pointers/mutation_context.rs b/core/gc/src/pointers/mutation_context.rs new file mode 100644 index 00000000000..fc527c6fc36 --- /dev/null +++ b/core/gc/src/pointers/mutation_context.rs @@ -0,0 +1,20 @@ +use std::marker::PhantomData; + +/// Context required to safely allocate or mutate the Gc heap +#[derive(Copy, Clone, Debug)] +pub struct MutationContext<'gc, 'a> { + _marker: PhantomData<&'a &'gc ()>, +} + +impl MutationContext<'_, '_> { + /// Creates a temporary dummy context + /// + /// # Safety + /// Bypasses lifetime branding, use only as a bridge during Gc migration. + #[must_use] + pub unsafe fn dummy() -> Self { + Self { + _marker: PhantomData, + } + } +} diff --git a/core/gc/src/pointers/weak.rs b/core/gc/src/pointers/weak.rs index 0649af2be54..7a3b5375ee8 100644 --- a/core/gc/src/pointers/weak.rs +++ b/core/gc/src/pointers/weak.rs @@ -15,9 +15,9 @@ impl WeakGc { /// Creates a new weak pointer for a garbage collected value. #[inline] #[must_use] - pub fn new(value: &Gc<'_, T>) -> Self { + pub fn new(_mc: &crate::MutationContext<'_, '_>, value: &Gc<'_, T>) -> Self { Self { - inner: Ephemeron::new(value, ()), + inner: Ephemeron::new(&unsafe { crate::MutationContext::dummy() }, value, ()), } } @@ -25,8 +25,8 @@ impl WeakGc { /// if the value was already garbage collected. #[inline] #[must_use] - pub fn upgrade(&self) -> Option> { - self.inner.key() + pub fn upgrade<'gc>(&self, _mc: &crate::MutationContext<'gc, '_>) -> Option> { + self.inner.key(&unsafe { crate::MutationContext::dummy() }) } /// Check if the [`WeakGc`] can be upgraded. @@ -58,7 +58,10 @@ impl From> for WeakGc { impl PartialEq for WeakGc { fn eq(&self, other: &Self) -> bool { - match (self.upgrade(), other.upgrade()) { + match ( + self.upgrade(&unsafe { crate::MutationContext::dummy() }), + other.upgrade(&unsafe { crate::MutationContext::dummy() }), + ) { (Some(a), Some(b)) => std::ptr::eq(a.as_ref(), b.as_ref()), _ => false, } @@ -69,7 +72,7 @@ impl Eq for WeakGc {} impl Hash for WeakGc { fn hash(&self, state: &mut H) { - if let Some(obj) = self.upgrade() { + if let Some(obj) = self.upgrade(&unsafe { crate::MutationContext::dummy() }) { std::ptr::hash(obj.as_ref(), state); } else { std::ptr::hash(self, state); diff --git a/core/gc/src/pointers/weak_map.rs b/core/gc/src/pointers/weak_map.rs index 12a7eb4dd75..f638e7d1648 100644 --- a/core/gc/src/pointers/weak_map.rs +++ b/core/gc/src/pointers/weak_map.rs @@ -25,7 +25,7 @@ impl WeakMap { /// Creates a new `WeakMap`. #[must_use] #[inline] - pub fn new() -> Self { + pub fn new(_mc: &crate::MutationContext<'_, '_>) -> Self { Allocator::alloc_weak_map() } @@ -309,7 +309,11 @@ where RawEntry::Vacant(vacant_entry) => (None, vacant_entry), }; - slot.insert(Ephemeron::new(k, v)); + slot.insert(Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + k, + v, + )); old } @@ -327,7 +331,10 @@ where /// Clears all the expired keys in the map. pub(crate) fn clear_expired(&mut self) { - self.retain(|eph| eph.value().is_some()); + self.retain(|eph| { + eph.value(&unsafe { crate::MutationContext::dummy() }) + .is_some() + }); } } diff --git a/core/gc/src/test/allocation.rs b/core/gc/src/test/allocation.rs index 12c7c5e0f04..3d332a0a288 100644 --- a/core/gc/src/test/allocation.rs +++ b/core/gc/src/test/allocation.rs @@ -7,7 +7,10 @@ mod miri { #[test] fn gc_basic_cell_allocation() { run_test(|| { - let gc_cell = Gc::new(GcRefCell::new(16_u16)); + let gc_cell = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(16_u16), + ); force_collect(); Harness::assert_collections(1); @@ -19,7 +22,7 @@ mod miri { #[test] fn gc_basic_pointer_alloc() { run_test(|| { - let gc = Gc::new(16_u8); + let gc = Gc::new(&unsafe { crate::MutationContext::dummy() }, 16_u8); force_collect(); Harness::assert_collections(1); @@ -47,12 +50,18 @@ mod miri { const SIZE: usize = size_of::>(); const COUNT: usize = 1_000_000; - let mut root = Gc::new(S { i: 0, next: None }); + let mut root = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + S { i: 0, next: None }, + ); for i in 1..COUNT { - root = Gc::new(S { - i, - next: Some(root), - }); + root = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + S { + i, + next: Some(root), + }, + ); } Harness::assert_bytes_allocated(); diff --git a/core/gc/src/test/cell.rs b/core/gc/src/test/cell.rs index 4acdff2b653..47218685580 100644 --- a/core/gc/src/test/cell.rs +++ b/core/gc/src/test/cell.rs @@ -5,10 +5,16 @@ mod miri { #[test] fn boa_borrow_mut_test() { run_test(|| { - let v = Gc::new(GcRefCell::new(Vec::new())); + let v = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(Vec::new()), + ); for _ in 1..=259 { - let cell = Gc::new(GcRefCell::new([0u8; 10])); + let cell = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new([0u8; 10]), + ); v.borrow_mut().push(cell); } }); diff --git a/core/gc/src/test/erased.rs b/core/gc/src/test/erased.rs index 95b34f9d5be..ada435ef673 100644 --- a/core/gc/src/test/erased.rs +++ b/core/gc/src/test/erased.rs @@ -10,7 +10,7 @@ mod miri { fn erased_gc() { run_test(|| { let value = vec![1, 2, 3]; - let gc = Gc::new(value.clone()); + let gc = Gc::new(&unsafe { crate::MutationContext::dummy() }, value.clone()); assert_eq!(Gc::type_id(&gc), TypeId::of::>()); @@ -37,16 +37,22 @@ mod miri { } run_test(|| { - let mut root = GcErased::new(Gc::new(List { - value: 0, - next: None, - })); + let mut root = GcErased::new(Gc::new( + &unsafe { crate::MutationContext::dummy() }, + List { + value: 0, + next: None, + }, + )); for value in 1..100 { - root = GcErased::new(Gc::new(List { - value, - next: Some(root), - })); + root = GcErased::new(Gc::new( + &unsafe { crate::MutationContext::dummy() }, + List { + value, + next: Some(root), + }, + )); } Harness::assert_exact_bytes_allocated(100 * size_of::>()); @@ -84,12 +90,15 @@ mod miri { run_test(|| { let value = vec![1, 2, 3]; - let derived = Gc::new(Derived { - base: Base { - base_field: value.clone(), + let derived = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + Derived { + base: Base { + base_field: value.clone(), + }, + derived_field: vec![4, 5, 6], }, - derived_field: vec![4, 5, 6], - }); + ); assert_eq!(Gc::type_id(&derived), TypeId::of::()); assert!(Gc::is::(&derived)); diff --git a/core/gc/src/test/weak.rs b/core/gc/src/test/weak.rs index 9ac4a248815..9c4a108243a 100644 --- a/core/gc/src/test/weak.rs +++ b/core/gc/src/test/weak.rs @@ -10,22 +10,35 @@ mod miri { #[test] fn eph_weak_gc_test() { run_test(|| { - let gc_value = Gc::new(3); + let gc_value = Gc::new(&unsafe { crate::MutationContext::dummy() }, 3); { let cloned_gc = gc_value.clone(); - let weak = WeakGc::new(&cloned_gc); + let weak = WeakGc::new(&unsafe { crate::MutationContext::dummy() }, &cloned_gc); - assert_eq!(*weak.upgrade().expect("Is live currently"), 3); + assert_eq!( + *weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("Is live currently"), + 3 + ); drop(cloned_gc); force_collect(); - assert_eq!(*weak.upgrade().expect("WeakGc is still live here"), 3); + assert_eq!( + *weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("WeakGc is still live here"), + 3 + ); drop(gc_value); force_collect(); - assert!(weak.upgrade().is_none()); + assert!( + weak.upgrade(&unsafe { crate::MutationContext::dummy() }) + .is_none() + ); } }); } @@ -33,28 +46,40 @@ mod miri { #[test] fn eph_ephemeron_test() { run_test(|| { - let gc_value = Gc::new(3); + let gc_value = Gc::new(&unsafe { crate::MutationContext::dummy() }, 3); { let cloned_gc = gc_value.clone(); - let ephemeron = Ephemeron::new(&cloned_gc, String::from("Hello World!")); + let ephemeron = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &cloned_gc, + String::from("Hello World!"), + ); assert_eq!( - *ephemeron.value().expect("Ephemeron is live"), + *ephemeron + .value(&unsafe { crate::MutationContext::dummy() }) + .expect("Ephemeron is live"), String::from("Hello World!") ); drop(cloned_gc); force_collect(); assert_eq!( - *ephemeron.value().expect("Ephemeron is still live here"), + *ephemeron + .value(&unsafe { crate::MutationContext::dummy() }) + .expect("Ephemeron is still live here"), String::from("Hello World!") ); drop(gc_value); force_collect(); - assert!(ephemeron.value().is_none()); + assert!( + ephemeron + .value(&unsafe { crate::MutationContext::dummy() }) + .is_none() + ); } }); } @@ -62,30 +87,59 @@ mod miri { #[test] fn eph_allocation_chains() { run_test(|| { - let gc_value = Gc::new(String::from("foo")); + let gc_value = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("foo"), + ); { let cloned_gc = gc_value.clone(); - let weak = WeakGc::new(&cloned_gc); - let wrap = Gc::new(weak); + let weak = WeakGc::new(&unsafe { crate::MutationContext::dummy() }, &cloned_gc); + let wrap = Gc::new(&unsafe { crate::MutationContext::dummy() }, weak); - assert_eq!(wrap.upgrade().as_deref().map(String::as_str), Some("foo")); + assert_eq!( + wrap.upgrade(&unsafe { crate::MutationContext::dummy() }) + .as_deref() + .map(String::as_str), + Some("foo") + ); - let eph = Ephemeron::new(&wrap, 3); + let eph = Ephemeron::new(&unsafe { crate::MutationContext::dummy() }, &wrap, 3); drop(cloned_gc); force_collect(); - assert_eq!(wrap.upgrade().as_deref().map(String::as_str), Some("foo")); - assert_eq!(&*eph.value().unwrap(), &3); + assert_eq!( + wrap.upgrade(&unsafe { crate::MutationContext::dummy() }) + .as_deref() + .map(String::as_str), + Some("foo") + ); + assert_eq!( + &*eph + .value(&unsafe { crate::MutationContext::dummy() }) + .unwrap(), + &3 + ); drop(gc_value); force_collect(); - assert!(wrap.upgrade().is_none()); - assert_eq!(&*eph.value().unwrap(), &3); + assert!( + wrap.upgrade(&unsafe { crate::MutationContext::dummy() }) + .is_none() + ); + assert_eq!( + &*eph + .value(&unsafe { crate::MutationContext::dummy() }) + .unwrap(), + &3 + ); drop(wrap); force_collect(); - assert!(eph.value().is_none()); + assert!( + eph.value(&unsafe { crate::MutationContext::dummy() }) + .is_none() + ); } }); } @@ -93,24 +147,37 @@ mod miri { #[test] fn eph_basic_alloc_dump_test() { run_test(|| { - let gc_value = Gc::new(String::from("gc here")); - let _gc_two = Gc::new("hmmm"); + let gc_value = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("gc here"), + ); + let _gc_two = Gc::new(&unsafe { crate::MutationContext::dummy() }, "hmmm"); - let eph = Ephemeron::new(&gc_value, 4); - let _fourth = Gc::new("tail"); + let eph = Ephemeron::new(&unsafe { crate::MutationContext::dummy() }, &gc_value, 4); + let _fourth = Gc::new(&unsafe { crate::MutationContext::dummy() }, "tail"); - assert_eq!(&*eph.value().unwrap(), &4); + assert_eq!( + &*eph + .value(&unsafe { crate::MutationContext::dummy() }) + .unwrap(), + &4 + ); }); } #[test] fn eph_basic_upgrade_test() { run_test(|| { - let init_gc = Gc::new(String::from("foo")); + let init_gc = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("foo"), + ); - let weak = WeakGc::new(&init_gc); + let weak = WeakGc::new(&unsafe { crate::MutationContext::dummy() }, &init_gc); - let new_gc = weak.upgrade().expect("Weak is still live"); + let new_gc = weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("Weak is still live"); drop(weak); force_collect(); @@ -122,20 +189,32 @@ mod miri { #[test] fn eph_basic_clone_test() { run_test(|| { - let init_gc = Gc::new(String::from("bar")); + let init_gc = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("bar"), + ); - let weak = WeakGc::new(&init_gc); + let weak = WeakGc::new(&unsafe { crate::MutationContext::dummy() }, &init_gc); - let new_gc = weak.upgrade().expect("Weak is live"); + let new_gc = weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("Weak is live"); let new_weak = weak.clone(); drop(weak); force_collect(); - assert_eq!(*new_gc, *new_weak.upgrade().expect("weak should be live")); + assert_eq!( + *new_gc, + *new_weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("weak should be live") + ); assert_eq!( *init_gc, - *new_weak.upgrade().expect("weak_should be live still") + *new_weak + .upgrade(&unsafe { crate::MutationContext::dummy() }) + .expect("weak_should be live still") ); }); } @@ -152,9 +231,12 @@ mod miri { } run_test(|| { let root = TestCell { - inner: Gc::new(InnerCell { - inner: GcRefCell::new(None), - }), + inner: Gc::new( + &unsafe { crate::MutationContext::dummy() }, + InnerCell { + inner: GcRefCell::new(None), + }, + ), }; let root_size = size_of::>(); @@ -163,10 +245,17 @@ mod miri { { let eph_size = size_of::>(); // Generate a self-referential ephemeron - let eph = Ephemeron::new(&root.inner, root.clone()); + let eph = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &root.inner, + root.clone(), + ); *root.inner.inner.borrow_mut() = Some(eph.clone()); - assert!(eph.value().is_some()); + assert!( + eph.value(&unsafe { crate::MutationContext::dummy() }) + .is_some() + ); Harness::assert_exact_bytes_allocated(root_size + eph_size); } @@ -185,26 +274,43 @@ mod miri { inner: Gc<'static, GcRefCell>>>, } run_test(|| { - let root = Gc::new(GcRefCell::new(None)); + let root = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(None), + ); let root_size = size_of::>>>>(); Harness::assert_exact_bytes_allocated(root_size); - let watched = Gc::new(0); + let watched = Gc::new(&unsafe { crate::MutationContext::dummy() }, 0); let watched_size = size_of::>(); { let eph_size = size_of::>(); // Generate a self-referential loop of weak and non-weak pointers let chain1 = TestCell { - inner: Gc::new(GcRefCell::new(None)), + inner: Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(None), + ), }; let chain2 = TestCell { - inner: Gc::new(GcRefCell::new(None)), + inner: Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new(None), + ), }; - let eph_start = Ephemeron::new(&watched, chain1.clone()); - let eph_chain2 = Ephemeron::new(&watched, chain2.clone()); + let eph_start = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &watched, + chain1.clone(), + ); + let eph_chain2 = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &watched, + chain2.clone(), + ); *chain1.inner.borrow_mut() = Some(eph_chain2.clone()); *chain2.inner.borrow_mut() = Some(eph_start.clone()); @@ -213,8 +319,16 @@ mod miri { force_collect(); - assert!(eph_start.value().is_some()); - assert!(eph_chain2.value().is_some()); + assert!( + eph_start + .value(&unsafe { crate::MutationContext::dummy() }) + .is_some() + ); + assert!( + eph_chain2 + .value(&unsafe { crate::MutationContext::dummy() }) + .is_some() + ); Harness::assert_exact_bytes_allocated(watched_size + 3 * root_size + 2 * eph_size); } @@ -249,8 +363,12 @@ mod miri { inner: Rc::new(Cell::new(0)), }; - let key = Gc::new(50u32); - let eph = Ephemeron::new(&key, val.clone()); + let key = Gc::new(&unsafe { crate::MutationContext::dummy() }, 50u32); + let eph = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &key, + val.clone(), + ); assert!(eph.has_value()); // finalize hasn't been run assert_eq!(val.inner.get(), 0); @@ -282,8 +400,12 @@ mod miri { inner: Rc::new(Cell::new(0)), }; - let key = Gc::new(50u32); - let eph = Ephemeron::new(&key, Gc::new(val.clone())); + let key = Gc::new(&unsafe { crate::MutationContext::dummy() }, 50u32); + let eph = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &key, + Gc::new(&unsafe { crate::MutationContext::dummy() }, val.clone()), + ); assert!(eph.has_value()); // finalize hasn't been run assert_eq!(val.inner.get(), 0); @@ -305,17 +427,24 @@ mod miri { } run_test(|| { let root = TestCell { - inner: Gc::new(GcRefCell::new((None, None))), + inner: Gc::new( + &unsafe { crate::MutationContext::dummy() }, + GcRefCell::new((None, None)), + ), }; let root_size = size_of::>(); Harness::assert_exact_bytes_allocated(root_size); - let watched = Gc::new(0); + let watched = Gc::new(&unsafe { crate::MutationContext::dummy() }, 0); let watched_size = size_of::>(); { - let eph = Ephemeron::new(&watched, root.clone()); + let eph = Ephemeron::new( + &unsafe { crate::MutationContext::dummy() }, + &watched, + root.clone(), + ); let eph_size = size_of::, TestCell>>(); root.inner.borrow_mut().0 = Some(root.clone()); @@ -323,7 +452,10 @@ mod miri { force_collect(); - assert!(eph.value().is_some()); + assert!( + eph.value(&unsafe { crate::MutationContext::dummy() }) + .is_some() + ); Harness::assert_exact_bytes_allocated(root_size + eph_size + watched_size); } diff --git a/core/gc/src/test/weak_map.rs b/core/gc/src/test/weak_map.rs index 2aeb820db47..461ad6a833d 100644 --- a/core/gc/src/test/weak_map.rs +++ b/core/gc/src/test/weak_map.rs @@ -5,13 +5,22 @@ mod miri { #[test] fn weak_map_basic() { run_test(|| { - let key1 = Gc::new(String::from("key1")); - let key2 = Gc::new(String::from("key2")); - let key3 = Gc::new(String::from("key3")); + let key1 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key1"), + ); + let key2 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key2"), + ); + let key3 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key3"), + ); assert!(!has_weak_maps()); - let mut map = WeakMap::new(); + let mut map = WeakMap::new(&unsafe { crate::MutationContext::dummy() }); assert!(has_weak_maps()); @@ -59,14 +68,23 @@ mod miri { #[test] fn weak_map_multiple() { run_test(|| { - let key1 = Gc::new(String::from("key1")); - let key2 = Gc::new(String::from("key2")); - let key3 = Gc::new(String::from("key3")); + let key1 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key1"), + ); + let key2 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key2"), + ); + let key3 = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key3"), + ); assert!(!has_weak_maps()); - let mut map_1 = WeakMap::new(); - let mut map_2 = WeakMap::new(); + let mut map_1 = WeakMap::new(&unsafe { crate::MutationContext::dummy() }); + let mut map_2 = WeakMap::new(&unsafe { crate::MutationContext::dummy() }); assert!(has_weak_maps()); @@ -116,10 +134,13 @@ mod miri { #[test] fn weak_map_key_live() { run_test(|| { - let key = Gc::new(String::from("key")); + let key = Gc::new( + &unsafe { crate::MutationContext::dummy() }, + String::from("key"), + ); let key_copy = key.clone(); - let mut map = WeakMap::new(); + let mut map = WeakMap::new(&unsafe { crate::MutationContext::dummy() }); map.insert(&key, ()); diff --git a/examples/src/bin/jstypedarray.rs b/examples/src/bin/jstypedarray.rs index 208f108fbbb..fc025712d89 100644 --- a/examples/src/bin/jstypedarray.rs +++ b/examples/src/bin/jstypedarray.rs @@ -92,7 +92,10 @@ fn main() -> JsResult<()> { // forEach let array = JsUint8Array::from_iter(vec![1, 2, 3, 4, 5], context)?; - let num_to_modify = Gc::new(GcRefCell::new(0u8)); + let num_to_modify = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + GcRefCell::new(0u8), + ); let js_function = FunctionObjectBuilder::new( context.realm(), diff --git a/tests/macros/tests/gcd_callback.rs b/tests/macros/tests/gcd_callback.rs index 0aa45890b30..29e30f0fe81 100644 --- a/tests/macros/tests/gcd_callback.rs +++ b/tests/macros/tests/gcd_callback.rs @@ -19,7 +19,10 @@ fn gcd_callback() { // Create the engine. let context = &mut Context::default(); - let result = Gc::new(AtomicUsize::new(0)); + let result = Gc::new( + &unsafe { boa_gc::MutationContext::dummy() }, + AtomicUsize::new(0), + ); context.insert_data(result.clone()); // Load the JavaScript code.