diff --git a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs index 7227851d..d06e55f4 100644 --- a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs +++ b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs @@ -58,7 +58,7 @@ pub(crate) fn require_object_coercible( pub(crate) fn is_array( agent: &mut Agent, argument: impl IntoValue, - gc: NoGcScope<'_, '_>, + gc: NoGcScope, ) -> JsResult { let argument = argument.into_value(); @@ -139,11 +139,7 @@ pub(crate) fn is_constructor<'a>( /// returns either a normal completion containing a Boolean or a throw /// completion. It is used to determine whether additional properties can be /// added to O. -pub(crate) fn try_is_extensible( - agent: &mut Agent, - o: Object, - gc: NoGcScope<'_, '_>, -) -> TryResult { +pub(crate) fn try_is_extensible(agent: &mut Agent, o: Object, gc: NoGcScope) -> TryResult { // 1. Return ? O.[[IsExtensible]](). o.try_is_extensible(agent, gc) } @@ -152,11 +148,7 @@ pub(crate) fn try_is_extensible( /// /// The abstract operation IsRegExp takes argument /// argument (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. -pub(crate) fn is_reg_exp( - agent: &mut Agent, - argument: Value, - gc: GcScope<'_, '_>, -) -> JsResult { +pub(crate) fn is_reg_exp(agent: &mut Agent, argument: Value, gc: GcScope) -> JsResult { // 1. If argument is not an Object, return false. if !argument.is_object() { return Ok(false); @@ -190,7 +182,7 @@ pub(crate) fn is_reg_exp( /// returns either a normal completion containing a Boolean or a throw /// completion. It is used to determine whether additional properties can be /// added to O. -pub(crate) fn is_extensible(agent: &mut Agent, o: Object, gc: GcScope<'_, '_>) -> JsResult { +pub(crate) fn is_extensible(agent: &mut Agent, o: Object, gc: GcScope) -> JsResult { // 1. Return ? O.[[IsExtensible]](). o.internal_is_extensible(agent, gc) } @@ -210,7 +202,7 @@ pub(crate) fn is_same_type, V2: Copy + Into>(x: V1 pub(crate) fn is_integral_number( agent: &mut Agent, argument: impl Copy + Into, - gc: GcScope<'_, '_>, + gc: GcScope, ) -> bool { let argument = argument.into(); @@ -349,7 +341,7 @@ pub(crate) fn is_less_than( agent: &mut Agent, x: impl Into + Copy, y: impl Into + Copy, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult> { let (px, py, gc) = match (Primitive::try_from(x.into()), Primitive::try_from(y.into())) { (Ok(px), Ok(py)) => { @@ -553,7 +545,7 @@ pub(crate) fn is_loosely_equal( agent: &mut Agent, x: impl Into + Copy, y: impl Into + Copy, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { let x: Value = x.into(); let y: Value = y.into(); diff --git a/nova_vm/src/ecmascript/builtins/proxy.rs b/nova_vm/src/ecmascript/builtins/proxy.rs index b694284e..9bb95069 100644 --- a/nova_vm/src/ecmascript/builtins/proxy.rs +++ b/nova_vm/src/ecmascript/builtins/proxy.rs @@ -26,7 +26,8 @@ use crate::{ }, engine::{ context::{GcScope, NoGcScope}, - TryResult, + rootable::HeapRootData, + Scoped, TryResult, }, heap::{ indexes::{BaseIndex, ProxyIndex}, @@ -41,55 +42,71 @@ pub mod data; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct Proxy(pub(crate) ProxyIndex<'static>); +pub struct Proxy<'a>(pub(crate) ProxyIndex<'a>); + +impl Proxy<'_> { + /// Unbind this Proxy from its current lifetime. This is necessary to use + /// the Proxy as a parameter in a call that can perform garbage + /// collection. + pub fn unbind(self) -> Proxy<'static> { + unsafe { std::mem::transmute::>(self) } + } -impl Proxy { - pub(crate) const fn _def() -> Self { - Self(BaseIndex::from_u32_index(0)) + // Bind this Proxy to the garbage collection lifetime. This enables Rust's + // borrow checker to verify that your Proxys cannot not be invalidated by + // garbage collection being performed. + // + // This function is best called with the form + // ```rs + // let proxy = proxy.bind(&gc); + // ``` + // to make sure that the unbound Proxy cannot be used after binding. + pub const fn bind<'gc>(self, _: NoGcScope<'gc, '_>) -> Proxy<'gc> { + unsafe { std::mem::transmute::>(self) } } - pub(crate) const fn get_index(self) -> usize { - self.0.into_index() + pub fn scope<'scope>( + self, + agent: &mut Agent, + gc: NoGcScope<'_, 'scope>, + ) -> Scoped<'scope, Proxy<'static>> { + Scoped::new(agent, self.unbind(), gc) } -} -impl From for ProxyIndex<'static> { - fn from(val: Proxy) -> Self { - val.0 + pub(crate) const fn _def() -> Self { + Self(BaseIndex::from_u32_index(0)) } -} -impl From> for Proxy { - fn from(value: ProxyIndex<'static>) -> Self { - Self(value) + pub(crate) const fn get_index(self) -> usize { + self.0.into_index() } } -impl IntoValue for Proxy { +impl IntoValue for Proxy<'_> { fn into_value(self) -> Value { self.into() } } -impl IntoObject for Proxy { +impl IntoObject for Proxy<'_> { fn into_object(self) -> Object { self.into() } } -impl From for Value { +impl From> for Value { fn from(val: Proxy) -> Self { - Value::Proxy(val) + Value::Proxy(val.unbind()) } } -impl From for Object { +impl From> for Object { fn from(val: Proxy) -> Self { - Object::Proxy(val) + Object::Proxy(val.unbind()) } } -impl InternalSlots for Proxy { +impl InternalSlots for Proxy<'_> { #[inline(always)] fn get_backing_object(self, _agent: &Agent) -> Option> { todo!() @@ -120,19 +137,15 @@ impl InternalSlots for Proxy { } } -impl InternalMethods for Proxy { - fn try_get_prototype_of( - self, - _: &mut Agent, - _: NoGcScope<'_, '_>, - ) -> TryResult> { +impl InternalMethods for Proxy<'_> { + fn try_get_prototype_of(self, _: &mut Agent, _: NoGcScope) -> TryResult> { TryResult::Break(()) } fn internal_get_prototype_of( self, agent: &mut Agent, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult> { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. @@ -238,7 +251,7 @@ impl InternalMethods for Proxy { self, agent: &mut Agent, prototype: Option, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. @@ -314,7 +327,7 @@ impl InternalMethods for Proxy { TryResult::Break(()) } - fn internal_is_extensible(self, agent: &mut Agent, mut gc: GcScope<'_, '_>) -> JsResult { + fn internal_is_extensible(self, agent: &mut Agent, mut gc: GcScope) -> JsResult { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. // 3. Let handler be O.[[ProxyHandler]]. @@ -383,11 +396,7 @@ impl InternalMethods for Proxy { TryResult::Break(()) } - fn internal_prevent_extensions( - self, - agent: &mut Agent, - mut gc: GcScope<'_, '_>, - ) -> JsResult { + fn internal_prevent_extensions(self, agent: &mut Agent, mut gc: GcScope) -> JsResult { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. // 3. Let handler be O.[[ProxyHandler]]. @@ -474,7 +483,7 @@ impl InternalMethods for Proxy { self, agent: &mut Agent, property_key: PropertyKey, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult> { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. @@ -644,7 +653,7 @@ impl InternalMethods for Proxy { agent: &mut Agent, property_key: PropertyKey, property_descriptor: PropertyDescriptor, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. @@ -807,7 +816,7 @@ impl InternalMethods for Proxy { self, agent: &mut Agent, property_key: PropertyKey, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { let mut property_key = property_key.bind(gc.nogc()); @@ -922,7 +931,7 @@ impl InternalMethods for Proxy { agent: &mut Agent, property_key: PropertyKey, mut receiver: Value, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { let mut property_key = property_key.bind(gc.nogc()); // 1. Perform ? ValidateNonRevokedProxy(O). @@ -1033,7 +1042,7 @@ impl InternalMethods for Proxy { property_key: PropertyKey, value: Value, mut receiver: Value, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { let mut property_key = property_key.bind(gc.nogc()); // 1. Perform ? ValidateNonRevokedProxy(O). @@ -1131,7 +1140,7 @@ impl InternalMethods for Proxy { self, agent: &mut Agent, mut property_key: PropertyKey, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { // 1. Perform ? ValidateNonRevokedProxy(O). // 2. Let target be O.[[ProxyTarget]]. @@ -1248,7 +1257,7 @@ impl InternalMethods for Proxy { agent: &mut Agent, _: Value, arguments: ArgumentsList, - mut gc: GcScope<'_, '_>, + mut gc: GcScope, ) -> JsResult { let this_argument = arguments.get(1); let arguments_list = arguments.get(2); @@ -1316,7 +1325,7 @@ impl InternalMethods for Proxy { _agent: &mut Agent, _arguments_list: ArgumentsList, _new_target: Function, - _gc: GcScope<'_, '_>, + _gc: GcScope, ) -> JsResult { todo!() } @@ -1328,12 +1337,12 @@ impl InternalMethods for Proxy { /// language value) and handler (an ECMAScript language value) and returns /// either a normal completion containing a Proxy exotic object or a throw /// completion. It is used to specify the creation of new Proxy objects. -pub(crate) fn proxy_create( +pub(crate) fn proxy_create<'a>( agent: &mut Agent, target: Value, handler: Value, - gc: NoGcScope, -) -> JsResult { + gc: NoGcScope<'a, '_>, +) -> JsResult> { // 1. If target is not an Object, throw a TypeError exception. let Ok(target) = Object::try_from(target) else { return Err(agent.throw_exception_with_static_message( @@ -1367,7 +1376,7 @@ pub(crate) fn proxy_create( Ok(p) } -impl Index for Agent { +impl Index> for Agent { type Output = ProxyHeapData; fn index(&self, index: Proxy) -> &Self::Output { @@ -1375,13 +1384,13 @@ impl Index for Agent { } } -impl IndexMut for Agent { +impl IndexMut> for Agent { fn index_mut(&mut self, index: Proxy) -> &mut Self::Output { &mut self.heap.proxys[index] } } -impl Index for Vec> { +impl Index> for Vec> { type Output = ProxyHeapData; fn index(&self, index: Proxy) -> &Self::Output { @@ -1392,7 +1401,7 @@ impl Index for Vec> { } } -impl IndexMut for Vec> { +impl IndexMut> for Vec> { fn index_mut(&mut self, index: Proxy) -> &mut Self::Output { self.get_mut(index.get_index()) .expect("Proxy out of bounds") @@ -1401,14 +1410,27 @@ impl IndexMut for Vec> { } } -impl CreateHeapData for Heap { - fn create(&mut self, data: ProxyHeapData) -> Proxy { +impl TryFrom for Proxy<'_> { + type Error = (); + + #[inline] + fn try_from(value: HeapRootData) -> Result { + if let HeapRootData::Proxy(value) = value { + Ok(value) + } else { + Err(()) + } + } +} + +impl CreateHeapData> for Heap { + fn create(&mut self, data: ProxyHeapData) -> Proxy<'static> { self.proxys.push(Some(data)); Proxy(ProxyIndex::last(&self.proxys)) } } -impl HeapMarkAndSweep for Proxy { +impl HeapMarkAndSweep for Proxy<'static> { fn mark_values(&self, queues: &mut crate::heap::WorkQueues) { queues.proxys.push(*self); } diff --git a/nova_vm/src/ecmascript/types/language/object.rs b/nova_vm/src/ecmascript/types/language/object.rs index 02ef258c..deddf5e9 100644 --- a/nova_vm/src/ecmascript/types/language/object.rs +++ b/nova_vm/src/ecmascript/types/language/object.rs @@ -133,7 +133,7 @@ pub enum Object { FinalizationRegistry(FinalizationRegistry<'static>) = FINALIZATION_REGISTRY_DISCRIMINANT, Map(Map<'static>) = MAP_DISCRIMINANT, Promise(Promise<'static>) = PROMISE_DISCRIMINANT, - Proxy(Proxy) = PROXY_DISCRIMINANT, + Proxy(Proxy<'static>) = PROXY_DISCRIMINANT, #[cfg(feature = "regexp")] RegExp(RegExp<'static>) = REGEXP_DISCRIMINANT, Set(Set<'static>) = SET_DISCRIMINANT, diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index 648420fc..dd936657 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -165,7 +165,7 @@ pub enum Value { FinalizationRegistry(FinalizationRegistry<'static>), Map(Map<'static>), Promise(Promise<'static>), - Proxy(Proxy), + Proxy(Proxy<'static>), #[cfg(feature = "regexp")] RegExp(RegExp<'static>), Set(Set<'static>), diff --git a/nova_vm/src/engine/rootable.rs b/nova_vm/src/engine/rootable.rs index d18e98aa..cbccc182 100644 --- a/nova_vm/src/engine/rootable.rs +++ b/nova_vm/src/engine/rootable.rs @@ -148,7 +148,7 @@ mod private { impl RootableSealed for PrimitiveObject<'_> {} impl RootableSealed for Promise<'_> {} impl RootableSealed for PropertyKey<'_> {} - impl RootableSealed for Proxy {} + impl RootableSealed for Proxy<'_> {} #[cfg(feature = "regexp")] impl RootableSealed for RegExp<'_> {} impl RootableSealed for Set<'_> {} @@ -263,7 +263,7 @@ pub enum HeapRootData { FinalizationRegistry(FinalizationRegistry<'static>) = FINALIZATION_REGISTRY_DISCRIMINANT, Map(Map<'static>) = MAP_DISCRIMINANT, Promise(Promise<'static>) = PROMISE_DISCRIMINANT, - Proxy(Proxy) = PROXY_DISCRIMINANT, + Proxy(Proxy<'static>) = PROXY_DISCRIMINANT, #[cfg(feature = "regexp")] RegExp(RegExp<'static>) = REGEXP_DISCRIMINANT, Set(Set<'static>) = SET_DISCRIMINANT, diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index 5cff9995..7df11012 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -168,7 +168,7 @@ pub(crate) struct WorkQueues { pub promises: Vec>, pub promise_reaction_records: Vec, pub promise_resolving_functions: Vec>, - pub proxys: Vec, + pub proxys: Vec>, pub realms: Vec, #[cfg(feature = "regexp")] pub regexps: Vec>, diff --git a/tests/metrics.json b/tests/metrics.json index 7a3a4348..4b9f12bb 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -2,8 +2,8 @@ "results": { "crash": 14288, "fail": 7295, - "pass": 23660, - "skip": 45, + "pass": 23659, + "skip": 46, "timeout": 3, "unresolved": 0 },