Skip to content

Commit

Permalink
feat: add v8::Isolate::snapshot_creator_from_existing_snapshot API (d…
Browse files Browse the repository at this point in the history
…enoland#973)

This commit adds "v8::Isolate::snapshot_creator_from_existing_snapshot" API,
that allows to create a new snapshot from already existing snapshot.

Following APIs were added as well:

"v8::Context::from_snapshot"
"v8::Isolate::add_context"

Co-authored-by: Bartek Iwańczuk <[email protected]>
Co-authored-by: Bert Belder <[email protected]>
  • Loading branch information
3 people committed Oct 14, 2022
1 parent 4b704ed commit 885e016
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 25 deletions.
18 changes: 16 additions & 2 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,13 @@ void v8__Context__SetPromiseHooks(v8::Context& self, v8::Function& init_hook,
ptr_to_local(&after_hook), ptr_to_local(&resolve_hook));
}

const v8::Context* v8__Context__FromSnapshot(v8::Isolate* isolate,
size_t context_snapshot_index) {
v8::MaybeLocal<v8::Context> maybe_local =
v8::Context::FromSnapshot(isolate, context_snapshot_index);
return maybe_local_to_ptr(maybe_local);
}

const v8::String* v8__Message__Get(const v8::Message& self) {
return local_to_ptr(self.Get());
}
Expand Down Expand Up @@ -2316,8 +2323,10 @@ bool v8__Proxy__IsRevoked(const v8::Proxy& self) {
void v8__Proxy__Revoke(const v8::Proxy& self) { ptr_to_local(&self)->Revoke(); }

void v8__SnapshotCreator__CONSTRUCT(uninit_t<v8::SnapshotCreator>* buf,
const intptr_t* external_references) {
construct_in_place<v8::SnapshotCreator>(buf, external_references);
const intptr_t* external_references,
v8::StartupData* existing_blob) {
construct_in_place<v8::SnapshotCreator>(buf, external_references,
existing_blob);
}

void v8__SnapshotCreator__DESTRUCT(v8::SnapshotCreator* self) {
Expand Down Expand Up @@ -2351,6 +2360,11 @@ void v8__SnapshotCreator__SetDefaultContext(v8::SnapshotCreator* self,
self->SetDefaultContext(ptr_to_local(&context), SerializeInternalFields);
}

size_t v8__SnapshotCreator__AddContext(v8::SnapshotCreator* self,
const v8::Context& context) {
return self->AddContext(ptr_to_local(&context), SerializeInternalFields);
}

size_t v8__SnapshotCreator__AddData_to_isolate(v8::SnapshotCreator* self,
const v8::Data& data) {
return self->AddData(ptr_to_local(&data));
Expand Down
18 changes: 18 additions & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ extern "C" {
index: c_int,
value: *mut c_void,
);
fn v8__Context__FromSnapshot(
isolate: *mut Isolate,
context_snapshot_index: usize,
) -> *const Context;
}

impl Context {
Expand Down Expand Up @@ -302,6 +306,20 @@ impl Context {
};
}
}

/// Create a new context from a (non-default) context snapshot. There
/// is no way to provide a global object template since we do not create
/// a new global object from template, but we can reuse a global object.
pub fn from_snapshot<'s>(
scope: &mut HandleScope<'s, ()>,
context_snapshot_index: usize,
) -> Option<Local<'s, Context>> {
unsafe {
scope.cast_local(|sd| {
v8__Context__FromSnapshot(sd.get_isolate_mut(), context_snapshot_index)
})
}
}
}

struct ContextAnnex {
Expand Down
31 changes: 30 additions & 1 deletion src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::isolate_create_params::CreateParams;
use crate::promise::PromiseRejectMessage;
use crate::scope::data::ScopeData;
use crate::snapshot::SnapshotCreator;
use crate::support::Allocated;
use crate::support::MapFnFrom;
use crate::support::MapFnTo;
use crate::support::Opaque;
Expand Down Expand Up @@ -543,6 +544,17 @@ impl Isolate {
SnapshotCreator::new(external_references)
}

#[allow(clippy::new_ret_no_self)]
pub fn snapshot_creator_from_existing_snapshot(
existing_snapshot_blob: impl Allocated<[u8]>,
external_references: Option<&'static ExternalReferences>,
) -> OwnedIsolate {
SnapshotCreator::from_existing_snapshot(
existing_snapshot_blob,
external_references,
)
}

/// Initial configuration parameters for a new Isolate.
#[inline(always)]
pub fn create_params() -> CreateParams {
Expand Down Expand Up @@ -1144,6 +1156,24 @@ impl Isolate {
snapshot_creator.set_default_context(context);
}

/// Add additional context to be included in the snapshot blob.
/// The snapshot will include the global proxy.
///
/// Returns the index of the context in the snapshot blob.
///
/// # Panics
///
/// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
#[inline(always)]
pub fn add_context(&mut self, context: Local<Context>) -> usize {
let snapshot_creator = self
.get_annex_mut()
.maybe_snapshot_creator
.as_mut()
.unwrap();
snapshot_creator.add_context(context)
}

/// Attach arbitrary `v8::Data` to the isolate snapshot, which can be
/// retrieved via `HandleScope::get_context_data_from_snapshot_once()` after
/// deserialization. This data does not survive when a new snapshot is created
Expand Down Expand Up @@ -1412,7 +1442,6 @@ impl OwnedIsolate {
) -> Option<StartupData> {
let mut snapshot_creator =
self.get_annex_mut().maybe_snapshot_creator.take().unwrap();
ScopeData::get_root_mut(&mut self);
unsafe { self.cxx_isolate.as_mut().clear_scope_and_annex() };
// The isolate is owned by the snapshot creator; we need to forget it
// here as the snapshot creator will drop it when running the destructor.
Expand Down
2 changes: 1 addition & 1 deletion src/isolate_create_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub(crate) mod raw {
}

impl StartupData {
pub(super) fn boxed_header(data: &Allocation<[u8]>) -> Box<Self> {
pub(crate) fn boxed_header(data: &Allocation<[u8]>) -> Box<Self> {
Box::new(Self {
data: &data[0] as *const _ as *const char,
raw_size: int::try_from(data.len()).unwrap(),
Expand Down
70 changes: 62 additions & 8 deletions src/snapshot.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::external_references::ExternalReferences;
use crate::isolate_create_params::raw;
use crate::scope::data::ScopeData;
use crate::support::char;
use crate::support::int;
use crate::support::intptr_t;
use crate::support::Allocated;
use crate::support::Allocation;
use crate::Context;
use crate::Data;
use crate::Isolate;
Expand All @@ -13,11 +16,13 @@ use std::borrow::Borrow;
use std::convert::TryFrom;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ptr::null;

extern "C" {
fn v8__SnapshotCreator__CONSTRUCT(
buf: *mut MaybeUninit<SnapshotCreator>,
external_references: *const intptr_t,
existing_blob: *const raw::StartupData,
);
fn v8__SnapshotCreator__DESTRUCT(this: *mut SnapshotCreator);
fn v8__SnapshotCreator__GetIsolate(
Expand All @@ -31,6 +36,10 @@ extern "C" {
this: *mut SnapshotCreator,
context: *const Context,
);
fn v8__SnapshotCreator__AddContext(
this: *mut SnapshotCreator,
context: *const Context,
) -> usize;
fn v8__SnapshotCreator__AddData_to_isolate(
this: *mut SnapshotCreator,
data: *const Data,
Expand All @@ -52,6 +61,12 @@ pub struct StartupData {
raw_size: int,
}

impl Drop for StartupData {
fn drop(&mut self) {
unsafe { v8__StartupData__DESTRUCT(self) }
}
}

impl Deref for StartupData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
Expand All @@ -73,12 +88,6 @@ impl Borrow<[u8]> for StartupData {
}
}

impl Drop for StartupData {
fn drop(&mut self) {
unsafe { v8__StartupData__DESTRUCT(self) }
}
}

#[repr(C)]
#[derive(Debug)]
pub enum FunctionCodeHandling {
Expand All @@ -92,23 +101,59 @@ pub enum FunctionCodeHandling {
pub(crate) struct SnapshotCreator([usize; 1]);

impl SnapshotCreator {
/// Create and enter an isolate, and set it up for serialization.
/// Create an isolate, and set it up for serialization.
/// The isolate is created from scratch.
#[inline(always)]
#[allow(clippy::new_ret_no_self)]
pub(crate) fn new(
external_references: Option<&'static ExternalReferences>,
) -> OwnedIsolate {
Self::new_impl(external_references, None::<&[u8]>)
}

/// Create an isolate, and set it up for serialization.
/// The isolate is created from scratch.
#[inline(always)]
#[allow(clippy::new_ret_no_self)]
pub(crate) fn from_existing_snapshot(
existing_snapshot_blob: impl Allocated<[u8]>,
external_references: Option<&'static ExternalReferences>,
) -> OwnedIsolate {
Self::new_impl(external_references, Some(existing_snapshot_blob))
}

/// Create and enter an isolate, and set it up for serialization.
/// The isolate is created from scratch.
#[inline(always)]
#[allow(clippy::new_ret_no_self)]
fn new_impl(
external_references: Option<&'static ExternalReferences>,
existing_snapshot_blob: Option<impl Allocated<[u8]>>,
) -> OwnedIsolate {
let mut snapshot_creator: MaybeUninit<Self> = MaybeUninit::uninit();
let external_references_ptr = if let Some(er) = external_references {
er.as_ptr()
} else {
std::ptr::null()
};

let snapshot_blob_ptr;
let snapshot_allocations;
if let Some(snapshot_blob) = existing_snapshot_blob {
let data = Allocation::of(snapshot_blob);
let header = Allocation::of(raw::StartupData::boxed_header(&data));
snapshot_blob_ptr = &*header as *const _;
snapshot_allocations = Some((header, data));
} else {
snapshot_blob_ptr = null();
snapshot_allocations = None;
}

let snapshot_creator = unsafe {
v8__SnapshotCreator__CONSTRUCT(
&mut snapshot_creator,
external_references_ptr,
snapshot_blob_ptr,
);
snapshot_creator.assume_init()
};
Expand All @@ -117,7 +162,7 @@ impl SnapshotCreator {
unsafe { v8__SnapshotCreator__GetIsolate(&snapshot_creator) };
let mut owned_isolate = OwnedIsolate::new(isolate_ptr);
ScopeData::new_root(&mut owned_isolate);
owned_isolate.create_annex(Box::new(()));
owned_isolate.create_annex(Box::new(snapshot_allocations));
owned_isolate.set_snapshot_creator(snapshot_creator);
owned_isolate
}
Expand All @@ -138,6 +183,15 @@ impl SnapshotCreator {
unsafe { v8__SnapshotCreator__SetDefaultContext(self, &*context) };
}

/// Add additional context to be included in the snapshot blob.
/// The snapshot will include the global proxy.
///
/// Returns the index of the context in the snapshot blob.
#[inline(always)]
pub(crate) fn add_context(&mut self, context: Local<Context>) -> usize {
unsafe { v8__SnapshotCreator__AddContext(self, &*context) }
}

/// Attach arbitrary `v8::Data` to the isolate snapshot, which can be
/// retrieved via `HandleScope::get_context_data_from_snapshot_once()` after
/// deserialization. This data does not survive when a new snapshot is created
Expand Down
Loading

0 comments on commit 885e016

Please sign in to comment.