diff --git a/src/isolate.rs b/src/isolate.rs index 28cec56278..3259947d86 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -728,24 +728,20 @@ impl Isolate { #[inline(always)] pub(crate) fn get_data_internal(&self, slot: u32) -> *mut c_void { - let slots = unsafe { + unsafe { let p = self as *const Self as *const u8; - let p = p.add(Self::EMBEDDER_DATA_OFFSET); - let p = p as *const [*mut c_void; Self::EMBEDDER_DATA_SLOT_COUNT as _]; - &*p - }; - slots[slot as usize] + let p = p.add(Self::EMBEDDER_DATA_OFFSET) as *const *mut c_void; + *p.add(slot as usize) + } } #[inline(always)] pub(crate) fn set_data_internal(&mut self, slot: u32, data: *mut c_void) { - let slots = unsafe { - let p = self as *mut Self as *mut u8; - let p = p.add(Self::EMBEDDER_DATA_OFFSET); - let p = p as *mut [*mut c_void; Self::EMBEDDER_DATA_SLOT_COUNT as _]; - &mut *p - }; - slots[slot as usize] = data; + unsafe { + let p = self as *const Self as *const u8; + let p = p.add(Self::EMBEDDER_DATA_OFFSET) as *mut *mut c_void; + *p.add(slot as usize) = data; + } } /// Returns a pointer to the `ScopeData` struct for the current scope. diff --git a/src/scope.rs b/src/scope.rs index 035ca1f9a1..1cc3ce8a83 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -1295,13 +1295,13 @@ pub(crate) mod data { previous: Option>, next: Option>, // The 'status' field is also always valid (but does change). - status: Cell, + status: ScopeStatus, // The following fields are only valid when this ScopeData object is in use // (eiter current or shadowed -- not free). context: Cell>>, escape_slot: Option>>, try_catch: Option>, - scope_type_specific_data: ScopeTypeSpecificData, + scope_type_specific_data: Option, } impl ScopeData { @@ -1315,8 +1315,8 @@ pub(crate) mod data { .map(NonNull::as_ptr) .map(|p| unsafe { &mut *p }) .unwrap(); - match self_mut.status.get() { - ScopeStatus::Current { .. } => self_mut, + match self_mut.status { + ScopeStatus::CurrentZombie | ScopeStatus::CurrentNoZombie => self_mut, _ => unreachable!(), } } @@ -1326,7 +1326,7 @@ pub(crate) mod data { /// ScopeData objects even when no scope is entered. pub(crate) fn new_root(isolate: &mut Isolate) { let root = Box::leak(Self::boxed(isolate.into())); - root.status = ScopeStatus::Current { zombie: false }.into(); + root.status = ScopeStatus::CurrentNoZombie; debug_assert!(isolate.get_current_scope_data().is_none()); isolate.set_current_scope_data(Some(root.into())); } @@ -1366,11 +1366,10 @@ pub(crate) mod data { context: Local<'s, Context>, ) -> &'s mut Self { self.new_scope_data_with(move |data| { - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::ContextScope { + data.scope_type_specific_data = + Some(ScopeTypeSpecificData::ContextScope { _raw_context_scope: raw::ContextScope::new(context), - } - }); + }); data.context.set(Some(context.as_non_null())); }) } @@ -1390,17 +1389,17 @@ pub(crate) mod data { { self.new_scope_data_with(|data| { let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { + data.scope_type_specific_data = Some({ ScopeTypeSpecificData::HandleScope { raw_handle_scope: unsafe { raw::HandleScope::uninit() }, raw_context_scope: None, } }); match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::HandleScope { + Some(ScopeTypeSpecificData::HandleScope { raw_handle_scope, raw_context_scope, - } => { + }) => { unsafe { raw_handle_scope.init(isolate) }; init_context_fn(isolate, &mut data.context, raw_context_scope); } @@ -1453,17 +1452,17 @@ pub(crate) mod data { // inside the `EscapableHandleScope` that's being constructed here, // rather than escaping from it. let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { + data.scope_type_specific_data = Some({ ScopeTypeSpecificData::EscapableHandleScope { raw_handle_scope: unsafe { raw::HandleScope::uninit() }, raw_escape_slot: Some(raw::EscapeSlot::new(isolate)), } }); match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::EscapableHandleScope { + Some(ScopeTypeSpecificData::EscapableHandleScope { raw_handle_scope, raw_escape_slot, - } => { + }) => { unsafe { raw_handle_scope.init(isolate) }; data.escape_slot.replace(raw_escape_slot.into()); } @@ -1476,13 +1475,13 @@ pub(crate) mod data { pub(super) fn new_try_catch_data(&mut self) -> &mut Self { self.new_scope_data_with(|data| { let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { + data.scope_type_specific_data = Some({ ScopeTypeSpecificData::TryCatch { raw_try_catch: unsafe { raw::TryCatch::uninit() }, } }); match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::TryCatch { raw_try_catch } => { + Some(ScopeTypeSpecificData::TryCatch { raw_try_catch }) => { unsafe { raw_try_catch.init(isolate) }; data.try_catch.replace(raw_try_catch.into()); } @@ -1498,7 +1497,7 @@ pub(crate) mod data { ) -> &mut Self { self.new_scope_data_with(|data| { let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { + data.scope_type_specific_data = Some({ ScopeTypeSpecificData::DisallowJavascriptExecutionScope { raw_scope: unsafe { raw::DisallowJavascriptExecutionScope::uninit() @@ -1506,9 +1505,9 @@ pub(crate) mod data { } }); match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::DisallowJavascriptExecutionScope { + Some(ScopeTypeSpecificData::DisallowJavascriptExecutionScope { raw_scope, - } => unsafe { raw_scope.init(isolate, on_failure) }, + }) => unsafe { raw_scope.init(isolate, on_failure) }, _ => unreachable!(), } }) @@ -1520,15 +1519,15 @@ pub(crate) mod data { ) -> &mut Self { self.new_scope_data_with(|data| { let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { + data.scope_type_specific_data = Some({ ScopeTypeSpecificData::AllowJavascriptExecutionScope { raw_scope: unsafe { raw::AllowJavascriptExecutionScope::uninit() }, } }); match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::AllowJavascriptExecutionScope { + Some(ScopeTypeSpecificData::AllowJavascriptExecutionScope { raw_scope, - } => unsafe { raw_scope.init(isolate) }, + }) => unsafe { raw_scope.init(isolate) }, _ => unreachable!(), } }) @@ -1541,9 +1540,9 @@ pub(crate) mod data { ) -> &'s mut Self { self.new_scope_data_with(|data| { debug_assert!(data.scope_type_specific_data.is_none()); - data - .context - .set(maybe_current_context.map(|cx| cx.as_non_null())); + if let Some(context) = maybe_current_context { + data.context.set(Some(context.as_non_null())); + } }) } @@ -1553,10 +1552,11 @@ pub(crate) mod data { init_fn: impl FnOnce(&mut Self), ) -> &mut Self { // Mark this scope (the parent of the newly created scope) as 'shadowed'; - self.status.set(match self.status.get() { - ScopeStatus::Current { zombie } => ScopeStatus::Shadowed { zombie }, + self.status = match self.status { + ScopeStatus::CurrentZombie => ScopeStatus::ShadowedZombie, + ScopeStatus::CurrentNoZombie => ScopeStatus::ShadowedNoZombie, _ => unreachable!(), - }); + }; // Copy fields that that will be inherited by the new scope. let context = self.context.get().into(); let escape_slot = self.escape_slot; @@ -1566,9 +1566,11 @@ pub(crate) mod data { // later cleared in the `as_scope()` method, to verify that we're // always creating exactly one scope from any `ScopeData` object. // For performance reasons this check is not performed in release builds. - new_scope_data.status = Cell::new(ScopeStatus::Current { - zombie: cfg!(debug_assertions), - }); + new_scope_data.status = if cfg!(debug_assertions) { + ScopeStatus::CurrentZombie + } else { + ScopeStatus::CurrentNoZombie + }; // Store fields inherited from the parent scope. new_scope_data.context = context; new_scope_data.escape_slot = escape_slot; @@ -1591,7 +1593,7 @@ pub(crate) mod data { // Reuse a free `Box` allocation. debug_assert_eq!(next_box.isolate, self.isolate); debug_assert_eq!(next_box.previous, self_nn); - debug_assert_eq!(next_box.status.get(), ScopeStatus::Free); + debug_assert_eq!(next_box.status, ScopeStatus::Free); debug_assert!(next_box.scope_type_specific_data.is_none()); next_box.as_mut() } @@ -1607,13 +1609,13 @@ pub(crate) mod data { #[inline(always)] pub(super) fn as_scope(&mut self) -> S { - assert_eq!(Layout::new::<&mut Self>(), Layout::new::()); + debug_assert_eq!(Layout::new::<&mut Self>(), Layout::new::()); // In debug builds, a new initialized `ScopeStatus` will have the `zombie` // flag set, so we have to reset it. In release builds, new `ScopeStatus` // objects come with the `zombie` flag cleared, so no update is necessary. if cfg!(debug_assertions) { - assert_eq!(self.status.get(), ScopeStatus::Current { zombie: true }); - self.status.set(ScopeStatus::Current { zombie: false }); + assert_eq!(self.status, ScopeStatus::CurrentZombie); + self.status = ScopeStatus::CurrentNoZombie; } let self_nn = NonNull::from(self); unsafe { ptr::read(&self_nn as *const _ as *const S) } @@ -1638,9 +1640,9 @@ pub(crate) mod data { #[inline(always)] fn try_activate_scope(mut self: &mut Self) -> &mut Self { - self = match self.status.get() { - ScopeStatus::Current { zombie: false } => self, - ScopeStatus::Shadowed { zombie: false } => { + self = match self.status { + ScopeStatus::CurrentNoZombie => self, + ScopeStatus::ShadowedNoZombie => { self.next.as_mut().unwrap().try_exit_scope() } _ => unreachable!(), @@ -1655,12 +1657,12 @@ pub(crate) mod data { #[inline(always)] fn try_exit_scope(mut self: &mut Self) -> &mut Self { loop { - self = match self.status.get() { - ScopeStatus::Shadowed { .. } => { + self = match self.status { + ScopeStatus::ShadowedZombie | ScopeStatus::ShadowedNoZombie => { self.next.as_mut().unwrap().try_exit_scope() } - ScopeStatus::Current { zombie: true } => break self.exit_scope(), - ScopeStatus::Current { zombie: false } => { + ScopeStatus::CurrentZombie => break self.exit_scope(), + ScopeStatus::CurrentNoZombie => { panic!("active scope can't be dropped") } _ => unreachable!(), @@ -1672,13 +1674,13 @@ pub(crate) mod data { fn exit_scope(&mut self) -> &mut Self { // Clear out the scope type specific data field. None of the other fields // have a destructor, and there's no need to do any cleanup on them. - if !matches!(self.scope_type_specific_data, ScopeTypeSpecificData::None) { + if self.scope_type_specific_data.is_some() { self.scope_type_specific_data = Default::default(); } // Change the ScopeData's status field from 'Current' to 'Free', which // means that it is not associated with a scope and can be reused. - self.status.set(ScopeStatus::Free); + self.status = ScopeStatus::Free; // Point the Isolate's current scope data slot at our parent scope. let previous_nn = self.previous.unwrap(); @@ -1689,10 +1691,11 @@ pub(crate) mod data { // Update the parent scope's status field to reflect that it is now // 'Current' again an no longer 'Shadowed'. let previous_mut = unsafe { &mut *previous_nn.as_ptr() }; - previous_mut.status.set(match previous_mut.status.get() { - ScopeStatus::Shadowed { zombie } => ScopeStatus::Current { zombie }, + previous_mut.status = match previous_mut.status { + ScopeStatus::ShadowedZombie => ScopeStatus::CurrentZombie, + ScopeStatus::ShadowedNoZombie => ScopeStatus::CurrentNoZombie, _ => unreachable!(), - }); + }; previous_mut } @@ -1719,15 +1722,15 @@ pub(crate) mod data { #[inline(always)] pub(super) fn notify_scope_dropped(&mut self) { match &self.scope_type_specific_data { - ScopeTypeSpecificData::HandleScope { .. } - | ScopeTypeSpecificData::EscapableHandleScope { .. } => { + Some( + ScopeTypeSpecificData::HandleScope { .. } + | ScopeTypeSpecificData::EscapableHandleScope { .. }, + ) => { // Defer scope exit until the parent scope is touched. - self.status.set(match self.status.get() { - ScopeStatus::Current { zombie: false } => { - ScopeStatus::Current { zombie: true } - } + self.status = match self.status { + ScopeStatus::CurrentNoZombie => ScopeStatus::CurrentZombie, _ => unreachable!(), - }) + } } _ => { // Regular, immediate exit. @@ -1832,10 +1835,13 @@ pub(crate) mod data { } #[derive(Debug, Clone, Copy, Eq, PartialEq)] + #[repr(u8)] enum ScopeStatus { Free, - Current { zombie: bool }, - Shadowed { zombie: bool }, + CurrentZombie, + CurrentNoZombie, + ShadowedZombie, + ShadowedNoZombie, } impl Default for ScopeStatus { @@ -1846,7 +1852,6 @@ pub(crate) mod data { #[derive(Debug)] enum ScopeTypeSpecificData { - None, ContextScope { _raw_context_scope: raw::ContextScope, }, @@ -1869,12 +1874,6 @@ pub(crate) mod data { }, } - impl Default for ScopeTypeSpecificData { - fn default() -> Self { - Self::None - } - } - impl Drop for ScopeTypeSpecificData { #[inline(always)] fn drop(&mut self) { @@ -1891,23 +1890,6 @@ pub(crate) mod data { } } } - - impl ScopeTypeSpecificData { - pub fn is_none(&self) -> bool { - matches!(self, Self::None) - } - - /// Replaces a `ScopeTypeSpecificData::None` value with the value returned - /// from the specified closure. This function exists because initializing - /// scopes is performance critical, and `ptr::write()` produces more - /// efficient code than using a regular assign statement, which will try to - /// drop the old value and move the new value into place, even after - /// asserting `self.is_none()`. - pub fn init_with(&mut self, init_fn: impl FnOnce() -> Self) { - assert!(self.is_none()); - unsafe { ptr::write(self, (init_fn)()) } - } - } } /// The `raw` module contains prototypes for all the `extern C` functions that