diff --git a/nova_vm/src/ecmascript/builtins/error.rs b/nova_vm/src/ecmascript/builtins/error.rs index 4d20b9eb..0950fc8a 100644 --- a/nova_vm/src/ecmascript/builtins/error.rs +++ b/nova_vm/src/ecmascript/builtins/error.rs @@ -9,7 +9,8 @@ use std::ops::{Index, IndexMut}; pub(crate) use data::ErrorHeapData; use crate::engine::context::{GcScope, NoGcScope}; -use crate::engine::{unwrap_try, TryResult}; +use crate::engine::rootable::{HeapRootData, HeapRootRef, Rootable}; +use crate::engine::{unwrap_try, Scoped, TryResult}; use crate::{ ecmascript::{ execution::{agent::ExceptionType, Agent, JsResult, ProtoIntrinsics}, @@ -26,9 +27,37 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct Error(pub(crate) ErrorIndex); +pub struct Error<'a>(pub(crate) ErrorIndex<'a>); + +impl<'a> Error<'a> { + /// Unbind this Error from its current lifetime. This is necessary to use + /// the Error as a parameter in a call that can perform garbage + /// collection. + pub fn unbind(self) -> Error<'static> { + unsafe { std::mem::transmute::, Error<'static>>(self) } + } + + // Bind this Error to the garbage collection lifetime. This enables Rust's + // borrow checker to verify that your Errors cannot not be invalidated by + // garbage collection being performed. + // + // This function is best called with the form + // ```rs + // let error = error.bind(&gc); + // ``` + // to make sure that the unbound Error cannot be used after binding. + pub const fn bind(self, _: NoGcScope<'a, '_>) -> Self { + unsafe { std::mem::transmute::(self) } + } + + pub fn scope<'scope>( + self, + agent: &mut Agent, + gc: NoGcScope<'_, 'scope>, + ) -> Scoped<'scope, Error<'static>> { + Scoped::new(agent, self.unbind(), gc) + } -impl Error { pub(crate) const fn _def() -> Self { Self(ErrorIndex::from_u32_index(0)) } @@ -38,31 +67,31 @@ impl Error { } } -impl IntoValue for Error { +impl IntoValue for Error<'_> { fn into_value(self) -> Value { self.into() } } -impl From for Value { +impl From> for Value { fn from(value: Error) -> Self { - Value::Error(value) + Value::Error(value.unbind()) } } -impl IntoObject for Error { +impl IntoObject for Error<'_> { fn into_object(self) -> Object { self.into() } } -impl From for Object { +impl From> for Object { fn from(value: Error) -> Self { - Object::Error(value) + Object::Error(value.unbind()) } } -impl TryFrom for Error { +impl TryFrom for Error<'_> { type Error = (); fn try_from(value: Value) -> Result { @@ -73,7 +102,7 @@ impl TryFrom for Error { } } -impl TryFrom for Error { +impl TryFrom for Error<'_> { type Error = (); fn try_from(value: Object) -> Result { @@ -84,7 +113,7 @@ impl TryFrom for Error { } } -impl InternalSlots for Error { +impl InternalSlots for Error<'_> { const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Error; #[inline(always)] @@ -166,7 +195,7 @@ impl InternalSlots for Error { } } -impl InternalMethods for Error { +impl InternalMethods for Error<'_> { fn try_get_own_property( self, agent: &mut Agent, @@ -410,7 +439,30 @@ impl InternalMethods for Error { } } -impl HeapMarkAndSweep for Error { +impl Rootable for Error<'_> { + type RootRepr = HeapRootRef; + + fn to_root_repr(value: Self) -> Result { + Err(HeapRootData::Error(value.unbind())) + } + + fn from_root_repr(value: &Self::RootRepr) -> Result { + Err(*value) + } + + fn from_heap_ref(heap_ref: HeapRootRef) -> Self::RootRepr { + heap_ref + } + + fn from_heap_data(heap_data: HeapRootData) -> Option { + match heap_data { + HeapRootData::Error(object) => Some(object), + _ => None, + } + } +} + +impl HeapMarkAndSweep for Error<'static> { fn mark_values(&self, queues: &mut WorkQueues) { queues.errors.push(*self); } @@ -420,14 +472,14 @@ impl HeapMarkAndSweep for Error { } } -impl CreateHeapData for Heap { - fn create(&mut self, data: ErrorHeapData) -> Error { +impl CreateHeapData> for Heap { + fn create(&mut self, data: ErrorHeapData) -> Error<'static> { self.errors.push(Some(data)); Error(ErrorIndex::last(&self.errors)) } } -impl Index for Agent { +impl Index> for Agent { type Output = ErrorHeapData; fn index(&self, index: Error) -> &Self::Output { @@ -435,13 +487,13 @@ impl Index for Agent { } } -impl IndexMut for Agent { +impl IndexMut> for Agent { fn index_mut(&mut self, index: Error) -> &mut Self::Output { &mut self.heap.errors[index] } } -impl Index for Vec> { +impl Index> for Vec> { type Output = ErrorHeapData; fn index(&self, index: Error) -> &Self::Output { @@ -452,7 +504,7 @@ impl Index for Vec> { } } -impl IndexMut for Vec> { +impl IndexMut> for Vec> { fn index_mut(&mut self, index: Error) -> &mut Self::Output { self.get_mut(index.get_index()) .expect("Error out of bounds") diff --git a/nova_vm/src/ecmascript/types/language/object.rs b/nova_vm/src/ecmascript/types/language/object.rs index 357d2169..3c95600f 100644 --- a/nova_vm/src/ecmascript/types/language/object.rs +++ b/nova_vm/src/ecmascript/types/language/object.rs @@ -129,7 +129,7 @@ pub enum Object { DataView(DataView<'static>) = DATA_VIEW_DISCRIMINANT, #[cfg(feature = "date")] Date(Date<'static>) = DATE_DISCRIMINANT, - Error(Error) = ERROR_DISCRIMINANT, + Error(Error<'static>) = ERROR_DISCRIMINANT, FinalizationRegistry(FinalizationRegistry<'static>) = FINALIZATION_REGISTRY_DISCRIMINANT, Map(Map) = MAP_DISCRIMINANT, Promise(Promise) = PROMISE_DISCRIMINANT, diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index bd8d02cf..c5a574c9 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -161,7 +161,7 @@ pub enum Value { DataView(DataView<'static>), #[cfg(feature = "date")] Date(Date<'static>), - Error(Error), + Error(Error<'static>), FinalizationRegistry(FinalizationRegistry<'static>), Map(Map), Promise(Promise), diff --git a/nova_vm/src/engine/rootable.rs b/nova_vm/src/engine/rootable.rs index d21d061e..eaa12516 100644 --- a/nova_vm/src/engine/rootable.rs +++ b/nova_vm/src/engine/rootable.rs @@ -234,7 +234,7 @@ pub enum HeapRootData { DataView(DataView<'static>) = DATA_VIEW_DISCRIMINANT, #[cfg(feature = "date")] Date(Date<'static>) = DATE_DISCRIMINANT, - Error(Error) = ERROR_DISCRIMINANT, + Error(Error<'static>) = ERROR_DISCRIMINANT, FinalizationRegistry(FinalizationRegistry<'static>) = FINALIZATION_REGISTRY_DISCRIMINANT, Map(Map) = MAP_DISCRIMINANT, Promise(Promise) = PROMISE_DISCRIMINANT, diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index ca4b9e86..0ac87ccf 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -152,7 +152,7 @@ pub(crate) struct WorkQueues { pub ecmascript_functions: Vec>, pub embedder_objects: Vec, pub source_codes: Vec, - pub errors: Vec, + pub errors: Vec>, pub executables: Vec, pub finalization_registrys: Vec>, pub function_environments: Vec, diff --git a/nova_vm/src/heap/indexes.rs b/nova_vm/src/heap/indexes.rs index bd959e3b..6ce38b43 100644 --- a/nova_vm/src/heap/indexes.rs +++ b/nova_vm/src/heap/indexes.rs @@ -201,7 +201,7 @@ pub type DateIndex<'a> = BaseIndex<'a, DateHeapData>; pub type ECMAScriptFunctionIndex<'a> = BaseIndex<'a, ECMAScriptFunctionHeapData>; pub type ElementIndex = BaseIndex<'static, [Option]>; pub type EmbedderObjectIndex = BaseIndex<'static, EmbedderObjectHeapData>; -pub type ErrorIndex = BaseIndex<'static, ErrorHeapData>; +pub type ErrorIndex<'a> = BaseIndex<'a, ErrorHeapData>; pub type FinalizationRegistryIndex<'a> = BaseIndex<'a, FinalizationRegistryHeapData>; pub type GeneratorIndex = BaseIndex<'static, GeneratorHeapData>; pub type MapIndex = BaseIndex<'static, MapHeapData>;