deno_runtime/
worker.rs

1// Copyright 2018-2025 the Deno authors. MIT license.
2use std::borrow::Cow;
3use std::collections::HashMap;
4use std::rc::Rc;
5use std::sync::Arc;
6#[cfg(target_os = "linux")]
7use std::sync::LazyLock;
8use std::sync::atomic::AtomicBool;
9use std::sync::atomic::Ordering;
10use std::time::Duration;
11use std::time::Instant;
12
13use deno_cache::CacheImpl;
14use deno_cache::CreateCache;
15use deno_cache::SqliteBackedCache;
16use deno_core::CompiledWasmModuleStore;
17use deno_core::Extension;
18use deno_core::InspectorSessionKind;
19use deno_core::JsRuntime;
20use deno_core::JsRuntimeInspector;
21use deno_core::LocalInspectorSession;
22use deno_core::ModuleCodeString;
23use deno_core::ModuleId;
24use deno_core::ModuleLoadOptions;
25use deno_core::ModuleLoadReferrer;
26use deno_core::ModuleLoader;
27use deno_core::ModuleSpecifier;
28use deno_core::OpMetricsFactoryFn;
29use deno_core::OpMetricsSummaryTracker;
30use deno_core::PollEventLoopOptions;
31use deno_core::RuntimeOptions;
32use deno_core::SharedArrayBufferStore;
33use deno_core::SourceCodeCacheInfo;
34use deno_core::error::CoreError;
35use deno_core::error::JsError;
36use deno_core::merge_op_metrics;
37use deno_core::v8;
38use deno_cron::local::LocalCronHandler;
39use deno_fs::FileSystem;
40use deno_io::Stdio;
41use deno_kv::dynamic::MultiBackendDbHandler;
42use deno_napi::DenoRtNativeAddonLoaderRc;
43use deno_node::ExtNodeSys;
44use deno_node::NodeExtInitServices;
45use deno_os::ExitCode;
46use deno_permissions::PermissionsContainer;
47use deno_process::NpmProcessStateProviderRc;
48use deno_tls::RootCertStoreProvider;
49use deno_tls::TlsKeys;
50use deno_web::BlobStore;
51use deno_web::InMemoryBroadcastChannel;
52use log::debug;
53use node_resolver::InNpmPackageChecker;
54use node_resolver::NpmPackageFolderResolver;
55
56use crate::BootstrapOptions;
57use crate::FeatureChecker;
58use crate::code_cache::CodeCache;
59use crate::code_cache::CodeCacheType;
60use crate::inspector_server::InspectorServer;
61use crate::ops;
62use crate::shared::runtime;
63
64pub type FormatJsErrorFn = dyn Fn(&JsError) -> String + Sync + Send;
65
66#[cfg(target_os = "linux")]
67pub(crate) static MEMORY_TRIM_HANDLER_ENABLED: LazyLock<bool> =
68  LazyLock::new(|| std::env::var_os("DENO_USR2_MEMORY_TRIM").is_some());
69
70#[cfg(target_os = "linux")]
71pub(crate) static SIGUSR2_RX: LazyLock<tokio::sync::watch::Receiver<()>> =
72  LazyLock::new(|| {
73    let (tx, rx) = tokio::sync::watch::channel(());
74
75    tokio::spawn(async move {
76      let mut sigusr2 = deno_signals::signal_stream(libc::SIGUSR2).unwrap();
77
78      loop {
79        sigusr2.recv().await;
80
81        // SAFETY: calling into libc, nothing relevant on the Rust side.
82        unsafe {
83          libc::malloc_trim(0);
84        }
85
86        if tx.send(()).is_err() {
87          break;
88        }
89      }
90    });
91
92    rx
93  });
94
95// TODO(bartlomieju): temporary measurement until we start supporting more
96// module types
97pub fn create_validate_import_attributes_callback(
98  enable_raw_imports: Arc<AtomicBool>,
99) -> deno_core::ValidateImportAttributesCb {
100  Box::new(
101    move |scope: &mut v8::PinScope<'_, '_>,
102          attributes: &HashMap<String, String>| {
103      let valid_attribute = |kind: &str| {
104        enable_raw_imports.load(Ordering::Relaxed)
105          && matches!(kind, "bytes" | "text")
106          || matches!(kind, "json")
107      };
108      for (key, value) in attributes {
109        let msg = if key != "type" {
110          Some(format!("\"{key}\" attribute is not supported."))
111        } else if !valid_attribute(value.as_str()) {
112          Some(format!("\"{value}\" is not a valid module type."))
113        } else {
114          None
115        };
116
117        let Some(msg) = msg else {
118          continue;
119        };
120
121        let message = v8::String::new(scope, &msg).unwrap();
122        let exception = v8::Exception::type_error(scope, message);
123        scope.throw_exception(exception);
124        return;
125      }
126    },
127  )
128}
129
130pub fn make_wait_for_inspector_disconnect_callback() -> Box<dyn Fn()> {
131  let has_notified_of_inspector_disconnect = AtomicBool::new(false);
132  Box::new(move || {
133    if !has_notified_of_inspector_disconnect
134      .swap(true, std::sync::atomic::Ordering::SeqCst)
135    {
136      log::info!(
137        "Program finished. Waiting for inspector to disconnect to exit the process..."
138      );
139    }
140  })
141}
142
143/// This worker is created and used by almost all
144/// subcommands in Deno executable.
145///
146/// It provides ops available in the `Deno` namespace.
147///
148/// All `WebWorker`s created during program execution
149/// are descendants of this worker.
150pub struct MainWorker {
151  pub js_runtime: JsRuntime,
152  should_break_on_first_statement: bool,
153  should_wait_for_inspector_session: bool,
154  exit_code: ExitCode,
155  bootstrap_fn_global: Option<v8::Global<v8::Function>>,
156  dispatch_load_event_fn_global: v8::Global<v8::Function>,
157  dispatch_beforeunload_event_fn_global: v8::Global<v8::Function>,
158  dispatch_unload_event_fn_global: v8::Global<v8::Function>,
159  dispatch_process_beforeexit_event_fn_global: v8::Global<v8::Function>,
160  dispatch_process_exit_event_fn_global: v8::Global<v8::Function>,
161  memory_trim_handle: Option<tokio::task::JoinHandle<()>>,
162}
163
164impl Drop for MainWorker {
165  fn drop(&mut self) {
166    if let Some(memory_trim_handle) = self.memory_trim_handle.take() {
167      memory_trim_handle.abort();
168    }
169  }
170}
171
172pub struct WorkerServiceOptions<
173  TInNpmPackageChecker: InNpmPackageChecker,
174  TNpmPackageFolderResolver: NpmPackageFolderResolver,
175  TExtNodeSys: ExtNodeSys,
176> {
177  pub blob_store: Arc<BlobStore>,
178  pub broadcast_channel: InMemoryBroadcastChannel,
179  pub deno_rt_native_addon_loader: Option<DenoRtNativeAddonLoaderRc>,
180  pub feature_checker: Arc<FeatureChecker>,
181  pub fs: Arc<dyn FileSystem>,
182  /// Implementation of `ModuleLoader` which will be
183  /// called when V8 requests to load ES modules.
184  ///
185  /// If not provided runtime will error if code being
186  /// executed tries to load modules.
187  pub module_loader: Rc<dyn ModuleLoader>,
188  pub node_services: Option<
189    NodeExtInitServices<
190      TInNpmPackageChecker,
191      TNpmPackageFolderResolver,
192      TExtNodeSys,
193    >,
194  >,
195  pub npm_process_state_provider: Option<NpmProcessStateProviderRc>,
196  pub permissions: PermissionsContainer,
197  pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
198  pub fetch_dns_resolver: deno_fetch::dns::Resolver,
199
200  /// The store to use for transferring SharedArrayBuffers between isolates.
201  /// If multiple isolates should have the possibility of sharing
202  /// SharedArrayBuffers, they should use the same [SharedArrayBufferStore]. If
203  /// no [SharedArrayBufferStore] is specified, SharedArrayBuffer can not be
204  /// serialized.
205  pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
206
207  /// The store to use for transferring `WebAssembly.Module` objects between
208  /// isolates.
209  /// If multiple isolates should have the possibility of sharing
210  /// `WebAssembly.Module` objects, they should use the same
211  /// [CompiledWasmModuleStore]. If no [CompiledWasmModuleStore] is specified,
212  /// `WebAssembly.Module` objects cannot be serialized.
213  pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
214
215  /// V8 code cache for module and script source code.
216  pub v8_code_cache: Option<Arc<dyn CodeCache>>,
217
218  pub bundle_provider: Option<Arc<dyn deno_bundle_runtime::BundleProvider>>,
219}
220
221pub struct WorkerOptions {
222  pub bootstrap: BootstrapOptions,
223
224  /// JsRuntime extensions, not to be confused with ES modules.
225  ///
226  /// Extensions register "ops" and JavaScript sources provided in `js` or `esm`
227  /// configuration. If you are using a snapshot, then extensions shouldn't
228  /// provide JavaScript sources that were already snapshotted.
229  pub extensions: Vec<Extension>,
230
231  /// V8 snapshot that should be loaded on startup.
232  pub startup_snapshot: Option<&'static [u8]>,
233
234  /// Should op registration be skipped?
235  pub skip_op_registration: bool,
236
237  /// Optional isolate creation parameters, such as heap limits.
238  pub create_params: Option<v8::CreateParams>,
239
240  pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
241  pub seed: Option<u64>,
242
243  // Callbacks invoked when creating new instance of WebWorker
244  pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
245  pub format_js_error_fn: Option<Arc<FormatJsErrorFn>>,
246
247  pub maybe_inspector_server: Option<Arc<InspectorServer>>,
248  // If true, the worker will wait for inspector session and break on first
249  // statement of user code. Takes higher precedence than
250  // `should_wait_for_inspector_session`.
251  pub should_break_on_first_statement: bool,
252  // If true, the worker will wait for inspector session before executing
253  // user code.
254  pub should_wait_for_inspector_session: bool,
255  /// If Some, print a low-level trace output for ops matching the given patterns.
256  pub trace_ops: Option<Vec<String>>,
257
258  pub cache_storage_dir: Option<std::path::PathBuf>,
259  pub origin_storage_dir: Option<std::path::PathBuf>,
260  pub stdio: Stdio,
261  pub enable_raw_imports: bool,
262  pub enable_stack_trace_arg_in_ops: bool,
263
264  pub unconfigured_runtime: Option<UnconfiguredRuntime>,
265}
266
267impl Default for WorkerOptions {
268  fn default() -> Self {
269    Self {
270      create_web_worker_cb: Arc::new(|_| {
271        unimplemented!("web workers are not supported")
272      }),
273      skip_op_registration: false,
274      seed: None,
275      unsafely_ignore_certificate_errors: Default::default(),
276      should_break_on_first_statement: Default::default(),
277      should_wait_for_inspector_session: Default::default(),
278      trace_ops: Default::default(),
279      maybe_inspector_server: Default::default(),
280      format_js_error_fn: Default::default(),
281      origin_storage_dir: Default::default(),
282      cache_storage_dir: Default::default(),
283      extensions: Default::default(),
284      startup_snapshot: Default::default(),
285      create_params: Default::default(),
286      bootstrap: Default::default(),
287      stdio: Default::default(),
288      enable_raw_imports: false,
289      enable_stack_trace_arg_in_ops: false,
290      unconfigured_runtime: None,
291    }
292  }
293}
294
295pub fn create_op_metrics(
296  enable_op_summary_metrics: bool,
297  trace_ops: Option<Vec<String>>,
298) -> (
299  Option<Rc<OpMetricsSummaryTracker>>,
300  Option<OpMetricsFactoryFn>,
301) {
302  let mut op_summary_metrics = None;
303  let mut op_metrics_factory_fn: Option<OpMetricsFactoryFn> = None;
304  let now = Instant::now();
305  let max_len: Rc<std::cell::Cell<usize>> = Default::default();
306  if let Some(patterns) = trace_ops {
307    /// Match an op name against a list of patterns
308    fn matches_pattern(patterns: &[String], name: &str) -> bool {
309      let mut found_match = false;
310      let mut found_nomatch = false;
311      for pattern in patterns.iter() {
312        if let Some(pattern) = pattern.strip_prefix('-') {
313          if name.contains(pattern) {
314            return false;
315          }
316        } else if name.contains(pattern.as_str()) {
317          found_match = true;
318        } else {
319          found_nomatch = true;
320        }
321      }
322
323      found_match || !found_nomatch
324    }
325
326    op_metrics_factory_fn = Some(Box::new(move |_, _, decl| {
327      // If we don't match a requested pattern, or we match a negative pattern, bail
328      if !matches_pattern(&patterns, decl.name) {
329        return None;
330      }
331
332      max_len.set(max_len.get().max(decl.name.len()));
333      let max_len = max_len.clone();
334      Some(Rc::new(
335        #[allow(clippy::print_stderr)]
336        move |op: &deno_core::_ops::OpCtx, event, source| {
337          eprintln!(
338            "[{: >10.3}] {name:max_len$}: {event:?} {source:?}",
339            now.elapsed().as_secs_f64(),
340            name = op.decl().name,
341            max_len = max_len.get()
342          );
343        },
344      ))
345    }));
346  }
347
348  if enable_op_summary_metrics {
349    let summary = Rc::new(OpMetricsSummaryTracker::default());
350    let summary_metrics = summary.clone().op_metrics_factory_fn(|_| true);
351    op_metrics_factory_fn = Some(match op_metrics_factory_fn {
352      Some(f) => merge_op_metrics(f, summary_metrics),
353      None => summary_metrics,
354    });
355    op_summary_metrics = Some(summary);
356  }
357
358  (op_summary_metrics, op_metrics_factory_fn)
359}
360
361impl MainWorker {
362  pub fn bootstrap_from_options<
363    TInNpmPackageChecker: InNpmPackageChecker + 'static,
364    TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
365    TExtNodeSys: ExtNodeSys + 'static,
366  >(
367    main_module: &ModuleSpecifier,
368    services: WorkerServiceOptions<
369      TInNpmPackageChecker,
370      TNpmPackageFolderResolver,
371      TExtNodeSys,
372    >,
373    options: WorkerOptions,
374  ) -> Self {
375    let (mut worker, bootstrap_options) =
376      Self::from_options(main_module, services, options);
377    worker.bootstrap(bootstrap_options);
378    worker
379  }
380
381  fn from_options<
382    TInNpmPackageChecker: InNpmPackageChecker + 'static,
383    TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
384    TExtNodeSys: ExtNodeSys + 'static,
385  >(
386    main_module: &ModuleSpecifier,
387    services: WorkerServiceOptions<
388      TInNpmPackageChecker,
389      TNpmPackageFolderResolver,
390      TExtNodeSys,
391    >,
392    mut options: WorkerOptions,
393  ) -> (Self, BootstrapOptions) {
394    fn create_cache_inner(options: &WorkerOptions) -> Option<CreateCache> {
395      if let Ok(var) = std::env::var("DENO_CACHE_LSC_ENDPOINT") {
396        let elems: Vec<_> = var.split(",").collect();
397        if elems.len() == 2 {
398          let endpoint = elems[0];
399          let token = elems[1];
400          use deno_cache::CacheShard;
401
402          let shard =
403            Rc::new(CacheShard::new(endpoint.to_string(), token.to_string()));
404          let create_cache_fn = move || {
405            let x = deno_cache::LscBackend::default();
406            x.set_shard(shard.clone());
407
408            Ok(CacheImpl::Lsc(x))
409          };
410          #[allow(clippy::arc_with_non_send_sync)]
411          return Some(CreateCache(Arc::new(create_cache_fn)));
412        }
413      }
414
415      if let Some(storage_dir) = &options.cache_storage_dir {
416        let storage_dir = storage_dir.clone();
417        let create_cache_fn = move || {
418          let s = SqliteBackedCache::new(storage_dir.clone())?;
419          Ok(CacheImpl::Sqlite(s))
420        };
421        return Some(CreateCache(Arc::new(create_cache_fn)));
422      }
423
424      None
425    }
426    let create_cache = create_cache_inner(&options);
427
428    // Get our op metrics
429    let (op_summary_metrics, op_metrics_factory_fn) = create_op_metrics(
430      options.bootstrap.enable_op_summary_metrics,
431      options.trace_ops,
432    );
433
434    // Permissions: many ops depend on this
435    let enable_testing_features = options.bootstrap.enable_testing_features;
436    let exit_code = ExitCode::default();
437
438    // check options that require configuring a new jsruntime
439    if options.unconfigured_runtime.is_some()
440      && (options.enable_stack_trace_arg_in_ops
441        || op_metrics_factory_fn.is_some())
442    {
443      options.unconfigured_runtime = None;
444    }
445
446    #[cfg(feature = "hmr")]
447    assert!(
448      cfg!(not(feature = "only_snapshotted_js_sources")),
449      "'hmr' is incompatible with 'only_snapshotted_js_sources'."
450    );
451
452    #[cfg(feature = "only_snapshotted_js_sources")]
453    options.startup_snapshot.as_ref().expect("A user snapshot was not provided, even though 'only_snapshotted_js_sources' is used.");
454
455    let mut js_runtime = if let Some(u) = options.unconfigured_runtime {
456      u.hydrate(services.module_loader)
457    } else {
458      let mut extensions = common_extensions::<
459        TInNpmPackageChecker,
460        TNpmPackageFolderResolver,
461        TExtNodeSys,
462      >(options.startup_snapshot.is_some(), false);
463
464      extensions.extend(std::mem::take(&mut options.extensions));
465
466      common_runtime(CommonRuntimeOptions {
467        module_loader: services.module_loader.clone(),
468        startup_snapshot: options.startup_snapshot,
469        create_params: options.create_params,
470        skip_op_registration: options.skip_op_registration,
471        shared_array_buffer_store: services.shared_array_buffer_store,
472        compiled_wasm_module_store: services.compiled_wasm_module_store,
473        extensions,
474        op_metrics_factory_fn,
475        enable_stack_trace_arg_in_ops: options.enable_stack_trace_arg_in_ops,
476      })
477    };
478
479    js_runtime
480      .set_eval_context_code_cache_cbs(services.v8_code_cache.map(|cache| {
481      let cache_clone = cache.clone();
482      (
483        Box::new(move |specifier: &ModuleSpecifier, code: &v8::String| {
484          let source_hash = {
485            use std::hash::Hash;
486            use std::hash::Hasher;
487            let mut hasher = twox_hash::XxHash64::default();
488            code.hash(&mut hasher);
489            hasher.finish()
490          };
491          let data = cache
492            .get_sync(specifier, CodeCacheType::Script, source_hash)
493            .inspect(|_| {
494              // This log line is also used by tests.
495              log::debug!(
496                "V8 code cache hit for script: {specifier}, [{source_hash}]"
497              );
498            })
499            .map(Cow::Owned);
500          Ok(SourceCodeCacheInfo {
501            data,
502            hash: source_hash,
503          })
504        }) as Box<dyn Fn(&_, &_) -> _>,
505        Box::new(
506          move |specifier: ModuleSpecifier, source_hash: u64, data: &[u8]| {
507            // This log line is also used by tests.
508            log::debug!(
509              "Updating V8 code cache for script: {specifier}, [{source_hash}]"
510            );
511            cache_clone.set_sync(
512              specifier,
513              CodeCacheType::Script,
514              source_hash,
515              data,
516            );
517          },
518        ) as Box<dyn Fn(_, _, &_)>,
519      )
520    }));
521
522    js_runtime
523      .op_state()
524      .borrow_mut()
525      .borrow::<EnableRawImports>()
526      .0
527      .store(options.enable_raw_imports, Ordering::Relaxed);
528
529    js_runtime
530      .lazy_init_extensions(vec![
531        deno_web::deno_web::args(
532          services.blob_store.clone(),
533          options.bootstrap.location.clone(),
534          services.broadcast_channel.clone(),
535        ),
536        deno_fetch::deno_fetch::args(deno_fetch::Options {
537          user_agent: options.bootstrap.user_agent.clone(),
538          root_cert_store_provider: services.root_cert_store_provider.clone(),
539          unsafely_ignore_certificate_errors: options
540            .unsafely_ignore_certificate_errors
541            .clone(),
542          file_fetch_handler: Rc::new(deno_fetch::FsFetchHandler),
543          resolver: services.fetch_dns_resolver,
544          ..Default::default()
545        }),
546        deno_cache::deno_cache::args(create_cache),
547        deno_websocket::deno_websocket::args(),
548        deno_webstorage::deno_webstorage::args(
549          options.origin_storage_dir.clone(),
550        ),
551        deno_crypto::deno_crypto::args(options.seed),
552        deno_ffi::deno_ffi::args(services.deno_rt_native_addon_loader.clone()),
553        deno_net::deno_net::args(
554          services.root_cert_store_provider.clone(),
555          options.unsafely_ignore_certificate_errors.clone(),
556        ),
557        deno_kv::deno_kv::args(
558          MultiBackendDbHandler::remote_or_sqlite(
559            options.origin_storage_dir.clone(),
560            options.seed,
561            deno_kv::remote::HttpOptions {
562              user_agent: options.bootstrap.user_agent.clone(),
563              root_cert_store_provider: services
564                .root_cert_store_provider
565                .clone(),
566              unsafely_ignore_certificate_errors: options
567                .unsafely_ignore_certificate_errors
568                .clone(),
569              client_cert_chain_and_key: TlsKeys::Null,
570              proxy: None,
571            },
572          ),
573          deno_kv::KvConfig::builder().build(),
574        ),
575        deno_napi::deno_napi::args(
576          services.deno_rt_native_addon_loader.clone(),
577        ),
578        deno_http::deno_http::args(deno_http::Options {
579          no_legacy_abort: options.bootstrap.no_legacy_abort,
580          ..Default::default()
581        }),
582        deno_io::deno_io::args(Some(options.stdio)),
583        deno_fs::deno_fs::args(services.fs.clone()),
584        deno_os::deno_os::args(Some(exit_code.clone())),
585        deno_process::deno_process::args(services.npm_process_state_provider),
586        deno_node::deno_node::args::<
587          TInNpmPackageChecker,
588          TNpmPackageFolderResolver,
589          TExtNodeSys,
590        >(services.node_services, services.fs.clone()),
591        ops::runtime::deno_runtime::args(main_module.clone()),
592        ops::worker_host::deno_worker_host::args(
593          options.create_web_worker_cb.clone(),
594          options.format_js_error_fn.clone(),
595        ),
596        deno_bundle_runtime::deno_bundle_runtime::args(
597          services.bundle_provider.clone(),
598        ),
599      ])
600      .unwrap();
601
602    if let Some(op_summary_metrics) = op_summary_metrics {
603      js_runtime.op_state().borrow_mut().put(op_summary_metrics);
604    }
605
606    {
607      let state = js_runtime.op_state();
608      let mut state = state.borrow_mut();
609
610      // Put inspector handle into the op state so we can put a breakpoint when
611      // executing a CJS entrypoint.
612      state.put(js_runtime.inspector());
613
614      state.put::<PermissionsContainer>(services.permissions);
615      state.put(ops::TestingFeaturesEnabled(enable_testing_features));
616      state.put(services.feature_checker);
617    }
618
619    if let Some(server) = options.maybe_inspector_server.clone() {
620      server.register_inspector(
621        main_module.to_string(),
622        js_runtime.inspector(),
623        options.should_break_on_first_statement
624          || options.should_wait_for_inspector_session,
625      );
626    }
627
628    let (
629      bootstrap_fn_global,
630      dispatch_load_event_fn_global,
631      dispatch_beforeunload_event_fn_global,
632      dispatch_unload_event_fn_global,
633      dispatch_process_beforeexit_event_fn_global,
634      dispatch_process_exit_event_fn_global,
635    ) = {
636      let context = js_runtime.main_context();
637      deno_core::scope!(scope, &mut js_runtime);
638      let context_local = v8::Local::new(scope, context);
639      let global_obj = context_local.global(scope);
640      let bootstrap_str =
641        v8::String::new_external_onebyte_static(scope, b"bootstrap").unwrap();
642      let bootstrap_ns: v8::Local<v8::Object> = global_obj
643        .get(scope, bootstrap_str.into())
644        .unwrap()
645        .try_into()
646        .unwrap();
647      let main_runtime_str =
648        v8::String::new_external_onebyte_static(scope, b"mainRuntime").unwrap();
649      let bootstrap_fn =
650        bootstrap_ns.get(scope, main_runtime_str.into()).unwrap();
651      let bootstrap_fn =
652        v8::Local::<v8::Function>::try_from(bootstrap_fn).unwrap();
653      let dispatch_load_event_fn_str =
654        v8::String::new_external_onebyte_static(scope, b"dispatchLoadEvent")
655          .unwrap();
656      let dispatch_load_event_fn = bootstrap_ns
657        .get(scope, dispatch_load_event_fn_str.into())
658        .unwrap();
659      let dispatch_load_event_fn =
660        v8::Local::<v8::Function>::try_from(dispatch_load_event_fn).unwrap();
661      let dispatch_beforeunload_event_fn_str =
662        v8::String::new_external_onebyte_static(
663          scope,
664          b"dispatchBeforeUnloadEvent",
665        )
666        .unwrap();
667      let dispatch_beforeunload_event_fn = bootstrap_ns
668        .get(scope, dispatch_beforeunload_event_fn_str.into())
669        .unwrap();
670      let dispatch_beforeunload_event_fn =
671        v8::Local::<v8::Function>::try_from(dispatch_beforeunload_event_fn)
672          .unwrap();
673      let dispatch_unload_event_fn_str =
674        v8::String::new_external_onebyte_static(scope, b"dispatchUnloadEvent")
675          .unwrap();
676      let dispatch_unload_event_fn = bootstrap_ns
677        .get(scope, dispatch_unload_event_fn_str.into())
678        .unwrap();
679      let dispatch_unload_event_fn =
680        v8::Local::<v8::Function>::try_from(dispatch_unload_event_fn).unwrap();
681      let dispatch_process_beforeexit_event =
682        v8::String::new_external_onebyte_static(
683          scope,
684          b"dispatchProcessBeforeExitEvent",
685        )
686        .unwrap();
687      let dispatch_process_beforeexit_event_fn = bootstrap_ns
688        .get(scope, dispatch_process_beforeexit_event.into())
689        .unwrap();
690      let dispatch_process_beforeexit_event_fn =
691        v8::Local::<v8::Function>::try_from(
692          dispatch_process_beforeexit_event_fn,
693        )
694        .unwrap();
695      let dispatch_process_exit_event =
696        v8::String::new_external_onebyte_static(
697          scope,
698          b"dispatchProcessExitEvent",
699        )
700        .unwrap();
701      let dispatch_process_exit_event_fn = bootstrap_ns
702        .get(scope, dispatch_process_exit_event.into())
703        .unwrap();
704      let dispatch_process_exit_event_fn =
705        v8::Local::<v8::Function>::try_from(dispatch_process_exit_event_fn)
706          .unwrap();
707      (
708        v8::Global::new(scope, bootstrap_fn),
709        v8::Global::new(scope, dispatch_load_event_fn),
710        v8::Global::new(scope, dispatch_beforeunload_event_fn),
711        v8::Global::new(scope, dispatch_unload_event_fn),
712        v8::Global::new(scope, dispatch_process_beforeexit_event_fn),
713        v8::Global::new(scope, dispatch_process_exit_event_fn),
714      )
715    };
716
717    let worker = Self {
718      js_runtime,
719      should_break_on_first_statement: options.should_break_on_first_statement,
720      should_wait_for_inspector_session: options
721        .should_wait_for_inspector_session,
722      exit_code,
723      bootstrap_fn_global: Some(bootstrap_fn_global),
724      dispatch_load_event_fn_global,
725      dispatch_beforeunload_event_fn_global,
726      dispatch_unload_event_fn_global,
727      dispatch_process_beforeexit_event_fn_global,
728      dispatch_process_exit_event_fn_global,
729      memory_trim_handle: None,
730    };
731    (worker, options.bootstrap)
732  }
733
734  pub fn bootstrap(&mut self, options: BootstrapOptions) {
735    // Setup bootstrap options for ops.
736    {
737      let op_state = self.js_runtime.op_state();
738      let mut state = op_state.borrow_mut();
739      state.put(options.clone());
740      if let Some((fd, serialization)) = options.node_ipc_init {
741        state.put(deno_node::ChildPipeFd(fd, serialization));
742      }
743    }
744
745    deno_core::scope!(scope, &mut self.js_runtime);
746    v8::tc_scope!(scope, scope);
747    let args = options.as_v8(scope);
748    let bootstrap_fn = self.bootstrap_fn_global.take().unwrap();
749    let bootstrap_fn = v8::Local::new(scope, bootstrap_fn);
750    let undefined = v8::undefined(scope);
751    bootstrap_fn.call(scope, undefined.into(), &[args]);
752    if let Some(exception) = scope.exception() {
753      let error = JsError::from_v8_exception(scope, exception);
754      panic!("Bootstrap exception: {error}");
755    }
756  }
757
758  #[cfg(not(target_os = "linux"))]
759  pub fn setup_memory_trim_handler(&mut self) {
760    // Noop
761  }
762
763  /// Sets up a handler that responds to SIGUSR2 signals by trimming unused
764  /// memory and notifying V8 of low memory conditions.
765  /// Note that this must be called within a tokio runtime.
766  /// Calling this method multiple times will be a no-op.
767  #[cfg(target_os = "linux")]
768  pub fn setup_memory_trim_handler(&mut self) {
769    if self.memory_trim_handle.is_some() {
770      return;
771    }
772
773    if !*MEMORY_TRIM_HANDLER_ENABLED {
774      return;
775    }
776
777    let mut sigusr2_rx = SIGUSR2_RX.clone();
778
779    let spawner = self
780      .js_runtime
781      .op_state()
782      .borrow()
783      .borrow::<deno_core::V8CrossThreadTaskSpawner>()
784      .clone();
785
786    let memory_trim_handle = tokio::spawn(async move {
787      loop {
788        if sigusr2_rx.changed().await.is_err() {
789          break;
790        }
791
792        spawner.spawn(move |isolate| {
793          isolate.low_memory_notification();
794        });
795      }
796    });
797
798    self.memory_trim_handle = Some(memory_trim_handle);
799  }
800
801  /// See [JsRuntime::execute_script](deno_core::JsRuntime::execute_script)
802  pub fn execute_script(
803    &mut self,
804    script_name: &'static str,
805    source_code: ModuleCodeString,
806  ) -> Result<v8::Global<v8::Value>, Box<JsError>> {
807    self.js_runtime.execute_script(script_name, source_code)
808  }
809
810  /// Loads and instantiates specified JavaScript module as "main" module.
811  pub async fn preload_main_module(
812    &mut self,
813    module_specifier: &ModuleSpecifier,
814  ) -> Result<ModuleId, CoreError> {
815    self.js_runtime.load_main_es_module(module_specifier).await
816  }
817
818  /// Loads and instantiates specified JavaScript module as "side" module.
819  pub async fn preload_side_module(
820    &mut self,
821    module_specifier: &ModuleSpecifier,
822  ) -> Result<ModuleId, CoreError> {
823    self.js_runtime.load_side_es_module(module_specifier).await
824  }
825
826  /// Executes specified JavaScript module.
827  pub async fn evaluate_module(
828    &mut self,
829    id: ModuleId,
830  ) -> Result<(), CoreError> {
831    self.wait_for_inspector_session();
832    let mut receiver = self.js_runtime.mod_evaluate(id);
833    tokio::select! {
834      // Not using biased mode leads to non-determinism for relatively simple
835      // programs.
836      biased;
837
838      maybe_result = &mut receiver => {
839        debug!("received module evaluate {:#?}", maybe_result);
840        maybe_result
841      }
842
843      event_loop_result = self.run_event_loop(false) => {
844        event_loop_result?;
845        receiver.await
846      }
847    }
848  }
849
850  /// Run the event loop up to a given duration. If the runtime resolves early, returns
851  /// early. Will always poll the runtime at least once.
852  pub async fn run_up_to_duration(
853    &mut self,
854    duration: Duration,
855  ) -> Result<(), CoreError> {
856    match tokio::time::timeout(
857      duration,
858      self
859        .js_runtime
860        .run_event_loop(PollEventLoopOptions::default()),
861    )
862    .await
863    {
864      Ok(Ok(_)) => Ok(()),
865      Err(_) => Ok(()),
866      Ok(Err(e)) => Err(e),
867    }
868  }
869
870  /// Loads, instantiates and executes specified JavaScript module.
871  pub async fn execute_side_module(
872    &mut self,
873    module_specifier: &ModuleSpecifier,
874  ) -> Result<(), CoreError> {
875    let id = self.preload_side_module(module_specifier).await?;
876    self.evaluate_module(id).await
877  }
878
879  /// Loads, instantiates and executes specified JavaScript module.
880  ///
881  /// This module will have "import.meta.main" equal to true.
882  pub async fn execute_main_module(
883    &mut self,
884    module_specifier: &ModuleSpecifier,
885  ) -> Result<(), CoreError> {
886    let id = self.preload_main_module(module_specifier).await?;
887    self.evaluate_module(id).await
888  }
889
890  fn wait_for_inspector_session(&mut self) {
891    if self.should_break_on_first_statement {
892      self
893        .js_runtime
894        .inspector()
895        .wait_for_session_and_break_on_next_statement();
896    } else if self.should_wait_for_inspector_session {
897      self.js_runtime.inspector().wait_for_session();
898    }
899  }
900
901  /// Create new inspector session. This function panics if Worker
902  /// was not configured to create inspector.
903  pub fn create_inspector_session(
904    &mut self,
905    cb: deno_core::InspectorSessionSend,
906  ) -> LocalInspectorSession {
907    self.js_runtime.maybe_init_inspector();
908    let insp = self.js_runtime.inspector();
909
910    JsRuntimeInspector::create_local_session(
911      insp,
912      cb,
913      InspectorSessionKind::Blocking,
914    )
915  }
916
917  pub async fn run_event_loop(
918    &mut self,
919    wait_for_inspector: bool,
920  ) -> Result<(), CoreError> {
921    self
922      .js_runtime
923      .run_event_loop(PollEventLoopOptions {
924        wait_for_inspector,
925        ..Default::default()
926      })
927      .await
928  }
929
930  /// Return exit code set by the executed code (either in main worker
931  /// or one of child web workers).
932  pub fn exit_code(&self) -> i32 {
933    self.exit_code.get()
934  }
935
936  /// Dispatches "load" event to the JavaScript runtime.
937  ///
938  /// Does not poll event loop, and thus not await any of the "load" event handlers.
939  pub fn dispatch_load_event(&mut self) -> Result<(), Box<JsError>> {
940    deno_core::scope!(scope, &mut self.js_runtime);
941    v8::tc_scope!(tc_scope, scope);
942    let dispatch_load_event_fn =
943      v8::Local::new(tc_scope, &self.dispatch_load_event_fn_global);
944    let undefined = v8::undefined(tc_scope);
945    dispatch_load_event_fn.call(tc_scope, undefined.into(), &[]);
946    if let Some(exception) = tc_scope.exception() {
947      let error = JsError::from_v8_exception(tc_scope, exception);
948      return Err(error);
949    }
950    Ok(())
951  }
952
953  /// Dispatches "unload" event to the JavaScript runtime.
954  ///
955  /// Does not poll event loop, and thus not await any of the "unload" event handlers.
956  pub fn dispatch_unload_event(&mut self) -> Result<(), Box<JsError>> {
957    deno_core::scope!(scope, &mut self.js_runtime);
958    v8::tc_scope!(tc_scope, scope);
959    let dispatch_unload_event_fn =
960      v8::Local::new(tc_scope, &self.dispatch_unload_event_fn_global);
961    let undefined = v8::undefined(tc_scope);
962    dispatch_unload_event_fn.call(tc_scope, undefined.into(), &[]);
963    if let Some(exception) = tc_scope.exception() {
964      let error = JsError::from_v8_exception(tc_scope, exception);
965      return Err(error);
966    }
967    Ok(())
968  }
969
970  /// Dispatches process.emit("exit") event for node compat.
971  pub fn dispatch_process_exit_event(&mut self) -> Result<(), Box<JsError>> {
972    deno_core::scope!(scope, &mut self.js_runtime);
973    v8::tc_scope!(tc_scope, scope);
974    let dispatch_process_exit_event_fn =
975      v8::Local::new(tc_scope, &self.dispatch_process_exit_event_fn_global);
976    let undefined = v8::undefined(tc_scope);
977    dispatch_process_exit_event_fn.call(tc_scope, undefined.into(), &[]);
978    if let Some(exception) = tc_scope.exception() {
979      let error = JsError::from_v8_exception(tc_scope, exception);
980      return Err(error);
981    }
982    Ok(())
983  }
984
985  /// Dispatches "beforeunload" event to the JavaScript runtime. Returns a boolean
986  /// indicating if the event was prevented and thus event loop should continue
987  /// running.
988  pub fn dispatch_beforeunload_event(&mut self) -> Result<bool, Box<JsError>> {
989    deno_core::scope!(scope, &mut self.js_runtime);
990    v8::tc_scope!(tc_scope, scope);
991    let dispatch_beforeunload_event_fn =
992      v8::Local::new(tc_scope, &self.dispatch_beforeunload_event_fn_global);
993    let undefined = v8::undefined(tc_scope);
994    let ret_val =
995      dispatch_beforeunload_event_fn.call(tc_scope, undefined.into(), &[]);
996    if let Some(exception) = tc_scope.exception() {
997      let error = JsError::from_v8_exception(tc_scope, exception);
998      return Err(error);
999    }
1000    let ret_val = ret_val.unwrap();
1001    Ok(ret_val.is_false())
1002  }
1003
1004  /// Dispatches process.emit("beforeExit") event for node compat.
1005  pub fn dispatch_process_beforeexit_event(
1006    &mut self,
1007  ) -> Result<bool, Box<JsError>> {
1008    deno_core::scope!(scope, &mut self.js_runtime);
1009    v8::tc_scope!(tc_scope, scope);
1010    let dispatch_process_beforeexit_event_fn = v8::Local::new(
1011      tc_scope,
1012      &self.dispatch_process_beforeexit_event_fn_global,
1013    );
1014    let undefined = v8::undefined(tc_scope);
1015    let ret_val = dispatch_process_beforeexit_event_fn.call(
1016      tc_scope,
1017      undefined.into(),
1018      &[],
1019    );
1020    if let Some(exception) = tc_scope.exception() {
1021      let error = JsError::from_v8_exception(tc_scope, exception);
1022      return Err(error);
1023    }
1024    let ret_val = ret_val.unwrap();
1025    Ok(ret_val.is_true())
1026  }
1027}
1028
1029fn common_extensions<
1030  TInNpmPackageChecker: InNpmPackageChecker + 'static,
1031  TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
1032  TExtNodeSys: ExtNodeSys + 'static,
1033>(
1034  has_snapshot: bool,
1035  unconfigured_runtime: bool,
1036) -> Vec<Extension> {
1037  // NOTE(bartlomieju): ordering is important here, keep it in sync with
1038  // `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`
1039  // and `runtime/snapshot.rs`!
1040  vec![
1041    deno_telemetry::deno_telemetry::init(),
1042    // Web APIs
1043    deno_webidl::deno_webidl::init(),
1044    deno_web::deno_web::lazy_init(),
1045    deno_webgpu::deno_webgpu::init(),
1046    deno_canvas::deno_canvas::init(),
1047    deno_fetch::deno_fetch::lazy_init(),
1048    deno_cache::deno_cache::lazy_init(),
1049    deno_websocket::deno_websocket::lazy_init(),
1050    deno_webstorage::deno_webstorage::lazy_init(),
1051    deno_crypto::deno_crypto::lazy_init(),
1052    deno_ffi::deno_ffi::lazy_init(),
1053    deno_net::deno_net::lazy_init(),
1054    deno_tls::deno_tls::init(),
1055    deno_kv::deno_kv::lazy_init::<MultiBackendDbHandler>(),
1056    deno_cron::deno_cron::init(LocalCronHandler::new()),
1057    deno_napi::deno_napi::lazy_init(),
1058    deno_http::deno_http::lazy_init(),
1059    deno_io::deno_io::lazy_init(),
1060    deno_fs::deno_fs::lazy_init(),
1061    deno_os::deno_os::lazy_init(),
1062    deno_process::deno_process::lazy_init(),
1063    deno_node::deno_node::lazy_init::<
1064      TInNpmPackageChecker,
1065      TNpmPackageFolderResolver,
1066      TExtNodeSys,
1067    >(),
1068    // Ops from this crate
1069    ops::runtime::deno_runtime::lazy_init(),
1070    ops::worker_host::deno_worker_host::lazy_init(),
1071    ops::fs_events::deno_fs_events::init(),
1072    ops::permissions::deno_permissions::init(),
1073    ops::tty::deno_tty::init(),
1074    ops::http::deno_http_runtime::init(),
1075    deno_bundle_runtime::deno_bundle_runtime::lazy_init(),
1076    ops::bootstrap::deno_bootstrap::init(
1077      has_snapshot.then(Default::default),
1078      unconfigured_runtime,
1079    ),
1080    runtime::init(),
1081    // NOTE(bartlomieju): this is done, just so that ops from this extension
1082    // are available and importing them in `99_main.js` doesn't cause an
1083    // error because they're not defined. Trying to use these ops in non-worker
1084    // context will cause a panic.
1085    ops::web_worker::deno_web_worker::init().disable(),
1086  ]
1087}
1088
1089struct CommonRuntimeOptions {
1090  module_loader: Rc<dyn ModuleLoader>,
1091  startup_snapshot: Option<&'static [u8]>,
1092  create_params: Option<v8::CreateParams>,
1093  skip_op_registration: bool,
1094  shared_array_buffer_store: Option<SharedArrayBufferStore>,
1095  compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
1096  extensions: Vec<Extension>,
1097  op_metrics_factory_fn: Option<OpMetricsFactoryFn>,
1098  enable_stack_trace_arg_in_ops: bool,
1099}
1100
1101struct EnableRawImports(Arc<AtomicBool>);
1102
1103#[allow(clippy::too_many_arguments)]
1104fn common_runtime(opts: CommonRuntimeOptions) -> JsRuntime {
1105  let enable_raw_imports = Arc::new(AtomicBool::new(false));
1106
1107  let js_runtime = JsRuntime::new(RuntimeOptions {
1108    module_loader: Some(opts.module_loader),
1109    startup_snapshot: opts.startup_snapshot,
1110    create_params: opts.create_params,
1111    skip_op_registration: opts.skip_op_registration,
1112    shared_array_buffer_store: opts.shared_array_buffer_store,
1113    compiled_wasm_module_store: opts.compiled_wasm_module_store,
1114    extensions: opts.extensions,
1115    #[cfg(feature = "transpile")]
1116    extension_transpiler: Some(Rc::new(|specifier, source| {
1117      crate::transpile::maybe_transpile_source(specifier, source)
1118    })),
1119    #[cfg(not(feature = "transpile"))]
1120    extension_transpiler: None,
1121    inspector: true,
1122    is_main: true,
1123    op_metrics_factory_fn: opts.op_metrics_factory_fn,
1124    wait_for_inspector_disconnect_callback: Some(
1125      make_wait_for_inspector_disconnect_callback(),
1126    ),
1127    validate_import_attributes_cb: Some(
1128      create_validate_import_attributes_callback(enable_raw_imports.clone()),
1129    ),
1130    import_assertions_support: deno_core::ImportAssertionsSupport::Error,
1131    maybe_op_stack_trace_callback: opts
1132      .enable_stack_trace_arg_in_ops
1133      .then(create_permissions_stack_trace_callback),
1134    extension_code_cache: None,
1135    v8_platform: None,
1136    custom_module_evaluation_cb: None,
1137    eval_context_code_cache_cbs: None,
1138  });
1139
1140  js_runtime
1141    .op_state()
1142    .borrow_mut()
1143    .put(EnableRawImports(enable_raw_imports));
1144
1145  js_runtime
1146}
1147
1148pub fn create_permissions_stack_trace_callback()
1149-> deno_core::OpStackTraceCallback {
1150  Box::new(|stack: Vec<deno_core::error::JsStackFrame>| {
1151    deno_permissions::prompter::set_current_stacktrace(Box::new(move || {
1152      stack
1153        .iter()
1154        .map(|frame| {
1155          deno_core::error::format_frame::<deno_core::error::NoAnsiColors>(
1156            frame, None,
1157          )
1158        })
1159        .collect()
1160    }))
1161  }) as _
1162}
1163
1164pub struct UnconfiguredRuntimeOptions {
1165  pub startup_snapshot: &'static [u8],
1166  pub create_params: Option<v8::CreateParams>,
1167  pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
1168  pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
1169  pub additional_extensions: Vec<Extension>,
1170}
1171
1172pub struct UnconfiguredRuntime {
1173  module_loader: Rc<PlaceholderModuleLoader>,
1174  js_runtime: JsRuntime,
1175}
1176
1177impl UnconfiguredRuntime {
1178  pub fn new<
1179    TInNpmPackageChecker: InNpmPackageChecker + 'static,
1180    TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
1181    TExtNodeSys: ExtNodeSys + 'static,
1182  >(
1183    options: UnconfiguredRuntimeOptions,
1184  ) -> Self {
1185    let mut extensions = common_extensions::<
1186      TInNpmPackageChecker,
1187      TNpmPackageFolderResolver,
1188      TExtNodeSys,
1189    >(true, true);
1190
1191    extensions.extend(options.additional_extensions);
1192
1193    let module_loader =
1194      Rc::new(PlaceholderModuleLoader(std::cell::RefCell::new(None)));
1195
1196    let js_runtime = common_runtime(CommonRuntimeOptions {
1197      module_loader: module_loader.clone(),
1198      startup_snapshot: Some(options.startup_snapshot),
1199      create_params: options.create_params,
1200      skip_op_registration: true,
1201      shared_array_buffer_store: options.shared_array_buffer_store,
1202      compiled_wasm_module_store: options.compiled_wasm_module_store,
1203      extensions,
1204      op_metrics_factory_fn: None,
1205      enable_stack_trace_arg_in_ops: false,
1206    });
1207
1208    UnconfiguredRuntime {
1209      module_loader,
1210      js_runtime,
1211    }
1212  }
1213
1214  fn hydrate(self, module_loader: Rc<dyn ModuleLoader>) -> JsRuntime {
1215    let _ = self.module_loader.0.borrow_mut().insert(module_loader);
1216    self.js_runtime
1217  }
1218}
1219
1220struct PlaceholderModuleLoader(
1221  std::cell::RefCell<Option<Rc<dyn ModuleLoader>>>,
1222);
1223
1224impl ModuleLoader for PlaceholderModuleLoader {
1225  fn resolve(
1226    &self,
1227    specifier: &str,
1228    referrer: &str,
1229    kind: deno_core::ResolutionKind,
1230  ) -> Result<ModuleSpecifier, deno_core::error::ModuleLoaderError> {
1231    self
1232      .0
1233      .borrow_mut()
1234      .clone()
1235      .unwrap()
1236      .resolve(specifier, referrer, kind)
1237  }
1238
1239  fn load(
1240    &self,
1241    module_specifier: &ModuleSpecifier,
1242    maybe_referrer: Option<&ModuleLoadReferrer>,
1243    options: ModuleLoadOptions,
1244  ) -> deno_core::ModuleLoadResponse {
1245    self.0.borrow_mut().clone().unwrap().load(
1246      module_specifier,
1247      maybe_referrer,
1248      options,
1249    )
1250  }
1251
1252  fn prepare_load(
1253    &self,
1254    module_specifier: &ModuleSpecifier,
1255    maybe_referrer: Option<String>,
1256    options: ModuleLoadOptions,
1257  ) -> std::pin::Pin<
1258    Box<
1259      dyn std::prelude::rust_2024::Future<
1260          Output = Result<(), deno_core::error::ModuleLoaderError>,
1261        >,
1262    >,
1263  > {
1264    self.0.borrow_mut().clone().unwrap().prepare_load(
1265      module_specifier,
1266      maybe_referrer,
1267      options,
1268    )
1269  }
1270
1271  fn finish_load(&self) {
1272    self.0.borrow_mut().clone().unwrap().finish_load()
1273  }
1274
1275  fn purge_and_prevent_code_cache(&self, module_specifier: &str) {
1276    self
1277      .0
1278      .borrow_mut()
1279      .clone()
1280      .unwrap()
1281      .purge_and_prevent_code_cache(module_specifier)
1282  }
1283
1284  fn get_source_map(&self, file_name: &str) -> Option<Cow<'_, [u8]>> {
1285    let v = self.0.borrow_mut().clone().unwrap();
1286    let v = v.get_source_map(file_name);
1287    v.map(|c| Cow::from(c.into_owned()))
1288  }
1289
1290  fn get_source_mapped_source_line(
1291    &self,
1292    file_name: &str,
1293    line_number: usize,
1294  ) -> Option<String> {
1295    self
1296      .0
1297      .borrow_mut()
1298      .clone()
1299      .unwrap()
1300      .get_source_mapped_source_line(file_name, line_number)
1301  }
1302
1303  fn get_host_defined_options<'s>(
1304    &self,
1305    scope: &mut v8::PinScope<'s, '_>,
1306    name: &str,
1307  ) -> Option<v8::Local<'s, v8::Data>> {
1308    self
1309      .0
1310      .borrow_mut()
1311      .clone()
1312      .unwrap()
1313      .get_host_defined_options(scope, name)
1314  }
1315}