1use super::SnapshotStoreDataStore;
4use super::SnapshottedData;
5use super::bindings;
6use super::bindings::create_exports_for_ops_virtual_module;
7use super::bindings::watch_promise;
8use super::exception_state::ExceptionState;
9use super::jsrealm::JsRealmInner;
10use super::op_driver::OpDriver;
11use super::setup;
12use super::snapshot;
13use super::stats::RuntimeActivityStatsFactory;
14use super::v8_static_strings::*;
15use crate::Extension;
16use crate::ExtensionArguments;
17use crate::ExtensionFileSource;
18use crate::ExtensionFileSourceCode;
19use crate::FastStaticString;
20use crate::FastString;
21use crate::ModuleCodeString;
22use crate::NoopModuleLoader;
23use crate::OpMetadata;
24use crate::OpMetricsEvent;
25use crate::OpStackTraceCallback;
26use crate::OpState;
27use crate::ascii_str;
28use crate::ascii_str_include;
29use crate::cppgc::FunctionTemplateData;
30use crate::error::CoreError;
31use crate::error::CoreErrorKind;
32use crate::error::CoreModuleExecuteError;
33use crate::error::CoreModuleParseError;
34use crate::error::ExtensionLazyInitCountMismatchError;
35use crate::error::ExtensionLazyInitOrderMismatchError;
36use crate::error::JsError;
37use crate::error::exception_to_err_result;
38use crate::extension_set;
39use crate::extension_set::LoadedSources;
40use crate::extensions::GlobalObjectMiddlewareFn;
41use crate::extensions::GlobalTemplateMiddlewareFn;
42use crate::inspector::JsRuntimeInspector;
43use crate::module_specifier::ModuleSpecifier;
44use crate::modules::CustomModuleEvaluationCb;
45use crate::modules::EvalContextCodeCacheReadyCb;
46use crate::modules::EvalContextGetCodeCacheCb;
47use crate::modules::ExtCodeCache;
48use crate::modules::ExtModuleLoader;
49use crate::modules::IntoModuleCodeString;
50use crate::modules::IntoModuleName;
51use crate::modules::ModuleId;
52use crate::modules::ModuleLoader;
53use crate::modules::ModuleMap;
54use crate::modules::ModuleName;
55use crate::modules::RequestedModuleType;
56use crate::modules::ValidateImportAttributesCb;
57use crate::modules::script_origin;
58use crate::ops_metrics::OpMetricsFactoryFn;
59use crate::ops_metrics::dispatch_metrics_async;
60use crate::runtime::ContextState;
61use crate::runtime::JsRealm;
62use crate::runtime::OpDriverImpl;
63use crate::runtime::jsrealm;
64use crate::source_map::SourceMapData;
65use crate::source_map::SourceMapper;
66use crate::stats::RuntimeActivityType;
67use deno_error::JsErrorBox;
68use futures::FutureExt;
69use futures::task::AtomicWaker;
70use smallvec::SmallVec;
71use std::any::Any;
72use std::future::Future;
73use std::future::poll_fn;
74use v8::MessageErrorLevel;
75
76use std::cell::Cell;
77use std::cell::RefCell;
78use std::collections::HashMap;
79use std::collections::VecDeque;
80use std::ffi::c_void;
81use std::mem::ManuallyDrop;
82use std::ops::Deref;
83use std::ops::DerefMut;
84use std::pin::Pin;
85use std::rc::Rc;
86use std::sync::Arc;
87use std::sync::Mutex;
88use std::task::Context;
89use std::task::Poll;
90use std::task::Waker;
91
92pub type WaitForInspectorDisconnectCallback = Box<dyn Fn()>;
93const STATE_DATA_OFFSET: u32 = 0;
94
95pub type ExtensionTranspiler =
96 dyn Fn(
97 ModuleName,
98 ModuleCodeString,
99 ) -> Result<(ModuleCodeString, Option<SourceMapData>), JsErrorBox>;
100
101#[derive(Default)]
103pub(crate) struct IsolateAllocations {
104 pub(crate) externalized_sources: Box<[v8::OneByteConst]>,
105 pub(crate) original_sources: Box<[FastString]>,
106 pub(crate) near_heap_limit_callback_data:
107 Option<(Box<RefCell<dyn Any>>, v8::NearHeapLimitCallback)>,
108}
109
110pub(crate) struct ManuallyDropRc<T>(ManuallyDrop<Rc<T>>);
113
114impl<T> ManuallyDropRc<T> {
115 #[allow(unused)]
116 pub fn clone(&self) -> Rc<T> {
117 self.0.deref().clone()
118 }
119}
120
121impl<T> Deref for ManuallyDropRc<T> {
122 type Target = Rc<T>;
123 fn deref(&self) -> &Self::Target {
124 self.0.deref()
125 }
126}
127
128impl<T> DerefMut for ManuallyDropRc<T> {
129 fn deref_mut(&mut self) -> &mut Self::Target {
130 self.0.deref_mut()
131 }
132}
133
134pub(crate) struct InnerIsolateState {
147 will_snapshot: bool,
148 extensions: Vec<&'static str>,
149 op_count: usize,
150 source_count: usize,
151 addl_refs_count: usize,
152 main_realm: ManuallyDrop<JsRealm>,
153 pub(crate) state: ManuallyDropRc<JsRuntimeState>,
154 v8_isolate: ManuallyDrop<v8::OwnedIsolate>,
155}
156
157impl InnerIsolateState {
158 pub fn prepare_for_cleanup(&mut self) {
162 self.main_realm.0.context_state.pending_ops.shutdown();
165 let inspector = self.state.inspector.take();
166 self.state.op_state.borrow_mut().clear();
167 if let Some(inspector) = inspector {
168 assert_eq!(
169 Rc::strong_count(&inspector),
170 1,
171 "The inspector must be dropped before the runtime"
172 );
173 }
174 }
175
176 pub fn cleanup(&mut self) {
177 self.prepare_for_cleanup();
178
179 let state_ptr = self.v8_isolate.get_data(STATE_DATA_OFFSET);
180 _ = unsafe { Rc::from_raw(state_ptr as *const JsRuntimeState) };
183
184 unsafe {
185 ManuallyDrop::take(&mut self.main_realm).0.destroy();
186 }
187
188 debug_assert_eq!(Rc::strong_count(&self.state), 1);
189 }
190
191 pub fn prepare_for_snapshot(mut self) -> v8::OwnedIsolate {
192 self.cleanup();
193
194 unsafe {
196 ManuallyDrop::drop(&mut self.state.0);
197
198 let isolate = ManuallyDrop::take(&mut self.v8_isolate);
199
200 std::mem::forget(self);
201
202 isolate
203 }
204 }
205}
206
207impl Drop for InnerIsolateState {
208 fn drop(&mut self) {
209 self.cleanup();
210 unsafe {
212 ManuallyDrop::drop(&mut self.state.0);
213
214 if self.will_snapshot {
215 #[allow(clippy::print_stderr)]
217 {
218 eprintln!("WARNING: v8::OwnedIsolate for snapshot was leaked");
219 }
220 } else {
221 ManuallyDrop::drop(&mut self.v8_isolate);
222 }
223 }
224 }
225}
226
227#[derive(Copy, Clone, Debug, Eq, PartialEq)]
228pub(crate) enum InitMode {
229 New,
231 FromSnapshot {
233 skip_op_registration: bool,
235 },
236}
237
238impl InitMode {
239 fn from_options(options: &RuntimeOptions) -> Self {
240 match options.startup_snapshot {
241 None => Self::New,
242 Some(_) => Self::FromSnapshot {
243 skip_op_registration: options.skip_op_registration,
244 },
245 }
246 }
247
248 #[inline]
249 pub fn needs_ops_bindings(&self) -> bool {
250 !matches!(
251 self,
252 InitMode::FromSnapshot {
253 skip_op_registration: true
254 }
255 )
256 }
257}
258
259#[derive(Default)]
260struct PromiseFuture {
261 resolved: Cell<Option<Result<v8::Global<v8::Value>, Box<JsError>>>>,
262 waker: Cell<Option<Waker>>,
263}
264
265#[derive(Clone, Default)]
266struct RcPromiseFuture(Rc<PromiseFuture>);
267
268impl RcPromiseFuture {
269 pub fn new(res: Result<v8::Global<v8::Value>, Box<JsError>>) -> Self {
270 Self(Rc::new(PromiseFuture {
271 resolved: Some(res).into(),
272 ..Default::default()
273 }))
274 }
275}
276
277impl Future for RcPromiseFuture {
278 type Output = Result<v8::Global<v8::Value>, Box<JsError>>;
279
280 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
281 let this = self.get_mut();
282 match this.0.resolved.take() {
283 Some(resolved) => Poll::Ready(resolved),
284 _ => {
285 this.0.waker.set(Some(cx.waker().clone()));
286 Poll::Pending
287 }
288 }
289 }
290}
291
292static VIRTUAL_OPS_MODULE_NAME: FastStaticString = ascii_str!("ext:core/ops");
293
294pub(crate) struct InternalSourceFile {
295 pub specifier: FastStaticString,
296 pub source: FastStaticString,
297}
298
299macro_rules! internal_source_file {
300 ($str_:literal) => {{
301 InternalSourceFile {
302 specifier: ascii_str!(concat!("ext:core/", $str_)),
303 source: ascii_str_include!(concat!("../", $str_)),
304 }
305 }};
306}
307
308pub(crate) static CONTEXT_SETUP_SOURCES: [InternalSourceFile; 2] = [
311 internal_source_file!("00_primordials.js"),
312 internal_source_file!("00_infra.js"),
313];
314
315pub(crate) static BUILTIN_SOURCES: [InternalSourceFile; 1] =
318 [internal_source_file!("01_core.js")];
319
320pub(crate) static BUILTIN_ES_MODULES: [ExtensionFileSource; 1] =
323 [ExtensionFileSource::new(
324 "ext:core/mod.js",
325 ascii_str_include!("../mod.js"),
326 )];
327
328#[cfg(test)]
330pub(crate) const NO_OF_BUILTIN_MODULES: usize = 2;
331
332pub struct JsRuntime {
345 pub(crate) inner: InnerIsolateState,
346 pub(crate) allocations: IsolateAllocations,
347 files_loaded_from_fs_during_snapshot: Vec<&'static str>,
351 is_main_runtime: bool,
353}
354
355pub struct JsRuntimeForSnapshot(JsRuntime);
357
358impl Deref for JsRuntimeForSnapshot {
359 type Target = JsRuntime;
360
361 fn deref(&self) -> &Self::Target {
362 &self.0
363 }
364}
365
366impl DerefMut for JsRuntimeForSnapshot {
367 fn deref_mut(&mut self) -> &mut Self::Target {
368 &mut self.0
369 }
370}
371
372pub struct CrossIsolateStore<T>(Arc<Mutex<CrossIsolateStoreInner<T>>>);
373
374struct CrossIsolateStoreInner<T> {
375 map: HashMap<u32, T>,
376 last_id: u32,
377}
378
379impl<T> CrossIsolateStore<T> {
380 pub(crate) fn insert(&self, value: T) -> u32 {
381 let mut store = self.0.lock().unwrap();
382 let last_id = store.last_id;
383 store.map.insert(last_id, value);
384 store.last_id += 1;
385 last_id
386 }
387
388 pub(crate) fn take(&self, id: u32) -> Option<T> {
389 let mut store = self.0.lock().unwrap();
390 store.map.remove(&id)
391 }
392}
393
394impl<T> Default for CrossIsolateStore<T> {
395 fn default() -> Self {
396 CrossIsolateStore(Arc::new(Mutex::new(CrossIsolateStoreInner {
397 map: Default::default(),
398 last_id: 0,
399 })))
400 }
401}
402
403impl<T> Clone for CrossIsolateStore<T> {
404 fn clone(&self) -> Self {
405 Self(self.0.clone())
406 }
407}
408
409pub type SharedArrayBufferStore =
410 CrossIsolateStore<v8::SharedRef<v8::BackingStore>>;
411
412pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
413
414pub struct JsRuntimeState {
417 pub(crate) source_mapper: Rc<RefCell<SourceMapper>>,
418 pub(crate) op_state: Rc<RefCell<OpState>>,
419 pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
420 pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
421 wait_for_inspector_disconnect_callback:
422 Option<WaitForInspectorDisconnectCallback>,
423 pub(crate) validate_import_attributes_cb: Option<ValidateImportAttributesCb>,
424 pub(crate) custom_module_evaluation_cb: Option<CustomModuleEvaluationCb>,
425 pub(crate) eval_context_get_code_cache_cb:
426 RefCell<Option<EvalContextGetCodeCacheCb>>,
427 pub(crate) eval_context_code_cache_ready_cb:
428 RefCell<Option<EvalContextCodeCacheReadyCb>>,
429 pub(crate) cppgc_template: RefCell<Option<v8::Global<v8::FunctionTemplate>>>,
430 pub(crate) function_templates: Rc<RefCell<FunctionTemplateData>>,
431 pub(crate) callsite_prototype: RefCell<Option<v8::Global<v8::Object>>>,
432 waker: Arc<AtomicWaker>,
433 inspector: RefCell<Option<Rc<JsRuntimeInspector>>>,
435 has_inspector: Cell<bool>,
436 import_assertions_support: ImportAssertionsSupport,
437 lazy_extensions: Vec<&'static str>,
438}
439
440#[derive(Default)]
441pub struct RuntimeOptions {
442 pub module_loader: Option<Rc<dyn ModuleLoader>>,
448
449 pub extension_code_cache: Option<Rc<dyn ExtCodeCache>>,
451
452 pub extension_transpiler: Option<Rc<ExtensionTranspiler>>,
454
455 pub op_metrics_factory_fn: Option<OpMetricsFactoryFn>,
458
459 pub extensions: Vec<Extension>,
467
468 pub startup_snapshot: Option<&'static [u8]>,
473
474 pub skip_op_registration: bool,
476
477 pub create_params: Option<v8::CreateParams>,
479
480 pub v8_platform: Option<v8::SharedRef<v8::Platform>>,
483
484 pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
490
491 pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
498
499 pub inspector: bool,
501
502 pub is_main: bool,
505
506 #[cfg(any(test, feature = "unsafe_runtime_options"))]
507 pub unsafe_expose_natives_and_gc: bool,
511
512 pub validate_import_attributes_cb: Option<ValidateImportAttributesCb>,
521
522 pub wait_for_inspector_disconnect_callback:
529 Option<WaitForInspectorDisconnectCallback>,
530
531 pub custom_module_evaluation_cb: Option<CustomModuleEvaluationCb>,
534
535 pub eval_context_code_cache_cbs:
538 Option<(EvalContextGetCodeCacheCb, EvalContextCodeCacheReadyCb)>,
539
540 pub import_assertions_support: ImportAssertionsSupport,
541
542 pub maybe_op_stack_trace_callback: Option<OpStackTraceCallback>,
546}
547
548pub struct ImportAssertionsSupportCustomCallbackArgs {
549 pub maybe_specifier: Option<String>,
550 pub maybe_line_number: Option<usize>,
551 pub column_number: usize,
552 pub maybe_source_line: Option<String>,
553}
554
555#[derive(Default)]
556pub enum ImportAssertionsSupport {
557 #[default]
562 Error,
563
564 Yes,
566
567 Warning,
569
570 CustomCallback(Box<dyn Fn(ImportAssertionsSupportCustomCallbackArgs)>),
574}
575
576impl ImportAssertionsSupport {
577 fn is_enabled(&self) -> bool {
578 matches!(self, Self::Yes | Self::Warning | Self::CustomCallback(_))
579 }
580
581 fn has_warning(&self) -> bool {
582 matches!(self, Self::Warning | Self::CustomCallback(_))
583 }
584}
585
586extern "C" fn isolate_message_listener(
588 message: v8::Local<v8::Message>,
589 _exception: v8::Local<v8::Value>,
590) {
591 v8::callback_scope!(unsafe scope, message);
592 v8::scope!(let scope, scope);
593
594 let message_v8_str = message.get(scope);
595 let message_str = message_v8_str.to_rust_string_lossy(scope);
596
597 if !message_str.starts_with("'assert' is deprecated") {
598 return;
599 }
600
601 let maybe_script_resource_name = message
602 .get_script_resource_name(scope)
603 .map(|s| s.to_rust_string_lossy(scope));
604 let maybe_source_line = message
605 .get_source_line(scope)
606 .map(|s| s.to_rust_string_lossy(scope));
607 let maybe_line_number = message.get_line_number(scope);
608 let start_column = message.get_start_column();
609
610 let js_runtime_state = JsRuntime::state_from(scope);
611 if let Some(specifier) = maybe_script_resource_name.as_ref() {
612 let module_map = JsRealm::module_map_from(scope);
613 module_map
614 .loader
615 .borrow()
616 .purge_and_prevent_code_cache(specifier);
617 }
618
619 match &js_runtime_state.import_assertions_support {
620 ImportAssertionsSupport::Warning => {
621 let mut msg = "⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.".to_string();
622 if let Some(specifier) = maybe_script_resource_name {
623 if let Some(source_line) = maybe_source_line {
624 msg.push('\n');
625 msg.push_str(&source_line);
626 msg.push('\n');
627 msg.push_str(&format!("{:0width$}^", " ", width = start_column));
628 }
629 msg.push_str(&format!(
630 " at {}:{}:{}",
631 specifier,
632 maybe_line_number.unwrap(),
633 start_column
634 ));
635 #[allow(clippy::print_stderr)]
636 {
637 eprintln!("{}", msg);
638 }
639 }
640 }
641 ImportAssertionsSupport::CustomCallback(cb) => {
642 cb(ImportAssertionsSupportCustomCallbackArgs {
643 maybe_specifier: maybe_script_resource_name,
644 maybe_line_number,
645 column_number: start_column,
646 maybe_source_line,
647 });
648 }
649 _ => unreachable!(),
650 }
651}
652
653impl RuntimeOptions {
654 #[cfg(any(test, feature = "unsafe_runtime_options"))]
655 fn unsafe_expose_natives_and_gc(&self) -> bool {
656 self.unsafe_expose_natives_and_gc
657 }
658
659 #[cfg(not(any(test, feature = "unsafe_runtime_options")))]
660 fn unsafe_expose_natives_and_gc(&self) -> bool {
661 false
662 }
663}
664
665#[derive(Copy, Clone, Debug)]
666pub struct PollEventLoopOptions {
667 pub wait_for_inspector: bool,
668 pub pump_v8_message_loop: bool,
669}
670
671impl Default for PollEventLoopOptions {
672 fn default() -> Self {
673 Self {
674 wait_for_inspector: false,
675 pump_v8_message_loop: true,
676 }
677 }
678}
679
680#[derive(Default)]
681pub struct CreateRealmOptions {
682 pub module_loader: Option<Rc<dyn ModuleLoader>>,
688}
689
690#[macro_export]
691macro_rules! scope {
692 ($scope: ident, $self: expr) => {
693 let context = $self.main_context();
694 let isolate = &mut *$self.v8_isolate();
695 $crate::v8::scope!($scope, isolate);
696 let context = $crate::v8::Local::new($scope, context);
697 let $scope = &mut $crate::v8::ContextScope::new($scope, context);
698 };
699}
700
701impl JsRuntime {
702 #[cfg(not(any(test, feature = "unsafe_runtime_options")))]
706 pub fn init_platform(
707 v8_platform: Option<v8::SharedRef<v8::Platform>>,
708 import_assertions_enabled: bool,
709 ) {
710 setup::init_v8(v8_platform, cfg!(test), false, import_assertions_enabled);
711 }
712
713 #[cfg(any(test, feature = "unsafe_runtime_options"))]
722 pub fn init_platform(
723 v8_platform: Option<v8::SharedRef<v8::Platform>>,
724 expose_natives: bool,
725 import_assertions_enabled: bool,
726 ) {
727 setup::init_v8(
728 v8_platform,
729 cfg!(test),
730 expose_natives,
731 import_assertions_enabled,
732 );
733 }
734
735 pub fn new(options: RuntimeOptions) -> JsRuntime {
738 match Self::try_new(options) {
739 Ok(runtime) => runtime,
740 Err(err) => {
741 panic!(
742 "Failed to initialize a JsRuntime: {}",
743 err.print_with_cause()
744 );
745 }
746 }
747 }
748
749 pub fn try_new(mut options: RuntimeOptions) -> Result<JsRuntime, CoreError> {
752 setup::init_v8(
753 options.v8_platform.take(),
754 cfg!(test),
755 options.unsafe_expose_natives_and_gc(),
756 options.import_assertions_support.is_enabled(),
757 );
758 JsRuntime::new_inner(options, false)
759 }
760
761 pub(crate) fn state_from(isolate: &v8::Isolate) -> Rc<JsRuntimeState> {
762 let state_ptr = isolate.get_data(STATE_DATA_OFFSET);
763 let state_rc =
764 unsafe { Rc::from_raw(state_ptr as *const JsRuntimeState) };
767 let state = state_rc.clone();
768 std::mem::forget(state_rc);
769 state
770 }
771
772 pub fn op_state_from(isolate: &v8::Isolate) -> Rc<RefCell<OpState>> {
774 let state = Self::state_from(isolate);
775 state.op_state.clone()
776 }
777
778 pub(crate) fn has_more_work(scope: &mut v8::PinScope) -> bool {
779 EventLoopPendingState::new_from_scope(scope).is_pending()
780 }
781
782 pub fn op_metadata(&self, name: &str) -> Option<OpMetadata> {
785 let state = &self.inner.main_realm.0.context_state;
786 state.op_ctxs.iter().find_map(|ctx| {
787 if ctx.decl.name == name {
788 Some(ctx.decl.metadata)
789 } else {
790 None
791 }
792 })
793 }
794
795 fn new_inner(
796 mut options: RuntimeOptions,
797 will_snapshot: bool,
798 ) -> Result<JsRuntime, CoreError> {
799 let init_mode = InitMode::from_options(&options);
800 let mut extensions = std::mem::take(&mut options.extensions);
801 let mut isolate_allocations = IsolateAllocations::default();
802
803 let enable_stack_trace_in_ops =
804 options.maybe_op_stack_trace_callback.is_some();
805
806 let mut op_state = OpState::new(options.maybe_op_stack_trace_callback);
808 let unrefed_ops = op_state.unrefed_ops.clone();
809
810 let lazy_extensions =
811 extension_set::setup_op_state(&mut op_state, &mut extensions);
812
813 let mut files_loaded = Vec::with_capacity(128);
815 let loader = options
816 .module_loader
817 .unwrap_or_else(|| Rc::new(NoopModuleLoader));
818
819 let mut source_mapper = SourceMapper::new(loader.clone());
820
821 let (maybe_startup_snapshot, mut sidecar_data) = options
822 .startup_snapshot
823 .take()
824 .map(snapshot::deconstruct)
825 .unzip();
826
827 let mut sources = extension_set::into_sources_and_source_maps(
828 options.extension_transpiler.as_deref(),
829 &extensions,
830 sidecar_data.as_ref().map(|s| &*s.snapshot_data.extensions),
831 |source| {
832 mark_as_loaded_from_fs_during_snapshot(&mut files_loaded, &source.code)
833 },
834 )?;
835
836 for loaded_source in sources
837 .js
838 .iter()
839 .chain(sources.esm.iter())
840 .chain(sources.lazy_esm.iter())
841 .filter(|s| s.maybe_source_map.is_some())
842 {
843 source_mapper.add_ext_source_map(
844 loaded_source.specifier.try_clone().unwrap(),
845 loaded_source.maybe_source_map.clone().unwrap(),
846 );
847 }
848
849 let waker = op_state.waker.clone();
852 let op_state = Rc::new(RefCell::new(op_state));
853 let (eval_context_get_code_cache_cb, eval_context_set_code_cache_cb) =
854 options
855 .eval_context_code_cache_cbs
856 .map(|cbs| (Some(cbs.0), Some(cbs.1)))
857 .unwrap_or_default();
858 let state_rc = Rc::new(JsRuntimeState {
859 source_mapper: Rc::new(RefCell::new(source_mapper)),
860 shared_array_buffer_store: options.shared_array_buffer_store,
861 compiled_wasm_module_store: options.compiled_wasm_module_store,
862 wait_for_inspector_disconnect_callback: options
863 .wait_for_inspector_disconnect_callback,
864 op_state: op_state.clone(),
865 validate_import_attributes_cb: options.validate_import_attributes_cb,
866 custom_module_evaluation_cb: options.custom_module_evaluation_cb,
867 eval_context_get_code_cache_cb: RefCell::new(
868 eval_context_get_code_cache_cb,
869 ),
870 eval_context_code_cache_ready_cb: RefCell::new(
871 eval_context_set_code_cache_cb,
872 ),
873 waker,
874 inspector: None.into(),
876 has_inspector: false.into(),
877 cppgc_template: None.into(),
878 function_templates: Default::default(),
879 callsite_prototype: None.into(),
880 import_assertions_support: options.import_assertions_support,
881 lazy_extensions,
882 });
883
884 let (op_decls, mut op_method_decls) =
887 extension_set::init_ops(crate::ops_builtin::BUILTIN_OPS, &mut extensions);
888
889 let op_driver = Rc::new(OpDriverImpl::default());
890 let op_metrics_factory_fn = options.op_metrics_factory_fn.take();
891
892 let (mut op_ctxs, methods_ctx_offset) = extension_set::create_op_ctxs(
893 op_decls,
894 &mut op_method_decls,
895 op_metrics_factory_fn,
896 op_driver.clone(),
897 op_state.clone(),
898 state_rc.clone(),
899 enable_stack_trace_in_ops,
900 );
901
902 let (
904 global_template_middleware,
905 global_object_middlewares,
906 additional_references,
907 ) = extension_set::get_middlewares_and_external_refs(&mut extensions);
908
909 let extensions = extensions.iter().map(|e| e.name).collect();
911 let op_count = op_ctxs.len();
912 let source_count = sources.len();
913 let addl_refs_count = additional_references.len();
914
915 let ops_in_snapshot = sidecar_data
916 .as_ref()
917 .map(|d| d.snapshot_data.op_count)
918 .unwrap_or_default();
919 let sources_in_snapshot = sidecar_data
920 .as_ref()
921 .map(|d| d.snapshot_data.source_count)
922 .unwrap_or_default();
923
924 let snapshot_sources: Vec<&[u8]> = sidecar_data
925 .as_mut()
926 .map(|s| std::mem::take(&mut s.snapshot_data.external_strings))
927 .unwrap_or_default();
928 (
929 isolate_allocations.externalized_sources,
930 isolate_allocations.original_sources,
931 ) = bindings::externalize_sources(&mut sources, snapshot_sources);
932
933 let external_references = bindings::create_external_references(
934 &op_ctxs,
935 &additional_references,
936 &isolate_allocations.externalized_sources,
937 ops_in_snapshot,
938 sources_in_snapshot,
939 );
940
941 let has_snapshot = maybe_startup_snapshot.is_some();
942 let mut isolate = setup::create_isolate(
943 will_snapshot,
944 options.create_params.take(),
945 maybe_startup_snapshot,
946 external_references.into(),
947 );
948
949 if state_rc.import_assertions_support.has_warning() {
950 isolate.add_message_listener_with_error_level(
951 isolate_message_listener,
952 MessageErrorLevel::ALL,
953 );
954 }
955
956 let isolate_ptr = unsafe { isolate.as_raw_isolate_ptr() };
957 for op_ctx in op_ctxs.iter_mut() {
960 op_ctx.isolate = isolate_ptr;
961 }
962
963 op_state.borrow_mut().put(isolate_ptr);
964
965 let context_state = Rc::new(ContextState::new(
967 op_driver.clone(),
968 isolate_ptr,
969 op_ctxs,
970 op_method_decls,
971 methods_ctx_offset,
972 op_state.borrow().external_ops_tracker.clone(),
973 unrefed_ops,
974 ));
975
976 let spawner = context_state
979 .task_spawner_factory
980 .clone()
981 .new_same_thread_spawner();
982 op_state.borrow_mut().put(spawner);
983 let spawner = context_state
984 .task_spawner_factory
985 .clone()
986 .new_cross_thread_spawner();
987 op_state.borrow_mut().put(spawner);
988
989 let mut snapshotted_data = None;
991 let main_context = {
992 v8::scope!(let scope, &mut isolate);
993
994 let cppgc_template = crate::cppgc::make_cppgc_template(scope);
995 state_rc
996 .cppgc_template
997 .borrow_mut()
998 .replace(v8::Global::new(scope, cppgc_template));
999
1000 let context = create_context(
1001 scope,
1002 &global_template_middleware,
1003 &global_object_middlewares,
1004 has_snapshot,
1005 );
1006
1007 if let Some(raw_data) = sidecar_data {
1009 snapshotted_data = Some(snapshot::load_snapshotted_data_from_snapshot(
1010 scope, context, raw_data,
1011 ));
1012 }
1013
1014 v8::Global::new(scope, context)
1015 };
1016
1017 let main_realm = {
1018 v8::scope_with_context!(context_scope, &mut isolate, &main_context);
1019 let scope = context_scope;
1020 let context = v8::Local::new(scope, &main_context);
1021
1022 let callsite_prototype = crate::error::make_callsite_prototype(scope);
1023 state_rc
1024 .callsite_prototype
1025 .borrow_mut()
1026 .replace(v8::Global::new(scope, callsite_prototype));
1027
1028 if init_mode == InitMode::New {
1031 bindings::initialize_deno_core_namespace(scope, context, init_mode);
1032 bindings::initialize_primordials_and_infra(scope)?;
1033 }
1034 if init_mode.needs_ops_bindings() {
1037 bindings::initialize_deno_core_ops_bindings(
1038 scope,
1039 context,
1040 &context_state.op_ctxs,
1041 &context_state.op_method_decls,
1042 methods_ctx_offset,
1043 &mut state_rc.function_templates.borrow_mut(),
1044 );
1045 }
1046
1047 unsafe {
1049 context.set_aligned_pointer_in_embedder_data(
1050 super::jsrealm::CONTEXT_STATE_SLOT_INDEX,
1051 Rc::into_raw(context_state.clone()) as *mut c_void,
1052 );
1053 }
1054
1055 let inspector = if options.inspector {
1056 Some(JsRuntimeInspector::new(
1057 isolate_ptr,
1058 scope,
1059 context,
1060 options.is_main,
1061 ))
1062 } else {
1063 None
1064 };
1065
1066 let exception_state = context_state.exception_state.clone();
1070 let module_map = Rc::new(ModuleMap::new(
1071 loader,
1072 state_rc.source_mapper.clone(),
1073 exception_state.clone(),
1074 will_snapshot,
1075 ));
1076
1077 if let Some((snapshotted_data, mut data_store)) = snapshotted_data {
1078 *exception_state.js_handled_promise_rejection_cb.borrow_mut() =
1079 snapshotted_data
1080 .js_handled_promise_rejection_cb
1081 .map(|cb| data_store.get(scope, cb));
1082 module_map.update_with_snapshotted_data(
1083 scope,
1084 &mut data_store,
1085 snapshotted_data.module_map_data,
1086 );
1087
1088 if let Some(index) = snapshotted_data.ext_import_meta_proto {
1089 *context_state.ext_import_meta_proto.borrow_mut() =
1090 Some(data_store.get(scope, index));
1091 }
1092
1093 state_rc
1094 .function_templates
1095 .borrow_mut()
1096 .update_with_snapshotted_data(
1097 scope,
1098 &mut data_store,
1099 snapshotted_data.function_templates_data,
1100 );
1101
1102 let mut mapper = state_rc.source_mapper.borrow_mut();
1103 for (key, map) in snapshotted_data.ext_source_maps {
1104 mapper.add_ext_source_map(ModuleName::from_static(key), map.into());
1105 }
1106 }
1107
1108 if context_state.ext_import_meta_proto.borrow().is_none() {
1109 let null = v8::null(scope);
1110 let obj = v8::Object::with_prototype_and_properties(
1111 scope,
1112 null.into(),
1113 &[],
1114 &[],
1115 );
1116 *context_state.ext_import_meta_proto.borrow_mut() =
1117 Some(v8::Global::new(scope, obj));
1118 }
1119
1120 unsafe {
1122 context.set_aligned_pointer_in_embedder_data(
1123 super::jsrealm::MODULE_MAP_SLOT_INDEX,
1124 Rc::into_raw(module_map.clone()) as *mut c_void,
1125 );
1126 }
1127
1128 let main_realm = {
1130 let main_realm = JsRealmInner::new(
1131 context_state,
1132 main_context,
1133 module_map.clone(),
1134 state_rc.function_templates.clone(),
1135 );
1136 state_rc.has_inspector.set(inspector.is_some());
1138 *state_rc.inspector.borrow_mut() = inspector;
1139 main_realm
1140 };
1141 let main_realm = JsRealm::new(main_realm);
1142 scope.set_data(
1143 STATE_DATA_OFFSET,
1144 Rc::into_raw(state_rc.clone()) as *mut c_void,
1145 );
1146 main_realm
1147 };
1148
1149 let mut js_runtime = JsRuntime {
1151 inner: InnerIsolateState {
1152 will_snapshot,
1153 op_count,
1154 extensions,
1155 source_count,
1156 addl_refs_count,
1157 main_realm: ManuallyDrop::new(main_realm),
1158 state: ManuallyDropRc(ManuallyDrop::new(state_rc)),
1159 v8_isolate: ManuallyDrop::new(isolate),
1160 },
1161 allocations: isolate_allocations,
1162 files_loaded_from_fs_during_snapshot: vec![],
1163 is_main_runtime: options.is_main,
1164 };
1165
1166 {
1169 let realm = JsRealm::clone(&js_runtime.inner.main_realm);
1170 let context_global = realm.context();
1171 let module_map = realm.0.module_map();
1172
1173 if init_mode == InitMode::New {
1183 js_runtime
1184 .execute_virtual_ops_module(context_global, module_map.clone());
1185 }
1186
1187 if init_mode == InitMode::New {
1188 js_runtime.execute_builtin_sources(
1189 &realm,
1190 &module_map,
1191 &mut files_loaded,
1192 )?;
1193 }
1194
1195 js_runtime.store_js_callbacks(&realm, will_snapshot);
1196
1197 js_runtime.init_extension_js(
1198 &realm,
1199 &module_map,
1200 sources,
1201 options.extension_code_cache,
1202 )?;
1203 }
1204
1205 if will_snapshot {
1206 js_runtime.files_loaded_from_fs_during_snapshot = files_loaded;
1207 }
1208
1209 Ok(js_runtime)
1211 }
1212
1213 pub fn lazy_init_extensions(
1216 &self,
1217 ext_args: Vec<ExtensionArguments>,
1218 ) -> Result<(), CoreError> {
1219 if ext_args.len() != self.inner.state.lazy_extensions.len() {
1220 return Err(
1221 CoreErrorKind::ExtensionLazyInitCountMismatch(
1222 ExtensionLazyInitCountMismatchError {
1223 lazy_init_extensions_len: self.inner.state.lazy_extensions.len(),
1224 arguments_len: ext_args.len(),
1225 },
1226 )
1227 .into_box(),
1228 );
1229 }
1230
1231 let mut state = self.inner.state.op_state.borrow_mut();
1232
1233 for (mut args, expected_name) in ext_args
1234 .into_iter()
1235 .zip(self.inner.state.lazy_extensions.iter())
1236 {
1237 if args.name != *expected_name {
1238 return Err(
1239 CoreErrorKind::ExtensionLazyInitOrderMismatch(
1240 ExtensionLazyInitOrderMismatchError {
1241 expected: expected_name,
1242 actual: args.name,
1243 },
1244 )
1245 .into_box(),
1246 );
1247 }
1248
1249 let Some(f) = args.op_state_fn.take() else {
1250 continue;
1251 };
1252
1253 f(&mut state);
1254 }
1255
1256 Ok(())
1257 }
1258
1259 pub fn set_eval_context_code_cache_cbs(
1260 &self,
1261 eval_context_code_cache_cbs: Option<(
1262 EvalContextGetCodeCacheCb,
1263 EvalContextCodeCacheReadyCb,
1264 )>,
1265 ) {
1266 let (eval_context_get_code_cache_cb, eval_context_set_code_cache_cb) =
1267 eval_context_code_cache_cbs
1268 .map(|cbs| (Some(cbs.0), Some(cbs.1)))
1269 .unwrap_or_default();
1270 *self.inner.state.eval_context_get_code_cache_cb.borrow_mut() =
1271 eval_context_get_code_cache_cb;
1272 *self
1273 .inner
1274 .state
1275 .eval_context_code_cache_ready_cb
1276 .borrow_mut() = eval_context_set_code_cache_cb;
1277 }
1278
1279 #[cfg(test)]
1280 #[inline]
1281 pub(crate) fn module_map(&self) -> Rc<ModuleMap> {
1282 self.inner.main_realm.0.module_map()
1283 }
1284
1285 #[inline]
1286 pub fn main_context(&self) -> v8::Global<v8::Context> {
1287 self.inner.main_realm.0.context().clone()
1288 }
1289
1290 #[cfg(test)]
1291 pub(crate) fn main_realm(&self) -> JsRealm {
1292 JsRealm::clone(&self.inner.main_realm)
1293 }
1294
1295 #[inline]
1296 pub fn v8_isolate(&mut self) -> &mut v8::OwnedIsolate {
1297 &mut self.inner.v8_isolate
1298 }
1299
1300 #[inline]
1301 fn v8_isolate_ptr(&mut self) -> v8::UnsafeRawIsolatePtr {
1302 unsafe { self.inner.v8_isolate.as_raw_isolate_ptr() }
1303 }
1304
1305 #[inline]
1306 pub fn inspector(&self) -> Rc<JsRuntimeInspector> {
1307 self.inner.state.inspector()
1308 }
1309
1310 #[inline]
1311 pub fn wait_for_inspector_disconnect(&self) {
1312 if let Some(callback) = self
1313 .inner
1314 .state
1315 .wait_for_inspector_disconnect_callback
1316 .as_ref()
1317 {
1318 callback();
1319 }
1320 }
1321
1322 pub fn runtime_activity_stats_factory(&self) -> RuntimeActivityStatsFactory {
1323 RuntimeActivityStatsFactory {
1324 context_state: self.inner.main_realm.0.context_state.clone(),
1325 op_state: self.inner.state.op_state.clone(),
1326 }
1327 }
1328
1329 pub(crate) fn files_loaded_from_fs_during_snapshot(&self) -> &[&'static str] {
1332 &self.files_loaded_from_fs_during_snapshot
1333 }
1334
1335 fn execute_virtual_ops_module(
1338 &mut self,
1339 context_global: &v8::Global<v8::Context>,
1340 module_map: Rc<ModuleMap>,
1341 ) {
1342 scope!(scope, self);
1343 let context_local = v8::Local::new(scope, context_global);
1344 let context_state = JsRealm::state_from_scope(scope);
1345 let global = context_local.global(scope);
1346 let synthetic_module_exports = create_exports_for_ops_virtual_module(
1347 &context_state.op_ctxs,
1348 &context_state.op_method_decls,
1349 context_state.methods_ctx_offset,
1350 scope,
1351 global,
1352 );
1353 let mod_id = module_map.new_synthetic_module(
1354 scope,
1355 VIRTUAL_OPS_MODULE_NAME,
1356 crate::ModuleType::JavaScript,
1357 synthetic_module_exports,
1358 );
1359 module_map.mod_evaluate_sync(scope, mod_id).unwrap();
1360 }
1361
1362 fn execute_builtin_sources(
1369 &mut self,
1370 _realm: &JsRealm,
1371 module_map: &Rc<ModuleMap>,
1372 files_loaded: &mut Vec<&'static str>,
1373 ) -> Result<(), CoreError> {
1374 scope!(scope, self);
1375
1376 for source_file in &BUILTIN_SOURCES {
1377 let name = source_file.specifier.v8_string(scope).unwrap();
1378 let source = source_file.source.v8_string(scope).unwrap();
1379
1380 let origin = script_origin(scope, name, false, None);
1381 let script = v8::Script::compile(scope, source, Some(&origin))
1382 .ok_or(CoreModuleParseError(source_file.specifier))?;
1383 script
1384 .run(scope)
1385 .ok_or(CoreModuleExecuteError(source_file.specifier))?;
1386 }
1387
1388 for file_source in &BUILTIN_ES_MODULES {
1389 mark_as_loaded_from_fs_during_snapshot(files_loaded, &file_source.code);
1390 module_map.lazy_load_es_module_with_code(
1391 scope,
1392 file_source.specifier,
1393 file_source.load()?,
1394 None,
1395 )?;
1396 }
1397
1398 Ok(())
1399 }
1400
1401 async fn init_extension_js_inner(
1403 &mut self,
1404 realm: &JsRealm,
1405 module_map: &Rc<ModuleMap>,
1406 loaded_sources: LoadedSources,
1407 ext_code_cache: Option<Rc<dyn ExtCodeCache>>,
1408 ) -> Result<(), CoreError> {
1409 for source in loaded_sources.lazy_esm {
1411 module_map.add_lazy_loaded_esm_source(source.specifier, source.code);
1412 }
1413
1414 let loader = module_map.loader.borrow().clone();
1420 let mut modules = Vec::with_capacity(loaded_sources.esm.len());
1421 let mut sources = Vec::with_capacity(loaded_sources.esm.len());
1422 for esm in loaded_sources.esm {
1423 modules.push(ModuleSpecifier::parse(&esm.specifier).unwrap());
1424 sources.push((esm.specifier, esm.code));
1425 }
1426 let ext_loader =
1427 Rc::new(ExtModuleLoader::new(sources, ext_code_cache.clone()));
1428 *module_map.loader.borrow_mut() = ext_loader.clone();
1429
1430 for module in modules {
1432 realm
1434 .load_side_es_module_from_code(self.v8_isolate(), &module, None)
1435 .await?;
1436 }
1437
1438 for source in loaded_sources.js {
1440 match &ext_code_cache {
1441 Some(ext_code_cache) => {
1442 let specifier = ModuleSpecifier::parse(&source.specifier)?;
1443 realm.execute_script_with_cache(
1444 self.v8_isolate(),
1445 specifier,
1446 source.code,
1447 &|specifier, code| {
1448 ext_code_cache.get_code_cache_info(specifier, code, false)
1449 },
1450 &|specifier, hash, code_cache| {
1451 ext_code_cache
1452 .code_cache_ready(specifier, hash, code_cache, false)
1453 },
1454 )?;
1455 }
1456 _ => {
1457 realm.execute_script(
1458 self.v8_isolate(),
1459 source.specifier,
1460 source.code,
1461 )?;
1462 }
1463 }
1464 }
1465
1466 for specifier in loaded_sources.esm_entry_points {
1468 let Some(mod_id) =
1469 module_map.get_id(&specifier, RequestedModuleType::None)
1470 else {
1471 return Err(
1472 CoreErrorKind::MissingFromModuleMap(specifier.to_string()).into_box(),
1473 );
1474 };
1475
1476 let isolate = self.v8_isolate();
1477 jsrealm::context_scope!(scope, realm, isolate);
1478 module_map.mod_evaluate_sync(scope, mod_id)?;
1479 let mut cx = Context::from_waker(Waker::noop());
1480 let _ = module_map.poll_progress(&mut cx, scope);
1483 }
1484
1485 #[cfg(debug_assertions)]
1486 {
1487 jsrealm::context_scope!(scope, realm, self.v8_isolate());
1488 module_map.check_all_modules_evaluated(scope)?;
1489 }
1490
1491 let module_map = realm.0.module_map();
1492 *module_map.loader.borrow_mut() = loader;
1493 ext_loader.finalize()?;
1494
1495 Ok(())
1496 }
1497
1498 fn init_extension_js(
1500 &mut self,
1501 realm: &JsRealm,
1502 module_map: &Rc<ModuleMap>,
1503 loaded_sources: LoadedSources,
1504 ext_code_cache: Option<Rc<dyn ExtCodeCache>>,
1505 ) -> Result<(), CoreError> {
1506 futures::executor::block_on(self.init_extension_js_inner(
1507 realm,
1508 module_map,
1509 loaded_sources,
1510 ext_code_cache,
1511 ))?;
1512
1513 Ok(())
1514 }
1515
1516 pub fn eval<'s, 'i, T>(
1517 scope: &mut v8::PinScope<'s, 'i>,
1518 code: &str,
1519 ) -> Option<v8::Local<'s, T>>
1520 where
1521 v8::Local<'s, T>: TryFrom<v8::Local<'s, v8::Value>, Error = v8::DataError>,
1522 {
1523 v8::escapable_handle_scope!(let scope, scope);
1524 let source = v8::String::new(scope, code).unwrap();
1525 let script = v8::Script::compile(scope, source, None).unwrap();
1526 let v = script.run(scope)?;
1527 scope.escape(v).try_into().ok()
1528 }
1529
1530 fn store_js_callbacks(&mut self, realm: &JsRealm, will_snapshot: bool) {
1533 let (
1534 event_loop_tick_cb,
1535 build_custom_error_cb,
1536 run_immediate_callbacks_cb,
1537 wasm_instance_fn,
1538 ) = {
1539 scope!(scope, self);
1540 let context = realm.context();
1541 let context_local = v8::Local::new(scope, context);
1542 let global = context_local.global(scope);
1543 let deno_obj: v8::Local<v8::Object> =
1546 bindings::get(scope, global, DENO, "Deno");
1547 let core_obj: v8::Local<v8::Object> =
1548 bindings::get(scope, deno_obj, CORE, "Deno.core");
1549
1550 let event_loop_tick_cb: v8::Local<v8::Function> = bindings::get(
1551 scope,
1552 core_obj,
1553 EVENT_LOOP_TICK,
1554 "Deno.core.eventLoopTick",
1555 );
1556 let build_custom_error_cb: v8::Local<v8::Function> = bindings::get(
1557 scope,
1558 core_obj,
1559 BUILD_CUSTOM_ERROR,
1560 "Deno.core.buildCustomError",
1561 );
1562 let run_immediate_callbacks_cb: v8::Local<v8::Function> = bindings::get(
1563 scope,
1564 core_obj,
1565 RUN_IMMEDIATE_CALLBACKS,
1566 "Deno.core.runImmediateCallbacks",
1567 );
1568
1569 let mut wasm_instance_fn = None;
1570 if !will_snapshot {
1571 let key = WEBASSEMBLY.v8_string(scope).unwrap();
1572 if let Some(web_assembly_obj_value) = global.get(scope, key.into()) {
1573 let maybe_web_assembly_object =
1576 TryInto::<v8::Local<v8::Object>>::try_into(web_assembly_obj_value);
1577 if let Ok(web_assembly_object) = maybe_web_assembly_object {
1578 wasm_instance_fn = Some(bindings::get::<v8::Local<v8::Function>>(
1579 scope,
1580 web_assembly_object,
1581 INSTANCE,
1582 "WebAssembly.Instance",
1583 ));
1584 }
1585 }
1586 }
1587
1588 (
1589 v8::Global::new(scope, event_loop_tick_cb),
1590 v8::Global::new(scope, build_custom_error_cb),
1591 v8::Global::new(scope, run_immediate_callbacks_cb),
1592 wasm_instance_fn.map(|f| v8::Global::new(scope, f)),
1593 )
1594 };
1595
1596 let state_rc = realm.0.state();
1598 state_rc
1599 .js_event_loop_tick_cb
1600 .borrow_mut()
1601 .replace(event_loop_tick_cb);
1602 state_rc
1603 .exception_state
1604 .js_build_custom_error_cb
1605 .borrow_mut()
1606 .replace(build_custom_error_cb);
1607 state_rc
1608 .run_immediate_callbacks_cb
1609 .borrow_mut()
1610 .replace(run_immediate_callbacks_cb);
1611 if let Some(wasm_instance_fn) = wasm_instance_fn {
1612 state_rc
1613 .wasm_instance_fn
1614 .borrow_mut()
1615 .replace(wasm_instance_fn);
1616 }
1617 }
1618
1619 pub fn op_state(&self) -> Rc<RefCell<OpState>> {
1622 self.inner.state.op_state.clone()
1623 }
1624
1625 pub fn op_names(&self) -> Vec<&'static str> {
1627 let state = &self.inner.main_realm.0.context_state;
1628 state.op_ctxs.iter().map(|o| o.decl.name).collect()
1629 }
1630
1631 pub fn execute_script(
1649 &mut self,
1650 name: impl IntoModuleName,
1651 source_code: impl IntoModuleCodeString,
1652 ) -> Result<v8::Global<v8::Value>, Box<JsError>> {
1653 let isolate = &mut self.inner.v8_isolate;
1654 self.inner.main_realm.execute_script(
1655 isolate,
1656 name.into_module_name(),
1657 source_code.into_module_code(),
1658 )
1659 }
1660
1661 pub fn call(
1669 &mut self,
1670 function: &v8::Global<v8::Function>,
1671 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1672 {
1673 self.call_with_args(function, &[])
1674 }
1675
1676 pub fn scoped_call(
1684 scope: &mut v8::PinScope,
1685 function: &v8::Global<v8::Function>,
1686 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1687 {
1688 Self::scoped_call_with_args(scope, function, &[])
1689 }
1690
1691 pub fn call_with_args(
1699 &mut self,
1700 function: &v8::Global<v8::Function>,
1701 args: &[v8::Global<v8::Value>],
1702 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1703 {
1704 scope!(scope, self);
1705 Self::scoped_call_with_args(scope, function, args)
1706 }
1707
1708 pub fn scoped_call_with_args(
1716 scope: &mut v8::PinScope,
1717 function: &v8::Global<v8::Function>,
1718 args: &[v8::Global<v8::Value>],
1719 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1720 {
1721 v8::tc_scope!(let scope, scope);
1722 let cb = function.open(scope);
1723 let this = v8::undefined(scope).into();
1724 let promise = if args.is_empty() {
1725 cb.call(scope, this, &[])
1726 } else {
1727 let mut local_args: SmallVec<[v8::Local<v8::Value>; 8]> =
1728 SmallVec::with_capacity(args.len());
1729 for v in args {
1730 local_args.push(v8::Local::new(scope, v));
1731 }
1732 cb.call(scope, this, &local_args)
1733 };
1734
1735 if promise.is_none() {
1736 if scope.is_execution_terminating() {
1737 let undefined = v8::undefined(scope).into();
1738 return RcPromiseFuture::new(exception_to_err_result(
1739 scope, undefined, false, true,
1740 ));
1741 }
1742 let exception = scope.exception().unwrap();
1743 return RcPromiseFuture::new(exception_to_err_result(
1744 scope, exception, false, true,
1745 ));
1746 }
1747 let promise = promise.unwrap();
1748 if !promise.is_promise() {
1749 return RcPromiseFuture::new(Ok(v8::Global::new(scope, promise)));
1750 }
1751 let promise = v8::Local::<v8::Promise>::try_from(promise).unwrap();
1752 Self::resolve_promise_inner(scope, promise)
1753 }
1754
1755 #[deprecated = "Use call"]
1759 pub async fn call_and_await(
1760 &mut self,
1761 function: &v8::Global<v8::Function>,
1762 ) -> Result<v8::Global<v8::Value>, CoreError> {
1763 let call = self.call(function);
1764 self
1765 .with_event_loop_promise(call, PollEventLoopOptions::default())
1766 .await
1767 }
1768
1769 #[deprecated = "Use call_with_args"]
1773 pub async fn call_with_args_and_await(
1774 &mut self,
1775 function: &v8::Global<v8::Function>,
1776 args: &[v8::Global<v8::Value>],
1777 ) -> Result<v8::Global<v8::Value>, CoreError> {
1778 let call = self.call_with_args(function, args);
1779 self
1780 .with_event_loop_promise(call, PollEventLoopOptions::default())
1781 .await
1782 }
1783
1784 pub fn get_module_namespace(
1789 &mut self,
1790 module_id: ModuleId,
1791 ) -> Result<v8::Global<v8::Object>, CoreError> {
1792 let isolate = &mut self.inner.v8_isolate;
1793 self
1794 .inner
1795 .main_realm
1796 .get_module_namespace(isolate, module_id)
1797 }
1798
1799 pub fn add_near_heap_limit_callback<C>(&mut self, cb: C)
1805 where
1806 C: FnMut(usize, usize) -> usize + 'static,
1807 {
1808 let boxed_cb = Box::new(RefCell::new(cb));
1809 let data = boxed_cb.as_ptr() as *mut c_void;
1810
1811 let prev = self
1812 .allocations
1813 .near_heap_limit_callback_data
1814 .replace((boxed_cb, near_heap_limit_callback::<C>));
1815 if let Some((_, prev_cb)) = prev {
1816 self
1817 .v8_isolate()
1818 .remove_near_heap_limit_callback(prev_cb, 0);
1819 }
1820
1821 self
1822 .v8_isolate()
1823 .add_near_heap_limit_callback(near_heap_limit_callback::<C>, data);
1824 }
1825
1826 pub fn remove_near_heap_limit_callback(&mut self, heap_limit: usize) {
1827 if let Some((_, cb)) = self.allocations.near_heap_limit_callback_data.take()
1828 {
1829 self
1830 .v8_isolate()
1831 .remove_near_heap_limit_callback(cb, heap_limit);
1832 }
1833 }
1834
1835 fn pump_v8_message_loop(
1836 &self,
1837 scope: &mut v8::PinScope,
1838 ) -> Result<(), Box<JsError>> {
1839 while v8::Platform::pump_message_loop(
1840 &v8::V8::get_current_platform(),
1841 scope,
1842 false, ) {
1844 }
1846
1847 v8::tc_scope!(let tc_scope, scope);
1848
1849 tc_scope.perform_microtask_checkpoint();
1850 match tc_scope.exception() {
1851 None => Ok(()),
1852 Some(exception) => {
1853 exception_to_err_result(tc_scope, exception, false, true)
1854 }
1855 }
1856 }
1857
1858 pub fn maybe_init_inspector(&mut self) {
1859 let inspector = &mut self.inner.state.inspector.borrow_mut();
1860 if inspector.is_some() {
1861 return;
1862 }
1863
1864 let context = self.main_context();
1865 let isolate_ptr = unsafe { self.inner.v8_isolate.as_raw_isolate_ptr() };
1866 v8::scope_with_context!(
1867 scope,
1868 self.inner.v8_isolate.as_mut(),
1869 context.clone(),
1870 );
1871 let context = v8::Local::new(scope, context);
1872
1873 self.inner.state.has_inspector.set(true);
1874 **inspector = Some(JsRuntimeInspector::new(
1875 isolate_ptr,
1876 scope,
1877 context,
1878 self.is_main_runtime,
1879 ));
1880 }
1881
1882 pub fn resolve(
1887 &mut self,
1888 promise: v8::Global<v8::Value>,
1889 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1890 {
1891 scope!(scope, self);
1892 Self::scoped_resolve(scope, promise)
1893 }
1894
1895 pub fn scoped_resolve(
1900 scope: &mut v8::PinScope,
1901 promise: v8::Global<v8::Value>,
1902 ) -> impl Future<Output = Result<v8::Global<v8::Value>, Box<JsError>>> + use<>
1903 {
1904 let promise = v8::Local::new(scope, promise);
1905 if !promise.is_promise() {
1906 return RcPromiseFuture::new(Ok(v8::Global::new(scope, promise)));
1907 }
1908 let promise = v8::Local::<v8::Promise>::try_from(promise).unwrap();
1909 Self::resolve_promise_inner(scope, promise)
1910 }
1911
1912 #[deprecated = "Use resolve"]
1917 pub async fn resolve_value(
1918 &mut self,
1919 global: v8::Global<v8::Value>,
1920 ) -> Result<v8::Global<v8::Value>, CoreError> {
1921 let resolve = self.resolve(global);
1922 self
1923 .with_event_loop_promise(resolve, PollEventLoopOptions::default())
1924 .await
1925 }
1926
1927 fn resolve_promise_inner<'s, 'i>(
1929 scope: &mut v8::PinScope<'s, 'i>,
1930 promise: v8::Local<'s, v8::Promise>,
1931 ) -> RcPromiseFuture {
1932 let future = RcPromiseFuture::default();
1933 let f = future.clone();
1934 watch_promise(scope, promise, move |scope, _rv, res| {
1935 let res = match res {
1936 Ok(l) => Ok(v8::Global::new(scope, l)),
1937 Err(e) => exception_to_err_result(scope, e, true, true),
1938 };
1939 f.0.resolved.set(Some(res));
1940 if let Some(waker) = f.0.waker.take() {
1941 waker.wake();
1942 }
1943 });
1944
1945 future
1946 }
1947
1948 pub async fn run_event_loop(
1956 &mut self,
1957 poll_options: PollEventLoopOptions,
1958 ) -> Result<(), CoreError> {
1959 poll_fn(|cx| self.poll_event_loop(cx, poll_options)).await
1960 }
1961
1962 pub async fn with_event_loop_promise<'fut, T, E>(
1967 &mut self,
1968 mut fut: impl Future<Output = Result<T, E>> + Unpin + 'fut,
1969 poll_options: PollEventLoopOptions,
1970 ) -> Result<T, CoreError>
1971 where
1972 CoreError: From<E>,
1973 {
1974 poll_fn(|cx| {
1976 if let Poll::Ready(t) = fut.poll_unpin(cx) {
1977 return Poll::Ready(t.map_err(|e| e.into()));
1978 }
1979 if let Poll::Ready(t) = self.poll_event_loop(cx, poll_options) {
1980 t?;
1981 if let Poll::Ready(t) = fut.poll_unpin(cx) {
1982 return Poll::Ready(t.map_err(|e| e.into()));
1983 }
1984 return Poll::Ready(Err(
1985 CoreErrorKind::PendingPromiseResolution.into_box(),
1986 ));
1987 }
1988 Poll::Pending
1989 })
1990 .await
1991 }
1992
1993 pub async fn with_event_loop_future<'fut, T, E>(
2000 &mut self,
2001 mut fut: impl Future<Output = Result<T, E>> + Unpin + 'fut,
2002 poll_options: PollEventLoopOptions,
2003 ) -> Result<T, E> {
2004 poll_fn(|cx| {
2006 if let Poll::Ready(t) = fut.poll_unpin(cx) {
2007 return Poll::Ready(t);
2008 }
2009 if let Poll::Ready(t) = self.poll_event_loop(cx, poll_options) {
2010 _ = t;
2014 }
2015 Poll::Pending
2016 })
2017 .await
2018 }
2019
2020 pub fn poll_event_loop(
2025 &mut self,
2026 cx: &mut Context,
2027 poll_options: PollEventLoopOptions,
2028 ) -> Poll<Result<(), CoreError>> {
2029 let mut isolate =
2031 unsafe { v8::Isolate::from_raw_isolate_ptr(self.v8_isolate_ptr()) };
2032 v8::scope!(let isolate_scope, &mut isolate);
2033 let context =
2034 v8::Local::new(isolate_scope, self.inner.main_realm.context());
2035 let mut scope = v8::ContextScope::new(isolate_scope, context);
2036 self.poll_event_loop_inner(cx, &mut scope, poll_options)
2037 }
2038
2039 fn poll_event_loop_inner(
2040 &self,
2041 cx: &mut Context,
2042 scope: &mut v8::PinScope,
2043 poll_options: PollEventLoopOptions,
2044 ) -> Poll<Result<(), CoreError>> {
2045 let has_inspector = self.inner.state.has_inspector.get();
2046 self.inner.state.waker.register(cx.waker());
2047
2048 if has_inspector {
2049 self.inspector().poll_sessions_from_event_loop(cx);
2051 }
2052
2053 if poll_options.pump_v8_message_loop {
2054 self.pump_v8_message_loop(scope)?;
2055 }
2056
2057 let realm = &self.inner.main_realm;
2058 let modules = &realm.0.module_map;
2059 let context_state = &realm.0.context_state;
2060 let exception_state = &context_state.exception_state;
2061
2062 modules.poll_progress(cx, scope)?;
2063
2064 let (dispatched_ops, did_work) = Self::do_js_event_loop_tick_realm(
2069 cx,
2070 scope,
2071 context_state,
2072 exception_state,
2073 )?;
2074 exception_state.check_exception_condition(scope)?;
2075
2076 let pending_state =
2078 EventLoopPendingState::new(scope, context_state, modules);
2079
2080 if !pending_state.is_pending() {
2081 if has_inspector {
2082 let inspector = self.inspector();
2083 let sessions_state = inspector.sessions_state();
2084
2085 if poll_options.wait_for_inspector && sessions_state.has_active {
2086 if sessions_state.has_blocking {
2087 return Poll::Pending;
2088 }
2089
2090 if sessions_state.has_nonblocking_wait_for_disconnect {
2091 let context = self.main_context();
2092 inspector.context_destroyed(scope, context);
2093 self.wait_for_inspector_disconnect();
2094 return Poll::Pending;
2095 }
2096 }
2097 }
2098
2099 return Poll::Ready(Ok(()));
2100 }
2101
2102 if !did_work
2103 && !context_state.timers.has_pending()
2104 && pending_state.has_refed_immediates > 0
2105 {
2106 Self::do_js_run_immediate_callbacks(scope, context_state)?;
2107 }
2108
2109 #[allow(clippy::suspicious_else_formatting, clippy::if_same_then_else)]
2117 {
2118 if pending_state.has_pending_background_tasks
2119 || pending_state.has_tick_scheduled
2120 || pending_state.has_outstanding_immediates
2121 || pending_state.has_refed_immediates > 0
2122 || pending_state.has_pending_promise_events
2123 {
2124 self.inner.state.waker.wake();
2125 } else
2126 if (pending_state.has_pending_module_evaluation
2128 || pending_state.has_pending_dyn_module_evaluation)
2129 && dispatched_ops
2130 {
2131 self.inner.state.waker.wake();
2132 }
2133 }
2134
2135 if pending_state.has_pending_module_evaluation {
2136 if pending_state.has_pending_ops
2137 || pending_state.has_pending_dyn_imports
2138 || pending_state.has_pending_dyn_module_evaluation
2139 || pending_state.has_pending_background_tasks
2140 || pending_state.has_pending_external_ops
2141 || pending_state.has_tick_scheduled
2142 || pending_state.has_refed_immediates > 0
2143 {
2144 } else {
2146 return Poll::Ready(Err(
2147 CoreErrorKind::Js(find_and_report_stalled_level_await_in_any_realm(
2148 scope, &realm.0,
2149 ))
2150 .into_box(),
2151 ));
2152 }
2153 }
2154
2155 if pending_state.has_pending_dyn_module_evaluation {
2156 if pending_state.has_pending_ops
2157 || pending_state.has_pending_dyn_imports
2158 || pending_state.has_pending_background_tasks
2159 || pending_state.has_pending_external_ops
2160 || pending_state.has_tick_scheduled
2161 || pending_state.has_refed_immediates > 0
2162 {
2163 } else if realm.modules_idle() {
2165 return Poll::Ready(Err(
2166 CoreErrorKind::Js(find_and_report_stalled_level_await_in_any_realm(
2167 scope, &realm.0,
2168 ))
2169 .into_box(),
2170 ));
2171 } else {
2172 realm.increment_modules_idle();
2176 self.inner.state.waker.wake();
2177 }
2178 }
2179
2180 Poll::Pending
2181 }
2182}
2183
2184fn find_and_report_stalled_level_await_in_any_realm(
2185 scope: &mut v8::PinScope,
2186 inner_realm: &JsRealmInner,
2187) -> Box<JsError> {
2188 let module_map = inner_realm.module_map();
2189 let messages = module_map.find_stalled_top_level_await(scope);
2190
2191 if !messages.is_empty() {
2192 let msg = v8::Local::new(scope, &messages[0]);
2197 let js_error = JsError::from_v8_message(scope, msg);
2198 return js_error;
2199 }
2200
2201 unreachable!("Expected at least one stalled top-level await");
2202}
2203
2204fn create_context<'s, 'i>(
2205 scope: &mut v8::PinScope<'s, 'i, ()>,
2206 global_template_middlewares: &[GlobalTemplateMiddlewareFn],
2207 global_object_middlewares: &[GlobalObjectMiddlewareFn],
2208 has_snapshot: bool,
2209) -> v8::Local<'s, v8::Context> {
2210 let context = if has_snapshot {
2211 v8::Context::from_snapshot(scope, 1, Default::default()).unwrap_or_else(
2213 || v8::Context::from_snapshot(scope, 0, Default::default()).unwrap(),
2214 )
2215 } else {
2216 let mut global_object_template = v8::ObjectTemplate::new(scope);
2218 for middleware in global_template_middlewares {
2219 global_object_template = middleware(scope, global_object_template);
2220 }
2221
2222 global_object_template.set_internal_field_count(2);
2223 v8::Context::new(
2224 scope,
2225 v8::ContextOptions {
2226 global_template: Some(global_object_template),
2227 ..Default::default()
2228 },
2229 )
2230 };
2231
2232 let scope = &mut v8::ContextScope::new(scope, context);
2233
2234 let global = context.global(scope);
2235 for middleware in global_object_middlewares {
2236 middleware(scope, global);
2237 }
2238 context
2239}
2240
2241impl JsRuntimeForSnapshot {
2242 pub fn new(options: RuntimeOptions) -> JsRuntimeForSnapshot {
2244 match Self::try_new(options) {
2245 Ok(runtime) => runtime,
2246 Err(err) => {
2247 panic!("Failed to initialize JsRuntime for snapshotting: {:?}", err);
2248 }
2249 }
2250 }
2251
2252 pub fn try_new(
2254 mut options: RuntimeOptions,
2255 ) -> Result<JsRuntimeForSnapshot, CoreError> {
2256 setup::init_v8(
2257 options.v8_platform.take(),
2258 true,
2259 options.unsafe_expose_natives_and_gc(),
2260 options.import_assertions_support.is_enabled(),
2261 );
2262
2263 let runtime = JsRuntime::new_inner(options, true)?;
2264 Ok(JsRuntimeForSnapshot(runtime))
2265 }
2266
2267 pub fn snapshot(mut self) -> Box<[u8]> {
2271 self.inner.prepare_for_cleanup();
2273 let original_sources =
2274 std::mem::take(&mut self.0.allocations.original_sources);
2275 let external_strings = original_sources
2276 .iter()
2277 .map(|s| s.as_str().as_bytes())
2278 .collect();
2279 let realm = JsRealm::clone(&self.inner.main_realm);
2280
2281 {
2283 jsrealm::context_scope!(scope, realm, self.v8_isolate());
2284 let default_context = v8::Context::new(scope, Default::default());
2285 scope.set_default_context(default_context);
2286
2287 let local_context = v8::Local::new(scope, realm.context());
2288 scope.add_context(local_context);
2289 }
2290
2291 let source_maps = self
2293 .inner
2294 .state
2295 .source_mapper
2296 .borrow_mut()
2297 .take_ext_source_maps();
2298 let mut ext_source_maps = HashMap::with_capacity(source_maps.len());
2299 for (k, v) in &source_maps {
2300 ext_source_maps.insert(k.as_static_str().unwrap(), v.as_ref());
2301 }
2302
2303 let sidecar_data = {
2309 let mut data_store = SnapshotStoreDataStore::default();
2310 let module_map_data = {
2311 let module_map = realm.0.module_map();
2312 module_map.serialize_for_snapshotting(&mut data_store)
2313 };
2314 let function_templates_data = {
2315 let function_templates = realm.0.function_templates();
2316 let f = std::mem::take(&mut *function_templates.borrow_mut());
2317
2318 f.serialize_for_snapshotting(&mut data_store)
2319 };
2320 let maybe_js_handled_promise_rejection_cb = {
2321 let context_state = &realm.0.context_state;
2322 let exception_state = &context_state.exception_state;
2323 exception_state
2324 .js_handled_promise_rejection_cb
2325 .borrow()
2326 .clone()
2327 }
2328 .map(|cb| data_store.register(cb));
2329
2330 let ext_import_meta_proto = realm
2331 .0
2332 .context_state
2333 .ext_import_meta_proto
2334 .borrow()
2335 .clone()
2336 .map(|p| data_store.register(p));
2337
2338 let snapshotted_data = SnapshottedData {
2339 module_map_data,
2340 function_templates_data,
2341 op_count: self.inner.op_count,
2342 addl_refs_count: self.inner.addl_refs_count,
2343 source_count: self.inner.source_count,
2344 extensions: self.inner.extensions.clone(),
2345 js_handled_promise_rejection_cb: maybe_js_handled_promise_rejection_cb,
2346 ext_import_meta_proto,
2347 ext_source_maps,
2348 external_strings,
2349 };
2350
2351 jsrealm::context_scope!(scope, realm, self.v8_isolate());
2352 snapshot::store_snapshotted_data_for_snapshot(
2353 scope,
2354 realm.context().clone(),
2355 snapshotted_data,
2356 data_store,
2357 )
2358 };
2359 drop(realm);
2360
2361 let v8_data = self
2362 .0
2363 .inner
2364 .prepare_for_snapshot()
2365 .create_blob(v8::FunctionCodeHandling::Keep)
2366 .unwrap();
2367
2368 snapshot::serialize(v8_data, sidecar_data)
2369 }
2370}
2371
2372#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2373pub(crate) struct EventLoopPendingState {
2374 has_pending_ops: bool,
2375 has_pending_refed_ops: bool,
2376 has_pending_dyn_imports: bool,
2377 has_pending_dyn_module_evaluation: bool,
2378 has_pending_module_evaluation: bool,
2379 has_pending_background_tasks: bool,
2380 has_tick_scheduled: bool,
2381 has_pending_promise_events: bool,
2382 has_pending_external_ops: bool,
2383 has_outstanding_immediates: bool,
2384 has_refed_immediates: u32,
2385}
2386
2387impl EventLoopPendingState {
2388 pub fn new(
2390 scope: &mut v8::PinScope<()>,
2391 state: &ContextState,
2392 modules: &ModuleMap,
2393 ) -> Self {
2394 let num_unrefed_ops = state.unrefed_ops.borrow().len();
2395 let num_pending_ops = state.pending_ops.len();
2396 let has_pending_tasks = state.task_spawner_factory.has_pending_tasks();
2397 let has_pending_timers = !state.timers.is_empty();
2398 let has_pending_refed_timers = state.timers.has_pending_timers();
2399 let has_pending_dyn_imports = modules.has_pending_dynamic_imports();
2400 let has_pending_dyn_module_evaluation =
2401 modules.has_pending_dyn_module_evaluation();
2402 let has_pending_module_evaluation = modules.has_pending_module_evaluation();
2403 let has_pending_promise_events = !state
2404 .exception_state
2405 .pending_promise_rejections
2406 .borrow()
2407 .is_empty()
2408 || !state
2409 .exception_state
2410 .pending_handled_promise_rejections
2411 .borrow()
2412 .is_empty();
2413 let has_pending_refed_ops = has_pending_tasks
2414 || has_pending_refed_timers
2415 || num_pending_ops > num_unrefed_ops;
2416 let (has_outstanding_immediates, has_refed_immediates) = {
2417 let info = state.immediate_info.borrow();
2418 (info.has_outstanding, info.ref_count)
2419 };
2420 EventLoopPendingState {
2421 has_pending_ops: has_pending_refed_ops
2422 || has_pending_timers
2423 || (num_pending_ops > 0),
2424 has_pending_refed_ops,
2425 has_pending_dyn_imports,
2426 has_pending_dyn_module_evaluation,
2427 has_pending_module_evaluation,
2428 has_pending_background_tasks: scope.has_pending_background_tasks(),
2429 has_tick_scheduled: state.has_next_tick_scheduled.get(),
2430 has_pending_promise_events,
2431 has_pending_external_ops: state.external_ops_tracker.has_pending_ops(),
2432 has_outstanding_immediates,
2433 has_refed_immediates,
2434 }
2435 }
2436
2437 pub fn new_from_scope(scope: &mut v8::PinScope) -> Self {
2439 let module_map = JsRealm::module_map_from(scope);
2440 let context_state = JsRealm::state_from_scope(scope);
2441 Self::new(scope, &context_state, &module_map)
2442 }
2443
2444 pub fn is_pending(&self) -> bool {
2445 self.has_pending_refed_ops
2446 || self.has_pending_dyn_imports
2447 || self.has_pending_dyn_module_evaluation
2448 || self.has_pending_module_evaluation
2449 || self.has_pending_background_tasks
2450 || self.has_tick_scheduled
2451 || self.has_refed_immediates > 0
2452 || self.has_pending_promise_events
2453 || self.has_pending_external_ops
2454 }
2455}
2456
2457extern "C" fn near_heap_limit_callback<F>(
2458 data: *mut c_void,
2459 current_heap_limit: usize,
2460 initial_heap_limit: usize,
2461) -> usize
2462where
2463 F: FnMut(usize, usize) -> usize,
2464{
2465 let callback = unsafe { &mut *(data as *mut F) };
2468 callback(current_heap_limit, initial_heap_limit)
2469}
2470
2471impl JsRuntimeState {
2472 pub(crate) fn inspector(&self) -> Rc<JsRuntimeInspector> {
2473 self.inspector.borrow().as_ref().unwrap().clone()
2474 }
2475
2476 pub fn notify_new_dynamic_import(&self) {
2479 self.waker.wake();
2481 }
2482
2483 pub(crate) fn with_inspector<T>(
2485 &self,
2486 mut f: impl FnMut(&JsRuntimeInspector) -> T,
2487 ) -> Option<T> {
2488 if !self.has_inspector.get() {
2490 return None;
2491 }
2492 self
2493 .inspector
2494 .borrow()
2495 .as_ref()
2496 .map(|inspector| f(inspector))
2497 }
2498}
2499
2500impl JsRuntime {
2502 #[cfg(test)]
2503 pub(crate) fn instantiate_module(
2504 &mut self,
2505 id: ModuleId,
2506 ) -> Result<(), v8::Global<v8::Value>> {
2507 let isolate = &mut *self.inner.v8_isolate;
2508 let realm = JsRealm::clone(&self.inner.main_realm);
2509 jsrealm::context_scope!(scope, realm, isolate);
2510 realm.instantiate_module(scope, id)
2511 }
2512
2513 pub fn mod_evaluate(
2531 &mut self,
2532 id: ModuleId,
2533 ) -> impl Future<Output = Result<(), CoreError>> + use<> {
2534 let isolate = &mut *self.inner.v8_isolate;
2535 let realm = &self.inner.main_realm;
2536 jsrealm::context_scope!(scope, realm, isolate);
2537 self.inner.main_realm.0.module_map.mod_evaluate(scope, id)
2538 }
2539
2540 pub async fn load_main_es_module_from_code(
2553 &mut self,
2554 specifier: &ModuleSpecifier,
2555 code: impl IntoModuleCodeString,
2556 ) -> Result<ModuleId, CoreError> {
2557 let isolate = &mut self.inner.v8_isolate;
2558 self
2559 .inner
2560 .main_realm
2561 .load_main_es_module_from_code(
2562 isolate,
2563 specifier,
2564 Some(code.into_module_code()),
2565 )
2566 .await
2567 }
2568
2569 pub async fn load_main_es_module(
2578 &mut self,
2579 specifier: &ModuleSpecifier,
2580 ) -> Result<ModuleId, CoreError> {
2581 let isolate = &mut self.inner.v8_isolate;
2582 self
2583 .inner
2584 .main_realm
2585 .load_main_es_module_from_code(isolate, specifier, None)
2586 .await
2587 }
2588
2589 pub async fn load_side_es_module_from_code(
2603 &mut self,
2604 specifier: &ModuleSpecifier,
2605 code: impl IntoModuleCodeString,
2606 ) -> Result<ModuleId, CoreError> {
2607 let isolate = &mut self.inner.v8_isolate;
2608 self
2609 .inner
2610 .main_realm
2611 .load_side_es_module_from_code(
2612 isolate,
2613 specifier,
2614 Some(code.into_module_code()),
2615 )
2616 .await
2617 }
2618
2619 pub async fn load_side_es_module(
2628 &mut self,
2629 specifier: &ModuleSpecifier,
2630 ) -> Result<ModuleId, CoreError> {
2631 let isolate = &mut self.inner.v8_isolate;
2632 self
2633 .inner
2634 .main_realm
2635 .load_side_es_module_from_code(isolate, specifier, None)
2636 .await
2637 }
2638
2639 pub fn lazy_load_es_module_with_code(
2647 &mut self,
2648 specifier: impl IntoModuleName,
2649 code: impl IntoModuleCodeString,
2650 ) -> Result<v8::Global<v8::Value>, CoreError> {
2651 let isolate = &mut self.inner.v8_isolate;
2652 self.inner.main_realm.lazy_load_es_module_with_code(
2653 isolate,
2654 specifier.into_module_name(),
2655 code.into_module_code(),
2656 )
2657 }
2658
2659 fn do_js_run_immediate_callbacks<'s, 'i>(
2660 scope: &mut v8::PinScope<'s, 'i>,
2661 context_state: &ContextState,
2662 ) -> Result<(), Box<JsError>> {
2663 v8::tc_scope!(let tc_scope, scope);
2664
2665 let undefined = v8::undefined(tc_scope).into();
2666 let run_immediate_callbacks_cb =
2667 context_state.run_immediate_callbacks_cb.borrow();
2668 let run_immediate_callbacks_cb =
2669 run_immediate_callbacks_cb.as_ref().unwrap().open(tc_scope);
2670
2671 run_immediate_callbacks_cb.call(tc_scope, undefined, &[]);
2672
2673 if let Some(exception) = tc_scope.exception() {
2674 let e: Result<(), Box<JsError>> =
2675 exception_to_err_result(tc_scope, exception, false, true);
2676 return e;
2677 }
2678 Ok(())
2679 }
2680
2681 fn do_js_event_loop_tick_realm<'s, 'i>(
2682 cx: &mut Context,
2683 scope: &mut v8::PinScope<'s, 'i>,
2684 context_state: &ContextState,
2685 exception_state: &ExceptionState,
2686 ) -> Result<(bool, bool), Box<JsError>> {
2687 let mut dispatched_ops = false;
2688 let mut did_work = false;
2689
2690 let mut retries = 3;
2693 while let Poll::Ready(tasks) =
2694 context_state.task_spawner_factory.poll_inner(cx)
2695 {
2696 dispatched_ops = true;
2698 for task in tasks {
2699 task(scope);
2700 }
2701 scope.perform_microtask_checkpoint();
2703
2704 retries -= 1;
2707 if retries == 0 {
2708 cx.waker().wake_by_ref();
2709 break;
2710 }
2711 }
2712
2713 const MAX_VEC_SIZE_FOR_OPS: usize = 1024;
2717
2718 let mut args: SmallVec<[v8::Local<v8::Value>; 32]> =
2725 SmallVec::with_capacity(32);
2726
2727 loop {
2728 if args.len() >= MAX_VEC_SIZE_FOR_OPS {
2729 cx.waker().wake_by_ref();
2731 break;
2732 }
2733
2734 let Poll::Ready((promise_id, op_id, res)) =
2735 context_state.pending_ops.poll_ready(cx)
2736 else {
2737 break;
2738 };
2739
2740 let res = res.unwrap(scope);
2741
2742 {
2743 let op_ctx = &context_state.op_ctxs[op_id as usize];
2744 if op_ctx.metrics_enabled() {
2745 if res.is_ok() {
2746 dispatch_metrics_async(op_ctx, OpMetricsEvent::CompletedAsync);
2747 } else {
2748 dispatch_metrics_async(op_ctx, OpMetricsEvent::ErrorAsync);
2749 }
2750 }
2751 }
2752
2753 context_state.unrefed_ops.borrow_mut().remove(&promise_id);
2754 context_state
2755 .activity_traces
2756 .complete(RuntimeActivityType::AsyncOp, promise_id as _);
2757 dispatched_ops |= true;
2758 did_work |= true;
2759 args.push(v8::Integer::new(scope, promise_id).into());
2760 args.push(v8::Boolean::new(scope, res.is_ok()).into());
2761 args.push(res.unwrap_or_else(std::convert::identity));
2762 }
2763
2764 let undefined: v8::Local<v8::Value> = v8::undefined(scope).into();
2765 let has_tick_scheduled = context_state.has_next_tick_scheduled.get();
2766 dispatched_ops |= has_tick_scheduled;
2767
2768 while let Some((promise, result)) = exception_state
2769 .pending_handled_promise_rejections
2770 .borrow_mut()
2771 .pop_front()
2772 {
2773 if let Some(handler) = exception_state
2774 .js_handled_promise_rejection_cb
2775 .borrow()
2776 .as_ref()
2777 {
2778 let function = handler.open(scope);
2779
2780 let args = [
2781 v8::Local::new(scope, promise).into(),
2782 v8::Local::new(scope, result),
2783 ];
2784 function.call(scope, undefined, &args);
2785 }
2786 }
2787
2788 let rejections = if !exception_state
2789 .pending_promise_rejections
2790 .borrow_mut()
2791 .is_empty()
2792 {
2793 let mut pending_rejections =
2795 exception_state.pending_promise_rejections.borrow_mut();
2796 let mut rejections = VecDeque::default();
2797 std::mem::swap(&mut *pending_rejections, &mut rejections);
2798 drop(pending_rejections);
2799
2800 let arr = v8::Array::new(scope, (rejections.len() * 2) as i32);
2801 let mut index = 0;
2802 for rejection in rejections.into_iter() {
2803 let value = v8::Local::new(scope, rejection.0);
2804 arr.set_index(scope, index, value.into());
2805 index += 1;
2806 let value = v8::Local::new(scope, rejection.1);
2807 arr.set_index(scope, index, value);
2808 index += 1;
2809 }
2810 arr.into()
2811 } else {
2812 undefined
2813 };
2814
2815 args.push(rejections);
2816
2817 let timers = match context_state.timers.poll_timers(cx) {
2820 Poll::Ready(timers) => {
2821 did_work |= true;
2822 let traces_enabled = context_state.activity_traces.is_enabled();
2823 let arr = v8::Array::new(scope, (timers.len() * 3) as _);
2824 #[allow(clippy::needless_range_loop)]
2825 for i in 0..timers.len() {
2826 if traces_enabled {
2827 context_state
2829 .activity_traces
2830 .complete(RuntimeActivityType::Timer, timers[i].0 as _);
2831 }
2832 let value = v8::Integer::new(scope, timers[i].1.1 as _);
2834 arr.set_index(scope, (i * 3) as _, value.into());
2835 let value = v8::Number::new(scope, timers[i].0 as _);
2836 arr.set_index(scope, (i * 3 + 1) as _, value.into());
2837 let value = v8::Local::new(scope, timers[i].1.0.clone());
2838 arr.set_index(scope, (i * 3 + 2) as _, value.into());
2839 }
2840 arr.into()
2841 }
2842 _ => undefined,
2843 };
2844 args.push(timers);
2845
2846 let has_tick_scheduled = v8::Boolean::new(scope, has_tick_scheduled);
2847 args.push(has_tick_scheduled.into());
2848
2849 v8::tc_scope!(let tc_scope, scope);
2850
2851 let js_event_loop_tick_cb = context_state.js_event_loop_tick_cb.borrow();
2852 let js_event_loop_tick_cb =
2853 js_event_loop_tick_cb.as_ref().unwrap().open(tc_scope);
2854
2855 js_event_loop_tick_cb.call(tc_scope, undefined, args.as_slice());
2856
2857 if let Some(exception) = tc_scope.exception() {
2858 return exception_to_err_result(tc_scope, exception, false, true);
2859 }
2860
2861 if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
2862 return Ok((false, false));
2863 }
2864
2865 Ok((dispatched_ops, did_work))
2866 }
2867}
2868
2869fn mark_as_loaded_from_fs_during_snapshot(
2870 files_loaded: &mut Vec<&'static str>,
2871 source: &ExtensionFileSourceCode,
2872) {
2873 #[allow(deprecated)]
2874 if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) = source {
2875 files_loaded.push(path);
2876 }
2877}