2020-04-20 15:18:03 -04:00
|
|
|
use crate::array_buffer;
|
|
|
|
use crate::array_buffer::Allocator as ArrayBufferAllocator;
|
|
|
|
use crate::support::char;
|
|
|
|
use crate::support::int;
|
|
|
|
use crate::support::intptr_t;
|
|
|
|
use crate::support::Allocated;
|
|
|
|
use crate::support::Allocation;
|
|
|
|
use crate::support::Opaque;
|
|
|
|
use crate::support::SharedPtr;
|
|
|
|
|
|
|
|
use std::any::Any;
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::iter::once;
|
|
|
|
use std::mem::size_of;
|
|
|
|
use std::mem::MaybeUninit;
|
|
|
|
use std::ptr::null;
|
|
|
|
|
2021-08-19 08:05:48 -04:00
|
|
|
/// Should return a pointer to memory that persists for the lifetime of the
|
|
|
|
/// isolate.
|
2022-11-24 09:53:52 -05:00
|
|
|
pub type CounterLookupCallback = extern "C" fn(name: *const char) -> *mut i32;
|
2021-08-19 08:05:48 -04:00
|
|
|
|
2020-04-20 15:18:03 -04:00
|
|
|
/// Initial configuration parameters for a new Isolate.
|
|
|
|
#[must_use]
|
2020-11-18 09:17:25 -05:00
|
|
|
#[derive(Debug, Default)]
|
2020-04-20 15:18:03 -04:00
|
|
|
pub struct CreateParams {
|
|
|
|
raw: raw::CreateParams,
|
|
|
|
allocations: CreateParamAllocations,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CreateParams {
|
2021-08-19 08:05:48 -04:00
|
|
|
/// Enables the host application to provide a mechanism for recording
|
|
|
|
/// statistics counters.
|
|
|
|
pub fn counter_lookup_callback(
|
|
|
|
mut self,
|
|
|
|
callback: CounterLookupCallback,
|
|
|
|
) -> Self {
|
|
|
|
self.raw.counter_lookup_callback = Some(callback);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-04-20 15:18:03 -04:00
|
|
|
/// Explicitly specify a startup snapshot blob.
|
|
|
|
pub fn snapshot_blob(mut self, data: impl Allocated<[u8]>) -> Self {
|
|
|
|
let data = Allocation::of(data);
|
|
|
|
let header = Allocation::of(raw::StartupData::boxed_header(&data));
|
|
|
|
self.raw.snapshot_blob = &*header;
|
|
|
|
self.allocations.snapshot_blob_data = Some(data);
|
|
|
|
self.allocations.snapshot_blob_header = Some(header);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-06-16 23:05:01 -04:00
|
|
|
/// The ArrayBuffer::ArrayBufferAllocator to use for allocating and freeing
|
|
|
|
/// the backing store of ArrayBuffers.
|
2020-04-20 15:18:03 -04:00
|
|
|
pub fn array_buffer_allocator(
|
|
|
|
mut self,
|
|
|
|
array_buffer_allocator: impl Into<SharedPtr<ArrayBufferAllocator>>,
|
|
|
|
) -> Self {
|
|
|
|
self.raw.array_buffer_allocator_shared = array_buffer_allocator.into();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2023-05-22 08:33:17 -04:00
|
|
|
/// Check if `array_buffer_allocator` has already been called. Useful to some
|
|
|
|
/// embedders that might want to set an allocator but not overwrite if one
|
|
|
|
/// was already set by a user.
|
|
|
|
pub fn has_set_array_buffer_allocator(&self) -> bool {
|
|
|
|
!self.raw.array_buffer_allocator_shared.is_null()
|
|
|
|
}
|
|
|
|
|
2020-04-20 15:18:03 -04:00
|
|
|
/// Specifies an optional nullptr-terminated array of raw addresses in the
|
|
|
|
/// embedder that V8 can match against during serialization and use for
|
|
|
|
/// deserialization. This array and its content must stay valid for the
|
|
|
|
/// entire lifetime of the isolate.
|
|
|
|
pub fn external_references(
|
|
|
|
mut self,
|
|
|
|
ext_refs: impl Allocated<[intptr_t]>,
|
|
|
|
) -> Self {
|
|
|
|
let last_non_null = ext_refs
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.enumerate()
|
|
|
|
.rev()
|
|
|
|
.find_map(|(idx, value)| if value != 0 { Some(idx) } else { None });
|
|
|
|
let first_null = ext_refs
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.enumerate()
|
|
|
|
.find_map(|(idx, value)| if value == 0 { Some(idx) } else { None });
|
|
|
|
match (last_non_null, first_null) {
|
|
|
|
(None, _) => {
|
|
|
|
// Empty list.
|
|
|
|
self.raw.external_references = null();
|
|
|
|
self.allocations.external_references = None;
|
|
|
|
}
|
|
|
|
(_, None) => {
|
|
|
|
// List does not have null terminator. Make a copy and add it.
|
|
|
|
let ext_refs =
|
|
|
|
ext_refs.iter().cloned().chain(once(0)).collect::<Vec<_>>();
|
|
|
|
let ext_refs = Allocation::of(ext_refs);
|
|
|
|
self.raw.external_references = &ext_refs[0];
|
|
|
|
self.allocations.external_references = Some(ext_refs);
|
|
|
|
}
|
|
|
|
(Some(idx1), Some(idx2)) if idx1 + 1 == idx2 => {
|
|
|
|
// List is properly null terminated, we'll use it as-is.
|
|
|
|
let ext_refs = Allocation::of(ext_refs);
|
|
|
|
self.raw.external_references = &ext_refs[0];
|
|
|
|
self.allocations.external_references = Some(ext_refs);
|
|
|
|
}
|
|
|
|
_ => panic!("unexpected null pointer in external references list"),
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether calling Atomics.wait (a function that may block) is allowed in
|
|
|
|
/// this isolate. This can also be configured via SetAllowAtomicsWait.
|
|
|
|
pub fn allow_atomics_wait(mut self, value: bool) -> Self {
|
|
|
|
self.raw.allow_atomics_wait = value;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Termination is postponed when there is no active SafeForTerminationScope.
|
|
|
|
pub fn only_terminate_in_safe_scope(mut self, value: bool) -> Self {
|
|
|
|
self.raw.only_terminate_in_safe_scope = value;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-05-05 18:06:35 -04:00
|
|
|
/// The following parameters describe the offsets for addressing type info
|
|
|
|
/// for wrapped API objects and are used by the fast C API
|
|
|
|
/// (for details see v8-fast-api-calls.h).
|
|
|
|
pub fn embedder_wrapper_type_info_offsets(
|
|
|
|
mut self,
|
|
|
|
embedder_wrapper_type_index: int,
|
|
|
|
embedder_wrapper_object_index: int,
|
|
|
|
) -> Self {
|
|
|
|
self.raw.embedder_wrapper_type_index = embedder_wrapper_type_index;
|
|
|
|
self.raw.embedder_wrapper_object_index = embedder_wrapper_object_index;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-07-30 12:40:18 -04:00
|
|
|
/// Configures the constraints with reasonable default values based on the
|
|
|
|
/// provided lower and upper bounds.
|
|
|
|
///
|
|
|
|
/// By default V8 starts with a small heap and dynamically grows it to match
|
|
|
|
/// the set of live objects. This may lead to ineffective garbage collections
|
|
|
|
/// at startup if the live set is large. Setting the initial heap size avoids
|
|
|
|
/// such garbage collections. Note that this does not affect young generation
|
|
|
|
/// garbage collections.
|
|
|
|
///
|
|
|
|
/// When the heap size approaches `max`, V8 will perform series of
|
|
|
|
/// garbage collections and invoke the
|
|
|
|
/// [NearHeapLimitCallback](struct.Isolate.html#method.add_near_heap_limit_callback).
|
|
|
|
/// If the garbage collections do not help and the callback does not
|
|
|
|
/// increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory.
|
|
|
|
///
|
|
|
|
/// The heap size includes both the young and the old generation.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `initial` - The initial heap size or zero in bytes
|
|
|
|
/// * `max` - The hard limit for the heap size in bytes
|
|
|
|
pub fn heap_limits(mut self, initial: usize, max: usize) -> Self {
|
|
|
|
self
|
|
|
|
.raw
|
|
|
|
.constraints
|
|
|
|
.configure_defaults_from_heap_size(initial, max);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-06-15 12:05:53 -04:00
|
|
|
pub(crate) fn finalize(mut self) -> (raw::CreateParams, Box<dyn Any>) {
|
2020-04-20 15:18:03 -04:00
|
|
|
if self.raw.array_buffer_allocator_shared.is_null() {
|
|
|
|
self = self.array_buffer_allocator(array_buffer::new_default_allocator());
|
|
|
|
}
|
|
|
|
let Self { raw, allocations } = self;
|
|
|
|
(raw, Box::new(allocations))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-18 09:17:25 -05:00
|
|
|
#[derive(Debug, Default)]
|
2020-04-20 15:18:03 -04:00
|
|
|
struct CreateParamAllocations {
|
|
|
|
// Owner of the snapshot data buffer itself.
|
|
|
|
snapshot_blob_data: Option<Allocation<[u8]>>,
|
|
|
|
// Owns `struct StartupData` which contains just the (ptr, len) tuple in V8's
|
|
|
|
// preferred format. We have to heap allocate this because we need to put a
|
|
|
|
// stable pointer to it in `CreateParams`.
|
|
|
|
snapshot_blob_header: Option<Allocation<raw::StartupData>>,
|
|
|
|
external_references: Option<Allocation<[intptr_t]>>,
|
|
|
|
}
|
|
|
|
|
2021-06-15 12:05:53 -04:00
|
|
|
#[test]
|
|
|
|
fn create_param_defaults() {
|
|
|
|
let params = CreateParams::default();
|
|
|
|
assert_eq!(params.raw.embedder_wrapper_type_index, -1);
|
|
|
|
assert_eq!(params.raw.embedder_wrapper_object_index, -1);
|
2021-06-18 11:35:53 -04:00
|
|
|
assert!(!params.raw.only_terminate_in_safe_scope);
|
|
|
|
assert!(params.raw.allow_atomics_wait);
|
2021-06-15 12:05:53 -04:00
|
|
|
}
|
|
|
|
|
2020-04-20 15:18:03 -04:00
|
|
|
pub(crate) mod raw {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[repr(C)]
|
2020-11-18 09:17:25 -05:00
|
|
|
#[derive(Debug)]
|
2020-04-20 15:18:03 -04:00
|
|
|
pub(crate) struct CreateParams {
|
|
|
|
pub code_event_handler: *const Opaque, // JitCodeEventHandler
|
|
|
|
pub constraints: ResourceConstraints,
|
|
|
|
pub snapshot_blob: *const StartupData,
|
2021-08-19 08:05:48 -04:00
|
|
|
pub counter_lookup_callback: Option<CounterLookupCallback>,
|
2020-04-20 15:18:03 -04:00
|
|
|
pub create_histogram_callback: *const Opaque, // CreateHistogramCallback
|
|
|
|
pub add_histogram_sample_callback: *const Opaque, // AddHistogramSampleCallback
|
|
|
|
pub array_buffer_allocator: *mut ArrayBufferAllocator,
|
|
|
|
pub array_buffer_allocator_shared: SharedPtr<ArrayBufferAllocator>,
|
|
|
|
pub external_references: *const intptr_t,
|
|
|
|
pub allow_atomics_wait: bool,
|
|
|
|
pub only_terminate_in_safe_scope: bool,
|
2020-05-05 18:06:35 -04:00
|
|
|
pub embedder_wrapper_type_index: int,
|
|
|
|
pub embedder_wrapper_object_index: int,
|
2021-02-04 18:22:26 -05:00
|
|
|
// NOTE(bartlomieju): this field is deprecated in V8 API.
|
2021-01-18 15:46:44 -05:00
|
|
|
// This is an std::vector<std::string>. It's usually no bigger
|
|
|
|
// than three or four words but let's take a generous upper bound.
|
|
|
|
pub supported_import_assertions: [usize; 8],
|
2020-04-20 15:18:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn v8__Isolate__CreateParams__CONSTRUCT(
|
|
|
|
buf: *mut MaybeUninit<CreateParams>,
|
|
|
|
);
|
|
|
|
fn v8__Isolate__CreateParams__SIZEOF() -> usize;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for CreateParams {
|
|
|
|
fn default() -> Self {
|
|
|
|
let size = unsafe { v8__Isolate__CreateParams__SIZEOF() };
|
2021-01-18 15:46:44 -05:00
|
|
|
assert!(size <= size_of::<Self>());
|
2020-04-20 15:18:03 -04:00
|
|
|
let mut buf = MaybeUninit::<Self>::uninit();
|
|
|
|
unsafe { v8__Isolate__CreateParams__CONSTRUCT(&mut buf) };
|
|
|
|
unsafe { buf.assume_init() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2020-11-18 09:17:25 -05:00
|
|
|
#[derive(Debug)]
|
2020-04-20 15:18:03 -04:00
|
|
|
pub(crate) struct StartupData {
|
|
|
|
pub data: *const char,
|
|
|
|
pub raw_size: int,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StartupData {
|
2022-10-14 06:33:09 -04:00
|
|
|
pub(crate) fn boxed_header(data: &Allocation<[u8]>) -> Box<Self> {
|
2020-04-20 15:18:03 -04:00
|
|
|
Box::new(Self {
|
|
|
|
data: &data[0] as *const _ as *const char,
|
|
|
|
raw_size: int::try_from(data.len()).unwrap(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2020-11-18 09:17:25 -05:00
|
|
|
#[derive(Debug)]
|
2020-04-20 15:18:03 -04:00
|
|
|
pub(crate) struct ResourceConstraints {
|
|
|
|
code_range_size_: usize,
|
|
|
|
max_old_generation_size_: usize,
|
|
|
|
max_young_generation_size_: usize,
|
|
|
|
initial_old_generation_size_: usize,
|
|
|
|
initial_young_generation_size_: usize,
|
|
|
|
stack_limit_: *mut u32,
|
|
|
|
}
|
2020-07-30 12:40:18 -04:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn v8__ResourceConstraints__ConfigureDefaultsFromHeapSize(
|
|
|
|
constraints: *mut ResourceConstraints,
|
|
|
|
initial_heap_size_in_bytes: usize,
|
|
|
|
maximum_heap_size_in_bytes: usize,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResourceConstraints {
|
|
|
|
pub fn configure_defaults_from_heap_size(
|
|
|
|
&mut self,
|
|
|
|
initial_heap_size_in_bytes: usize,
|
|
|
|
maximum_heap_size_in_bytes: usize,
|
|
|
|
) {
|
|
|
|
unsafe {
|
|
|
|
v8__ResourceConstraints__ConfigureDefaultsFromHeapSize(
|
|
|
|
self,
|
|
|
|
initial_heap_size_in_bytes,
|
|
|
|
maximum_heap_size_in_bytes,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2020-04-20 15:18:03 -04:00
|
|
|
}
|