Skip to content

Commit

Permalink
perf: optimize scope construction and Isolate::get_slot/set_slot() (d…
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed Oct 8, 2022
1 parent fc26f63 commit b2a09e2
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 91 deletions.
12 changes: 4 additions & 8 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8-fast-api-calls.h"
#include "v8/include/v8-inspector.h"
#include "v8/include/v8-internal.h"
#include "v8/include/v8-platform.h"
#include "v8/include/v8-profiler.h"
#include "v8/include/v8.h"
Expand Down Expand Up @@ -99,6 +100,9 @@ static_assert(offsetof(v8::ScriptCompiler::CachedData, buffer_policy) == 12,
#endif

extern "C" {
const extern size_t v8__internal__Internals__kIsolateEmbedderDataOffset =
v8::internal::Internals::kIsolateEmbedderDataOffset;

void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv,
const char* usage) {
namespace i = v8::internal;
Expand Down Expand Up @@ -159,14 +163,6 @@ const v8::Context* v8__Isolate__GetEnteredOrMicrotaskContext(
return local_to_ptr(isolate->GetEnteredOrMicrotaskContext());
}

void v8__Isolate__SetData(v8::Isolate* isolate, uint32_t slot, void* data) {
isolate->SetData(slot, data);
}

void* v8__Isolate__GetData(v8::Isolate* isolate, uint32_t slot) {
return isolate->GetData(slot);
}

uint32_t v8__Isolate__GetNumberOfDataSlots(v8::Isolate* isolate) {
return isolate->GetNumberOfDataSlots();
}
Expand Down
105 changes: 69 additions & 36 deletions src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@ pub type PrepareStackTraceCallback<'s> =
) -> PrepareStackTraceCallbackRet;

extern "C" {
static v8__internal__Internals__kIsolateEmbedderDataOffset: usize;

fn v8__Isolate__New(params: *const raw::CreateParams) -> *mut Isolate;
fn v8__Isolate__Dispose(this: *mut Isolate);
fn v8__Isolate__SetData(this: *mut Isolate, slot: u32, data: *mut c_void);
fn v8__Isolate__GetData(this: *const Isolate, slot: u32) -> *mut c_void;
fn v8__Isolate__GetNumberOfDataSlots(this: *const Isolate) -> u32;
fn v8__Isolate__Enter(this: *mut Isolate);
fn v8__Isolate__Exit(this: *mut Isolate);
Expand Down Expand Up @@ -485,9 +485,30 @@ extern "C" {
pub struct Isolate(Opaque);

impl Isolate {
// Total number of isolate data slots provided by V8.
const EMBEDDER_DATA_SLOT_COUNT: u32 = 4;

// Byte offset inside `Isolate` where the isolate data slots are stored. This
// should be the same as the value of `kIsolateEmbedderDataOffset` which is
// defined in `v8-internal.h`.
const EMBEDDER_DATA_OFFSET: usize = size_of::<[*const (); 23]>();

// Isolate data slots used internally by rusty_v8.
const ANNEX_SLOT: u32 = 0;
const CURRENT_SCOPE_DATA_SLOT: u32 = 1;
const INTERNAL_SLOT_COUNT: u32 = 2;
const INTERNAL_DATA_SLOT_COUNT: u32 = 2;

#[inline(always)]
fn assert_embedder_data_slot_count_and_offset_correct(&self) {
assert_eq!(
unsafe { v8__Isolate__GetNumberOfDataSlots(self) },
Self::EMBEDDER_DATA_SLOT_COUNT
);
assert_eq!(
unsafe { v8__internal__Internals__kIsolateEmbedderDataOffset },
Self::EMBEDDER_DATA_OFFSET
);
}

/// Creates a new isolate. Does not change the currently entered
/// isolate.
Expand All @@ -502,6 +523,7 @@ impl Isolate {
let (raw_create_params, create_param_allocations) = params.finalize();
let cxx_isolate = unsafe { v8__Isolate__New(&raw_create_params) };
let mut owned_isolate = OwnedIsolate::new(cxx_isolate);
owned_isolate.assert_embedder_data_slot_count_and_offset_correct();
ScopeData::new_root(&mut owned_isolate);
owned_isolate.create_annex(create_param_allocations);
unsafe {
Expand Down Expand Up @@ -545,25 +567,24 @@ impl Isolate {
) {
let annex_arc = Arc::new(IsolateAnnex::new(self, create_param_allocations));
let annex_ptr = Arc::into_raw(annex_arc);
unsafe {
assert!(v8__Isolate__GetData(self, Self::ANNEX_SLOT).is_null());
v8__Isolate__SetData(self, Self::ANNEX_SLOT, annex_ptr as *mut c_void);
};
assert!(self.get_data_internal(Self::ANNEX_SLOT).is_null());
self.set_data_internal(Self::ANNEX_SLOT, annex_ptr as *mut _);
}

#[inline(always)]
fn get_annex(&self) -> &IsolateAnnex {
unsafe {
&*(v8__Isolate__GetData(self, Self::ANNEX_SLOT) as *const _
as *const IsolateAnnex)
}
let annex_ptr =
self.get_data_internal(Self::ANNEX_SLOT) as *const IsolateAnnex;
assert!(!annex_ptr.is_null());
unsafe { &*annex_ptr }
}

#[inline(always)]
fn get_annex_mut(&mut self) -> &mut IsolateAnnex {
unsafe {
&mut *(v8__Isolate__GetData(self, Self::ANNEX_SLOT) as *mut IsolateAnnex)
}
let annex_ptr =
self.get_data_internal(Self::ANNEX_SLOT) as *mut IsolateAnnex;
assert!(!annex_ptr.is_null());
unsafe { &mut *annex_ptr }
}

pub(crate) fn get_finalizer_map(&self) -> &FinalizerMap {
Expand All @@ -581,37 +602,51 @@ impl Isolate {
annex_arc
}

/// Associate embedder-specific data with the isolate. `slot` has to be
/// between 0 and `Isolate::get_number_of_data_slots()`.
///
/// 0-indexed slot is used internally by rusty_v8, so users have 3 slots
/// left to use.
#[inline(always)]
pub unsafe fn set_data(&mut self, slot: u32, ptr: *mut c_void) {
assert!(slot < 4);
v8__Isolate__SetData(self, slot + Self::INTERNAL_SLOT_COUNT, ptr)
}

/// Retrieve embedder-specific data from the isolate.
/// Returns NULL if SetData has never been called for the given `slot`.
pub fn get_data(&self, slot: u32) -> *mut c_void {
assert!(slot < 4);
unsafe { v8__Isolate__GetData(self, slot + Self::INTERNAL_SLOT_COUNT) }
self.get_data_internal(Self::INTERNAL_DATA_SLOT_COUNT + slot)
}

/// Associate embedder-specific data with the isolate. `slot` has to be
/// between 0 and `Isolate::get_number_of_data_slots()`.
#[inline(always)]
pub fn set_data(&mut self, slot: u32, data: *mut c_void) {
self.set_data_internal(Self::INTERNAL_DATA_SLOT_COUNT + slot, data)
}

/// Returns the maximum number of available embedder data slots. Valid slots
/// are in the range of 0 - `Isolate::get_number_of_data_slots() - 1`.
/// are in the range of `0 <= n < Isolate::get_number_of_data_slots()`.
pub fn get_number_of_data_slots(&self) -> u32 {
unsafe {
v8__Isolate__GetNumberOfDataSlots(self) - Self::INTERNAL_SLOT_COUNT
}
Self::EMBEDDER_DATA_SLOT_COUNT - Self::INTERNAL_DATA_SLOT_COUNT
}

#[inline(always)]
pub(crate) fn get_data_internal(&self, slot: u32) -> *mut c_void {
let slots = 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]
}

#[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;
}

/// Returns a pointer to the `ScopeData` struct for the current scope.
#[inline(always)]
pub(crate) fn get_current_scope_data(&self) -> Option<NonNull<ScopeData>> {
let scope_data_ptr =
unsafe { v8__Isolate__GetData(self, Self::CURRENT_SCOPE_DATA_SLOT) };
let scope_data_ptr = self.get_data_internal(Self::CURRENT_SCOPE_DATA_SLOT);
NonNull::new(scope_data_ptr).map(NonNull::cast)
}

Expand All @@ -625,9 +660,7 @@ impl Isolate {
.map(NonNull::cast)
.map(NonNull::as_ptr)
.unwrap_or_else(null_mut);
unsafe {
v8__Isolate__SetData(self, Self::CURRENT_SCOPE_DATA_SLOT, scope_data_ptr)
};
self.set_data_internal(Self::CURRENT_SCOPE_DATA_SLOT, scope_data_ptr);
}

/// Get a reference to embedder data added with `set_slot()`.
Expand Down
Loading

0 comments on commit b2a09e2

Please sign in to comment.