use crate::array_buffer::Allocator;
use crate::external_references::ExternalReferences;
use crate::promise::PromiseRejectMessage;
use crate::support::intptr_t;
use crate::support::Delete;
use crate::support::Opaque;
use crate::support::SharedRef;
use crate::support::UniqueRef;
use crate::Context;
use crate::Function;
use crate::InIsolate;
use crate::Local;
use crate::Message;
use crate::Module;
use crate::Object;
use crate::Promise;
use crate::ScriptOrModule;
use crate::StartupData;
use crate::String;
use crate::Value;
use std::ffi::c_void;
use std::mem::replace;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr::null_mut;
use std::ptr::NonNull;
use std::sync::Arc;
use std::sync::Mutex;
pub type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
pub type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage);
pub type HostInitializeImportMetaObjectCallback =
extern "C" fn(Local<Context>, Local<Module>, Local<Object>);
pub type HostImportModuleDynamicallyCallback = extern "C" fn(
Local<Context>,
Local<ScriptOrModule>,
Local<String>,
) -> *mut Promise;
pub type InterruptCallback =
extern "C" fn(isolate: &mut Isolate, data: *mut c_void);
extern "C" {
fn v8__Isolate__New(params: *mut 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);
fn v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(
this: *mut Isolate,
caputre: bool,
frame_limit: i32,
);
fn v8__Isolate__AddMessageListener(
this: &mut Isolate,
callback: MessageCallback,
) -> bool;
fn v8__Isolate__SetPromiseRejectCallback(
isolate: *mut Isolate,
callback: PromiseRejectCallback,
);
fn v8__Isolate__SetHostInitializeImportMetaObjectCallback(
isolate: *mut Isolate,
callback: HostInitializeImportMetaObjectCallback,
);
fn v8__Isolate__SetHostImportModuleDynamicallyCallback(
isolate: *mut Isolate,
callback: HostImportModuleDynamicallyCallback,
);
fn v8__Isolate__RequestInterrupt(
isolate: *const Isolate,
callback: InterruptCallback,
data: *mut c_void,
);
fn v8__Isolate__ThrowException(
isolate: *mut Isolate,
exception: Local<Value>,
) -> *mut Value;
fn v8__Isolate__TerminateExecution(isolate: *const Isolate);
fn v8__Isolate__IsExecutionTerminating(isolate: *const Isolate) -> bool;
fn v8__Isolate__CancelTerminateExecution(isolate: *const Isolate);
fn v8__Isolate__RunMicrotasks(isolate: *mut Isolate);
fn v8__Isolate__EnqueueMicrotask(
isolate: *mut Isolate,
microtask: Local<Function>,
);
fn v8__Isolate__CreateParams__NEW() -> *mut CreateParams;
fn v8__Isolate__CreateParams__DELETE(this: &mut CreateParams);
fn v8__Isolate__CreateParams__SET__array_buffer_allocator(
this: &mut CreateParams,
allocator: &SharedRef<Allocator>,
);
fn v8__Isolate__CreateParams__SET__external_references(
this: &mut CreateParams,
value: *const intptr_t,
);
fn v8__Isolate__CreateParams__SET__snapshot_blob(
this: &mut CreateParams,
snapshot_blob: *mut StartupData,
);
fn v8__HeapProfiler__TakeHeapSnapshot(
isolate: *mut Isolate,
callback: extern "C" fn(*mut c_void, *const u8, usize) -> bool,
arg: *mut c_void,
);
}
#[repr(C)]
pub struct Isolate(Opaque);
impl Isolate {
#[allow(clippy::new_ret_no_self)]
pub fn new(params: UniqueRef<CreateParams>) -> OwnedIsolate {
crate::V8::assert_initialized();
unsafe { new_owned_isolate(v8__Isolate__New(params.into_raw())) }
}
pub fn create_params() -> UniqueRef<CreateParams> {
CreateParams::new()
}
pub fn thread_safe_handle(&mut self) -> IsolateHandle {
IsolateHandle::new(self)
}
unsafe fn set_annex(&mut self, ptr: *mut IsolateAnnex) {
v8__Isolate__SetData(self, 0, ptr as *mut c_void)
}
fn get_annex(&self) -> *mut IsolateAnnex {
unsafe { v8__Isolate__GetData(self, 0) as *mut _ }
}
pub unsafe fn set_data(&mut self, slot: u32, ptr: *mut c_void) {
v8__Isolate__SetData(self, slot + 1, ptr)
}
pub fn get_data(&self, slot: u32) -> *mut c_void {
unsafe { v8__Isolate__GetData(self, slot + 1) }
}
pub fn get_number_of_data_slots(&self) -> u32 {
unsafe { v8__Isolate__GetNumberOfDataSlots(self) - 1 }
}
pub(crate) fn enter(&mut self) {
unsafe { v8__Isolate__Enter(self) }
}
pub(crate) fn exit(&mut self) {
unsafe { v8__Isolate__Exit(self) }
}
pub fn set_capture_stack_trace_for_uncaught_exceptions(
&mut self,
capture: bool,
frame_limit: i32,
) {
unsafe {
v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(
self,
capture,
frame_limit,
)
}
}
pub fn add_message_listener(&mut self, callback: MessageCallback) -> bool {
unsafe { v8__Isolate__AddMessageListener(self, callback) }
}
pub fn set_promise_reject_callback(
&mut self,
callback: PromiseRejectCallback,
) {
unsafe { v8__Isolate__SetPromiseRejectCallback(self, callback) }
}
pub fn set_host_initialize_import_meta_object_callback(
&mut self,
callback: HostInitializeImportMetaObjectCallback,
) {
unsafe {
v8__Isolate__SetHostInitializeImportMetaObjectCallback(self, callback)
}
}
pub fn set_host_import_module_dynamically_callback(
&mut self,
callback: HostImportModuleDynamicallyCallback,
) {
unsafe {
v8__Isolate__SetHostImportModuleDynamicallyCallback(self, callback)
}
}
pub fn throw_exception<'sc>(
&mut self,
exception: Local<Value>,
) -> Local<'sc, Value> {
unsafe {
let ptr = v8__Isolate__ThrowException(self, exception);
Local::from_raw(ptr).unwrap()
}
}
pub fn run_microtasks(&mut self) {
unsafe { v8__Isolate__RunMicrotasks(self) }
}
pub fn enqueue_microtask(&mut self, microtask: Local<Function>) {
unsafe { v8__Isolate__EnqueueMicrotask(self, microtask) }
}
unsafe fn dispose(&mut self) {
IsolateHandle::dispose_isolate(self);
v8__Isolate__Dispose(self)
}
pub fn take_heap_snapshot<F>(&mut self, mut callback: F)
where
F: FnMut(&[u8]) -> bool,
{
extern "C" fn trampoline<F>(
arg: *mut c_void,
data: *const u8,
size: usize,
) -> bool
where
F: FnMut(&[u8]) -> bool,
{
let p = arg as *mut F;
let callback = unsafe { &mut *p };
let slice = unsafe { std::slice::from_raw_parts(data, size) };
callback(slice)
}
let arg = &mut callback as *mut F as *mut c_void;
unsafe { v8__HeapProfiler__TakeHeapSnapshot(self, trampoline::<F>, arg) }
}
}
pub(crate) struct IsolateAnnex {
isolate: *mut Isolate,
mutex: Mutex<()>,
}
impl IsolateAnnex {
fn new(isolate: &mut Isolate) -> Self {
Self {
isolate,
mutex: Mutex::new(()),
}
}
}
#[derive(Clone)]
pub struct IsolateHandle(Arc<IsolateAnnex>);
unsafe impl Send for IsolateHandle {}
unsafe impl Sync for IsolateHandle {}
impl IsolateHandle {
pub(crate) unsafe fn get_isolate_ptr(&self) -> *mut Isolate {
self.0.isolate
}
pub(crate) fn new(isolate: &mut Isolate) -> Self {
let annex_ptr = isolate.get_annex();
if annex_ptr.is_null() {
let annex_arc = Arc::new(IsolateAnnex::new(isolate));
let annex_ptr = Arc::into_raw(annex_arc.clone());
unsafe {
isolate.set_annex(annex_ptr as *mut IsolateAnnex);
}
IsolateHandle(annex_arc)
} else {
let annex_arc = unsafe { Arc::from_raw(annex_ptr) };
Arc::into_raw(annex_arc.clone());
IsolateHandle(annex_arc)
}
}
fn dispose_isolate(isolate: &mut Isolate) {
let annex_ptr = isolate.get_annex();
if !annex_ptr.is_null() {
unsafe {
{
let _lock = (*annex_ptr).mutex.lock().unwrap();
isolate.set_data(0, null_mut());
let isolate_ptr = replace(&mut (*annex_ptr).isolate, null_mut());
assert_eq!(isolate as *mut _, isolate_ptr);
}
Arc::from_raw(annex_ptr);
};
}
}
pub fn terminate_execution(&self) -> bool {
let _lock = self.0.mutex.lock().unwrap();
if self.0.isolate.is_null() {
false
} else {
unsafe { v8__Isolate__TerminateExecution(self.0.isolate) };
true
}
}
pub fn cancel_terminate_execution(&self) -> bool {
let _lock = self.0.mutex.lock().unwrap();
if self.0.isolate.is_null() {
false
} else {
unsafe { v8__Isolate__CancelTerminateExecution(self.0.isolate) };
true
}
}
pub fn is_execution_terminating(&self) -> bool {
let _lock = self.0.mutex.lock().unwrap();
if self.0.isolate.is_null() {
false
} else {
unsafe { v8__Isolate__IsExecutionTerminating(self.0.isolate) }
}
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn request_interrupt(
&self,
callback: InterruptCallback,
data: *mut c_void,
) -> bool {
let _lock = self.0.mutex.lock().unwrap();
if self.0.isolate.is_null() {
false
} else {
unsafe { v8__Isolate__RequestInterrupt(self.0.isolate, callback, data) };
true
}
}
}
pub(crate) unsafe fn new_owned_isolate(
isolate_ptr: *mut Isolate,
) -> OwnedIsolate {
OwnedIsolate(NonNull::new(isolate_ptr).unwrap())
}
pub struct OwnedIsolate(NonNull<Isolate>);
impl InIsolate for OwnedIsolate {
fn isolate(&mut self) -> &mut Isolate {
self.deref_mut()
}
}
impl Drop for OwnedIsolate {
fn drop(&mut self) {
unsafe { self.0.as_mut().dispose() }
}
}
impl Deref for OwnedIsolate {
type Target = Isolate;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl DerefMut for OwnedIsolate {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
#[repr(C)]
pub struct CreateParams(Opaque);
impl CreateParams {
pub fn new() -> UniqueRef<CreateParams> {
unsafe { UniqueRef::from_raw(v8__Isolate__CreateParams__NEW()) }
}
pub fn set_array_buffer_allocator(&mut self, value: SharedRef<Allocator>) {
unsafe {
v8__Isolate__CreateParams__SET__array_buffer_allocator(self, &value)
};
}
pub fn set_external_references(
&mut self,
external_references: &'static ExternalReferences,
) {
unsafe {
v8__Isolate__CreateParams__SET__external_references(
self,
external_references.as_ptr(),
)
};
}
pub fn set_snapshot_blob(&mut self, snapshot_blob: &StartupData) {
unsafe {
v8__Isolate__CreateParams__SET__snapshot_blob(
self,
snapshot_blob as *const _ as *mut StartupData,
)
};
}
}
impl Delete for CreateParams {
fn delete(&'static mut self) {
unsafe { v8__Isolate__CreateParams__DELETE(self) }
}
}