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; use crate::Local; use crate::OwnedIsolate; 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, external_references: *const intptr_t, existing_blob: *const raw::StartupData, ); fn v8__SnapshotCreator__DESTRUCT(this: *mut SnapshotCreator); fn v8__SnapshotCreator__GetIsolate( this: *const SnapshotCreator, ) -> *mut Isolate; fn v8__SnapshotCreator__CreateBlob( this: *mut SnapshotCreator, function_code_handling: FunctionCodeHandling, ) -> StartupData; fn v8__SnapshotCreator__SetDefaultContext( 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, ) -> usize; fn v8__SnapshotCreator__AddData_to_context( this: *mut SnapshotCreator, context: *const Context, data: *const Data, ) -> usize; fn v8__StartupData__DESTRUCT(this: *mut StartupData); } // TODO(piscisaureus): merge this struct with // `isolate_create_params::raw::StartupData`. #[repr(C)] #[derive(Debug)] pub struct StartupData { data: *const char, 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 { let data = self.data as *const u8; let len = usize::try_from(self.raw_size).unwrap(); unsafe { std::slice::from_raw_parts(data, len) } } } impl AsRef<[u8]> for StartupData { fn as_ref(&self) -> &[u8] { self } } impl Borrow<[u8]> for StartupData { fn borrow(&self) -> &[u8] { self } } #[repr(C)] #[derive(Debug)] pub enum FunctionCodeHandling { Clear, Keep, } /// Helper class to create a snapshot data blob. #[repr(C)] #[derive(Debug)] pub(crate) struct SnapshotCreator([usize; 1]); impl SnapshotCreator { /// 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>, ) -> OwnedIsolate { let mut snapshot_creator: MaybeUninit = 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() }; let isolate_ptr = 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(snapshot_allocations)); owned_isolate.set_snapshot_creator(snapshot_creator); owned_isolate } } impl Drop for SnapshotCreator { fn drop(&mut self) { unsafe { v8__SnapshotCreator__DESTRUCT(self) }; } } impl SnapshotCreator { /// Set the default context to be included in the snapshot blob. /// The snapshot will not contain the global proxy, and we expect one or a /// global object template to create one, to be provided upon deserialization. #[inline(always)] pub(crate) fn set_default_context(&mut self, context: Local) { 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) -> 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 /// from an existing snapshot. #[inline(always)] pub(crate) fn add_isolate_data(&mut self, data: Local) -> usize where for<'l> Local<'l, T>: Into>, { unsafe { v8__SnapshotCreator__AddData_to_isolate(self, &*data.into()) } } /// Attach arbitrary `v8::Data` to the context 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 from an existing snapshot. #[inline(always)] pub(crate) fn add_context_data( &mut self, context: Local, data: Local, ) -> usize where for<'l> Local<'l, T>: Into>, { unsafe { v8__SnapshotCreator__AddData_to_context(self, &*context, &*data.into()) } } /// Creates a snapshot data blob. /// This must not be called from within a handle scope. #[inline(always)] pub(crate) fn create_blob( &mut self, function_code_handling: FunctionCodeHandling, ) -> Option { let blob = unsafe { v8__SnapshotCreator__CreateBlob(self, function_code_handling) }; if blob.data.is_null() { debug_assert!(blob.raw_size == 0); None } else { debug_assert!(blob.raw_size > 0); Some(blob) } } }