Skip to main content

v8/
isolate.rs

1// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
2use crate::Array;
3use crate::CallbackScope;
4use crate::Context;
5use crate::Data;
6use crate::FixedArray;
7use crate::Function;
8use crate::FunctionCodeHandling;
9use crate::Local;
10use crate::Message;
11use crate::Module;
12use crate::Object;
13use crate::PinScope;
14use crate::Platform;
15use crate::Promise;
16use crate::PromiseResolver;
17use crate::StartupData;
18use crate::String;
19use crate::V8::get_current_platform;
20use crate::Value;
21use crate::binding::v8__HeapCodeStatistics;
22use crate::binding::v8__HeapSpaceStatistics;
23use crate::binding::v8__HeapStatistics;
24use crate::binding::v8__Isolate__UseCounterFeature;
25pub use crate::binding::v8__ModuleImportPhase as ModuleImportPhase;
26use crate::cppgc::Heap;
27use crate::external_references::ExternalReference;
28use crate::function::FunctionCallbackInfo;
29use crate::gc::GCCallbackFlags;
30use crate::gc::GCType;
31use crate::handle::FinalizerCallback;
32use crate::handle::FinalizerMap;
33use crate::isolate_create_params::CreateParams;
34use crate::isolate_create_params::raw;
35use crate::promise::PromiseRejectMessage;
36use crate::snapshot::SnapshotCreator;
37use crate::support::MapFnFrom;
38use crate::support::MapFnTo;
39use crate::support::Opaque;
40use crate::support::ToCFn;
41use crate::support::UnitType;
42use crate::support::char;
43use crate::support::int;
44use crate::support::size_t;
45use crate::wasm::WasmStreaming;
46use crate::wasm::trampoline;
47use std::cell::UnsafeCell;
48use std::ffi::CStr;
49
50use std::any::Any;
51use std::any::TypeId;
52use std::borrow::Cow;
53use std::collections::HashMap;
54use std::ffi::c_void;
55use std::fmt::{self, Debug, Formatter};
56use std::hash::BuildHasher;
57use std::hash::Hasher;
58use std::mem::MaybeUninit;
59use std::mem::align_of;
60use std::mem::forget;
61use std::mem::needs_drop;
62use std::mem::size_of;
63use std::ops::Deref;
64use std::ops::DerefMut;
65use std::pin::pin;
66use std::ptr;
67use std::ptr::NonNull;
68use std::ptr::addr_of_mut;
69use std::ptr::drop_in_place;
70use std::ptr::null_mut;
71use std::sync::Arc;
72use std::sync::Mutex;
73use std::sync::atomic::AtomicPtr;
74
75/// Policy for running microtasks:
76///   - explicit: microtasks are invoked with the
77///     Isolate::PerformMicrotaskCheckpoint() method;
78///   - auto: microtasks are invoked when the script call depth decrements
79///     to zero.
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[repr(C)]
82pub enum MicrotasksPolicy {
83  Explicit = 0,
84  // Scoped = 1 (RAII) is omitted for now, doesn't quite map to idiomatic Rust.
85  Auto = 2,
86}
87
88/// Memory pressure level for the MemoryPressureNotification.
89/// None hints V8 that there is no memory pressure.
90/// Moderate hints V8 to speed up incremental garbage collection at the cost
91/// of higher latency due to garbage collection pauses.
92/// Critical hints V8 to free memory as soon as possible. Garbage collection
93/// pauses at this level will be large.
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95#[repr(C)]
96pub enum MemoryPressureLevel {
97  None = 0,
98  Moderate = 1,
99  Critical = 2,
100}
101
102/// Time zone redetection indicator for
103/// DateTimeConfigurationChangeNotification.
104///
105/// kSkip indicates V8 that the notification should not trigger redetecting
106/// host time zone. kRedetect indicates V8 that host time zone should be
107/// redetected, and used to set the default time zone.
108///
109/// The host time zone detection may require file system access or similar
110/// operations unlikely to be available inside a sandbox. If v8 is run inside a
111/// sandbox, the host time zone has to be detected outside the sandbox before
112/// calling DateTimeConfigurationChangeNotification function.
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114#[repr(C)]
115pub enum TimeZoneDetection {
116  Skip = 0,
117  Redetect = 1,
118}
119
120/// PromiseHook with type Init is called when a new promise is
121/// created. When a new promise is created as part of the chain in the
122/// case of Promise.then or in the intermediate promises created by
123/// Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise
124/// otherwise we pass undefined.
125///
126/// PromiseHook with type Resolve is called at the beginning of
127/// resolve or reject function defined by CreateResolvingFunctions.
128///
129/// PromiseHook with type Before is called at the beginning of the
130/// PromiseReactionJob.
131///
132/// PromiseHook with type After is called right at the end of the
133/// PromiseReactionJob.
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135#[repr(C)]
136pub enum PromiseHookType {
137  Init,
138  Resolve,
139  Before,
140  After,
141}
142
143/// Types of garbage collections that can be requested via
144/// [`Isolate::request_garbage_collection_for_testing`].
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146#[repr(C)]
147pub enum GarbageCollectionType {
148  Full,
149  Minor,
150}
151
152pub type MessageCallback = unsafe extern "C" fn(Local<Message>, Local<Value>);
153
154bitflags! {
155  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
156  #[repr(transparent)]
157  pub struct MessageErrorLevel: int {
158    const LOG = 1 << 0;
159    const DEBUG = 1 << 1;
160    const INFO = 1 << 2;
161    const ERROR = 1 << 3;
162    const WARNING = 1 << 4;
163    const ALL = (1 << 5) - 1;
164  }
165}
166
167pub type PromiseHook =
168  unsafe extern "C" fn(PromiseHookType, Local<Promise>, Local<Value>);
169
170pub type PromiseRejectCallback = unsafe extern "C" fn(PromiseRejectMessage);
171
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173#[repr(C)]
174pub enum WasmAsyncSuccess {
175  Success,
176  Fail,
177}
178pub type WasmAsyncResolvePromiseCallback = unsafe extern "C" fn(
179  UnsafeRawIsolatePtr,
180  Local<Context>,
181  Local<PromiseResolver>,
182  Local<Value>,
183  WasmAsyncSuccess,
184);
185
186pub type AllowWasmCodeGenerationCallback =
187  unsafe extern "C" fn(Local<Context>, Local<String>) -> bool;
188
189/// HostInitializeImportMetaObjectCallback is called the first time import.meta
190/// is accessed for a module. Subsequent access will reuse the same value.
191///
192/// The method combines two implementation-defined abstract operations into one:
193/// HostGetImportMetaProperties and HostFinalizeImportMeta.
194///
195/// The embedder should use v8::Object::CreateDataProperty to add properties on
196/// the meta object.
197pub type HostInitializeImportMetaObjectCallback =
198  unsafe extern "C" fn(Local<Context>, Local<Module>, Local<Object>);
199
200/// HostImportModuleDynamicallyCallback is called when we require the embedder
201/// to load a module. This is used as part of the dynamic import syntax.
202///
203/// The host_defined_options are metadata provided by the host environment, which may be used
204/// to customize or further specify how the module should be imported.
205///
206/// The resource_name is the identifier or path for the module or script making the import request.
207///
208/// The specifier is the name of the module that should be imported.
209///
210/// The import_attributes are import assertions for this request in the form:
211/// [key1, value1, key2, value2, ...] where the keys and values are of type
212/// v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and
213/// returned from ModuleRequest::GetImportAssertions(), this array does not
214/// contain the source Locations of the assertions.
215///
216/// The embedder must compile, instantiate, evaluate the Module, and obtain its
217/// namespace object.
218///
219/// The Promise returned from this function is forwarded to userland JavaScript.
220/// The embedder must resolve this promise with the module namespace object. In
221/// case of an exception, the embedder must reject this promise with the
222/// exception. If the promise creation itself fails (e.g. due to stack
223/// overflow), the embedder must propagate that exception by returning an empty
224/// MaybeLocal.
225///
226/// # Example
227///
228/// ```
229/// fn host_import_module_dynamically_callback_example<'s>(
230///   scope: &mut v8::HandleScope<'s>,
231///   host_defined_options: v8::Local<'s, v8::Data>,
232///   resource_name: v8::Local<'s, v8::Value>,
233///   specifier: v8::Local<'s, v8::String>,
234///   import_attributes: v8::Local<'s, v8::FixedArray>,
235/// ) -> Option<v8::Local<'s, v8::Promise>> {
236///   todo!()
237/// }
238/// ```
239pub trait HostImportModuleDynamicallyCallback:
240  UnitType
241  + for<'s, 'i> FnOnce(
242    &mut PinScope<'s, 'i>,
243    Local<'s, Data>,
244    Local<'s, Value>,
245    Local<'s, String>,
246    Local<'s, FixedArray>,
247  ) -> Option<Local<'s, Promise>>
248{
249  fn to_c_fn(self) -> RawHostImportModuleDynamicallyCallback;
250}
251
252#[cfg(target_family = "unix")]
253pub(crate) type RawHostImportModuleDynamicallyCallback =
254  for<'s> unsafe extern "C" fn(
255    Local<'s, Context>,
256    Local<'s, Data>,
257    Local<'s, Value>,
258    Local<'s, String>,
259    Local<'s, FixedArray>,
260  ) -> *mut Promise;
261
262#[cfg(all(
263  target_family = "windows",
264  any(target_arch = "x86_64", target_arch = "aarch64")
265))]
266pub type RawHostImportModuleDynamicallyCallback =
267  for<'s> unsafe extern "C" fn(
268    *mut *mut Promise,
269    Local<'s, Context>,
270    Local<'s, Data>,
271    Local<'s, Value>,
272    Local<'s, String>,
273    Local<'s, FixedArray>,
274  ) -> *mut *mut Promise;
275
276impl<F> HostImportModuleDynamicallyCallback for F
277where
278  F: UnitType
279    + for<'s, 'i> FnOnce(
280      &mut PinScope<'s, 'i>,
281      Local<'s, Data>,
282      Local<'s, Value>,
283      Local<'s, String>,
284      Local<'s, FixedArray>,
285    ) -> Option<Local<'s, Promise>>,
286{
287  #[inline(always)]
288  fn to_c_fn(self) -> RawHostImportModuleDynamicallyCallback {
289    #[allow(unused_variables)]
290    #[inline(always)]
291    fn scope_adapter<'s, 'i: 's, F: HostImportModuleDynamicallyCallback>(
292      context: Local<'s, Context>,
293      host_defined_options: Local<'s, Data>,
294      resource_name: Local<'s, Value>,
295      specifier: Local<'s, String>,
296      import_attributes: Local<'s, FixedArray>,
297    ) -> Option<Local<'s, Promise>> {
298      let scope = pin!(unsafe { CallbackScope::new(context) });
299      let mut scope = scope.init();
300      (F::get())(
301        &mut scope,
302        host_defined_options,
303        resource_name,
304        specifier,
305        import_attributes,
306      )
307    }
308
309    #[cfg(target_family = "unix")]
310    #[inline(always)]
311    unsafe extern "C" fn abi_adapter<
312      's,
313      F: HostImportModuleDynamicallyCallback,
314    >(
315      context: Local<'s, Context>,
316      host_defined_options: Local<'s, Data>,
317      resource_name: Local<'s, Value>,
318      specifier: Local<'s, String>,
319      import_attributes: Local<'s, FixedArray>,
320    ) -> *mut Promise {
321      scope_adapter::<F>(
322        context,
323        host_defined_options,
324        resource_name,
325        specifier,
326        import_attributes,
327      )
328      .map_or_else(null_mut, |return_value| return_value.as_non_null().as_ptr())
329    }
330
331    #[cfg(all(
332      target_family = "windows",
333      any(target_arch = "x86_64", target_arch = "aarch64")
334    ))]
335    #[inline(always)]
336    unsafe extern "C" fn abi_adapter<
337      's,
338      F: HostImportModuleDynamicallyCallback,
339    >(
340      return_value: *mut *mut Promise,
341      context: Local<'s, Context>,
342      host_defined_options: Local<'s, Data>,
343      resource_name: Local<'s, Value>,
344      specifier: Local<'s, String>,
345      import_attributes: Local<'s, FixedArray>,
346    ) -> *mut *mut Promise {
347      unsafe {
348        std::ptr::write(
349          return_value,
350          scope_adapter::<F>(
351            context,
352            host_defined_options,
353            resource_name,
354            specifier,
355            import_attributes,
356          )
357          .map(|return_value| return_value.as_non_null().as_ptr())
358          .unwrap_or_else(null_mut),
359        );
360        return_value
361      }
362    }
363
364    abi_adapter::<F>
365  }
366}
367
368/// HostImportModuleWithPhaseDynamicallyCallback is called when we
369/// require the embedder to load a module with a specific phase. This is used
370/// as part of the dynamic import syntax.
371///
372/// The referrer contains metadata about the script/module that calls
373/// import.
374///
375/// The specifier is the name of the module that should be imported.
376///
377/// The phase is the phase of the import requested.
378///
379/// The import_attributes are import attributes for this request in the form:
380/// [key1, value1, key2, value2, ...] where the keys and values are of type
381/// v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and
382/// returned from ModuleRequest::GetImportAttributes(), this array does not
383/// contain the source Locations of the attributes.
384///
385/// The Promise returned from this function is forwarded to userland
386/// JavaScript. The embedder must resolve this promise according to the phase
387/// requested:
388/// - For ModuleImportPhase::kSource, the promise must be resolved with a
389///   compiled ModuleSource object, or rejected with a SyntaxError if the
390///   module does not support source representation.
391/// - For ModuleImportPhase::kEvaluation, the promise must be resolved with a
392///   ModuleNamespace object of a module that has been compiled, instantiated,
393///   and evaluated.
394///
395/// In case of an exception, the embedder must reject this promise with the
396/// exception. If the promise creation itself fails (e.g. due to stack
397/// overflow), the embedder must propagate that exception by returning an empty
398/// MaybeLocal.
399///
400/// This callback is still experimental and is only invoked for source phase
401/// imports.
402pub trait HostImportModuleWithPhaseDynamicallyCallback:
403  UnitType
404  + for<'s, 'i> FnOnce(
405    &mut PinScope<'s, 'i>,
406    Local<'s, Data>,
407    Local<'s, Value>,
408    Local<'s, String>,
409    ModuleImportPhase,
410    Local<'s, FixedArray>,
411  ) -> Option<Local<'s, Promise>>
412{
413  fn to_c_fn(self) -> RawHostImportModuleWithPhaseDynamicallyCallback;
414}
415
416#[cfg(target_family = "unix")]
417pub(crate) type RawHostImportModuleWithPhaseDynamicallyCallback =
418  for<'s> unsafe extern "C" fn(
419    Local<'s, Context>,
420    Local<'s, Data>,
421    Local<'s, Value>,
422    Local<'s, String>,
423    ModuleImportPhase,
424    Local<'s, FixedArray>,
425  ) -> *mut Promise;
426
427#[cfg(all(
428  target_family = "windows",
429  any(target_arch = "x86_64", target_arch = "aarch64")
430))]
431pub type RawHostImportModuleWithPhaseDynamicallyCallback =
432  for<'s> unsafe extern "C" fn(
433    *mut *mut Promise,
434    Local<'s, Context>,
435    Local<'s, Data>,
436    Local<'s, Value>,
437    Local<'s, String>,
438    ModuleImportPhase,
439    Local<'s, FixedArray>,
440  ) -> *mut *mut Promise;
441
442impl<F> HostImportModuleWithPhaseDynamicallyCallback for F
443where
444  F: UnitType
445    + for<'s, 'i> FnOnce(
446      &mut PinScope<'s, 'i>,
447      Local<'s, Data>,
448      Local<'s, Value>,
449      Local<'s, String>,
450      ModuleImportPhase,
451      Local<'s, FixedArray>,
452    ) -> Option<Local<'s, Promise>>,
453{
454  #[inline(always)]
455  fn to_c_fn(self) -> RawHostImportModuleWithPhaseDynamicallyCallback {
456    #[allow(unused_variables)]
457    #[inline(always)]
458    fn scope_adapter<'s, F: HostImportModuleWithPhaseDynamicallyCallback>(
459      context: Local<'s, Context>,
460      host_defined_options: Local<'s, Data>,
461      resource_name: Local<'s, Value>,
462      specifier: Local<'s, String>,
463      import_phase: ModuleImportPhase,
464      import_attributes: Local<'s, FixedArray>,
465    ) -> Option<Local<'s, Promise>> {
466      let scope = pin!(unsafe { CallbackScope::new(context) });
467      let mut scope = scope.init();
468      (F::get())(
469        &mut scope,
470        host_defined_options,
471        resource_name,
472        specifier,
473        import_phase,
474        import_attributes,
475      )
476    }
477
478    #[cfg(target_family = "unix")]
479    #[inline(always)]
480    unsafe extern "C" fn abi_adapter<
481      's,
482      F: HostImportModuleWithPhaseDynamicallyCallback,
483    >(
484      context: Local<'s, Context>,
485      host_defined_options: Local<'s, Data>,
486      resource_name: Local<'s, Value>,
487      specifier: Local<'s, String>,
488      import_phase: ModuleImportPhase,
489      import_attributes: Local<'s, FixedArray>,
490    ) -> *mut Promise {
491      scope_adapter::<F>(
492        context,
493        host_defined_options,
494        resource_name,
495        specifier,
496        import_phase,
497        import_attributes,
498      )
499      .map_or_else(null_mut, |return_value| return_value.as_non_null().as_ptr())
500    }
501
502    #[cfg(all(
503      target_family = "windows",
504      any(target_arch = "x86_64", target_arch = "aarch64")
505    ))]
506    #[inline(always)]
507    unsafe extern "C" fn abi_adapter<
508      's,
509      F: HostImportModuleWithPhaseDynamicallyCallback,
510    >(
511      return_value: *mut *mut Promise,
512      context: Local<'s, Context>,
513      host_defined_options: Local<'s, Data>,
514      resource_name: Local<'s, Value>,
515      specifier: Local<'s, String>,
516      import_phase: ModuleImportPhase,
517      import_attributes: Local<'s, FixedArray>,
518    ) -> *mut *mut Promise {
519      unsafe {
520        std::ptr::write(
521          return_value,
522          scope_adapter::<F>(
523            context,
524            host_defined_options,
525            resource_name,
526            specifier,
527            import_phase,
528            import_attributes,
529          )
530          .map(|return_value| return_value.as_non_null().as_ptr())
531          .unwrap_or_else(null_mut),
532        );
533        return_value
534      }
535    }
536
537    abi_adapter::<F>
538  }
539}
540
541/// `HostCreateShadowRealmContextCallback` is called each time a `ShadowRealm`
542/// is being constructed. You can use [`HandleScope::get_current_context`] to
543/// get the [`Context`] in which the constructor is being run.
544///
545/// The method combines [`Context`] creation and the implementation-defined
546/// abstract operation `HostInitializeShadowRealm` into one.
547///
548/// The embedder should use [`Context::new`] to create a new context. If the
549/// creation fails, the embedder must propagate that exception by returning
550/// [`None`].
551pub type HostCreateShadowRealmContextCallback =
552  for<'s, 'i> fn(scope: &mut PinScope<'s, 'i>) -> Option<Local<'s, Context>>;
553
554pub type GcCallbackWithData = unsafe extern "C" fn(
555  isolate: UnsafeRawIsolatePtr,
556  r#type: GCType,
557  flags: GCCallbackFlags,
558  data: *mut c_void,
559);
560
561pub type InterruptCallback =
562  unsafe extern "C" fn(isolate: UnsafeRawIsolatePtr, data: *mut c_void);
563
564pub type NearHeapLimitCallback = unsafe extern "C" fn(
565  data: *mut c_void,
566  current_heap_limit: usize,
567  initial_heap_limit: usize,
568) -> usize;
569
570#[repr(C)]
571pub struct OomDetails {
572  pub is_heap_oom: bool,
573  pub detail: *const char,
574}
575
576pub type OomErrorCallback =
577  unsafe extern "C" fn(location: *const char, details: &OomDetails);
578
579// Windows x64 ABI: MaybeLocal<Value> returned on the stack.
580#[cfg(target_os = "windows")]
581pub type PrepareStackTraceCallback<'s> =
582  unsafe extern "C" fn(
583    *mut *const Value,
584    Local<'s, Context>,
585    Local<'s, Value>,
586    Local<'s, Array>,
587  ) -> *mut *const Value;
588
589#[cfg(not(target_os = "windows"))]
590pub type PrepareStackTraceCallback<'s> =
591  unsafe extern "C" fn(
592    Local<'s, Context>,
593    Local<'s, Value>,
594    Local<'s, Array>,
595  ) -> PrepareStackTraceCallbackRet;
596
597// System V ABI: MaybeLocal<Value> returned in a register.
598// System V i386 ABI: Local<Value> returned in hidden pointer (struct).
599#[cfg(not(target_os = "windows"))]
600#[repr(C)]
601pub struct PrepareStackTraceCallbackRet(*const Value);
602
603pub type UseCounterFeature = v8__Isolate__UseCounterFeature;
604pub type UseCounterCallback =
605  unsafe extern "C" fn(&mut Isolate, UseCounterFeature);
606
607unsafe extern "C" {
608  fn v8__Isolate__New(params: *const raw::CreateParams) -> *mut RealIsolate;
609  fn v8__Isolate__Dispose(this: *mut RealIsolate);
610  fn v8__Isolate__GetNumberOfDataSlots(this: *const RealIsolate) -> u32;
611  fn v8__Isolate__GetData(
612    isolate: *const RealIsolate,
613    slot: u32,
614  ) -> *mut c_void;
615  fn v8__Isolate__SetData(
616    isolate: *const RealIsolate,
617    slot: u32,
618    data: *mut c_void,
619  );
620  fn v8__Isolate__Enter(this: *mut RealIsolate);
621  fn v8__Isolate__Exit(this: *mut RealIsolate);
622  fn v8__Isolate__GetCurrent() -> *mut RealIsolate;
623  fn v8__Isolate__MemoryPressureNotification(this: *mut RealIsolate, level: u8);
624  fn v8__Isolate__ClearKeptObjects(isolate: *mut RealIsolate);
625  fn v8__Isolate__LowMemoryNotification(isolate: *mut RealIsolate);
626  fn v8__Isolate__SetIdle(isolate: *mut RealIsolate, is_idle: bool);
627  fn v8__CpuProfiler__CollectSample(
628    isolate: *mut RealIsolate,
629    trace_id: *const u64,
630  );
631  fn v8__CpuProfiler__UseDetailedSourcePositionsForProfiling(
632    isolate: *mut RealIsolate,
633  );
634  fn v8__Isolate__GetHeapStatistics(
635    this: *mut RealIsolate,
636    s: *mut v8__HeapStatistics,
637  );
638  fn v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(
639    this: *mut RealIsolate,
640    capture: bool,
641    frame_limit: i32,
642  );
643  fn v8__Isolate__AddMessageListener(
644    isolate: *mut RealIsolate,
645    callback: MessageCallback,
646  ) -> bool;
647  fn v8__Isolate__AddMessageListenerWithErrorLevel(
648    isolate: *mut RealIsolate,
649    callback: MessageCallback,
650    message_levels: MessageErrorLevel,
651  ) -> bool;
652  fn v8__Isolate__AddGCPrologueCallback(
653    isolate: *mut RealIsolate,
654    callback: GcCallbackWithData,
655    data: *mut c_void,
656    gc_type_filter: GCType,
657  );
658  fn v8__Isolate__RemoveGCPrologueCallback(
659    isolate: *mut RealIsolate,
660    callback: GcCallbackWithData,
661    data: *mut c_void,
662  );
663  fn v8__Isolate__AddGCEpilogueCallback(
664    isolate: *mut RealIsolate,
665    callback: GcCallbackWithData,
666    data: *mut c_void,
667    gc_type_filter: GCType,
668  );
669  fn v8__Isolate__RemoveGCEpilogueCallback(
670    isolate: *mut RealIsolate,
671    callback: GcCallbackWithData,
672    data: *mut c_void,
673  );
674  fn v8__Isolate__NumberOfHeapSpaces(isolate: *mut RealIsolate) -> size_t;
675  fn v8__Isolate__GetHeapSpaceStatistics(
676    isolate: *mut RealIsolate,
677    space_statistics: *mut v8__HeapSpaceStatistics,
678    index: size_t,
679  ) -> bool;
680  fn v8__Isolate__GetHeapCodeAndMetadataStatistics(
681    isolate: *mut RealIsolate,
682    code_statistics: *mut v8__HeapCodeStatistics,
683  ) -> bool;
684  fn v8__Isolate__AddNearHeapLimitCallback(
685    isolate: *mut RealIsolate,
686    callback: NearHeapLimitCallback,
687    data: *mut c_void,
688  );
689  fn v8__Isolate__RemoveNearHeapLimitCallback(
690    isolate: *mut RealIsolate,
691    callback: NearHeapLimitCallback,
692    heap_limit: usize,
693  );
694  fn v8__Isolate__SetOOMErrorHandler(
695    isolate: *mut RealIsolate,
696    callback: OomErrorCallback,
697  );
698  fn v8__Isolate__AdjustAmountOfExternalAllocatedMemory(
699    isolate: *mut RealIsolate,
700    change_in_bytes: i64,
701  ) -> i64;
702  fn v8__Isolate__GetCppHeap(isolate: *mut RealIsolate) -> *mut Heap;
703  fn v8__Isolate__SetPrepareStackTraceCallback(
704    isolate: *mut RealIsolate,
705    callback: PrepareStackTraceCallback,
706  );
707  fn v8__Isolate__SetPromiseHook(isolate: *mut RealIsolate, hook: PromiseHook);
708  fn v8__Isolate__SetPromiseRejectCallback(
709    isolate: *mut RealIsolate,
710    callback: PromiseRejectCallback,
711  );
712  fn v8__Isolate__SetWasmAsyncResolvePromiseCallback(
713    isolate: *mut RealIsolate,
714    callback: WasmAsyncResolvePromiseCallback,
715  );
716  fn v8__Isolate__SetAllowWasmCodeGenerationCallback(
717    isolate: *mut RealIsolate,
718    callback: AllowWasmCodeGenerationCallback,
719  );
720  fn v8__Isolate__SetHostInitializeImportMetaObjectCallback(
721    isolate: *mut RealIsolate,
722    callback: HostInitializeImportMetaObjectCallback,
723  );
724  fn v8__Isolate__SetHostImportModuleDynamicallyCallback(
725    isolate: *mut RealIsolate,
726    callback: RawHostImportModuleDynamicallyCallback,
727  );
728  fn v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback(
729    isolate: *mut RealIsolate,
730    callback: RawHostImportModuleWithPhaseDynamicallyCallback,
731  );
732  #[cfg(not(target_os = "windows"))]
733  fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
734    isolate: *mut RealIsolate,
735    callback: unsafe extern "C" fn(
736      initiator_context: Local<Context>,
737    ) -> *mut Context,
738  );
739  #[cfg(target_os = "windows")]
740  fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
741    isolate: *mut RealIsolate,
742    callback: unsafe extern "C" fn(
743      rv: *mut *mut Context,
744      initiator_context: Local<Context>,
745    ) -> *mut *mut Context,
746  );
747  fn v8__Isolate__SetUseCounterCallback(
748    isolate: *mut RealIsolate,
749    callback: UseCounterCallback,
750  );
751  fn v8__Isolate__RequestInterrupt(
752    isolate: *const RealIsolate,
753    callback: InterruptCallback,
754    data: *mut c_void,
755  );
756  fn v8__Isolate__TerminateExecution(isolate: *const RealIsolate);
757  fn v8__Isolate__IsExecutionTerminating(isolate: *const RealIsolate) -> bool;
758  fn v8__Isolate__CancelTerminateExecution(isolate: *const RealIsolate);
759  fn v8__Isolate__GetMicrotasksPolicy(
760    isolate: *const RealIsolate,
761  ) -> MicrotasksPolicy;
762  fn v8__Isolate__SetMicrotasksPolicy(
763    isolate: *mut RealIsolate,
764    policy: MicrotasksPolicy,
765  );
766  fn v8__Isolate__PerformMicrotaskCheckpoint(isolate: *mut RealIsolate);
767  fn v8__Isolate__EnqueueMicrotask(
768    isolate: *mut RealIsolate,
769    function: *const Function,
770  );
771  fn v8__Isolate__SetAllowAtomicsWait(isolate: *mut RealIsolate, allow: bool);
772  fn v8__Isolate__SetWasmStreamingCallback(
773    isolate: *mut RealIsolate,
774    callback: unsafe extern "C" fn(*const FunctionCallbackInfo),
775  );
776  fn v8__Isolate__DateTimeConfigurationChangeNotification(
777    isolate: *mut RealIsolate,
778    time_zone_detection: TimeZoneDetection,
779  );
780  fn v8__Isolate__HasPendingBackgroundTasks(
781    isolate: *const RealIsolate,
782  ) -> bool;
783  fn v8__Isolate__RequestGarbageCollectionForTesting(
784    isolate: *mut RealIsolate,
785    r#type: usize,
786  );
787
788  fn v8__HeapProfiler__TakeHeapSnapshot(
789    isolate: *mut RealIsolate,
790    callback: unsafe extern "C" fn(*mut c_void, *const u8, usize) -> bool,
791    arg: *mut c_void,
792  );
793}
794
795/// Isolate represents an isolated instance of the V8 engine.  V8 isolates have
796/// completely separate states.  Objects from one isolate must not be used in
797/// other isolates.  The embedder can create multiple isolates and use them in
798/// parallel in multiple threads.  An isolate can be entered by at most one
799/// thread at any given time.  The Locker/Unlocker API must be used to
800/// synchronize.
801///
802/// rusty_v8 note: Unlike in the C++ API, the Isolate is entered when it is
803/// constructed and exited when dropped. Because of that v8::OwnedIsolate
804/// instances must be dropped in the reverse order of creation
805#[repr(transparent)]
806#[derive(Debug)]
807pub struct Isolate(NonNull<RealIsolate>);
808
809#[repr(transparent)]
810#[derive(Debug, Clone, Copy)]
811pub struct UnsafeRawIsolatePtr(*mut RealIsolate);
812
813impl UnsafeRawIsolatePtr {
814  #[inline]
815  pub(crate) fn from_real_ptr(ptr: *mut RealIsolate) -> Self {
816    Self(ptr)
817  }
818
819  pub fn null() -> Self {
820    Self(std::ptr::null_mut())
821  }
822
823  pub fn is_null(&self) -> bool {
824    self.0.is_null()
825  }
826
827  #[inline]
828  pub(crate) fn as_real_ptr(&self) -> *mut RealIsolate {
829    self.0
830  }
831}
832
833#[repr(C)]
834pub struct RealIsolate(Opaque);
835
836impl Isolate {
837  pub(crate) fn as_real_ptr(&self) -> *mut RealIsolate {
838    self.0.as_ptr()
839  }
840
841  pub unsafe fn as_raw_isolate_ptr(&self) -> UnsafeRawIsolatePtr {
842    UnsafeRawIsolatePtr(self.0.as_ptr())
843  }
844
845  #[inline]
846  pub unsafe fn from_raw_isolate_ptr(ptr: UnsafeRawIsolatePtr) -> Self {
847    Self(NonNull::new(ptr.0).unwrap())
848  }
849
850  #[inline]
851  pub unsafe fn from_raw_isolate_ptr_unchecked(
852    ptr: UnsafeRawIsolatePtr,
853  ) -> Self {
854    Self(unsafe { NonNull::new_unchecked(ptr.0) })
855  }
856
857  pub unsafe fn from_raw_ptr_unchecked(ptr: *mut RealIsolate) -> Self {
858    Self(unsafe { NonNull::new_unchecked(ptr) })
859  }
860
861  pub unsafe fn from_raw_ptr(ptr: *mut RealIsolate) -> Self {
862    Self(NonNull::new(ptr).unwrap())
863  }
864
865  #[inline]
866  pub unsafe fn ref_from_raw_isolate_ptr(ptr: &UnsafeRawIsolatePtr) -> &Self {
867    if ptr.is_null() {
868      panic!("UnsafeRawIsolatePtr is null");
869    }
870    unsafe { &*(ptr as *const UnsafeRawIsolatePtr as *const Isolate) }
871  }
872
873  #[inline]
874  pub unsafe fn ref_from_raw_isolate_ptr_unchecked(
875    ptr: &UnsafeRawIsolatePtr,
876  ) -> &Self {
877    unsafe { &*(ptr as *const UnsafeRawIsolatePtr as *const Isolate) }
878  }
879
880  #[inline]
881  pub unsafe fn ref_from_raw_isolate_ptr_mut(
882    ptr: &mut UnsafeRawIsolatePtr,
883  ) -> &mut Self {
884    if ptr.is_null() {
885      panic!("UnsafeRawIsolatePtr is null");
886    }
887    unsafe { &mut *(ptr as *mut UnsafeRawIsolatePtr as *mut Isolate) }
888  }
889
890  #[inline]
891  pub unsafe fn ref_from_raw_isolate_ptr_mut_unchecked(
892    ptr: &mut UnsafeRawIsolatePtr,
893  ) -> &mut Self {
894    unsafe { &mut *(ptr as *mut UnsafeRawIsolatePtr as *mut Isolate) }
895  }
896
897  #[inline]
898  pub(crate) unsafe fn from_non_null(ptr: NonNull<RealIsolate>) -> Self {
899    Self(ptr)
900  }
901
902  #[inline]
903  pub(crate) unsafe fn from_raw_ref(ptr: &NonNull<RealIsolate>) -> &Self {
904    // SAFETY: Isolate is a repr(transparent) wrapper around NonNull<RealIsolate>
905    unsafe { &*(ptr as *const NonNull<RealIsolate> as *const Isolate) }
906  }
907
908  #[inline]
909  pub(crate) unsafe fn from_raw_ref_mut(
910    ptr: &mut NonNull<RealIsolate>,
911  ) -> &mut Self {
912    // SAFETY: Isolate is a repr(transparent) wrapper around NonNull<RealIsolate>
913    unsafe { &mut *(ptr as *mut NonNull<RealIsolate> as *mut Isolate) }
914  }
915
916  // Isolate data slots used internally by rusty_v8.
917  const ANNEX_SLOT: u32 = 0;
918  const INTERNAL_DATA_SLOT_COUNT: u32 = 1;
919
920  #[inline(always)]
921  fn assert_embedder_data_slot_count_and_offset_correct(&self) {
922    assert!(
923      unsafe { v8__Isolate__GetNumberOfDataSlots(self.as_real_ptr()) }
924        >= Self::INTERNAL_DATA_SLOT_COUNT
925    )
926  }
927
928  fn new_impl(params: CreateParams) -> *mut RealIsolate {
929    crate::V8::assert_initialized();
930    let (raw_create_params, create_param_allocations) = params.finalize();
931    let cxx_isolate = unsafe { v8__Isolate__New(&raw_create_params) };
932    let mut isolate = unsafe { Isolate::from_raw_ptr(cxx_isolate) };
933    isolate.initialize(create_param_allocations);
934    cxx_isolate
935  }
936
937  pub(crate) fn initialize(&mut self, create_param_allocations: Box<dyn Any>) {
938    self.assert_embedder_data_slot_count_and_offset_correct();
939    self.create_annex(create_param_allocations);
940  }
941
942  /// Creates a new isolate.  Does not change the currently entered
943  /// isolate.
944  ///
945  /// When an isolate is no longer used its resources should be freed
946  /// by calling V8::dispose().  Using the delete operator is not allowed.
947  ///
948  /// V8::initialize() must have run prior to this.
949  #[allow(clippy::new_ret_no_self)]
950  pub fn new(params: CreateParams) -> OwnedIsolate {
951    OwnedIsolate::new(Self::new_impl(params))
952  }
953
954  #[allow(clippy::new_ret_no_self)]
955  pub fn snapshot_creator(
956    external_references: Option<Cow<'static, [ExternalReference]>>,
957    params: Option<CreateParams>,
958  ) -> OwnedIsolate {
959    SnapshotCreator::new(external_references, params)
960  }
961
962  #[allow(clippy::new_ret_no_self)]
963  pub fn snapshot_creator_from_existing_snapshot(
964    existing_snapshot_blob: StartupData,
965    external_references: Option<Cow<'static, [ExternalReference]>>,
966    params: Option<CreateParams>,
967  ) -> OwnedIsolate {
968    SnapshotCreator::from_existing_snapshot(
969      existing_snapshot_blob,
970      external_references,
971      params,
972    )
973  }
974
975  /// Initial configuration parameters for a new Isolate.
976  #[inline(always)]
977  pub fn create_params() -> CreateParams {
978    CreateParams::default()
979  }
980
981  #[inline(always)]
982  pub fn thread_safe_handle(&self) -> IsolateHandle {
983    self.get_annex().isolate_handle.clone()
984  }
985
986  #[inline(always)]
987  pub(crate) fn global_liveness(&self) -> NonNull<IsolateLiveness> {
988    self.get_annex().global_liveness
989  }
990
991  /// See [`IsolateHandle::terminate_execution`]
992  #[inline(always)]
993  pub fn terminate_execution(&self) -> bool {
994    unsafe { v8__Isolate__TerminateExecution(self.as_real_ptr()) };
995    true
996  }
997
998  /// See [`IsolateHandle::cancel_terminate_execution`]
999  #[inline(always)]
1000  pub fn cancel_terminate_execution(&self) -> bool {
1001    unsafe { v8__Isolate__CancelTerminateExecution(self.as_real_ptr()) };
1002    true
1003  }
1004
1005  /// See [`IsolateHandle::is_execution_terminating`]
1006  #[inline(always)]
1007  pub fn is_execution_terminating(&self) -> bool {
1008    unsafe { v8__Isolate__IsExecutionTerminating(self.as_real_ptr()) }
1009  }
1010
1011  pub(crate) fn create_annex(
1012    &mut self,
1013    create_param_allocations: Box<dyn Any>,
1014  ) {
1015    let annex_box = Box::new(IsolateAnnex::new(self, create_param_allocations));
1016    let annex_ptr = Box::into_raw(annex_box);
1017    assert!(self.get_data_internal(Self::ANNEX_SLOT).is_null());
1018    self.set_data_internal(Self::ANNEX_SLOT, annex_ptr as *mut _);
1019  }
1020
1021  /// Prepare annex teardown while keeping `ANNEX_SLOT` pointing at the annex.
1022  ///
1023  /// Nulls the `IsolateHandle`'s inner pointer, reclaims
1024  /// `create_param_allocations`, and drops the slot storage. The annex
1025  /// allocation itself stays alive and `ANNEX_SLOT` keeps pointing at it,
1026  /// so code that runs during the subsequent V8 teardown GC (weak
1027  /// callbacks, guaranteed finalizers, embedder slot drops) can still
1028  /// resolve the annex through `get_annex()` / `get_annex_mut()`.
1029  ///
1030  /// The returned pointer must be passed exactly once to
1031  /// [`Self::finish_annex_dispose`] (or, on the snapshot path, dropped by
1032  /// [`Self::dispose_annex`]).
1033  ///
1034  /// # Safety
1035  ///
1036  /// Called once per isolate, from teardown paths only.
1037  unsafe fn prepare_annex_for_dispose(
1038    &mut self,
1039  ) -> (*mut IsolateAnnex, Box<dyn Any>) {
1040    let annex_ptr =
1041      self.get_data_internal(Self::ANNEX_SLOT) as *mut IsolateAnnex;
1042    assert!(!annex_ptr.is_null());
1043
1044    // Each step below operates through the raw pointer rather than a
1045    // long-lived `&mut IsolateAnnex`. The borrows we form here are
1046    // narrowly-scoped expressions that end before any user-controlled
1047    // Drop runs. This matters because slot Drops, weak callbacks, and
1048    // guaranteed finalizers may re-enter the isolate (e.g. via
1049    // `Isolate::thread_safe_handle()`) and resolve the annex through
1050    // `get_annex()`. An outer `&mut IsolateAnnex` held across that
1051    // re-entry would alias the shared borrow they obtain.
1052
1053    // SAFETY: `annex_ptr` is non-null and points at a live `IsolateAnnex`
1054    // (ANNEX_SLOT is only cleared by code further down this teardown
1055    // path).
1056    unsafe {
1057      // Null the `IsolateHandle` so handles outliving the isolate see a
1058      // disposed state.
1059      (*annex_ptr).global_liveness().dispose();
1060      (*annex_ptr).isolate_handle.dispose();
1061    }
1062
1063    // Reclaim `create_param_allocations` so the caller can keep it alive
1064    // for as long as V8 needs (during snapshot blob creation, V8 reads
1065    // external references out of it).
1066    let create_param_allocations =
1067      unsafe { (*annex_ptr).create_param_allocations.take().unwrap() };
1068
1069    // Move slots out before dropping them. A user Drop may re-enter the
1070    // annex; holding `&mut (*annex_ptr).slots` across that would alias
1071    // any `&IsolateAnnex` the re-entry obtains.
1072    let slots = unsafe { std::mem::take(&mut (*annex_ptr).slots) };
1073    drop(slots);
1074
1075    (annex_ptr, create_param_allocations)
1076  }
1077
1078  /// Drain `finalizer_map` and invoke any guaranteed finalizers.
1079  ///
1080  /// New finalizers registered by the running callbacks land in the
1081  /// annex's now-empty `finalizer_map` and will be picked up by the next
1082  /// call (currently the second drain in [`OwnedIsolate::drop`] after V8
1083  /// finishes its teardown GC).
1084  ///
1085  /// # Safety
1086  ///
1087  /// `annex_ptr` must point at a live `IsolateAnnex` with `ANNEX_SLOT`
1088  /// still referencing it, so re-entrant callbacks resolve the annex
1089  /// through normal accessors.
1090  unsafe fn run_remaining_guaranteed_finalizers(annex_ptr: *mut IsolateAnnex) {
1091    // Take the map out under a narrow borrow so the for-loop below
1092    // borrows a local instead of `(*annex_ptr).finalizer_map`. Callbacks
1093    // re-entering the annex via `get_annex_mut()` would otherwise alias
1094    // an in-flight `&mut`.
1095    let mut map = unsafe { std::mem::take(&mut (*annex_ptr).finalizer_map) };
1096    for finalizer in map.drain() {
1097      if let FinalizerCallback::Guaranteed(callback) = finalizer {
1098        callback();
1099      }
1100    }
1101  }
1102
1103  /// Free the annex allocation after V8's final teardown.
1104  ///
1105  /// Drains any guaranteed finalizers V8's teardown GC may have
1106  /// registered, then drops the annex box. `ANNEX_SLOT` is not cleared
1107  /// because the isolate is gone — its embedder data storage no longer
1108  /// exists.
1109  ///
1110  /// # Safety
1111  ///
1112  /// `annex_ptr` must be the pointer returned from a matching
1113  /// [`Self::prepare_annex_for_dispose`] call, and the V8 isolate must
1114  /// already be fully disposed (so no further callbacks can fire).
1115  unsafe fn finish_annex_dispose(annex_ptr: *mut IsolateAnnex) {
1116    unsafe { Self::run_remaining_guaranteed_finalizers(annex_ptr) };
1117    unsafe { drop(Box::from_raw(annex_ptr)) };
1118  }
1119
1120  /// Snapshot-path teardown.
1121  ///
1122  /// Used by [`OwnedIsolate::create_blob`], which consumes the isolate
1123  /// before V8 has run its final dispose. Cleans up the annex synchronously
1124  /// (no weak-callback re-entry to worry about here) and nulls `ANNEX_SLOT`
1125  /// so the snapshot creator's later isolate-dispose sees a clean slot.
1126  unsafe fn dispose_annex(&mut self) -> Box<dyn Any> {
1127    let (annex_ptr, create_param_allocations) =
1128      unsafe { self.prepare_annex_for_dispose() };
1129    unsafe { Self::run_remaining_guaranteed_finalizers(annex_ptr) };
1130    let taken_annex =
1131      self.take_data_internal(Self::ANNEX_SLOT) as *mut IsolateAnnex;
1132    debug_assert_eq!(taken_annex, annex_ptr);
1133    unsafe { drop(Box::from_raw(annex_ptr)) };
1134    create_param_allocations
1135  }
1136
1137  #[inline(always)]
1138  fn get_annex(&self) -> &IsolateAnnex {
1139    let annex_ptr =
1140      self.get_data_internal(Self::ANNEX_SLOT) as *const IsolateAnnex;
1141    assert!(!annex_ptr.is_null());
1142    unsafe { &*annex_ptr }
1143  }
1144
1145  #[inline(always)]
1146  fn get_annex_mut(&mut self) -> &mut IsolateAnnex {
1147    let annex_ptr =
1148      self.get_data_internal(Self::ANNEX_SLOT) as *mut IsolateAnnex;
1149    assert!(!annex_ptr.is_null());
1150    unsafe { &mut *annex_ptr }
1151  }
1152
1153  /// Returns a non-null pointer to the isolate's annex data.
1154  /// This is used by scopes to cache the annex pointer and avoid
1155  /// repeated FFI calls to `v8__Isolate__GetData`.
1156  #[inline(always)]
1157  pub(crate) fn get_annex_ptr(&self) -> NonNull<IsolateAnnex> {
1158    let annex_ptr =
1159      self.get_data_internal(Self::ANNEX_SLOT) as *mut IsolateAnnex;
1160    debug_assert!(!annex_ptr.is_null());
1161    unsafe { NonNull::new_unchecked(annex_ptr) }
1162  }
1163
1164  pub(crate) fn set_snapshot_creator(
1165    &mut self,
1166    snapshot_creator: SnapshotCreator,
1167  ) {
1168    let prev = self
1169      .get_annex_mut()
1170      .maybe_snapshot_creator
1171      .replace(snapshot_creator);
1172    assert!(prev.is_none());
1173  }
1174
1175  pub(crate) fn get_finalizer_map(&self) -> &FinalizerMap {
1176    &self.get_annex().finalizer_map
1177  }
1178
1179  pub(crate) fn get_finalizer_map_mut(&mut self) -> &mut FinalizerMap {
1180    &mut self.get_annex_mut().finalizer_map
1181  }
1182
1183  /// Retrieve embedder-specific data from the isolate.
1184  /// Returns NULL if SetData has never been called for the given `slot`.
1185  pub fn get_data(&self, slot: u32) -> *mut c_void {
1186    self.get_data_internal(Self::INTERNAL_DATA_SLOT_COUNT + slot)
1187  }
1188
1189  /// Associate embedder-specific data with the isolate. `slot` has to be
1190  /// between 0 and `Isolate::get_number_of_data_slots()`.
1191  #[inline(always)]
1192  pub fn set_data(&mut self, slot: u32, data: *mut c_void) {
1193    self.set_data_internal(Self::INTERNAL_DATA_SLOT_COUNT + slot, data);
1194  }
1195
1196  /// Returns the maximum number of available embedder data slots. Valid slots
1197  /// are in the range of `0 <= n < Isolate::get_number_of_data_slots()`.
1198  pub fn get_number_of_data_slots(&self) -> u32 {
1199    let n = unsafe { v8__Isolate__GetNumberOfDataSlots(self.as_real_ptr()) };
1200    n - Self::INTERNAL_DATA_SLOT_COUNT
1201  }
1202
1203  #[inline(always)]
1204  pub(crate) fn get_data_internal(&self, slot: u32) -> *mut c_void {
1205    unsafe { v8__Isolate__GetData(self.as_real_ptr(), slot) }
1206  }
1207
1208  #[inline(always)]
1209  pub(crate) fn set_data_internal(&mut self, slot: u32, data: *mut c_void) {
1210    unsafe { v8__Isolate__SetData(self.as_real_ptr(), slot, data) }
1211  }
1212
1213  /// Get the value of the slot and replace it with a null pointer.
1214  #[inline(always)]
1215  fn take_data_internal(&mut self, slot: u32) -> *mut c_void {
1216    let ptr = self.get_data_internal(slot);
1217    self.set_data_internal(slot, null_mut());
1218    ptr
1219  }
1220
1221  // pub(crate) fn init_scope_root(&mut self) {
1222  //   ScopeData::new_root(self);
1223  // }
1224
1225  // pub(crate) fn dispose_scope_root(&mut self) {
1226  //   ScopeData::drop_root(self);
1227  // }
1228
1229  // /// Returns a pointer to the `ScopeData` struct for the current scope.
1230  // #[inline(always)]
1231  // pub(crate) fn get_current_scope_data(&self) -> Option<NonNull<ScopeData>> {
1232  //   let scope_data_ptr = self.get_data_internal(Self::CURRENT_SCOPE_DATA_SLOT);
1233  //   NonNull::new(scope_data_ptr).map(NonNull::cast)
1234  // }
1235
1236  // /// Updates the slot that stores a `ScopeData` pointer for the current scope.
1237  // #[inline(always)]
1238  // pub(crate) fn set_current_scope_data(
1239  //   &mut self,
1240  //   scope_data: Option<NonNull<ScopeData>>,
1241  // ) {
1242  //   let scope_data_ptr = scope_data
1243  //     .map(NonNull::cast)
1244  //     .map_or_else(null_mut, NonNull::as_ptr);
1245  //   self.set_data_internal(Self::CURRENT_SCOPE_DATA_SLOT, scope_data_ptr);
1246  // }
1247
1248  /// Get a reference to embedder data added with `set_slot()`.
1249  #[inline(always)]
1250  pub fn get_slot<T: 'static>(&self) -> Option<&T> {
1251    self.get_annex().get_slot::<T>()
1252  }
1253
1254  /// Get a mutable reference to embedder data added with `set_slot()`.
1255  #[inline(always)]
1256  pub fn get_slot_mut<T: 'static>(&mut self) -> Option<&mut T> {
1257    self.get_annex_mut().get_slot_mut::<T>()
1258  }
1259
1260  /// Use with Isolate::get_slot and Isolate::get_slot_mut to associate state
1261  /// with an Isolate.
1262  ///
1263  /// This method gives ownership of value to the Isolate. Exactly one object of
1264  /// each type can be associated with an Isolate. If called more than once with
1265  /// an object of the same type, the earlier version will be dropped and
1266  /// replaced.
1267  ///
1268  /// Returns true if value was set without replacing an existing value.
1269  ///
1270  /// The value will be dropped when the isolate is dropped.
1271  #[inline(always)]
1272  pub fn set_slot<T: 'static>(&mut self, value: T) -> bool {
1273    self.get_annex_mut().set_slot(value)
1274  }
1275
1276  /// Removes the embedder data added with `set_slot()` and returns it if it exists.
1277  #[inline(always)]
1278  pub fn remove_slot<T: 'static>(&mut self) -> Option<T> {
1279    self.get_annex_mut().remove_slot::<T>()
1280  }
1281
1282  /// Sets this isolate as the entered one for the current thread.
1283  /// Saves the previously entered one (if any), so that it can be
1284  /// restored when exiting.  Re-entering an isolate is allowed.
1285  ///
1286  /// rusty_v8 note: Unlike in the C++ API, the isolate is entered when it is
1287  /// constructed and exited when dropped.
1288  #[inline(always)]
1289  pub unsafe fn enter(&self) {
1290    unsafe {
1291      v8__Isolate__Enter(self.as_real_ptr());
1292    }
1293  }
1294
1295  /// Exits this isolate by restoring the previously entered one in the
1296  /// current thread.  The isolate may still stay the same, if it was
1297  /// entered more than once.
1298  ///
1299  /// Requires: self == Isolate::GetCurrent().
1300  ///
1301  /// rusty_v8 note: Unlike in the C++ API, the isolate is entered when it is
1302  /// constructed and exited when dropped.
1303  #[inline(always)]
1304  pub unsafe fn exit(&self) {
1305    unsafe {
1306      v8__Isolate__Exit(self.as_real_ptr());
1307    }
1308  }
1309
1310  /// Optional notification that the system is running low on memory.
1311  /// V8 uses these notifications to guide heuristics.
1312  /// It is allowed to call this function from another thread while
1313  /// the isolate is executing long running JavaScript code.
1314  #[inline(always)]
1315  pub fn memory_pressure_notification(&mut self, level: MemoryPressureLevel) {
1316    unsafe {
1317      v8__Isolate__MemoryPressureNotification(self.as_real_ptr(), level as u8)
1318    }
1319  }
1320
1321  /// Clears the set of objects held strongly by the heap. This set of
1322  /// objects are originally built when a WeakRef is created or
1323  /// successfully dereferenced.
1324  ///
1325  /// This is invoked automatically after microtasks are run. See
1326  /// MicrotasksPolicy for when microtasks are run.
1327  ///
1328  /// This needs to be manually invoked only if the embedder is manually
1329  /// running microtasks via a custom MicrotaskQueue class's PerformCheckpoint.
1330  /// In that case, it is the embedder's responsibility to make this call at a
1331  /// time which does not interrupt synchronous ECMAScript code execution.
1332  #[inline(always)]
1333  pub fn clear_kept_objects(&mut self) {
1334    unsafe { v8__Isolate__ClearKeptObjects(self.as_real_ptr()) }
1335  }
1336
1337  /// Optional notification that the system is running low on memory.
1338  /// V8 uses these notifications to attempt to free memory.
1339  #[inline(always)]
1340  pub fn low_memory_notification(&mut self) {
1341    unsafe { v8__Isolate__LowMemoryNotification(self.as_real_ptr()) }
1342  }
1343
1344  /// Tells the VM whether the embedder is currently idle or not.
1345  ///
1346  /// This is consulted by V8's CPU profiler: samples taken while the embedder
1347  /// is idle (for instance, blocked waiting for I/O in the event loop) are
1348  /// attributed to the "(idle)" node instead of being counted as running code.
1349  /// Embedders that don't call this end up reporting ~100% CPU usage in tools
1350  /// like Chrome DevTools even when the program is doing nothing.
1351  ///
1352  /// Must be called on the isolate's own thread while no JavaScript is
1353  /// executing (e.g. right before parking the event loop, and again with
1354  /// `false` once it resumes).
1355  #[inline(always)]
1356  pub fn set_idle(&mut self, is_idle: bool) {
1357    unsafe { v8__Isolate__SetIdle(self.as_real_ptr(), is_idle) }
1358  }
1359
1360  /// Synchronously collect a CPU profiling sample in all CPU profilers
1361  /// attached to this isolate. This does not affect the number of ticks
1362  /// recorded for the current top node.
1363  ///
1364  /// When `trace_id` is `Some`, the sample is tagged with that identifier,
1365  /// which is useful to associate the sample with a trace event.
1366  #[inline(always)]
1367  pub fn collect_cpu_profiler_sample(&mut self, trace_id: Option<u64>) {
1368    let trace_id_ptr = match &trace_id {
1369      Some(id) => id as *const u64,
1370      None => std::ptr::null(),
1371    };
1372    unsafe { v8__CpuProfiler__CollectSample(self.as_real_ptr(), trace_id_ptr) }
1373  }
1374
1375  /// Generate more detailed source positions for code objects. This results in
1376  /// better accuracy when mapping CPU profiling samples back to script source,
1377  /// at the cost of some additional memory and CPU overhead.
1378  #[inline(always)]
1379  pub fn use_detailed_source_positions_for_profiling(&mut self) {
1380    unsafe {
1381      v8__CpuProfiler__UseDetailedSourcePositionsForProfiling(
1382        self.as_real_ptr(),
1383      )
1384    }
1385  }
1386
1387  /// Get statistics about the heap memory usage.
1388  #[inline(always)]
1389  pub fn get_heap_statistics(&mut self) -> HeapStatistics {
1390    let inner = unsafe {
1391      let mut s = MaybeUninit::zeroed();
1392      v8__Isolate__GetHeapStatistics(self.as_real_ptr(), s.as_mut_ptr());
1393      s.assume_init()
1394    };
1395    HeapStatistics(inner)
1396  }
1397
1398  /// Returns the number of spaces in the heap.
1399  #[inline(always)]
1400  pub fn number_of_heap_spaces(&mut self) -> usize {
1401    unsafe { v8__Isolate__NumberOfHeapSpaces(self.as_real_ptr()) }
1402  }
1403
1404  /// Get the memory usage of a space in the heap.
1405  ///
1406  /// \param space_statistics The HeapSpaceStatistics object to fill in
1407  ///   statistics.
1408  /// \param index The index of the space to get statistics from, which ranges
1409  ///   from 0 to NumberOfHeapSpaces() - 1.
1410  /// \returns true on success.
1411  #[inline(always)]
1412  pub fn get_heap_space_statistics(
1413    &mut self,
1414    index: usize,
1415  ) -> Option<HeapSpaceStatistics> {
1416    let inner = unsafe {
1417      let mut s = MaybeUninit::zeroed();
1418      if !v8__Isolate__GetHeapSpaceStatistics(
1419        self.as_real_ptr(),
1420        s.as_mut_ptr(),
1421        index,
1422      ) {
1423        return None;
1424      }
1425      s.assume_init()
1426    };
1427    Some(HeapSpaceStatistics(inner))
1428  }
1429
1430  /// Get code and metadata statistics for the heap.
1431  ///
1432  /// \returns true on success.
1433  #[inline(always)]
1434  pub fn get_heap_code_and_metadata_statistics(
1435    &mut self,
1436  ) -> Option<HeapCodeStatistics> {
1437    let inner = unsafe {
1438      let mut s = MaybeUninit::zeroed();
1439      if !v8__Isolate__GetHeapCodeAndMetadataStatistics(
1440        self.as_real_ptr(),
1441        s.as_mut_ptr(),
1442      ) {
1443        return None;
1444      }
1445      s.assume_init()
1446    };
1447    Some(HeapCodeStatistics(inner))
1448  }
1449
1450  /// Tells V8 to capture current stack trace when uncaught exception occurs
1451  /// and report it to the message listeners. The option is off by default.
1452  #[inline(always)]
1453  pub fn set_capture_stack_trace_for_uncaught_exceptions(
1454    &mut self,
1455    capture: bool,
1456    frame_limit: i32,
1457  ) {
1458    unsafe {
1459      v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(
1460        self.as_real_ptr(),
1461        capture,
1462        frame_limit,
1463      );
1464    }
1465  }
1466
1467  /// Adds a message listener (errors only).
1468  ///
1469  /// The same message listener can be added more than once and in that
1470  /// case it will be called more than once for each message.
1471  ///
1472  /// The exception object will be passed to the callback.
1473  #[inline(always)]
1474  pub fn add_message_listener(&mut self, callback: MessageCallback) -> bool {
1475    unsafe { v8__Isolate__AddMessageListener(self.as_real_ptr(), callback) }
1476  }
1477
1478  /// Adds a message listener for the specified message levels.
1479  #[inline(always)]
1480  pub fn add_message_listener_with_error_level(
1481    &mut self,
1482    callback: MessageCallback,
1483    message_levels: MessageErrorLevel,
1484  ) -> bool {
1485    unsafe {
1486      v8__Isolate__AddMessageListenerWithErrorLevel(
1487        self.as_real_ptr(),
1488        callback,
1489        message_levels,
1490      )
1491    }
1492  }
1493
1494  /// This specifies the callback called when the stack property of Error
1495  /// is accessed.
1496  ///
1497  /// PrepareStackTraceCallback is called when the stack property of an error is
1498  /// first accessed. The return value will be used as the stack value. If this
1499  /// callback is registed, the |Error.prepareStackTrace| API will be disabled.
1500  /// |sites| is an array of call sites, specified in
1501  /// https://v8.dev/docs/stack-trace-api
1502  #[inline(always)]
1503  pub fn set_prepare_stack_trace_callback<'s>(
1504    &mut self,
1505    callback: impl MapFnTo<PrepareStackTraceCallback<'s>>,
1506  ) {
1507    // Note: the C++ API returns a MaybeLocal but V8 asserts at runtime when
1508    // it's empty. That is, you can't return None and that's why the Rust API
1509    // expects Local<Value> instead of Option<Local<Value>>.
1510    unsafe {
1511      v8__Isolate__SetPrepareStackTraceCallback(
1512        self.as_real_ptr(),
1513        callback.map_fn_to(),
1514      );
1515    };
1516  }
1517
1518  /// Set the PromiseHook callback for various promise lifecycle
1519  /// events.
1520  #[inline(always)]
1521  pub fn set_promise_hook(&mut self, hook: PromiseHook) {
1522    unsafe { v8__Isolate__SetPromiseHook(self.as_real_ptr(), hook) }
1523  }
1524
1525  /// Set callback to notify about promise reject with no handler, or
1526  /// revocation of such a previous notification once the handler is added.
1527  #[inline(always)]
1528  pub fn set_promise_reject_callback(
1529    &mut self,
1530    callback: PromiseRejectCallback,
1531  ) {
1532    unsafe {
1533      v8__Isolate__SetPromiseRejectCallback(self.as_real_ptr(), callback)
1534    }
1535  }
1536
1537  #[inline(always)]
1538  pub fn set_wasm_async_resolve_promise_callback(
1539    &mut self,
1540    callback: WasmAsyncResolvePromiseCallback,
1541  ) {
1542    unsafe {
1543      v8__Isolate__SetWasmAsyncResolvePromiseCallback(
1544        self.as_real_ptr(),
1545        callback,
1546      )
1547    }
1548  }
1549
1550  #[inline(always)]
1551  pub fn set_allow_wasm_code_generation_callback(
1552    &mut self,
1553    callback: AllowWasmCodeGenerationCallback,
1554  ) {
1555    unsafe {
1556      v8__Isolate__SetAllowWasmCodeGenerationCallback(
1557        self.as_real_ptr(),
1558        callback,
1559      );
1560    }
1561  }
1562
1563  #[inline(always)]
1564  /// This specifies the callback called by the upcoming importa.meta
1565  /// language feature to retrieve host-defined meta data for a module.
1566  pub fn set_host_initialize_import_meta_object_callback(
1567    &mut self,
1568    callback: HostInitializeImportMetaObjectCallback,
1569  ) {
1570    unsafe {
1571      v8__Isolate__SetHostInitializeImportMetaObjectCallback(
1572        self.as_real_ptr(),
1573        callback,
1574      );
1575    }
1576  }
1577
1578  /// This specifies the callback called by the upcoming dynamic
1579  /// import() language feature to load modules.
1580  #[inline(always)]
1581  pub fn set_host_import_module_dynamically_callback(
1582    &mut self,
1583    callback: impl HostImportModuleDynamicallyCallback,
1584  ) {
1585    unsafe {
1586      v8__Isolate__SetHostImportModuleDynamicallyCallback(
1587        self.as_real_ptr(),
1588        callback.to_c_fn(),
1589      );
1590    }
1591  }
1592
1593  /// This specifies the callback called by the upcoming dynamic
1594  /// import() and import.source() language feature to load modules.
1595  ///
1596  /// This API is experimental and is expected to be changed or removed in the
1597  /// future. The callback is currently only called when for source-phase
1598  /// imports. Evaluation-phase imports use the existing
1599  /// HostImportModuleDynamicallyCallback callback.
1600  #[inline(always)]
1601  pub fn set_host_import_module_with_phase_dynamically_callback(
1602    &mut self,
1603    callback: impl HostImportModuleWithPhaseDynamicallyCallback,
1604  ) {
1605    unsafe {
1606      v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback(
1607        self.as_real_ptr(),
1608        callback.to_c_fn(),
1609      );
1610    }
1611  }
1612
1613  /// This specifies the callback called by the upcoming `ShadowRealm`
1614  /// construction language feature to retrieve host created globals.
1615  pub fn set_host_create_shadow_realm_context_callback(
1616    &mut self,
1617    callback: HostCreateShadowRealmContextCallback,
1618  ) {
1619    #[inline]
1620    unsafe extern "C" fn rust_shadow_realm_callback(
1621      initiator_context: Local<Context>,
1622    ) -> *mut Context {
1623      let scope = pin!(unsafe { CallbackScope::new(initiator_context) });
1624      let mut scope = scope.init();
1625      let isolate = scope.as_ref();
1626      let callback = isolate
1627        .get_slot::<HostCreateShadowRealmContextCallback>()
1628        .unwrap();
1629      let context = callback(&mut scope);
1630      context.map_or_else(null_mut, |l| l.as_non_null().as_ptr())
1631    }
1632
1633    // Windows x64 ABI: MaybeLocal<Context> must be returned on the stack.
1634    #[cfg(target_os = "windows")]
1635    unsafe extern "C" fn rust_shadow_realm_callback_windows(
1636      rv: *mut *mut Context,
1637      initiator_context: Local<Context>,
1638    ) -> *mut *mut Context {
1639      unsafe {
1640        let ret = rust_shadow_realm_callback(initiator_context);
1641        rv.write(ret);
1642      }
1643      rv
1644    }
1645
1646    let slot_didnt_exist_before = self.set_slot(callback);
1647    if slot_didnt_exist_before {
1648      unsafe {
1649        #[cfg(target_os = "windows")]
1650        v8__Isolate__SetHostCreateShadowRealmContextCallback(
1651          self.as_real_ptr(),
1652          rust_shadow_realm_callback_windows,
1653        );
1654        #[cfg(not(target_os = "windows"))]
1655        v8__Isolate__SetHostCreateShadowRealmContextCallback(
1656          self.as_real_ptr(),
1657          rust_shadow_realm_callback,
1658        );
1659      }
1660    }
1661  }
1662
1663  /// Sets a callback for counting the number of times a feature of V8 is used.
1664  #[inline(always)]
1665  pub fn set_use_counter_callback(&mut self, callback: UseCounterCallback) {
1666    unsafe {
1667      v8__Isolate__SetUseCounterCallback(self.as_real_ptr(), callback);
1668    }
1669  }
1670
1671  /// Enables the host application to receive a notification before a
1672  /// garbage collection. Allocations are allowed in the callback function,
1673  /// but the callback is not re-entrant: if the allocation inside it will
1674  /// trigger the garbage collection, the callback won't be called again.
1675  /// It is possible to specify the GCType filter for your callback. But it is
1676  /// not possible to register the same callback function two times with
1677  /// different GCType filters.
1678  #[allow(clippy::not_unsafe_ptr_arg_deref)] // False positive.
1679  #[inline(always)]
1680  pub fn add_gc_prologue_callback(
1681    &mut self,
1682    callback: GcCallbackWithData,
1683    data: *mut c_void,
1684    gc_type_filter: GCType,
1685  ) {
1686    unsafe {
1687      v8__Isolate__AddGCPrologueCallback(
1688        self.as_real_ptr(),
1689        callback,
1690        data,
1691        gc_type_filter,
1692      );
1693    }
1694  }
1695
1696  /// This function removes callback which was installed by
1697  /// AddGCPrologueCallback function.
1698  #[allow(clippy::not_unsafe_ptr_arg_deref)] // False positive.
1699  #[inline(always)]
1700  pub fn remove_gc_prologue_callback(
1701    &mut self,
1702    callback: GcCallbackWithData,
1703    data: *mut c_void,
1704  ) {
1705    unsafe {
1706      v8__Isolate__RemoveGCPrologueCallback(self.as_real_ptr(), callback, data)
1707    }
1708  }
1709
1710  /// Enables the host application to receive a notification after a
1711  /// garbage collection.
1712  #[allow(clippy::not_unsafe_ptr_arg_deref)] // False positive.
1713  #[inline(always)]
1714  pub fn add_gc_epilogue_callback(
1715    &mut self,
1716    callback: GcCallbackWithData,
1717    data: *mut c_void,
1718    gc_type_filter: GCType,
1719  ) {
1720    unsafe {
1721      v8__Isolate__AddGCEpilogueCallback(
1722        self.as_real_ptr(),
1723        callback,
1724        data,
1725        gc_type_filter,
1726      );
1727    }
1728  }
1729
1730  /// This function removes a callback which was added by
1731  /// `AddGCEpilogueCallback`.
1732  #[allow(clippy::not_unsafe_ptr_arg_deref)] // False positive.
1733  #[inline(always)]
1734  pub fn remove_gc_epilogue_callback(
1735    &mut self,
1736    callback: GcCallbackWithData,
1737    data: *mut c_void,
1738  ) {
1739    unsafe {
1740      v8__Isolate__RemoveGCEpilogueCallback(self.as_real_ptr(), callback, data)
1741    }
1742  }
1743
1744  /// Add a callback to invoke in case the heap size is close to the heap limit.
1745  /// If multiple callbacks are added, only the most recently added callback is
1746  /// invoked.
1747  #[allow(clippy::not_unsafe_ptr_arg_deref)] // False positive.
1748  #[inline(always)]
1749  pub fn add_near_heap_limit_callback(
1750    &mut self,
1751    callback: NearHeapLimitCallback,
1752    data: *mut c_void,
1753  ) {
1754    unsafe {
1755      v8__Isolate__AddNearHeapLimitCallback(self.as_real_ptr(), callback, data)
1756    };
1757  }
1758
1759  /// Remove the given callback and restore the heap limit to the given limit.
1760  /// If the given limit is zero, then it is ignored. If the current heap size
1761  /// is greater than the given limit, then the heap limit is restored to the
1762  /// minimal limit that is possible for the current heap size.
1763  #[inline(always)]
1764  pub fn remove_near_heap_limit_callback(
1765    &mut self,
1766    callback: NearHeapLimitCallback,
1767    heap_limit: usize,
1768  ) {
1769    unsafe {
1770      v8__Isolate__RemoveNearHeapLimitCallback(
1771        self.as_real_ptr(),
1772        callback,
1773        heap_limit,
1774      );
1775    };
1776  }
1777
1778  /// Adjusts the amount of registered external memory. Used to give V8 an
1779  /// indication of the amount of externally allocated memory that is kept
1780  /// alive by JavaScript objects. V8 uses this to decide when to perform
1781  /// global garbage collections. Registering externally allocated memory
1782  /// will trigger global garbage collections more often than it would
1783  /// otherwise in an attempt to garbage collect the JavaScript objects
1784  /// that keep the externally allocated memory alive.
1785  #[inline(always)]
1786  pub fn adjust_amount_of_external_allocated_memory(
1787    &mut self,
1788    change_in_bytes: i64,
1789  ) -> i64 {
1790    unsafe {
1791      v8__Isolate__AdjustAmountOfExternalAllocatedMemory(
1792        self.as_real_ptr(),
1793        change_in_bytes,
1794      )
1795    }
1796  }
1797
1798  #[inline(always)]
1799  pub fn get_cpp_heap(&mut self) -> Option<&Heap> {
1800    unsafe { v8__Isolate__GetCppHeap(self.as_real_ptr()).as_ref() }
1801  }
1802
1803  #[inline(always)]
1804  pub fn set_oom_error_handler(&mut self, callback: OomErrorCallback) {
1805    unsafe { v8__Isolate__SetOOMErrorHandler(self.as_real_ptr(), callback) };
1806  }
1807
1808  /// Returns the policy controlling how Microtasks are invoked.
1809  #[inline(always)]
1810  pub fn get_microtasks_policy(&self) -> MicrotasksPolicy {
1811    unsafe { v8__Isolate__GetMicrotasksPolicy(self.as_real_ptr()) }
1812  }
1813
1814  /// Returns the policy controlling how Microtasks are invoked.
1815  #[inline(always)]
1816  pub fn set_microtasks_policy(&mut self, policy: MicrotasksPolicy) {
1817    unsafe { v8__Isolate__SetMicrotasksPolicy(self.as_real_ptr(), policy) }
1818  }
1819
1820  /// Runs the default MicrotaskQueue until it gets empty and perform other
1821  /// microtask checkpoint steps, such as calling ClearKeptObjects. Asserts that
1822  /// the MicrotasksPolicy is not kScoped. Any exceptions thrown by microtask
1823  /// callbacks are swallowed.
1824  #[inline(always)]
1825  pub fn perform_microtask_checkpoint(&mut self) {
1826    unsafe { v8__Isolate__PerformMicrotaskCheckpoint(self.as_real_ptr()) }
1827  }
1828
1829  /// Enqueues the callback to the default MicrotaskQueue
1830  #[inline(always)]
1831  pub fn enqueue_microtask(&mut self, microtask: Local<Function>) {
1832    unsafe { v8__Isolate__EnqueueMicrotask(self.as_real_ptr(), &*microtask) }
1833  }
1834
1835  /// Set whether calling Atomics.wait (a function that may block) is allowed in
1836  /// this isolate. This can also be configured via
1837  /// CreateParams::allow_atomics_wait.
1838  #[inline(always)]
1839  pub fn set_allow_atomics_wait(&mut self, allow: bool) {
1840    unsafe { v8__Isolate__SetAllowAtomicsWait(self.as_real_ptr(), allow) }
1841  }
1842
1843  /// Embedder injection point for `WebAssembly.compileStreaming(source)`.
1844  /// The expectation is that the embedder sets it at most once.
1845  ///
1846  /// The callback receives the source argument (string, Promise, etc.)
1847  /// and an instance of [WasmStreaming]. The [WasmStreaming] instance
1848  /// can outlive the callback and is used to feed data chunks to V8
1849  /// asynchronously.
1850  #[inline(always)]
1851  pub fn set_wasm_streaming_callback<F>(&mut self, _: F)
1852  where
1853    F: UnitType
1854      + for<'a, 'b, 'c> Fn(
1855        &'c mut PinScope<'a, 'b>,
1856        Local<'a, Value>,
1857        WasmStreaming<false>,
1858      ),
1859  {
1860    unsafe {
1861      v8__Isolate__SetWasmStreamingCallback(
1862        self.as_real_ptr(),
1863        trampoline::<F>(),
1864      )
1865    }
1866  }
1867
1868  /// Notification that the embedder has changed the time zone, daylight savings
1869  /// time or other date / time configuration parameters. V8 keeps a cache of
1870  /// various values used for date / time computation. This notification will
1871  /// reset those cached values for the current context so that date / time
1872  /// configuration changes would be reflected.
1873  ///
1874  /// This API should not be called more than needed as it will negatively impact
1875  /// the performance of date operations.
1876  #[inline(always)]
1877  pub fn date_time_configuration_change_notification(
1878    &mut self,
1879    time_zone_detection: TimeZoneDetection,
1880  ) {
1881    unsafe {
1882      v8__Isolate__DateTimeConfigurationChangeNotification(
1883        self.as_real_ptr(),
1884        time_zone_detection,
1885      );
1886    }
1887  }
1888
1889  /// Returns true if there is ongoing background work within V8 that will
1890  /// eventually post a foreground task, like asynchronous WebAssembly
1891  /// compilation.
1892  #[inline(always)]
1893  pub fn has_pending_background_tasks(&self) -> bool {
1894    unsafe { v8__Isolate__HasPendingBackgroundTasks(self.as_real_ptr()) }
1895  }
1896
1897  /// Request garbage collection with a specific embedderstack state in this
1898  /// Isolate. It is only valid to call this function if --expose_gc was
1899  /// specified.
1900  ///
1901  /// This should only be used for testing purposes and not to enforce a garbage
1902  /// collection schedule. It has strong negative impact on the garbage
1903  /// collection performance. Use IdleNotificationDeadline() or
1904  /// LowMemoryNotification() instead to influence the garbage collection
1905  /// schedule.
1906  #[inline(always)]
1907  pub fn request_garbage_collection_for_testing(
1908    &mut self,
1909    r#type: GarbageCollectionType,
1910  ) {
1911    unsafe {
1912      v8__Isolate__RequestGarbageCollectionForTesting(
1913        self.as_real_ptr(),
1914        match r#type {
1915          GarbageCollectionType::Full => 0,
1916          GarbageCollectionType::Minor => 1,
1917        },
1918      );
1919    }
1920  }
1921
1922  /// Disposes the isolate.  The isolate must not be entered by any
1923  /// thread to be disposable.
1924  unsafe fn dispose(&mut self) {
1925    // No test case in rusty_v8 show this, but there have been situations in
1926    // deno where dropping Annex before the states causes a segfault.
1927    unsafe {
1928      v8__Isolate__Dispose(self.as_real_ptr());
1929    }
1930  }
1931
1932  /// Take a heap snapshot. The callback is invoked one or more times
1933  /// with byte slices containing the snapshot serialized as JSON.
1934  /// It's the callback's responsibility to reassemble them into
1935  /// a single document, e.g., by writing them to a file.
1936  /// Note that Chrome DevTools refuses to load snapshots without
1937  /// a .heapsnapshot suffix.
1938  pub fn take_heap_snapshot<F>(&mut self, mut callback: F)
1939  where
1940    F: FnMut(&[u8]) -> bool,
1941  {
1942    unsafe extern "C" fn trampoline<F>(
1943      arg: *mut c_void,
1944      data: *const u8,
1945      size: usize,
1946    ) -> bool
1947    where
1948      F: FnMut(&[u8]) -> bool,
1949    {
1950      unsafe {
1951        let mut callback = NonNull::<F>::new_unchecked(arg as _);
1952        if size > 0 {
1953          (callback.as_mut())(std::slice::from_raw_parts(data, size))
1954        } else {
1955          (callback.as_mut())(&[])
1956        }
1957      }
1958    }
1959
1960    let arg = addr_of_mut!(callback);
1961    unsafe {
1962      v8__HeapProfiler__TakeHeapSnapshot(
1963        self.as_real_ptr(),
1964        trampoline::<F>,
1965        arg as _,
1966      );
1967    }
1968  }
1969
1970  /// Set the default context to be included in the snapshot blob.
1971  /// The snapshot will not contain the global proxy, and we expect one or a
1972  /// global object template to create one, to be provided upon deserialization.
1973  ///
1974  /// # Panics
1975  ///
1976  /// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
1977  #[inline(always)]
1978  pub fn set_default_context(&mut self, context: Local<Context>) {
1979    let snapshot_creator = self
1980      .get_annex_mut()
1981      .maybe_snapshot_creator
1982      .as_mut()
1983      .unwrap();
1984    snapshot_creator.set_default_context(context);
1985  }
1986
1987  /// Add additional context to be included in the snapshot blob.
1988  /// The snapshot will include the global proxy.
1989  ///
1990  /// Returns the index of the context in the snapshot blob.
1991  ///
1992  /// # Panics
1993  ///
1994  /// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
1995  #[inline(always)]
1996  pub fn add_context(&mut self, context: Local<Context>) -> usize {
1997    let snapshot_creator = self
1998      .get_annex_mut()
1999      .maybe_snapshot_creator
2000      .as_mut()
2001      .unwrap();
2002    snapshot_creator.add_context(context)
2003  }
2004
2005  /// Attach arbitrary `v8::Data` to the isolate snapshot, which can be
2006  /// retrieved via `HandleScope::get_context_data_from_snapshot_once()` after
2007  /// deserialization. This data does not survive when a new snapshot is created
2008  /// from an existing snapshot.
2009  ///
2010  /// # Panics
2011  ///
2012  /// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
2013  #[inline(always)]
2014  pub fn add_isolate_data<T>(&mut self, data: Local<T>) -> usize
2015  where
2016    for<'l> Local<'l, T>: Into<Local<'l, Data>>,
2017  {
2018    let snapshot_creator = self
2019      .get_annex_mut()
2020      .maybe_snapshot_creator
2021      .as_mut()
2022      .unwrap();
2023    snapshot_creator.add_isolate_data(data)
2024  }
2025
2026  /// Attach arbitrary `v8::Data` to the context snapshot, which can be
2027  /// retrieved via `HandleScope::get_context_data_from_snapshot_once()` after
2028  /// deserialization. This data does not survive when a new snapshot is
2029  /// created from an existing snapshot.
2030  ///
2031  /// # Panics
2032  ///
2033  /// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
2034  #[inline(always)]
2035  pub fn add_context_data<T>(
2036    &mut self,
2037    context: Local<Context>,
2038    data: Local<T>,
2039  ) -> usize
2040  where
2041    for<'l> Local<'l, T>: Into<Local<'l, Data>>,
2042  {
2043    let snapshot_creator = self
2044      .get_annex_mut()
2045      .maybe_snapshot_creator
2046      .as_mut()
2047      .unwrap();
2048    snapshot_creator.add_context_data(context, data)
2049  }
2050}
2051
2052pub(crate) struct IsolateAnnex {
2053  // Wrapped in `Option` so teardown can `take()` it through a `&mut
2054  // IsolateAnnex` without having to move ownership of the whole annex out
2055  // of `ANNEX_SLOT`. Only `prepare_annex_for_dispose` consumes it; that
2056  // function runs at most once per annex, so the `unwrap()` there can
2057  // never observe a `None`.
2058  create_param_allocations: Option<Box<dyn Any>>,
2059  slots: HashMap<TypeId, RawSlot, BuildTypeIdHasher>,
2060  finalizer_map: FinalizerMap,
2061  maybe_snapshot_creator: Option<SnapshotCreator>,
2062  isolate_handle: IsolateHandle,
2063  global_liveness: NonNull<IsolateLiveness>,
2064}
2065
2066impl IsolateAnnex {
2067  fn new(isolate: &Isolate, create_param_allocations: Box<dyn Any>) -> Self {
2068    // Globals may be dropped after their host isolate is disposed. Keep this
2069    // tiny liveness cell valid so those late drops can observe the null isolate
2070    // pointer without retaining an Arc per Global.
2071    let global_liveness = Box::leak(Box::new(IsolateLiveness::new(isolate)));
2072    Self {
2073      create_param_allocations: Some(create_param_allocations),
2074      slots: HashMap::default(),
2075      finalizer_map: FinalizerMap::default(),
2076      maybe_snapshot_creator: None,
2077      isolate_handle: IsolateHandle::new(isolate),
2078      global_liveness: NonNull::from(global_liveness),
2079    }
2080  }
2081
2082  #[inline(always)]
2083  fn global_liveness(&self) -> &IsolateLiveness {
2084    unsafe { self.global_liveness.as_ref() }
2085  }
2086
2087  #[inline(always)]
2088  pub(crate) fn get_slot<T: 'static>(&self) -> Option<&T> {
2089    self
2090      .slots
2091      .get(&TypeId::of::<T>())
2092      .map(|slot| unsafe { slot.borrow::<T>() })
2093  }
2094
2095  #[inline(always)]
2096  pub(crate) fn get_slot_mut<T: 'static>(&mut self) -> Option<&mut T> {
2097    self
2098      .slots
2099      .get_mut(&TypeId::of::<T>())
2100      .map(|slot| unsafe { slot.borrow_mut::<T>() })
2101  }
2102
2103  #[inline(always)]
2104  pub(crate) fn set_slot<T: 'static>(&mut self, value: T) -> bool {
2105    self
2106      .slots
2107      .insert(TypeId::of::<T>(), RawSlot::new(value))
2108      .is_none()
2109  }
2110
2111  #[inline(always)]
2112  pub(crate) fn remove_slot<T: 'static>(&mut self) -> Option<T> {
2113    self
2114      .slots
2115      .remove(&TypeId::of::<T>())
2116      .map(|slot| unsafe { slot.into_inner::<T>() })
2117  }
2118}
2119
2120pub(crate) struct IsolateLiveness {
2121  isolate: AtomicPtr<RealIsolate>,
2122}
2123
2124impl IsolateLiveness {
2125  #[inline(always)]
2126  fn new(isolate: &Isolate) -> Self {
2127    Self {
2128      isolate: AtomicPtr::new(isolate.as_real_ptr()),
2129    }
2130  }
2131
2132  #[inline(always)]
2133  fn dispose(&self) {
2134    self
2135      .isolate
2136      .store(null_mut(), std::sync::atomic::Ordering::Relaxed);
2137  }
2138
2139  #[inline(always)]
2140  pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate {
2141    self.isolate.load(std::sync::atomic::Ordering::Relaxed)
2142  }
2143}
2144
2145impl Debug for IsolateAnnex {
2146  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2147    f.debug_struct("IsolateAnnex")
2148      .field("isolate_handle", &self.isolate_handle)
2149      .finish()
2150  }
2151}
2152
2153pub(crate) struct IsolateHandleInner {
2154  /// Safety invariants:
2155  /// - The 'main thread' must lock the mutex and reset `isolate` to null just
2156  ///   before the isolate is disposed.
2157  /// - Any other thread must lock the mutex while it's reading/using the
2158  ///   `isolate` pointer.
2159  // These two fields can be replaced with a `Mutex<*mut RealIsolate>` once
2160  // `Mutex::data_ptr()` is stabilized.
2161  isolate: UnsafeCell<*mut RealIsolate>,
2162  isolate_mutex: Mutex<()>,
2163}
2164
2165unsafe impl Send for IsolateHandleInner {}
2166unsafe impl Sync for IsolateHandleInner {}
2167
2168/// IsolateHandle is a thread-safe reference to an Isolate. Its main use is to
2169/// terminate execution of a running isolate from another thread.
2170///
2171/// It is created with [`Isolate::thread_safe_handle()`].
2172///
2173/// IsolateHandle is Cloneable, Send, and Sync.
2174#[derive(Clone)]
2175pub struct IsolateHandle(Arc<IsolateHandleInner>);
2176
2177impl fmt::Debug for IsolateHandle {
2178  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2179    if let Ok(_lock) = self.0.isolate_mutex.try_lock() {
2180      // SAFETY: mutex lock is held
2181      let ptr = unsafe { *self.0.isolate.get() };
2182      f.debug_struct("IsolateHandle")
2183        .field("isolate_ptr", &ptr)
2184        .finish()
2185    } else {
2186      f.debug_struct("IsolateHandle").finish_non_exhaustive()
2187    }
2188  }
2189}
2190
2191impl IsolateHandle {
2192  #[inline(always)]
2193  fn new(isolate: &Isolate) -> Self {
2194    let inner = Arc::new(IsolateHandleInner {
2195      isolate: UnsafeCell::new(isolate.as_real_ptr()),
2196      isolate_mutex: Mutex::new(()),
2197    });
2198    Self(inner)
2199  }
2200
2201  /// Set the inner isolate pointer to null.
2202  fn dispose(&self) {
2203    let _lock = self.0.isolate_mutex.lock().unwrap();
2204    // SAFETY: mutex lock is held
2205    unsafe { *self.0.isolate.get() = null_mut() }
2206  }
2207
2208  /// Access the isolate, if it hasn't yet been disposed of.
2209  ///
2210  /// A lock is taken on the pointer and held for the scope of `f`, which
2211  /// means the isolate can't be dropped until after `f` returns. If you
2212  /// do something with the isolate afterwards, that needs to be verified
2213  /// to be safe separately.
2214  pub(crate) fn with_isolate_ptr<R>(
2215    &self,
2216    f: impl FnOnce(NonNull<RealIsolate>) -> R,
2217  ) -> Option<R> {
2218    let _lock = self.0.isolate_mutex.lock().unwrap();
2219    // SAFETY: mutex lock is held
2220    let ptr = unsafe { *self.0.isolate.get() };
2221    NonNull::new(ptr).map(f)
2222  }
2223
2224  /// Access the pointer for this isolate - it may be null.
2225  ///
2226  /// # Safety
2227  /// This function must only be called from the main thread associated with
2228  /// the V8 isolate.
2229  // TODO: have this return an `Option<NonNull<RealIsolate>>`
2230  pub(crate) unsafe fn get_isolate_ptr(&self) -> *mut RealIsolate {
2231    // SAFETY: this function must only be called from the main thread of the
2232    // isolate. On that thread, the caller cannot race with teardown code that
2233    // sets this pointer to null.
2234    unsafe { *self.0.isolate.get() }
2235  }
2236
2237  /// Forcefully terminate the current thread of JavaScript execution
2238  /// in the given isolate.
2239  ///
2240  /// This method can be used by any thread even if that thread has not
2241  /// acquired the V8 lock with a Locker object.
2242  ///
2243  /// Returns false if Isolate was already destroyed.
2244  #[inline(always)]
2245  pub fn terminate_execution(&self) -> bool {
2246    self
2247      .with_isolate_ptr(|isolate| unsafe {
2248        v8__Isolate__TerminateExecution(isolate.as_ptr())
2249      })
2250      .is_some()
2251  }
2252
2253  /// Resume execution capability in the given isolate, whose execution
2254  /// was previously forcefully terminated using TerminateExecution().
2255  ///
2256  /// When execution is forcefully terminated using TerminateExecution(),
2257  /// the isolate can not resume execution until all JavaScript frames
2258  /// have propagated the uncatchable exception which is generated.  This
2259  /// method allows the program embedding the engine to handle the
2260  /// termination event and resume execution capability, even if
2261  /// JavaScript frames remain on the stack.
2262  ///
2263  /// This method can be used by any thread even if that thread has not
2264  /// acquired the V8 lock with a Locker object.
2265  ///
2266  /// Returns false if Isolate was already destroyed.
2267  #[inline(always)]
2268  pub fn cancel_terminate_execution(&self) -> bool {
2269    self
2270      .with_isolate_ptr(|isolate| unsafe {
2271        v8__Isolate__CancelTerminateExecution(isolate.as_ptr())
2272      })
2273      .is_some()
2274  }
2275
2276  /// Is V8 terminating JavaScript execution.
2277  ///
2278  /// Returns true if JavaScript execution is currently terminating
2279  /// because of a call to TerminateExecution.  In that case there are
2280  /// still JavaScript frames on the stack and the termination
2281  /// exception is still active.
2282  ///
2283  /// Returns false if Isolate was already destroyed.
2284  #[inline(always)]
2285  pub fn is_execution_terminating(&self) -> bool {
2286    self
2287      .with_isolate_ptr(|isolate| unsafe {
2288        v8__Isolate__IsExecutionTerminating(isolate.as_ptr())
2289      })
2290      .unwrap_or(false)
2291  }
2292
2293  /// Request V8 to interrupt long running JavaScript code and invoke
2294  /// the given |callback| passing the given |data| to it. After |callback|
2295  /// returns control will be returned to the JavaScript code.
2296  /// There may be a number of interrupt requests in flight.
2297  /// Can be called from another thread without acquiring a |Locker|.
2298  /// Registered |callback| must not reenter interrupted Isolate.
2299  ///
2300  /// Returns false if Isolate was already destroyed.
2301  // Clippy warns that this method is dereferencing a raw pointer, but it is
2302  // not: https://github.com/rust-lang/rust-clippy/issues/3045
2303  #[allow(clippy::not_unsafe_ptr_arg_deref)]
2304  #[inline(always)]
2305  pub fn request_interrupt(
2306    &self,
2307    callback: InterruptCallback,
2308    data: *mut c_void,
2309  ) -> bool {
2310    self
2311      .with_isolate_ptr(|isolate| unsafe {
2312        v8__Isolate__RequestInterrupt(isolate.as_ptr(), callback, data)
2313      })
2314      .is_some()
2315  }
2316}
2317
2318/// Same as Isolate but gets disposed when it goes out of scope.
2319#[derive(Debug)]
2320pub struct OwnedIsolate {
2321  cxx_isolate: NonNull<RealIsolate>,
2322}
2323
2324impl OwnedIsolate {
2325  pub(crate) fn new(cxx_isolate: *mut RealIsolate) -> Self {
2326    let isolate = Self::new_already_entered(cxx_isolate);
2327    unsafe {
2328      isolate.enter();
2329    }
2330    isolate
2331  }
2332
2333  pub(crate) fn new_already_entered(cxx_isolate: *mut RealIsolate) -> Self {
2334    let cxx_isolate = NonNull::new(cxx_isolate).unwrap();
2335    let owned_isolate: OwnedIsolate = Self { cxx_isolate };
2336    // owned_isolate.init_scope_root();
2337    owned_isolate
2338  }
2339}
2340
2341impl Drop for OwnedIsolate {
2342  fn drop(&mut self) {
2343    unsafe {
2344      let snapshot_creator = self.get_annex_mut().maybe_snapshot_creator.take();
2345      assert!(
2346        snapshot_creator.is_none(),
2347        "If isolate was created using v8::Isolate::snapshot_creator, you should use v8::OwnedIsolate::create_blob before dropping an isolate."
2348      );
2349      // Safety: We need to check `this == Isolate::GetCurrent()` before calling exit()
2350      assert!(
2351        std::ptr::eq(self.cxx_isolate.as_mut(), v8__Isolate__GetCurrent()),
2352        "v8::OwnedIsolate instances must be dropped in the reverse order of creation. They are entered upon creation and exited upon being dropped."
2353      );
2354      // self.dispose_scope_root();
2355      self.exit();
2356      let (annex_ptr, _create_param_allocations) =
2357        self.prepare_annex_for_dispose();
2358      // Drain finalizers registered up to this point, before V8's final
2359      // teardown GC has a chance to fire weak callbacks that need the
2360      // annex.
2361      Isolate::run_remaining_guaranteed_finalizers(annex_ptr);
2362      Platform::notify_isolate_shutdown(&get_current_platform(), self);
2363      // V8's final teardown runs here. `ANNEX_SLOT` still references the
2364      // (drained) annex, so any re-entrant access from weak callbacks or
2365      // embedder code resolves normally instead of panicking on a null
2366      // slot.
2367      self.dispose();
2368      // Drain finalizers V8 may have registered during teardown, then free
2369      // the annex allocation. V8 has fully disposed the isolate, so its
2370      // embedder data storage no longer exists and `ANNEX_SLOT` needs no
2371      // explicit clearing.
2372      Isolate::finish_annex_dispose(annex_ptr);
2373    }
2374  }
2375}
2376
2377impl OwnedIsolate {
2378  /// Creates a snapshot data blob.
2379  /// This must not be called from within a handle scope.
2380  ///
2381  /// # Panics
2382  ///
2383  /// Panics if the isolate was not created using [`Isolate::snapshot_creator`]
2384  #[inline(always)]
2385  pub fn create_blob(
2386    mut self,
2387    function_code_handling: FunctionCodeHandling,
2388  ) -> Option<StartupData> {
2389    let mut snapshot_creator =
2390      self.get_annex_mut().maybe_snapshot_creator.take().unwrap();
2391
2392    // create_param_allocations is needed during CreateBlob
2393    // so v8 can read external references
2394    let _create_param_allocations = unsafe {
2395      // self.dispose_scope_root();
2396      self.dispose_annex()
2397    };
2398
2399    // The isolate is owned by the snapshot creator; we need to forget it
2400    // here as the snapshot creator will drop it when running the destructor.
2401    std::mem::forget(self);
2402    snapshot_creator.create_blob(function_code_handling)
2403  }
2404}
2405
2406impl Deref for OwnedIsolate {
2407  type Target = Isolate;
2408  fn deref(&self) -> &Self::Target {
2409    unsafe {
2410      std::mem::transmute::<&NonNull<RealIsolate>, &Isolate>(&self.cxx_isolate)
2411    }
2412  }
2413}
2414
2415impl DerefMut for OwnedIsolate {
2416  fn deref_mut(&mut self) -> &mut Self::Target {
2417    unsafe {
2418      std::mem::transmute::<&mut NonNull<RealIsolate>, &mut Isolate>(
2419        &mut self.cxx_isolate,
2420      )
2421    }
2422  }
2423}
2424
2425impl AsMut<Isolate> for OwnedIsolate {
2426  fn as_mut(&mut self) -> &mut Isolate {
2427    self
2428  }
2429}
2430
2431impl AsMut<Isolate> for Isolate {
2432  fn as_mut(&mut self) -> &mut Isolate {
2433    self
2434  }
2435}
2436
2437/// Collection of V8 heap information.
2438///
2439/// Instances of this class can be passed to v8::Isolate::GetHeapStatistics to
2440/// get heap statistics from V8.
2441pub struct HeapStatistics(v8__HeapStatistics);
2442
2443impl HeapStatistics {
2444  #[inline(always)]
2445  pub fn total_heap_size(&self) -> usize {
2446    self.0.total_heap_size_
2447  }
2448
2449  #[inline(always)]
2450  pub fn total_heap_size_executable(&self) -> usize {
2451    self.0.total_heap_size_executable_
2452  }
2453
2454  #[inline(always)]
2455  pub fn total_physical_size(&self) -> usize {
2456    self.0.total_physical_size_
2457  }
2458
2459  #[inline(always)]
2460  pub fn total_available_size(&self) -> usize {
2461    self.0.total_available_size_
2462  }
2463
2464  #[inline(always)]
2465  pub fn total_global_handles_size(&self) -> usize {
2466    self.0.total_global_handles_size_
2467  }
2468
2469  #[inline(always)]
2470  pub fn used_global_handles_size(&self) -> usize {
2471    self.0.used_global_handles_size_
2472  }
2473
2474  #[inline(always)]
2475  pub fn used_heap_size(&self) -> usize {
2476    self.0.used_heap_size_
2477  }
2478
2479  #[inline(always)]
2480  pub fn heap_size_limit(&self) -> usize {
2481    self.0.heap_size_limit_
2482  }
2483
2484  #[inline(always)]
2485  pub fn malloced_memory(&self) -> usize {
2486    self.0.malloced_memory_
2487  }
2488
2489  #[inline(always)]
2490  pub fn external_memory(&self) -> usize {
2491    self.0.external_memory_
2492  }
2493
2494  #[inline(always)]
2495  pub fn peak_malloced_memory(&self) -> usize {
2496    self.0.peak_malloced_memory_
2497  }
2498
2499  #[inline(always)]
2500  pub fn number_of_native_contexts(&self) -> usize {
2501    self.0.number_of_native_contexts_
2502  }
2503
2504  #[inline(always)]
2505  pub fn number_of_detached_contexts(&self) -> usize {
2506    self.0.number_of_detached_contexts_
2507  }
2508
2509  /// Returns the total number of bytes allocated since the Isolate was created.
2510  /// This includes all heap objects allocated in any space (new, old, code,
2511  /// etc.).
2512  #[inline(always)]
2513  pub fn total_allocated_bytes(&self) -> u64 {
2514    self.0.total_allocated_bytes_
2515  }
2516
2517  /// Returns a 0/1 boolean, which signifies whether the V8 overwrite heap
2518  /// garbage with a bit pattern.
2519  #[inline(always)]
2520  pub fn does_zap_garbage(&self) -> bool {
2521    self.0.does_zap_garbage_
2522  }
2523}
2524
2525pub struct HeapSpaceStatistics(v8__HeapSpaceStatistics);
2526
2527impl HeapSpaceStatistics {
2528  pub fn space_name(&self) -> &'static CStr {
2529    unsafe { CStr::from_ptr(self.0.space_name_) }
2530  }
2531
2532  pub fn space_size(&self) -> usize {
2533    self.0.space_size_
2534  }
2535
2536  pub fn space_used_size(&self) -> usize {
2537    self.0.space_used_size_
2538  }
2539
2540  pub fn space_available_size(&self) -> usize {
2541    self.0.space_available_size_
2542  }
2543
2544  pub fn physical_space_size(&self) -> usize {
2545    self.0.physical_space_size_
2546  }
2547}
2548
2549pub struct HeapCodeStatistics(v8__HeapCodeStatistics);
2550
2551impl HeapCodeStatistics {
2552  pub fn code_and_metadata_size(&self) -> usize {
2553    self.0.code_and_metadata_size_
2554  }
2555
2556  pub fn bytecode_and_metadata_size(&self) -> usize {
2557    self.0.bytecode_and_metadata_size_
2558  }
2559
2560  pub fn external_script_source_size(&self) -> usize {
2561    self.0.external_script_source_size_
2562  }
2563
2564  pub fn cpu_profiler_metadata_size(&self) -> usize {
2565    self.0.cpu_profiler_metadata_size_
2566  }
2567}
2568
2569impl<'s, F> MapFnFrom<F> for PrepareStackTraceCallback<'s>
2570where
2571  F: UnitType
2572    + for<'a> Fn(
2573      &mut PinScope<'s, 'a>,
2574      Local<'s, Value>,
2575      Local<'s, Array>,
2576    ) -> Local<'s, Value>,
2577{
2578  // Windows x64 ABI: MaybeLocal<Value> returned on the stack.
2579  #[cfg(target_os = "windows")]
2580  fn mapping() -> Self {
2581    let f = |ret_ptr, context, error, sites| {
2582      let scope = pin!(unsafe { CallbackScope::new(context) });
2583      let mut scope: crate::PinnedRef<CallbackScope> = scope.init();
2584      let r = (F::get())(&mut scope, error, sites);
2585      unsafe { std::ptr::write(ret_ptr, &*r as *const _) };
2586      ret_ptr
2587    };
2588    f.to_c_fn()
2589  }
2590
2591  // System V ABI
2592  #[cfg(not(target_os = "windows"))]
2593  fn mapping() -> Self {
2594    let f = |context, error, sites| {
2595      let scope = pin!(unsafe { CallbackScope::new(context) });
2596      let mut scope: crate::PinnedRef<CallbackScope> = scope.init();
2597
2598      let r = (F::get())(&mut scope, error, sites);
2599      PrepareStackTraceCallbackRet(&*r as *const _)
2600    };
2601    f.to_c_fn()
2602  }
2603}
2604
2605/// A special hasher that is optimized for hashing `std::any::TypeId` values.
2606/// `TypeId` values are actually 64-bit values which themselves come out of some
2607/// hash function, so it's unnecessary to shuffle their bits any further.
2608#[derive(Clone, Default)]
2609pub(crate) struct TypeIdHasher {
2610  state: Option<u64>,
2611}
2612
2613impl Hasher for TypeIdHasher {
2614  fn write(&mut self, _bytes: &[u8]) {
2615    panic!("TypeIdHasher::write() called unexpectedly");
2616  }
2617
2618  #[inline]
2619  fn write_u64(&mut self, value: u64) {
2620    // The internal hash function of TypeId only takes the bottom 64-bits, even on versions
2621    // of Rust that use a 128-bit TypeId.
2622    let prev_state = self.state.replace(value);
2623    debug_assert_eq!(prev_state, None);
2624  }
2625
2626  #[inline]
2627  fn finish(&self) -> u64 {
2628    self.state.unwrap()
2629  }
2630}
2631
2632/// Factory for instances of `TypeIdHasher`. This is the type that one would
2633/// pass to the constructor of some map/set type in order to make it use
2634/// `TypeIdHasher` instead of the default hasher implementation.
2635#[derive(Copy, Clone, Default)]
2636pub(crate) struct BuildTypeIdHasher;
2637
2638impl BuildHasher for BuildTypeIdHasher {
2639  type Hasher = TypeIdHasher;
2640
2641  #[inline]
2642  fn build_hasher(&self) -> Self::Hasher {
2643    Default::default()
2644  }
2645}
2646
2647const _: () = {
2648  assert!(
2649    size_of::<TypeId>() == size_of::<u64>()
2650      || size_of::<TypeId>() == size_of::<u128>()
2651  );
2652  assert!(
2653    align_of::<TypeId>() == align_of::<u64>()
2654      || align_of::<TypeId>() == align_of::<u128>()
2655  );
2656};
2657
2658pub(crate) struct RawSlot {
2659  data: RawSlotData,
2660  dtor: Option<RawSlotDtor>,
2661}
2662
2663type RawSlotData = MaybeUninit<usize>;
2664type RawSlotDtor = unsafe fn(&mut RawSlotData) -> ();
2665
2666impl RawSlot {
2667  #[inline]
2668  pub fn new<T: 'static>(value: T) -> Self {
2669    if Self::needs_box::<T>() {
2670      Self::new_internal(Box::new(value))
2671    } else {
2672      Self::new_internal(value)
2673    }
2674  }
2675
2676  // SAFETY: a valid value of type `T` must haven been stored in the slot
2677  // earlier. There is no verification that the type param provided by the
2678  // caller is correct.
2679  #[inline]
2680  pub unsafe fn borrow<T: 'static>(&self) -> &T {
2681    unsafe {
2682      if Self::needs_box::<T>() {
2683        &*(self.data.as_ptr() as *const Box<T>)
2684      } else {
2685        &*(self.data.as_ptr() as *const T)
2686      }
2687    }
2688  }
2689
2690  // Safety: see [`RawSlot::borrow`].
2691  #[inline]
2692  pub unsafe fn borrow_mut<T: 'static>(&mut self) -> &mut T {
2693    unsafe {
2694      if Self::needs_box::<T>() {
2695        &mut *(self.data.as_mut_ptr() as *mut Box<T>)
2696      } else {
2697        &mut *(self.data.as_mut_ptr() as *mut T)
2698      }
2699    }
2700  }
2701
2702  // Safety: see [`RawSlot::borrow`].
2703  #[inline]
2704  pub unsafe fn into_inner<T: 'static>(self) -> T {
2705    unsafe {
2706      let value = if Self::needs_box::<T>() {
2707        *std::ptr::read(self.data.as_ptr() as *mut Box<T>)
2708      } else {
2709        std::ptr::read(self.data.as_ptr() as *mut T)
2710      };
2711      forget(self);
2712      value
2713    }
2714  }
2715
2716  const fn needs_box<T: 'static>() -> bool {
2717    size_of::<T>() > size_of::<RawSlotData>()
2718      || align_of::<T>() > align_of::<RawSlotData>()
2719  }
2720
2721  #[inline]
2722  fn new_internal<B: 'static>(value: B) -> Self {
2723    assert!(!Self::needs_box::<B>());
2724    let mut self_ = Self {
2725      data: RawSlotData::zeroed(),
2726      dtor: None,
2727    };
2728    unsafe {
2729      ptr::write(self_.data.as_mut_ptr() as *mut B, value);
2730    }
2731    if needs_drop::<B>() {
2732      self_.dtor.replace(Self::drop_internal::<B>);
2733    };
2734    self_
2735  }
2736
2737  // SAFETY: a valid value of type `T` or `Box<T>` must be stored in the slot.
2738  unsafe fn drop_internal<B: 'static>(data: &mut RawSlotData) {
2739    assert!(!Self::needs_box::<B>());
2740    unsafe {
2741      drop_in_place(data.as_mut_ptr() as *mut B);
2742    }
2743  }
2744}
2745
2746impl Drop for RawSlot {
2747  fn drop(&mut self) {
2748    if let Some(dtor) = self.dtor {
2749      unsafe { dtor(&mut self.data) };
2750    }
2751  }
2752}
2753
2754impl AsRef<Isolate> for OwnedIsolate {
2755  fn as_ref(&self) -> &Isolate {
2756    unsafe { Isolate::from_raw_ref(&self.cxx_isolate) }
2757  }
2758}
2759impl AsRef<Isolate> for Isolate {
2760  fn as_ref(&self) -> &Isolate {
2761    self
2762  }
2763}