1use std::cell::{Cell, OnceCell, Ref};
6use std::collections::hash_map::Entry;
7use std::collections::{HashMap, HashSet, VecDeque};
8use std::ffi::CStr;
9use std::ops::Index;
10use std::rc::Rc;
11use std::sync::atomic::{AtomicBool, Ordering};
12use std::sync::{Arc, Mutex};
13use std::thread::JoinHandle;
14use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
15use std::{mem, ptr};
16
17use base::IpcSend;
18use base::id::{
19 BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
20 ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
21};
22use constellation_traits::{
23 BlobData, BlobImpl, BroadcastChannelMsg, FileBlob, MessagePortImpl, MessagePortMsg,
24 PortMessageTask, ScriptToConstellationChan, ScriptToConstellationMessage,
25};
26use content_security_policy::CspList;
27use crossbeam_channel::Sender;
28use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
29use dom_struct::dom_struct;
30use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan};
31use fonts::FontContext;
32use ipc_channel::ipc::{self, IpcSender};
33use ipc_channel::router::ROUTER;
34use js::glue::{IsWrapper, UnwrapObjectDynamic};
35use js::jsapi::{
36 Compile1, CurrentGlobalOrNull, DelazificationOption, GetNonCCWObjectGlobal, HandleObject, Heap,
37 InstantiateGlobalStencil, InstantiateOptions, JSContext, JSObject, JSScript, SetScriptPrivate,
38};
39use js::jsval::{PrivateValue, UndefinedValue};
40use js::panic::maybe_resume_unwind;
41use js::rust::wrappers::{JS_ExecuteScript, JS_GetScriptPrivate};
42use js::rust::{
43 CompileOptionsWrapper, CustomAutoRooter, CustomAutoRooterGuard, HandleValue,
44 MutableHandleValue, ParentRuntime, Runtime, get_object_class, transform_str_to_source_text,
45};
46use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
47use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
48use net_traits::filemanager_thread::{
49 FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
50};
51use net_traits::image_cache::ImageCache;
52use net_traits::policy_container::PolicyContainer;
53use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBuilder};
54use net_traits::response::HttpsState;
55use net_traits::{
56 CoreResourceMsg, CoreResourceThread, FetchResponseListener, ReferrerPolicy, ResourceThreads,
57 fetch_async,
58};
59use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
60use rustc_hash::{FxBuildHasher, FxHashMap};
61use script_bindings::interfaces::GlobalScopeHelpers;
62use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
63use storage_traits::StorageThreads;
64use timers::{TimerEventRequest, TimerId};
65use uuid::Uuid;
66#[cfg(feature = "webgpu")]
67use webgpu_traits::{DeviceLostReason, WebGPUDevice};
68
69use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
70#[cfg(feature = "webgpu")]
71use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
72use super::bindings::error::Fallible;
73use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox};
74use super::serviceworkerglobalscope::ServiceWorkerGlobalScope;
75use super::transformstream::CrossRealmTransform;
76use crate::dom::bindings::cell::{DomRefCell, RefMut};
77use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
78use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods;
79use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
80use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
81use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
82 PermissionName, PermissionState,
83};
84use crate::dom::bindings::codegen::Bindings::ReportingObserverBinding::Report;
85use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
86use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
87use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
88use crate::dom::bindings::conversions::{root_from_object, root_from_object_static};
89use crate::dom::bindings::error::{
90 Error, ErrorInfo, report_pending_exception, take_and_report_pending_exception_for_api,
91};
92use crate::dom::bindings::frozenarray::CachedFrozenArray;
93use crate::dom::bindings::inheritance::Castable;
94use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
95use crate::dom::bindings::reflector::{DomGlobal, DomObject};
96use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
97use crate::dom::bindings::settings_stack::{AutoEntryScript, entry_global, incumbent_global};
98use crate::dom::bindings::str::DOMString;
99use crate::dom::bindings::structuredclone;
100use crate::dom::bindings::trace::CustomTraceable;
101use crate::dom::bindings::weakref::{DOMTracker, WeakRef};
102use crate::dom::blob::Blob;
103use crate::dom::broadcastchannel::BroadcastChannel;
104use crate::dom::crypto::Crypto;
105use crate::dom::dedicatedworkerglobalscope::{
106 DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
107};
108use crate::dom::errorevent::ErrorEvent;
109use crate::dom::event::{Event, EventBubbles, EventCancelable};
110use crate::dom::eventsource::EventSource;
111use crate::dom::eventtarget::EventTarget;
112use crate::dom::file::File;
113use crate::dom::html::htmlscriptelement::{ScriptId, SourceCode};
114use crate::dom::messageport::MessagePort;
115use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
116use crate::dom::performance::Performance;
117use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
118use crate::dom::promise::Promise;
119use crate::dom::readablestream::{CrossRealmTransformReadable, ReadableStream};
120use crate::dom::reportingobserver::ReportingObserver;
121use crate::dom::serviceworker::ServiceWorker;
122use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
123use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
124use crate::dom::types::{CookieStore, DebuggerGlobalScope, MessageEvent};
125use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
126#[cfg(feature = "webgpu")]
127use crate::dom::webgpu::gpudevice::GPUDevice;
128#[cfg(feature = "webgpu")]
129use crate::dom::webgpu::identityhub::IdentityHub;
130use crate::dom::window::Window;
131use crate::dom::workerglobalscope::WorkerGlobalScope;
132use crate::dom::workletglobalscope::WorkletGlobalScope;
133use crate::dom::writablestream::CrossRealmTransformWritable;
134use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
135use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
136use crate::network_listener::{NetworkListener, PreInvoke};
137use crate::realms::{InRealm, enter_realm};
138use crate::script_module::{
139 DynamicModuleList, ImportMap, ModuleScript, ModuleTree, ResolvedModule, ScriptFetchOptions,
140};
141use crate::script_runtime::{CanGc, JSContext as SafeJSContext, ThreadSafeJSContext};
142use crate::script_thread::{ScriptThread, with_script_thread};
143use crate::task_manager::TaskManager;
144use crate::task_source::SendableTaskSource;
145use crate::timers::{
146 IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
147 TimerEventId, TimerSource,
148};
149use crate::unminify::unminified_path;
150
151#[derive(JSTraceable, MallocSizeOf)]
152pub(crate) struct AutoCloseWorker {
153 #[conditional_malloc_size_of]
155 closing: Arc<AtomicBool>,
156 #[ignore_malloc_size_of = "JoinHandle"]
158 join_handle: Option<JoinHandle<()>>,
159 #[no_trace]
162 control_sender: Sender<DedicatedWorkerControlMsg>,
163 #[ignore_malloc_size_of = "mozjs"]
165 #[no_trace]
166 context: ThreadSafeJSContext,
167}
168
169impl Drop for AutoCloseWorker {
170 fn drop(&mut self) {
172 self.closing.store(true, Ordering::SeqCst);
174
175 if self
176 .control_sender
177 .send(DedicatedWorkerControlMsg::Exit)
178 .is_err()
179 {
180 warn!("Couldn't send an exit message to a dedicated worker.");
181 }
182
183 self.context.request_interrupt_callback();
184
185 if self
188 .join_handle
189 .take()
190 .expect("No handle to join on worker.")
191 .join()
192 .is_err()
193 {
194 warn!("Failed to join on dedicated worker thread.");
195 }
196 }
197}
198
199#[dom_struct]
200pub(crate) struct GlobalScope {
201 eventtarget: EventTarget,
202 crypto: MutNullableDom<Crypto>,
203
204 task_manager: OnceCell<TaskManager>,
206
207 message_port_state: DomRefCell<MessagePortState>,
209
210 broadcast_channel_state: DomRefCell<BroadcastChannelState>,
212
213 blob_state: DomRefCell<HashMapTracedValues<BlobId, BlobInfo, FxBuildHasher>>,
215
216 registration_map: DomRefCell<
218 HashMapTracedValues<
219 ServiceWorkerRegistrationId,
220 Dom<ServiceWorkerRegistration>,
221 FxBuildHasher,
222 >,
223 >,
224
225 cookie_store: MutNullableDom<CookieStore>,
227
228 worker_map: DomRefCell<HashMapTracedValues<ServiceWorkerId, Dom<ServiceWorker>, FxBuildHasher>>,
230
231 #[no_trace]
233 pipeline_id: PipelineId,
234
235 devtools_wants_updates: Cell<bool>,
238
239 console_timers: DomRefCell<HashMap<DOMString, Instant>>,
241
242 #[ignore_malloc_size_of = "mozjs"]
245 module_map: DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>>,
246
247 #[ignore_malloc_size_of = "mozjs"]
248 inline_module_map: DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>>,
249
250 #[no_trace]
252 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
253
254 #[ignore_malloc_size_of = "channels are hard"]
256 #[no_trace]
257 mem_profiler_chan: profile_mem::ProfilerChan,
258
259 #[ignore_malloc_size_of = "channels are hard"]
261 #[no_trace]
262 time_profiler_chan: profile_time::ProfilerChan,
263
264 #[ignore_malloc_size_of = "channels are hard"]
266 #[no_trace]
267 script_to_constellation_chan: ScriptToConstellationChan,
268
269 #[ignore_malloc_size_of = "channels are hard"]
271 #[no_trace]
272 script_to_embedder_chan: ScriptToEmbedderChan,
273
274 in_error_reporting_mode: Cell<bool>,
276
277 #[no_trace]
280 resource_threads: ResourceThreads,
281
282 #[no_trace]
285 storage_threads: StorageThreads,
286
287 timers: OnceCell<OneshotTimers>,
290
291 #[no_trace]
293 origin: MutableOrigin,
294
295 #[no_trace]
297 creation_url: ServoUrl,
298
299 #[no_trace]
301 top_level_creation_url: Option<ServoUrl>,
302
303 permission_state_invocation_results: DomRefCell<HashMap<PermissionName, PermissionState>>,
305
306 #[conditional_malloc_size_of]
313 microtask_queue: Rc<MicrotaskQueue>,
314
315 list_auto_close_worker: DomRefCell<Vec<AutoCloseWorker>>,
317
318 event_source_tracker: DOMTracker<EventSource>,
320
321 #[ignore_malloc_size_of = "mozjs"]
330 #[allow(clippy::vec_box)]
333 uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
334
335 #[ignore_malloc_size_of = "mozjs"]
341 #[allow(clippy::vec_box)]
344 consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
345
346 #[ignore_malloc_size_of = "defined in wgpu"]
348 #[no_trace]
349 #[cfg(feature = "webgpu")]
350 gpu_id_hub: Arc<IdentityHub>,
351
352 #[cfg(feature = "webgpu")]
354 gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>, FxBuildHasher>>,
355
356 #[ignore_malloc_size_of = "mozjs"]
358 frozen_supported_performance_entry_types: CachedFrozenArray,
359
360 #[no_trace]
362 https_state: Cell<HttpsState>,
363
364 console_group_stack: DomRefCell<Vec<DOMString>>,
366
367 console_count_map: DomRefCell<HashMap<DOMString, usize>>,
371
372 dynamic_modules: DomRefCell<DynamicModuleList>,
374
375 inherited_secure_context: Option<bool>,
377
378 unminified_js_dir: Option<String>,
381
382 #[ignore_malloc_size_of = "callbacks are hard"]
387 byte_length_queuing_strategy_size_function: OnceCell<Rc<Function>>,
388
389 #[ignore_malloc_size_of = "callbacks are hard"]
394 count_queuing_strategy_size_function: OnceCell<Rc<Function>>,
395
396 #[ignore_malloc_size_of = "callbacks are hard"]
397 notification_permission_request_callback_map:
398 DomRefCell<HashMap<String, Rc<NotificationPermissionCallback>>>,
399
400 import_map: DomRefCell<ImportMap>,
405
406 resolved_module_set: DomRefCell<HashSet<ResolvedModule>>,
408
409 #[conditional_malloc_size_of]
413 #[no_trace]
414 font_context: Option<Arc<FontContext>>,
415}
416
417struct MessageListener {
419 task_source: SendableTaskSource,
420 context: Trusted<GlobalScope>,
421}
422
423struct BroadcastListener {
425 task_source: SendableTaskSource,
426 context: Trusted<GlobalScope>,
427}
428
429type FileListenerCallback = Box<dyn Fn(Rc<Promise>, Fallible<Vec<u8>>) + Send>;
430
431struct FileListener {
433 state: Option<FileListenerState>,
437 task_source: SendableTaskSource,
438}
439
440enum FileListenerTarget {
441 Promise(TrustedPromise, FileListenerCallback),
442 Stream(Trusted<ReadableStream>),
443}
444
445enum FileListenerState {
446 Empty(FileListenerTarget),
447 Receiving(Vec<u8>, FileListenerTarget),
448}
449
450#[derive(JSTraceable, MallocSizeOf)]
451pub(crate) enum BlobTracker {
453 File(WeakRef<File>),
455 Blob(WeakRef<Blob>),
457}
458
459#[derive(JSTraceable, MallocSizeOf)]
460pub(crate) struct BlobInfo {
462 tracker: BlobTracker,
464 #[no_trace]
466 blob_impl: BlobImpl,
467 has_url: bool,
470}
471
472enum BlobResult {
476 Bytes(Vec<u8>),
477 File(Uuid, usize),
478}
479
480#[derive(JSTraceable, MallocSizeOf)]
482#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
483pub(crate) struct ManagedMessagePort {
484 dom_port: Dom<MessagePort>,
486 #[no_trace]
491 port_impl: Option<MessagePortImpl>,
492 pending: bool,
496 explicitly_closed: bool,
499 cross_realm_transform: Option<CrossRealmTransform>,
502}
503
504#[derive(JSTraceable, MallocSizeOf)]
506#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
507pub(crate) enum BroadcastChannelState {
508 Managed(
513 #[no_trace] BroadcastChannelRouterId,
514 HashMap<DOMString, VecDeque<Dom<BroadcastChannel>>>,
516 ),
517 UnManaged,
519}
520
521#[derive(JSTraceable, MallocSizeOf)]
523#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
524pub(crate) enum MessagePortState {
525 Managed(
527 #[no_trace] MessagePortRouterId,
528 HashMapTracedValues<MessagePortId, ManagedMessagePort, FxBuildHasher>,
529 ),
530 UnManaged,
532}
533
534impl BroadcastListener {
535 fn handle(&self, event: BroadcastChannelMsg) {
538 let context = self.context.clone();
539
540 self.task_source
546 .queue(task!(broadcast_message_event: move || {
547 let global = context.root();
548 global.broadcast_message_event(event, None);
551 }));
552 }
553}
554
555impl MessageListener {
556 fn notify(&self, msg: MessagePortMsg) {
560 match msg {
561 MessagePortMsg::CompleteTransfer(ports) => {
562 let context = self.context.clone();
563 self.task_source.queue(
564 task!(process_complete_transfer: move || {
565 let global = context.root();
566
567 let router_id = match global.port_router_id() {
568 Some(router_id) => router_id,
569 None => {
570 let _ = global.script_to_constellation_chan().send(
573 ScriptToConstellationMessage::MessagePortTransferResult(None, vec![], ports),
574 );
575 return;
576 }
577 };
578
579 let mut succeeded = vec![];
580 let mut failed = FxHashMap::default();
581
582 for (id, info) in ports.into_iter() {
583 if global.is_managing_port(&id) {
584 succeeded.push(id);
585 global.complete_port_transfer(
586 id,
587 info.port_message_queue,
588 info.disentangled,
589 CanGc::note()
590 );
591 } else {
592 failed.insert(id, info);
593 }
594 }
595 let _ = global.script_to_constellation_chan().send(
596 ScriptToConstellationMessage::MessagePortTransferResult(Some(router_id), succeeded, failed),
597 );
598 })
599 );
600 },
601 MessagePortMsg::CompletePendingTransfer(port_id, info) => {
602 let context = self.context.clone();
603 self.task_source.queue(task!(complete_pending: move || {
604 let global = context.root();
605 global.complete_port_transfer(port_id, info.port_message_queue, info.disentangled, CanGc::note());
606 }));
607 },
608 MessagePortMsg::CompleteDisentanglement(port_id) => {
609 let context = self.context.clone();
610 self.task_source
611 .queue(task!(try_complete_disentanglement: move || {
612 let global = context.root();
613 global.try_complete_disentanglement(port_id, CanGc::note());
614 }));
615 },
616 MessagePortMsg::NewTask(port_id, task) => {
617 let context = self.context.clone();
618 self.task_source.queue(task!(process_new_task: move || {
619 let global = context.root();
620 global.route_task_to_port(port_id, task, CanGc::note());
621 }));
622 },
623 }
624 }
625}
626
627fn stream_handle_incoming(stream: &ReadableStream, bytes: Fallible<Vec<u8>>, can_gc: CanGc) {
629 match bytes {
630 Ok(b) => {
631 stream.enqueue_native(b, can_gc);
632 },
633 Err(e) => {
634 stream.error_native(e, can_gc);
635 },
636 }
637}
638
639fn stream_handle_eof(stream: &ReadableStream, can_gc: CanGc) {
641 stream.controller_close_native(can_gc);
642}
643
644impl FileListener {
645 fn handle(&mut self, msg: FileManagerResult<ReadFileProgress>) {
646 match msg {
647 Ok(ReadFileProgress::Meta(blob_buf)) => match self.state.take() {
648 Some(FileListenerState::Empty(target)) => {
649 let bytes = if let FileListenerTarget::Stream(ref trusted_stream) = target {
650 let trusted = trusted_stream.clone();
651
652 let task = task!(enqueue_stream_chunk: move || {
653 let stream = trusted.root();
654 stream_handle_incoming(&stream, Ok(blob_buf.bytes), CanGc::note());
655 });
656 self.task_source.queue(task);
657
658 Vec::with_capacity(0)
659 } else {
660 blob_buf.bytes
661 };
662
663 self.state = Some(FileListenerState::Receiving(bytes, target));
664 },
665 _ => panic!(
666 "Unexpected FileListenerState when receiving ReadFileProgress::Meta msg."
667 ),
668 },
669 Ok(ReadFileProgress::Partial(mut bytes_in)) => match self.state.take() {
670 Some(FileListenerState::Receiving(mut bytes, target)) => {
671 if let FileListenerTarget::Stream(ref trusted_stream) = target {
672 let trusted = trusted_stream.clone();
673
674 let task = task!(enqueue_stream_chunk: move || {
675 let stream = trusted.root();
676 stream_handle_incoming(&stream, Ok(bytes_in), CanGc::note());
677 });
678
679 self.task_source.queue(task);
680 } else {
681 bytes.append(&mut bytes_in);
682 };
683
684 self.state = Some(FileListenerState::Receiving(bytes, target));
685 },
686 _ => panic!(
687 "Unexpected FileListenerState when receiving ReadFileProgress::Partial msg."
688 ),
689 },
690 Ok(ReadFileProgress::EOF) => match self.state.take() {
691 Some(FileListenerState::Receiving(bytes, target)) => match target {
692 FileListenerTarget::Promise(trusted_promise, callback) => {
693 let task = task!(resolve_promise: move || {
694 let promise = trusted_promise.root();
695 let _ac = enter_realm(&*promise.global());
696 callback(promise, Ok(bytes));
697 });
698
699 self.task_source.queue(task);
700 },
701 FileListenerTarget::Stream(trusted_stream) => {
702 let trusted = trusted_stream.clone();
703
704 let task = task!(enqueue_stream_chunk: move || {
705 let stream = trusted.root();
706 stream_handle_eof(&stream, CanGc::note());
707 });
708
709 self.task_source.queue(task);
710 },
711 },
712 _ => {
713 panic!("Unexpected FileListenerState when receiving ReadFileProgress::EOF msg.")
714 },
715 },
716 Err(_) => match self.state.take() {
717 Some(FileListenerState::Receiving(_, target)) |
718 Some(FileListenerState::Empty(target)) => {
719 let error = Err(Error::Network);
720
721 match target {
722 FileListenerTarget::Promise(trusted_promise, callback) => {
723 self.task_source.queue(task!(reject_promise: move || {
724 let promise = trusted_promise.root();
725 let _ac = enter_realm(&*promise.global());
726 callback(promise, error);
727 }));
728 },
729 FileListenerTarget::Stream(trusted_stream) => {
730 self.task_source.queue(task!(error_stream: move || {
731 let stream = trusted_stream.root();
732 stream_handle_incoming(&stream, error, CanGc::note());
733 }));
734 },
735 }
736 },
737 _ => panic!("Unexpected FileListenerState when receiving Err msg."),
738 },
739 }
740 }
741}
742
743impl GlobalScope {
744 pub(crate) fn webview_id(&self) -> Option<WebViewId> {
748 if let Some(window) = self.downcast::<Window>() {
749 Some(window.webview_id())
750 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
751 dedicated.webview_id()
752 } else {
753 None
755 }
756 }
757
758 #[allow(clippy::too_many_arguments)]
759 pub(crate) fn new_inherited(
760 pipeline_id: PipelineId,
761 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
762 mem_profiler_chan: profile_mem::ProfilerChan,
763 time_profiler_chan: profile_time::ProfilerChan,
764 script_to_constellation_chan: ScriptToConstellationChan,
765 script_to_embedder_chan: ScriptToEmbedderChan,
766 resource_threads: ResourceThreads,
767 storage_threads: StorageThreads,
768 origin: MutableOrigin,
769 creation_url: ServoUrl,
770 top_level_creation_url: Option<ServoUrl>,
771 microtask_queue: Rc<MicrotaskQueue>,
772 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
773 inherited_secure_context: Option<bool>,
774 unminify_js: bool,
775 font_context: Option<Arc<FontContext>>,
776 ) -> Self {
777 Self {
778 task_manager: Default::default(),
779 message_port_state: DomRefCell::new(MessagePortState::UnManaged),
780 broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
781 blob_state: Default::default(),
782 eventtarget: EventTarget::new_inherited(),
783 crypto: Default::default(),
784 registration_map: DomRefCell::new(HashMapTracedValues::new_fx()),
785 cookie_store: Default::default(),
786 worker_map: DomRefCell::new(HashMapTracedValues::new_fx()),
787 pipeline_id,
788 devtools_wants_updates: Default::default(),
789 console_timers: DomRefCell::new(Default::default()),
790 module_map: DomRefCell::new(Default::default()),
791 inline_module_map: DomRefCell::new(Default::default()),
792 devtools_chan,
793 mem_profiler_chan,
794 time_profiler_chan,
795 script_to_constellation_chan,
796 script_to_embedder_chan,
797 in_error_reporting_mode: Default::default(),
798 resource_threads,
799 storage_threads,
800 timers: OnceCell::default(),
801 origin,
802 creation_url,
803 top_level_creation_url,
804 permission_state_invocation_results: Default::default(),
805 microtask_queue,
806 list_auto_close_worker: Default::default(),
807 event_source_tracker: DOMTracker::new(),
808 uncaught_rejections: Default::default(),
809 consumed_rejections: Default::default(),
810 #[cfg(feature = "webgpu")]
811 gpu_id_hub,
812 #[cfg(feature = "webgpu")]
813 gpu_devices: DomRefCell::new(HashMapTracedValues::new_fx()),
814 frozen_supported_performance_entry_types: CachedFrozenArray::new(),
815 https_state: Cell::new(HttpsState::None),
816 console_group_stack: DomRefCell::new(Vec::new()),
817 console_count_map: Default::default(),
818 dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
819 inherited_secure_context,
820 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
821 byte_length_queuing_strategy_size_function: OnceCell::new(),
822 count_queuing_strategy_size_function: OnceCell::new(),
823 notification_permission_request_callback_map: Default::default(),
824 import_map: Default::default(),
825 resolved_module_set: Default::default(),
826 font_context,
827 }
828 }
829
830 fn port_router_id(&self) -> Option<MessagePortRouterId> {
832 if let MessagePortState::Managed(id, _message_ports) = &*self.message_port_state.borrow() {
833 Some(*id)
834 } else {
835 None
836 }
837 }
838
839 fn is_managing_port(&self, port_id: &MessagePortId) -> bool {
841 if let MessagePortState::Managed(_router_id, message_ports) =
842 &*self.message_port_state.borrow()
843 {
844 return message_ports.contains_key(port_id);
845 }
846 false
847 }
848
849 fn timers(&self) -> &OneshotTimers {
850 self.timers.get_or_init(|| OneshotTimers::new(self))
851 }
852
853 pub(crate) fn font_context(&self) -> Option<&Arc<FontContext>> {
854 self.font_context.as_ref()
855 }
856
857 #[allow(clippy::too_many_arguments)]
859 pub(crate) fn get_serviceworker_registration(
860 &self,
861 script_url: &ServoUrl,
862 scope: &ServoUrl,
863 registration_id: ServiceWorkerRegistrationId,
864 installing_worker: Option<ServiceWorkerId>,
865 _waiting_worker: Option<ServiceWorkerId>,
866 _active_worker: Option<ServiceWorkerId>,
867 can_gc: CanGc,
868 ) -> DomRoot<ServiceWorkerRegistration> {
869 let mut registrations = self.registration_map.borrow_mut();
871
872 if let Some(registration) = registrations.get(®istration_id) {
873 return DomRoot::from_ref(&**registration);
875 }
876
877 let new_registration =
879 ServiceWorkerRegistration::new(self, scope.clone(), registration_id, can_gc);
880
881 if let Some(worker_id) = installing_worker {
883 let worker = self.get_serviceworker(script_url, scope, worker_id, can_gc);
884 new_registration.set_installing(&worker);
885 }
886
887 registrations.insert(registration_id, Dom::from_ref(&*new_registration));
893
894 new_registration
896 }
897
898 pub(crate) fn get_serviceworker(
900 &self,
901 script_url: &ServoUrl,
902 scope: &ServoUrl,
903 worker_id: ServiceWorkerId,
904 can_gc: CanGc,
905 ) -> DomRoot<ServiceWorker> {
906 let mut workers = self.worker_map.borrow_mut();
908
909 if let Some(worker) = workers.get(&worker_id) {
910 DomRoot::from_ref(&**worker)
912 } else {
913 let new_worker =
916 ServiceWorker::new(self, script_url.clone(), scope.clone(), worker_id, can_gc);
917
918 workers.insert(worker_id, Dom::from_ref(&*new_worker));
920
921 new_worker
923 }
924 }
925
926 fn complete_port_transfer(
928 &self,
929 port_id: MessagePortId,
930 tasks: VecDeque<PortMessageTask>,
931 disentangled: bool,
932 can_gc: CanGc,
933 ) {
934 let should_start = if let MessagePortState::Managed(_id, message_ports) =
935 &mut *self.message_port_state.borrow_mut()
936 {
937 match message_ports.get_mut(&port_id) {
938 None => {
939 panic!("complete_port_transfer called for an unknown port.");
940 },
941 Some(managed_port) => {
942 if managed_port.pending {
943 panic!("CompleteTransfer msg received for a pending port.");
944 }
945 if let Some(port_impl) = managed_port.port_impl.as_mut() {
946 port_impl.complete_transfer(tasks);
947 if disentangled {
948 port_impl.disentangle();
949 managed_port.dom_port.disentangle();
950 }
951 port_impl.enabled()
952 } else {
953 panic!("managed-port has no port-impl.");
954 }
955 },
956 }
957 } else {
958 panic!("complete_port_transfer called for an unknown port.");
959 };
960 if should_start {
961 self.start_message_port(&port_id, can_gc);
962 }
963 }
964
965 fn try_complete_disentanglement(&self, port_id: MessagePortId, can_gc: CanGc) {
968 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
969 &mut *self.message_port_state.borrow_mut()
970 {
971 if let Some(managed_port) = message_ports.get_mut(&port_id) {
972 if managed_port.pending {
973 unreachable!("CompleteDisentanglement msg received for a pending port.");
974 }
975 let port_impl = managed_port
976 .port_impl
977 .as_mut()
978 .expect("managed-port has no port-impl.");
979 port_impl.disentangle();
980 managed_port.dom_port.as_rooted()
981 } else {
982 return;
986 }
987 } else {
988 return;
989 };
990
991 dom_port.upcast().fire_event(atom!("close"), can_gc);
993
994 let res = self.script_to_constellation_chan().send(
995 ScriptToConstellationMessage::DisentanglePorts(port_id, None),
996 );
997 if res.is_err() {
998 warn!("Sending DisentanglePorts failed");
999 }
1000 }
1001
1002 pub(crate) fn perform_a_dom_garbage_collection_checkpoint(&self) {
1004 self.perform_a_message_port_garbage_collection_checkpoint();
1005 self.perform_a_blob_garbage_collection_checkpoint();
1006 self.perform_a_broadcast_channel_garbage_collection_checkpoint();
1007 }
1008
1009 pub(crate) fn remove_web_messaging_and_dedicated_workers_infra(&self) {
1012 self.remove_message_ports_router();
1013 self.remove_broadcast_channel_router();
1014
1015 self.list_auto_close_worker
1019 .borrow_mut()
1020 .drain(0..)
1021 .for_each(drop);
1022 }
1023
1024 fn remove_message_ports_router(&self) {
1027 if let MessagePortState::Managed(router_id, _message_ports) =
1028 &*self.message_port_state.borrow()
1029 {
1030 let _ = self.script_to_constellation_chan().send(
1031 ScriptToConstellationMessage::RemoveMessagePortRouter(*router_id),
1032 );
1033 }
1034 *self.message_port_state.borrow_mut() = MessagePortState::UnManaged;
1035 }
1036
1037 fn remove_broadcast_channel_router(&self) {
1040 if let BroadcastChannelState::Managed(router_id, _channels) =
1041 &*self.broadcast_channel_state.borrow()
1042 {
1043 let _ = self.script_to_constellation_chan().send(
1044 ScriptToConstellationMessage::RemoveBroadcastChannelRouter(
1045 *router_id,
1046 self.origin().immutable().clone(),
1047 ),
1048 );
1049 }
1050 *self.broadcast_channel_state.borrow_mut() = BroadcastChannelState::UnManaged;
1051 }
1052
1053 pub(crate) fn disentangle_port(&self, port: &MessagePort, can_gc: CanGc) {
1055 let initiator_port = port.message_port_id();
1056 let Some(other_port) = port.disentangle() else {
1058 return;
1062 };
1063
1064 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
1067 &mut *self.message_port_state.borrow_mut()
1068 {
1069 let mut dom_port = None;
1070 for port_id in &[initiator_port, &other_port] {
1071 match message_ports.get_mut(port_id) {
1072 None => {
1073 continue;
1074 },
1075 Some(managed_port) => {
1076 let port_impl = managed_port
1077 .port_impl
1078 .as_mut()
1079 .expect("managed-port has no port-impl.");
1080 managed_port.dom_port.disentangle();
1081 port_impl.disentangle();
1082
1083 if **port_id == other_port {
1084 dom_port = Some(managed_port.dom_port.as_rooted())
1085 }
1086 },
1087 }
1088 }
1089 dom_port
1090 } else {
1091 panic!("disentangle_port called on a global not managing any ports.");
1092 };
1093
1094 if let Some(dom_port) = dom_port {
1097 dom_port.upcast().fire_event(atom!("close"), can_gc);
1098 }
1099
1100 let chan = self.script_to_constellation_chan().clone();
1101 let initiator_port = *initiator_port;
1102 self.task_manager()
1103 .port_message_queue()
1104 .queue(task!(post_message: move || {
1105 let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
1108 if res.is_err() {
1109 warn!("Sending DisentanglePorts failed");
1110 }
1111 }));
1112 }
1113
1114 pub(crate) fn entangle_ports(&self, port1: MessagePortId, port2: MessagePortId) {
1116 if let MessagePortState::Managed(_id, message_ports) =
1117 &mut *self.message_port_state.borrow_mut()
1118 {
1119 for (port_id, entangled_id) in &[(port1, port2), (port2, port1)] {
1120 match message_ports.get_mut(port_id) {
1121 None => {
1122 return warn!("entangled_ports called on a global not managing the port.");
1123 },
1124 Some(managed_port) => {
1125 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1126 managed_port.dom_port.entangle(*entangled_id);
1127 port_impl.entangle(*entangled_id);
1128 } else {
1129 panic!("managed-port has no port-impl.");
1130 }
1131 },
1132 }
1133 }
1134 } else {
1135 panic!("entangled_ports called on a global not managing any ports.");
1136 }
1137
1138 let _ = self
1139 .script_to_constellation_chan()
1140 .send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
1141 }
1142
1143 pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
1145 if let MessagePortState::Managed(_id, message_ports) =
1146 &mut *self.message_port_state.borrow_mut()
1147 {
1148 let mut port_impl = message_ports
1149 .remove(port_id)
1150 .map(|ref mut managed_port| {
1151 managed_port
1152 .port_impl
1153 .take()
1154 .expect("Managed port doesn't have a port-impl.")
1155 })
1156 .expect("mark_port_as_transferred called on a global not managing the port.");
1157 port_impl.set_has_been_shipped();
1158 let _ = self
1159 .script_to_constellation_chan()
1160 .send(ScriptToConstellationMessage::MessagePortShipped(*port_id));
1161 port_impl
1162 } else {
1163 panic!("mark_port_as_transferred called on a global not managing any ports.");
1164 }
1165 }
1166
1167 pub(crate) fn start_message_port(&self, port_id: &MessagePortId, can_gc: CanGc) {
1169 let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
1170 &mut *self.message_port_state.borrow_mut()
1171 {
1172 let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
1173 None => panic!("start_message_port called on a unknown port."),
1174 Some(managed_port) => {
1175 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1176 (port_impl.start(), managed_port.dom_port.as_rooted())
1177 } else {
1178 panic!("managed-port has no port-impl.");
1179 }
1180 },
1181 };
1182 (message_buffer, dom_port)
1183 } else {
1184 return warn!("start_message_port called on a global not managing any ports.");
1185 };
1186 if let Some(message_buffer) = message_buffer {
1187 for task in message_buffer {
1188 self.route_task_to_port(*port_id, task, CanGc::note());
1189 }
1190 if dom_port.disentangled() {
1191 dom_port.upcast().fire_event(atom!("close"), can_gc);
1194
1195 let res = self.script_to_constellation_chan().send(
1196 ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
1197 );
1198 if res.is_err() {
1199 warn!("Sending DisentanglePorts failed");
1200 }
1201 }
1202 }
1203 }
1204
1205 pub(crate) fn close_message_port(&self, port_id: &MessagePortId) {
1207 if let MessagePortState::Managed(_id, message_ports) =
1208 &mut *self.message_port_state.borrow_mut()
1209 {
1210 match message_ports.get_mut(port_id) {
1211 None => panic!("close_message_port called on an unknown port."),
1212 Some(managed_port) => {
1213 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1214 port_impl.close();
1215 managed_port.explicitly_closed = true;
1216 } else {
1217 panic!("managed-port has no port-impl.");
1218 }
1219 },
1220 };
1221 } else {
1222 warn!("close_message_port called on a global not managing any ports.")
1223 }
1224 }
1225
1226 pub(crate) fn post_messageport_msg(&self, port_id: MessagePortId, task: PortMessageTask) {
1229 if let MessagePortState::Managed(_id, message_ports) =
1230 &mut *self.message_port_state.borrow_mut()
1231 {
1232 let entangled_port = match message_ports.get_mut(&port_id) {
1233 None => panic!("post_messageport_msg called on an unknown port."),
1234 Some(managed_port) => {
1235 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1236 port_impl.entangled_port_id()
1237 } else {
1238 panic!("managed-port has no port-impl.");
1239 }
1240 },
1241 };
1242 if let Some(entangled_id) = entangled_port {
1243 let this = Trusted::new(self);
1245 self.task_manager()
1246 .port_message_queue()
1247 .queue(task!(post_message: move || {
1248 let global = this.root();
1249 global.route_task_to_port(entangled_id, task, CanGc::note());
1252 }));
1253 }
1254 } else {
1255 warn!("post_messageport_msg called on a global not managing any ports.");
1256 }
1257 }
1258
1259 fn re_route_port_task(&self, port_id: MessagePortId, task: PortMessageTask) {
1262 let _ = self.script_to_constellation_chan().send(
1263 ScriptToConstellationMessage::RerouteMessagePort(port_id, task),
1264 );
1265 }
1266
1267 pub(crate) fn schedule_broadcast(&self, msg: BroadcastChannelMsg, channel_id: &Uuid) {
1270 self.broadcast_message_event(msg.clone(), Some(channel_id));
1272
1273 if let BroadcastChannelState::Managed(router_id, _) =
1274 &*self.broadcast_channel_state.borrow()
1275 {
1276 let _ = self.script_to_constellation_chan().send(
1281 ScriptToConstellationMessage::ScheduleBroadcast(*router_id, msg),
1282 );
1283 } else {
1284 panic!("Attemps to broadcast a message via global not managing any channels.");
1285 }
1286 }
1287
1288 pub(crate) fn broadcast_message_event(
1291 &self,
1292 event: BroadcastChannelMsg,
1293 channel_id: Option<&Uuid>,
1294 ) {
1295 if let BroadcastChannelState::Managed(_, channels) = &*self.broadcast_channel_state.borrow()
1296 {
1297 let BroadcastChannelMsg {
1298 data,
1299 origin,
1300 channel_name,
1301 } = event;
1302
1303 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
1307 if worker.is_closing() {
1308 return;
1309 }
1310 }
1311
1312 if let Some(window) = self.downcast::<Window>() {
1314 if !window.Document().is_fully_active() {
1315 return;
1316 }
1317 }
1318
1319 let channel_name = DOMString::from_string(channel_name);
1321
1322 if let Some(channels) = channels.get(&channel_name) {
1323 channels
1324 .iter()
1325 .filter(|channel| {
1326 if let Some(id) = channel_id {
1329 channel.id() != id
1330 } else {
1331 true
1332 }
1333 })
1334 .map(|channel| DomRoot::from_ref(&**channel))
1335 .for_each(|channel| {
1338 let data = data.clone_for_broadcast();
1339 let origin = origin.clone();
1340
1341 let channel = Trusted::new(&*channel);
1344 let global = Trusted::new(self);
1345 self.task_manager().dom_manipulation_task_source().queue(
1346 task!(process_pending_port_messages: move || {
1347 let destination = channel.root();
1348 let global = global.root();
1349
1350 if destination.closed() {
1352 return;
1353 }
1354
1355 rooted!(in(*GlobalScope::get_cx()) let mut message = UndefinedValue());
1356
1357 if let Ok(ports) = structuredclone::read(&global, data, message.handle_mut()) {
1359 MessageEvent::dispatch_jsval(
1361 destination.upcast(),
1362 &global,
1363 message.handle(),
1364 Some(&origin.ascii_serialization()),
1365 None,
1366 ports,
1367 CanGc::note()
1368 );
1369 } else {
1370 MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note());
1372 }
1373 })
1374 );
1375 });
1376 }
1377 }
1378 }
1379
1380 pub(crate) fn note_cross_realm_transform_readable(
1384 &self,
1385 cross_realm_transform_readable: &CrossRealmTransformReadable,
1386 port_id: &MessagePortId,
1387 ) {
1388 let MessagePortState::Managed(_id, message_ports) =
1389 &mut *self.message_port_state.borrow_mut()
1390 else {
1391 unreachable!(
1392 "Cross realm transform readable must be called on a global managing ports"
1393 );
1394 };
1395
1396 let Some(managed_port) = message_ports.get_mut(port_id) else {
1397 unreachable!("Cross realm transform readable must match a managed port");
1398 };
1399
1400 managed_port.cross_realm_transform = Some(CrossRealmTransform::Readable(
1401 cross_realm_transform_readable.clone(),
1402 ));
1403 }
1404
1405 pub(crate) fn note_cross_realm_transform_writable(
1409 &self,
1410 cross_realm_transform_writable: &CrossRealmTransformWritable,
1411 port_id: &MessagePortId,
1412 ) {
1413 let MessagePortState::Managed(_id, message_ports) =
1414 &mut *self.message_port_state.borrow_mut()
1415 else {
1416 unreachable!(
1417 "Cross realm transform writable must be called on a global managing ports"
1418 );
1419 };
1420
1421 let Some(managed_port) = message_ports.get_mut(port_id) else {
1422 unreachable!("Cross realm transform writable must match a managed port");
1423 };
1424
1425 managed_port.cross_realm_transform = Some(CrossRealmTransform::Writable(
1426 cross_realm_transform_writable.clone(),
1427 ));
1428 }
1429
1430 pub(crate) fn route_task_to_port(
1433 &self,
1434 port_id: MessagePortId,
1435 task: PortMessageTask,
1436 can_gc: CanGc,
1437 ) {
1438 let cx = GlobalScope::get_cx();
1439 rooted!(in(*cx) let mut cross_realm_transform = None);
1440
1441 let should_dispatch = if let MessagePortState::Managed(_id, message_ports) =
1442 &mut *self.message_port_state.borrow_mut()
1443 {
1444 if !message_ports.contains_key(&port_id) {
1445 self.re_route_port_task(port_id, task);
1446 return;
1447 }
1448 match message_ports.get_mut(&port_id) {
1449 None => panic!("route_task_to_port called for an unknown port."),
1450 Some(managed_port) => {
1451 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1454 let to_dispatch = port_impl.handle_incoming(task).map(|to_dispatch| {
1455 (DomRoot::from_ref(&*managed_port.dom_port), to_dispatch)
1456 });
1457 cross_realm_transform.set(managed_port.cross_realm_transform.clone());
1458 to_dispatch
1459 } else {
1460 panic!("managed-port has no port-impl.");
1461 }
1462 },
1463 }
1464 } else {
1465 self.re_route_port_task(port_id, task);
1466 return;
1467 };
1468
1469 if let Some((dom_port, PortMessageTask { origin, data })) = should_dispatch {
1474 let message_event_target = dom_port.upcast();
1476
1477 rooted!(in(*cx) let mut message_clone = UndefinedValue());
1483
1484 let realm = enter_realm(self);
1485 let comp = InRealm::Entered(&realm);
1486
1487 let _aes = AutoEntryScript::new(self);
1491
1492 if let Ok(ports) = structuredclone::read(self, data, message_clone.handle_mut()) {
1498 if let Some(transform) = cross_realm_transform.as_ref() {
1500 match transform {
1501 CrossRealmTransform::Readable(readable) => {
1504 readable.handle_message(
1505 cx,
1506 self,
1507 &dom_port,
1508 message_clone.handle(),
1509 comp,
1510 can_gc,
1511 );
1512 },
1513 CrossRealmTransform::Writable(writable) => {
1516 writable.handle_message(cx, self, message_clone.handle(), comp, can_gc);
1517 },
1518 }
1519 } else {
1520 MessageEvent::dispatch_jsval(
1525 message_event_target,
1526 self,
1527 message_clone.handle(),
1528 Some(&origin.ascii_serialization()),
1529 None,
1530 ports,
1531 can_gc,
1532 );
1533 }
1534 } else if let Some(transform) = cross_realm_transform.as_ref() {
1535 match transform {
1536 CrossRealmTransform::Readable(readable) => {
1539 readable.handle_error(cx, self, &dom_port, comp, can_gc);
1540 },
1541 CrossRealmTransform::Writable(writable) => {
1544 writable.handle_error(cx, self, &dom_port, comp, can_gc);
1545 },
1546 }
1547 } else {
1548 MessageEvent::dispatch_error(message_event_target, self, can_gc);
1552 }
1553 }
1554 }
1555
1556 pub(crate) fn maybe_add_pending_ports(&self) {
1559 if let MessagePortState::Managed(router_id, message_ports) =
1560 &mut *self.message_port_state.borrow_mut()
1561 {
1562 let to_be_added: Vec<MessagePortId> = message_ports
1563 .iter()
1564 .filter_map(|(id, managed_port)| {
1565 if managed_port.pending {
1566 Some(*id)
1567 } else {
1568 None
1569 }
1570 })
1571 .collect();
1572 for id in to_be_added.iter() {
1573 let managed_port = message_ports
1574 .get_mut(id)
1575 .expect("Collected port-id to match an entry");
1576 if !managed_port.pending {
1577 panic!("Only pending ports should be found in to_be_added")
1578 }
1579 managed_port.pending = false;
1580 }
1581 let _ = self.script_to_constellation_chan().send(
1582 ScriptToConstellationMessage::CompleteMessagePortTransfer(*router_id, to_be_added),
1583 );
1584 } else {
1585 warn!("maybe_add_pending_ports called on a global not managing any ports.");
1586 }
1587 }
1588
1589 pub(crate) fn perform_a_message_port_garbage_collection_checkpoint(&self) {
1591 let is_empty = if let MessagePortState::Managed(_id, message_ports) =
1592 &mut *self.message_port_state.borrow_mut()
1593 {
1594 let to_be_removed: Vec<MessagePortId> = message_ports
1595 .iter()
1596 .filter_map(|(id, managed_port)| {
1597 if managed_port.explicitly_closed {
1598 Some(*id)
1599 } else {
1600 None
1601 }
1602 })
1603 .collect();
1604 for id in to_be_removed {
1605 message_ports.remove(&id);
1606 }
1607 message_ports.is_empty()
1611 } else {
1612 false
1613 };
1614 if is_empty {
1615 self.remove_message_ports_router();
1616 }
1617 }
1618
1619 pub(crate) fn perform_a_broadcast_channel_garbage_collection_checkpoint(&self) {
1623 let is_empty = if let BroadcastChannelState::Managed(router_id, channels) =
1624 &mut *self.broadcast_channel_state.borrow_mut()
1625 {
1626 channels.retain(|name, ref mut channels| {
1627 channels.retain(|chan| !chan.closed());
1628 if channels.is_empty() {
1629 let _ = self.script_to_constellation_chan().send(
1630 ScriptToConstellationMessage::RemoveBroadcastChannelNameInRouter(
1631 *router_id,
1632 name.to_string(),
1633 self.origin().immutable().clone(),
1634 ),
1635 );
1636 false
1637 } else {
1638 true
1639 }
1640 });
1641 channels.is_empty()
1642 } else {
1643 false
1644 };
1645 if is_empty {
1646 self.remove_broadcast_channel_router();
1647 }
1648 }
1649
1650 pub(crate) fn track_broadcast_channel(&self, dom_channel: &BroadcastChannel) {
1652 let mut current_state = self.broadcast_channel_state.borrow_mut();
1653
1654 if let BroadcastChannelState::UnManaged = &*current_state {
1655 let (broadcast_control_sender, broadcast_control_receiver) =
1657 ipc::channel().expect("ipc channel failure");
1658 let context = Trusted::new(self);
1659 let listener = BroadcastListener {
1660 task_source: self.task_manager().dom_manipulation_task_source().into(),
1661 context,
1662 };
1663 ROUTER.add_typed_route(
1664 broadcast_control_receiver,
1665 Box::new(move |message| match message {
1666 Ok(msg) => listener.handle(msg),
1667 Err(err) => warn!("Error receiving a BroadcastChannelMsg: {:?}", err),
1668 }),
1669 );
1670 let router_id = BroadcastChannelRouterId::new();
1671 *current_state = BroadcastChannelState::Managed(router_id, HashMap::new());
1672 let _ = self.script_to_constellation_chan().send(
1673 ScriptToConstellationMessage::NewBroadcastChannelRouter(
1674 router_id,
1675 broadcast_control_sender,
1676 self.origin().immutable().clone(),
1677 ),
1678 );
1679 }
1680
1681 if let BroadcastChannelState::Managed(router_id, channels) = &mut *current_state {
1682 let entry = channels.entry(dom_channel.Name()).or_insert_with(|| {
1683 let _ = self.script_to_constellation_chan().send(
1684 ScriptToConstellationMessage::NewBroadcastChannelNameInRouter(
1685 *router_id,
1686 dom_channel.Name().to_string(),
1687 self.origin().immutable().clone(),
1688 ),
1689 );
1690 VecDeque::new()
1691 });
1692 entry.push_back(Dom::from_ref(dom_channel));
1693 } else {
1694 panic!("track_broadcast_channel should have first switched the state to managed.");
1695 }
1696 }
1697
1698 pub(crate) fn track_message_port(
1700 &self,
1701 dom_port: &MessagePort,
1702 port_impl: Option<MessagePortImpl>,
1703 ) {
1704 let mut current_state = self.message_port_state.borrow_mut();
1705
1706 if let MessagePortState::UnManaged = &*current_state {
1707 let (port_control_sender, port_control_receiver) =
1709 ipc::channel().expect("ipc channel failure");
1710 let context = Trusted::new(self);
1711 let listener = MessageListener {
1712 task_source: self.task_manager().port_message_queue().into(),
1713 context,
1714 };
1715 ROUTER.add_typed_route(
1716 port_control_receiver,
1717 Box::new(move |message| match message {
1718 Ok(msg) => listener.notify(msg),
1719 Err(err) => warn!("Error receiving a MessagePortMsg: {:?}", err),
1720 }),
1721 );
1722 let router_id = MessagePortRouterId::new();
1723 *current_state = MessagePortState::Managed(router_id, HashMapTracedValues::new_fx());
1724 let _ = self.script_to_constellation_chan().send(
1725 ScriptToConstellationMessage::NewMessagePortRouter(router_id, port_control_sender),
1726 );
1727 }
1728
1729 if let MessagePortState::Managed(router_id, message_ports) = &mut *current_state {
1730 if let Some(port_impl) = port_impl {
1731 message_ports.insert(
1735 *dom_port.message_port_id(),
1736 ManagedMessagePort {
1737 port_impl: Some(port_impl),
1738 dom_port: Dom::from_ref(dom_port),
1739 pending: true,
1740 explicitly_closed: false,
1741 cross_realm_transform: None,
1742 },
1743 );
1744
1745 let this = Trusted::new(self);
1748 self.task_manager().port_message_queue().queue(
1749 task!(process_pending_port_messages: move || {
1750 let target_global = this.root();
1751 target_global.maybe_add_pending_ports();
1752 }),
1753 );
1754 } else {
1755 let port_impl = MessagePortImpl::new(*dom_port.message_port_id());
1757 message_ports.insert(
1758 *dom_port.message_port_id(),
1759 ManagedMessagePort {
1760 port_impl: Some(port_impl),
1761 dom_port: Dom::from_ref(dom_port),
1762 pending: false,
1763 explicitly_closed: false,
1764 cross_realm_transform: None,
1765 },
1766 );
1767 let _ = self.script_to_constellation_chan().send(
1768 ScriptToConstellationMessage::NewMessagePort(
1769 *router_id,
1770 *dom_port.message_port_id(),
1771 ),
1772 );
1773 };
1774 } else {
1775 panic!("track_message_port should have first switched the state to managed.");
1776 }
1777 }
1778
1779 pub(crate) fn serialize_blob(&self, blob_id: &BlobId) -> BlobImpl {
1783 let bytes = self
1787 .get_blob_bytes(blob_id)
1788 .expect("Could not read bytes from blob as part of serialization steps.");
1789 let type_string = self.get_blob_type_string(blob_id);
1790
1791 BlobImpl::new_from_bytes(bytes, type_string)
1793 }
1794
1795 fn track_blob_info(&self, blob_info: BlobInfo, blob_id: BlobId) {
1796 self.blob_state.borrow_mut().insert(blob_id, blob_info);
1797 }
1798
1799 pub(crate) fn track_blob(&self, dom_blob: &Blob, blob_impl: BlobImpl) {
1801 let blob_id = blob_impl.blob_id();
1802
1803 let blob_info = BlobInfo {
1804 blob_impl,
1805 tracker: BlobTracker::Blob(WeakRef::new(dom_blob)),
1806 has_url: false,
1807 };
1808
1809 self.track_blob_info(blob_info, blob_id);
1810 }
1811
1812 pub(crate) fn track_file(&self, file: &File, blob_impl: BlobImpl) {
1814 let blob_id = blob_impl.blob_id();
1815
1816 let blob_info = BlobInfo {
1817 blob_impl,
1818 tracker: BlobTracker::File(WeakRef::new(file)),
1819 has_url: false,
1820 };
1821
1822 self.track_blob_info(blob_info, blob_id);
1823 }
1824
1825 fn perform_a_blob_garbage_collection_checkpoint(&self) {
1829 let mut blob_state = self.blob_state.borrow_mut();
1830 blob_state.0.retain(|_id, blob_info| {
1831 let garbage_collected = match &blob_info.tracker {
1832 BlobTracker::File(weak) => weak.root().is_none(),
1833 BlobTracker::Blob(weak) => weak.root().is_none(),
1834 };
1835 if garbage_collected && !blob_info.has_url {
1836 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1837 self.decrement_file_ref(f.get_id());
1838 }
1839 false
1840 } else {
1841 true
1842 }
1843 });
1844 }
1845
1846 pub(crate) fn clean_up_all_file_resources(&self) {
1849 self.blob_state
1850 .borrow_mut()
1851 .drain()
1852 .for_each(|(_id, blob_info)| {
1853 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1854 self.decrement_file_ref(f.get_id());
1855 }
1856 });
1857 }
1858
1859 fn decrement_file_ref(&self, id: Uuid) {
1860 let origin = get_blob_origin(&self.get_url());
1861
1862 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
1863
1864 let msg = FileManagerThreadMsg::DecRef(id, origin, tx);
1865 self.send_to_file_manager(msg);
1866 let _ = rx.recv();
1867 }
1868
1869 pub(crate) fn get_blob_bytes(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1872 let parent = {
1873 match *self.get_blob_data(blob_id) {
1874 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1875 _ => None,
1876 }
1877 };
1878
1879 match parent {
1880 Some((parent_id, rel_pos)) => self.get_blob_bytes_non_sliced(&parent_id).map(|v| {
1881 let range = rel_pos.to_abs_range(v.len());
1882 v.index(range).to_vec()
1883 }),
1884 None => self.get_blob_bytes_non_sliced(blob_id),
1885 }
1886 }
1887
1888 pub(crate) fn get_blob_data<'a>(&'a self, blob_id: &BlobId) -> Ref<'a, BlobData> {
1893 Ref::map(self.blob_state.borrow(), |blob_state| {
1894 blob_state
1895 .get(blob_id)
1896 .expect("get_blob_impl called for a unknown blob")
1897 .blob_impl
1898 .blob_data()
1899 })
1900 }
1901
1902 fn get_blob_bytes_non_sliced(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1904 match *self.get_blob_data(blob_id) {
1905 BlobData::File(ref f) => {
1906 let (buffer, is_new_buffer) = match f.get_cache() {
1907 Some(bytes) => (bytes, false),
1908 None => {
1909 let bytes = self.read_file(f.get_id())?;
1910 (bytes, true)
1911 },
1912 };
1913
1914 if is_new_buffer {
1916 f.cache_bytes(buffer.clone());
1917 }
1918
1919 Ok(buffer)
1920 },
1921 BlobData::Memory(ref s) => Ok(s.clone()),
1922 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1923 }
1924 }
1925
1926 fn get_blob_bytes_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1933 let parent = {
1934 match *self.get_blob_data(blob_id) {
1935 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1936 _ => None,
1937 }
1938 };
1939
1940 match parent {
1941 Some((parent_id, rel_pos)) => {
1942 match self.get_blob_bytes_non_sliced_or_file_id(&parent_id) {
1943 BlobResult::Bytes(bytes) => {
1944 let range = rel_pos.to_abs_range(bytes.len());
1945 BlobResult::Bytes(bytes.index(range).to_vec())
1946 },
1947 res => res,
1948 }
1949 },
1950 None => self.get_blob_bytes_non_sliced_or_file_id(blob_id),
1951 }
1952 }
1953
1954 fn get_blob_bytes_non_sliced_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1960 match *self.get_blob_data(blob_id) {
1961 BlobData::File(ref f) => match f.get_cache() {
1962 Some(bytes) => BlobResult::Bytes(bytes.clone()),
1963 None => BlobResult::File(f.get_id(), f.get_size() as usize),
1964 },
1965 BlobData::Memory(ref s) => BlobResult::Bytes(s.clone()),
1966 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1967 }
1968 }
1969
1970 pub(crate) fn get_blob_type_string(&self, blob_id: &BlobId) -> String {
1972 let blob_state = self.blob_state.borrow();
1973 let blob_info = blob_state
1974 .get(blob_id)
1975 .expect("get_blob_type_string called for a unknown blob.");
1976 blob_info.blob_impl.type_string()
1977 }
1978
1979 pub(crate) fn get_blob_size(&self, blob_id: &BlobId) -> u64 {
1981 let parent = {
1982 match *self.get_blob_data(blob_id) {
1983 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1984 _ => None,
1985 }
1986 };
1987 match parent {
1988 Some((parent_id, rel_pos)) => {
1989 let parent_size = match *self.get_blob_data(&parent_id) {
1990 BlobData::File(ref f) => f.get_size(),
1991 BlobData::Memory(ref v) => v.len() as u64,
1992 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
1993 };
1994 rel_pos.to_abs_range(parent_size as usize).len() as u64
1995 },
1996 None => match *self.get_blob_data(blob_id) {
1997 BlobData::File(ref f) => f.get_size(),
1998 BlobData::Memory(ref v) => v.len() as u64,
1999 BlobData::Sliced(_, _) => {
2000 panic!("It was previously checked that this blob does not have a parent.")
2001 },
2002 },
2003 }
2004 }
2005
2006 pub(crate) fn get_blob_url_id(&self, blob_id: &BlobId) -> Uuid {
2007 let mut blob_state = self.blob_state.borrow_mut();
2008 let parent = {
2009 let blob_info = blob_state
2010 .get_mut(blob_id)
2011 .expect("get_blob_url_id called for a unknown blob.");
2012
2013 blob_info.has_url = true;
2015
2016 match blob_info.blob_impl.blob_data() {
2017 BlobData::Sliced(parent, rel_pos) => Some((*parent, *rel_pos)),
2018 _ => None,
2019 }
2020 };
2021 match parent {
2022 Some((parent_id, rel_pos)) => {
2023 let parent_info = blob_state
2024 .get_mut(&parent_id)
2025 .expect("Parent of blob whose url is requested is unknown.");
2026 let parent_file_id = self.promote(parent_info, false);
2027 let parent_size = match parent_info.blob_impl.blob_data() {
2028 BlobData::File(f) => f.get_size(),
2029 BlobData::Memory(v) => v.len() as u64,
2030 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
2031 };
2032 let parent_size = rel_pos.to_abs_range(parent_size as usize).len() as u64;
2033 let blob_info = blob_state
2034 .get_mut(blob_id)
2035 .expect("Blob whose url is requested is unknown.");
2036 self.create_sliced_url_id(blob_info, &parent_file_id, &rel_pos, parent_size)
2037 },
2038 None => {
2039 let blob_info = blob_state
2040 .get_mut(blob_id)
2041 .expect("Blob whose url is requested is unknown.");
2042 self.promote(blob_info, true)
2043 },
2044 }
2045 }
2046
2047 fn create_sliced_url_id(
2049 &self,
2050 blob_info: &mut BlobInfo,
2051 parent_file_id: &Uuid,
2052 rel_pos: &RelativePos,
2053 parent_len: u64,
2054 ) -> Uuid {
2055 let origin = get_blob_origin(&self.get_url());
2056
2057 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2058 let msg =
2059 FileManagerThreadMsg::AddSlicedURLEntry(*parent_file_id, *rel_pos, tx, origin.clone());
2060 self.send_to_file_manager(msg);
2061 match rx.recv().expect("File manager thread is down.") {
2062 Ok(new_id) => {
2063 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2064 new_id,
2065 None,
2066 None,
2067 rel_pos.to_abs_range(parent_len as usize).len() as u64,
2068 ));
2069
2070 new_id
2072 },
2073 Err(_) => {
2074 Uuid::new_v4()
2076 },
2077 }
2078 }
2079
2080 pub(crate) fn promote(&self, blob_info: &mut BlobInfo, set_valid: bool) -> Uuid {
2086 let mut bytes = vec![];
2087 let global_url = self.get_url();
2088
2089 match blob_info.blob_impl.blob_data_mut() {
2090 BlobData::Sliced(_, _) => {
2091 panic!("Sliced blobs should use create_sliced_url_id instead of promote.");
2092 },
2093 BlobData::File(f) => {
2094 if set_valid {
2095 let origin = get_blob_origin(&global_url);
2096 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2097
2098 let msg = FileManagerThreadMsg::ActivateBlobURL(f.get_id(), tx, origin.clone());
2099 self.send_to_file_manager(msg);
2100
2101 match rx.recv().unwrap() {
2102 Ok(_) => return f.get_id(),
2103 Err(_) => return Uuid::new_v4(),
2105 }
2106 } else {
2107 return f.get_id();
2109 }
2110 },
2111 BlobData::Memory(bytes_in) => mem::swap(bytes_in, &mut bytes),
2112 };
2113
2114 let origin = get_blob_origin(&global_url);
2115
2116 let blob_buf = BlobBuf {
2117 filename: None,
2118 type_string: blob_info.blob_impl.type_string(),
2119 size: bytes.len() as u64,
2120 bytes: bytes.to_vec(),
2121 };
2122
2123 let id = Uuid::new_v4();
2124 let msg = FileManagerThreadMsg::PromoteMemory(id, blob_buf, set_valid, origin.clone());
2125 self.send_to_file_manager(msg);
2126
2127 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2128 id,
2129 None,
2130 Some(bytes.to_vec()),
2131 bytes.len() as u64,
2132 ));
2133
2134 id
2135 }
2136
2137 fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
2138 let resource_threads = self.resource_threads();
2139 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2140 }
2141
2142 fn read_file(&self, id: Uuid) -> Result<Vec<u8>, ()> {
2143 let recv = self.send_msg(id);
2144 GlobalScope::read_msg(recv)
2145 }
2146
2147 pub(crate) fn get_blob_stream(
2149 &self,
2150 blob_id: &BlobId,
2151 can_gc: CanGc,
2152 ) -> Fallible<DomRoot<ReadableStream>> {
2153 let (file_id, size) = match self.get_blob_bytes_or_file_id(blob_id) {
2154 BlobResult::Bytes(bytes) => {
2155 return ReadableStream::new_from_bytes(self, bytes, can_gc);
2157 },
2158 BlobResult::File(id, size) => (id, size),
2159 };
2160
2161 let stream = ReadableStream::new_with_external_underlying_source(
2162 self,
2163 UnderlyingSourceType::Blob(size),
2164 can_gc,
2165 )?;
2166
2167 let recv = self.send_msg(file_id);
2168
2169 let trusted_stream = Trusted::new(&*stream.clone());
2170 let mut file_listener = FileListener {
2171 state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
2172 trusted_stream,
2173 ))),
2174 task_source: self.task_manager().file_reading_task_source().into(),
2175 };
2176
2177 ROUTER.add_typed_route(
2178 recv.to_ipc_receiver(),
2179 Box::new(move |msg| {
2180 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2181 }),
2182 );
2183
2184 Ok(stream)
2185 }
2186
2187 pub(crate) fn read_file_async(
2188 &self,
2189 id: Uuid,
2190 promise: Rc<Promise>,
2191 callback: FileListenerCallback,
2192 ) {
2193 let recv = self.send_msg(id);
2194
2195 let trusted_promise = TrustedPromise::new(promise);
2196 let mut file_listener = FileListener {
2197 state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
2198 trusted_promise,
2199 callback,
2200 ))),
2201 task_source: self.task_manager().file_reading_task_source().into(),
2202 };
2203
2204 ROUTER.add_typed_route(
2205 recv.to_ipc_receiver(),
2206 Box::new(move |msg| {
2207 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2208 }),
2209 );
2210 }
2211
2212 fn send_msg(&self, id: Uuid) -> profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>> {
2213 let resource_threads = self.resource_threads();
2214 let (chan, recv) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2215 let origin = get_blob_origin(&self.get_url());
2216 let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
2217 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2218 recv
2219 }
2220
2221 fn read_msg(
2222 receiver: profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>>,
2223 ) -> Result<Vec<u8>, ()> {
2224 let mut bytes = vec![];
2225
2226 loop {
2227 match receiver.recv().unwrap() {
2228 Ok(ReadFileProgress::Meta(mut blob_buf)) => {
2229 bytes.append(&mut blob_buf.bytes);
2230 },
2231 Ok(ReadFileProgress::Partial(mut bytes_in)) => {
2232 bytes.append(&mut bytes_in);
2233 },
2234 Ok(ReadFileProgress::EOF) => {
2235 return Ok(bytes);
2236 },
2237 Err(_) => return Err(()),
2238 }
2239 }
2240 }
2241
2242 pub(crate) fn permission_state_invocation_results(
2243 &self,
2244 ) -> &DomRefCell<HashMap<PermissionName, PermissionState>> {
2245 &self.permission_state_invocation_results
2246 }
2247
2248 pub(crate) fn track_worker(
2249 &self,
2250 closing: Arc<AtomicBool>,
2251 join_handle: JoinHandle<()>,
2252 control_sender: Sender<DedicatedWorkerControlMsg>,
2253 context: ThreadSafeJSContext,
2254 ) {
2255 self.list_auto_close_worker
2256 .borrow_mut()
2257 .push(AutoCloseWorker {
2258 closing,
2259 join_handle: Some(join_handle),
2260 control_sender,
2261 context,
2262 });
2263 }
2264
2265 pub(crate) fn track_event_source(&self, event_source: &EventSource) {
2266 self.event_source_tracker.track(event_source);
2267 }
2268
2269 pub(crate) fn close_event_sources(&self) -> bool {
2270 let mut canceled_any_fetch = false;
2271 self.event_source_tracker
2272 .for_each(
2273 |event_source: DomRoot<EventSource>| match event_source.ReadyState() {
2274 2 => {},
2275 _ => {
2276 event_source.cancel();
2277 canceled_any_fetch = true;
2278 },
2279 },
2280 );
2281 canceled_any_fetch
2282 }
2283
2284 #[allow(unsafe_code)]
2287 pub(crate) fn from_reflector<T: DomObject>(reflector: &T, _realm: InRealm) -> DomRoot<Self> {
2288 unsafe { GlobalScope::from_object(*reflector.reflector().get_jsobject()) }
2289 }
2290
2291 #[allow(unsafe_code)]
2293 pub(crate) unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
2294 assert!(!obj.is_null());
2295 let global = unsafe { GetNonCCWObjectGlobal(obj) };
2296 unsafe { global_scope_from_global_static(global) }
2297 }
2298
2299 #[allow(unsafe_code)]
2301 pub(crate) unsafe fn from_context(cx: *mut JSContext, _realm: InRealm) -> DomRoot<Self> {
2302 let global = unsafe { CurrentGlobalOrNull(cx) };
2303 assert!(!global.is_null());
2304 unsafe { global_scope_from_global(global, cx) }
2305 }
2306
2307 #[allow(unsafe_code)]
2309 pub(crate) fn from_safe_context(cx: SafeJSContext, realm: InRealm) -> DomRoot<Self> {
2310 unsafe { Self::from_context(*cx, realm) }
2311 }
2312
2313 #[allow(unsafe_code)]
2316 pub(crate) unsafe fn from_object_maybe_wrapped(
2317 mut obj: *mut JSObject,
2318 cx: *mut JSContext,
2319 ) -> DomRoot<Self> {
2320 unsafe {
2321 if IsWrapper(obj) {
2322 obj = UnwrapObjectDynamic(obj, cx, false);
2323 assert!(!obj.is_null());
2324 }
2325 GlobalScope::from_object(obj)
2326 }
2327 }
2328
2329 pub(crate) fn add_uncaught_rejection(&self, rejection: HandleObject) {
2330 self.uncaught_rejections
2331 .borrow_mut()
2332 .push(Heap::boxed(rejection.get()));
2333 }
2334
2335 pub(crate) fn remove_uncaught_rejection(&self, rejection: HandleObject) {
2336 let mut uncaught_rejections = self.uncaught_rejections.borrow_mut();
2337
2338 if let Some(index) = uncaught_rejections
2339 .iter()
2340 .position(|promise| *promise == Heap::boxed(rejection.get()))
2341 {
2342 uncaught_rejections.remove(index);
2343 }
2344 }
2345
2346 #[allow(clippy::vec_box)]
2349 pub(crate) fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2350 &self.uncaught_rejections
2351 }
2352
2353 pub(crate) fn add_consumed_rejection(&self, rejection: HandleObject) {
2354 self.consumed_rejections
2355 .borrow_mut()
2356 .push(Heap::boxed(rejection.get()));
2357 }
2358
2359 pub(crate) fn remove_consumed_rejection(&self, rejection: HandleObject) {
2360 let mut consumed_rejections = self.consumed_rejections.borrow_mut();
2361
2362 if let Some(index) = consumed_rejections
2363 .iter()
2364 .position(|promise| *promise == Heap::boxed(rejection.get()))
2365 {
2366 consumed_rejections.remove(index);
2367 }
2368 }
2369
2370 #[allow(clippy::vec_box)]
2373 pub(crate) fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2374 &self.consumed_rejections
2375 }
2376
2377 pub(crate) fn set_module_map(&self, url: ServoUrl, module: ModuleTree) {
2378 self.module_map.borrow_mut().insert(url, Rc::new(module));
2379 }
2380
2381 pub(crate) fn get_module_map(
2382 &self,
2383 ) -> &DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>> {
2384 &self.module_map
2385 }
2386
2387 pub(crate) fn set_inline_module_map(&self, script_id: ScriptId, module: ModuleTree) {
2388 self.inline_module_map
2389 .borrow_mut()
2390 .insert(script_id, Rc::new(module));
2391 }
2392
2393 pub(crate) fn get_inline_module_map(&self) -> &DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>> {
2394 &self.inline_module_map
2395 }
2396
2397 #[allow(unsafe_code)]
2398 pub(crate) fn get_cx() -> SafeJSContext {
2399 let cx = Runtime::get()
2400 .expect("Can't obtain context after runtime shutdown")
2401 .as_ptr();
2402 unsafe { SafeJSContext::from_ptr(cx) }
2403 }
2404
2405 pub(crate) fn crypto(&self, can_gc: CanGc) -> DomRoot<Crypto> {
2406 self.crypto.or_init(|| Crypto::new(self, can_gc))
2407 }
2408
2409 pub(crate) fn cookie_store(&self, can_gc: CanGc) -> DomRoot<CookieStore> {
2410 self.cookie_store.or_init(|| CookieStore::new(self, can_gc))
2411 }
2412
2413 pub(crate) fn live_devtools_updates(&self) -> bool {
2414 self.devtools_wants_updates.get()
2415 }
2416
2417 pub(crate) fn set_devtools_wants_updates(&self, value: bool) {
2418 self.devtools_wants_updates.set(value);
2419 }
2420
2421 pub(crate) fn time(&self, label: DOMString) -> Result<(), ()> {
2422 let mut timers = self.console_timers.borrow_mut();
2423 if timers.len() >= 10000 {
2424 return Err(());
2425 }
2426 match timers.entry(label) {
2427 Entry::Vacant(entry) => {
2428 entry.insert(Instant::now());
2429 Ok(())
2430 },
2431 Entry::Occupied(_) => Err(()),
2432 }
2433 }
2434
2435 pub(crate) fn time_log(&self, label: &DOMString) -> Result<u64, ()> {
2439 self.console_timers
2440 .borrow()
2441 .get(label)
2442 .ok_or(())
2443 .map(|&start| (Instant::now() - start).as_millis() as u64)
2444 }
2445
2446 pub(crate) fn time_end(&self, label: &DOMString) -> Result<u64, ()> {
2451 self.console_timers
2452 .borrow_mut()
2453 .remove(label)
2454 .ok_or(())
2455 .map(|start| (Instant::now() - start).as_millis() as u64)
2456 }
2457
2458 pub(crate) fn devtools_chan(&self) -> Option<&IpcSender<ScriptToDevtoolsControlMsg>> {
2461 self.devtools_chan.as_ref()
2462 }
2463
2464 pub(crate) fn issue_page_warning(&self, warning: &str) {
2465 if let Some(ref chan) = self.devtools_chan {
2466 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2467 self.pipeline_id,
2468 PageError {
2469 type_: "PageError".to_string(),
2470 error_message: warning.to_string(),
2471 source_name: self.get_url().to_string(),
2472 line_text: "".to_string(),
2473 line_number: 0,
2474 column_number: 0,
2475 category: "script".to_string(),
2476 time_stamp: SystemTime::now()
2477 .duration_since(UNIX_EPOCH)
2478 .unwrap_or_default()
2479 .as_millis() as u64,
2480 error: false,
2481 warning: true,
2482 exception: true,
2483 strict: false,
2484 private: false,
2485 },
2486 ));
2487 }
2488 }
2489
2490 pub(crate) fn mem_profiler_chan(&self) -> &profile_mem::ProfilerChan {
2492 &self.mem_profiler_chan
2493 }
2494
2495 pub(crate) fn time_profiler_chan(&self) -> &profile_time::ProfilerChan {
2497 &self.time_profiler_chan
2498 }
2499
2500 pub(crate) fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {
2502 &self.script_to_constellation_chan
2503 }
2504
2505 pub(crate) fn script_to_embedder_chan(&self) -> &ScriptToEmbedderChan {
2506 &self.script_to_embedder_chan
2507 }
2508
2509 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
2510 self.script_to_embedder_chan().send(msg).unwrap();
2511 }
2512
2513 pub(crate) fn send_to_constellation(&self, msg: ScriptToConstellationMessage) {
2514 self.script_to_constellation_chan().send(msg).unwrap();
2515 }
2516
2517 pub(crate) fn pipeline_id(&self) -> PipelineId {
2519 self.pipeline_id
2520 }
2521
2522 pub(crate) fn origin(&self) -> &MutableOrigin {
2524 &self.origin
2525 }
2526
2527 pub(crate) fn creation_url(&self) -> &ServoUrl {
2529 &self.creation_url
2530 }
2531
2532 pub(crate) fn top_level_creation_url(&self) -> &Option<ServoUrl> {
2534 &self.top_level_creation_url
2535 }
2536
2537 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
2538 if let Some(window) = self.downcast::<Window>() {
2539 return window.image_cache();
2540 }
2541 if let Some(worker) = self.downcast::<DedicatedWorkerGlobalScope>() {
2542 return worker.image_cache();
2543 }
2544 if let Some(worker) = self.downcast::<PaintWorkletGlobalScope>() {
2545 return worker.image_cache();
2546 }
2547 unreachable!();
2548 }
2549
2550 pub(crate) fn schedule_timer(&self, request: TimerEventRequest) -> Option<TimerId> {
2554 match self.downcast::<WorkerGlobalScope>() {
2555 Some(worker_global) => Some(worker_global.timer_scheduler().schedule_timer(request)),
2556 _ => with_script_thread(|script_thread| Some(script_thread.schedule_timer(request))),
2557 }
2558 }
2559
2560 pub(crate) fn policy_container(&self) -> PolicyContainer {
2562 if let Some(window) = self.downcast::<Window>() {
2563 return window.Document().policy_container().to_owned();
2564 }
2565 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2566 return worker.policy_container().to_owned();
2567 }
2568 unreachable!();
2569 }
2570
2571 pub(crate) fn api_base_url(&self) -> ServoUrl {
2574 if let Some(window) = self.downcast::<Window>() {
2575 return window.Document().base_url();
2577 }
2578 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2579 return worker.get_url().clone();
2581 }
2582 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2583 return worklet.base_url();
2585 }
2586 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2587 return self.creation_url.clone();
2588 }
2589 unreachable!();
2590 }
2591
2592 pub(crate) fn get_url(&self) -> ServoUrl {
2594 if let Some(window) = self.downcast::<Window>() {
2595 return window.get_url();
2596 }
2597 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2598 return worker.get_url().clone();
2599 }
2600 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2601 return worklet.base_url();
2603 }
2604 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2605 return self.creation_url.clone();
2606 }
2607 unreachable!();
2608 }
2609
2610 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
2612 if let Some(window) = self.downcast::<Window>() {
2613 let document = window.Document();
2614
2615 return document.get_referrer_policy();
2616 }
2617 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2618 let policy_container = worker.policy_container().to_owned();
2619
2620 return policy_container.get_referrer_policy();
2621 }
2622 unreachable!();
2623 }
2624
2625 pub(crate) fn get_referrer(&self) -> Referrer {
2627 if let Some(window) = self.downcast::<Window>() {
2629 let mut document = window.Document();
2633
2634 if let ImmutableOrigin::Opaque(_) = document.origin().immutable() {
2636 return Referrer::NoReferrer;
2637 }
2638
2639 let mut url = document.url();
2640
2641 while url.as_str() == "about:srcdoc" {
2643 let Some(parent_document) =
2646 document.browsing_context().and_then(|browsing_context| {
2647 browsing_context
2648 .parent()
2649 .and_then(|parent| parent.document())
2650 })
2651 else {
2652 return Referrer::NoReferrer;
2653 };
2654 document = parent_document;
2655 url = document.url();
2656 }
2657
2658 Referrer::Client(url)
2660 } else {
2661 Referrer::Client(self.get_url())
2663 }
2664 }
2665
2666 pub(crate) fn as_window(&self) -> &Window {
2668 self.downcast::<Window>().expect("expected a Window scope")
2669 }
2670
2671 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
2673 if let Some(window) = self.downcast::<Window>() {
2674 return window.Document().insecure_requests_policy();
2675 }
2676 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2677 return worker.insecure_requests_policy();
2678 }
2679 debug!("unsupported global, defaulting insecure requests policy to DoNotUpgrade");
2680 InsecureRequestsPolicy::DoNotUpgrade
2681 }
2682
2683 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
2685 self.downcast::<Window>()
2686 .is_some_and(|window| window.Document().has_trustworthy_ancestor_origin())
2687 }
2688
2689 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
2691 self.downcast::<Window>().is_some_and(|window| {
2692 window
2693 .Document()
2694 .has_trustworthy_ancestor_or_current_origin()
2695 })
2696 }
2697
2698 pub(crate) fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue, can_gc: CanGc) {
2700 if self.in_error_reporting_mode.get() {
2702 return;
2703 }
2704
2705 self.in_error_reporting_mode.set(true);
2707
2708 let event = ErrorEvent::new(
2714 self,
2715 atom!("error"),
2716 EventBubbles::DoesNotBubble,
2717 EventCancelable::Cancelable,
2718 error_info.message.as_str().into(),
2719 error_info.filename.as_str().into(),
2720 error_info.lineno,
2721 error_info.column,
2722 value,
2723 can_gc,
2724 );
2725
2726 let not_handled = event
2727 .upcast::<Event>()
2728 .fire(self.upcast::<EventTarget>(), can_gc);
2729
2730 self.in_error_reporting_mode.set(false);
2732
2733 if not_handled {
2735 if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2737 dedicated.forward_error_to_worker_object(error_info);
2738 } else if self.is::<Window>() {
2739 if let Some(ref chan) = self.devtools_chan {
2740 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2741 self.pipeline_id,
2742 PageError {
2743 type_: "PageError".to_string(),
2744 error_message: error_info.message.clone(),
2745 source_name: error_info.filename.clone(),
2746 line_text: "".to_string(), line_number: error_info.lineno,
2748 column_number: error_info.column,
2749 category: "script".to_string(),
2750 time_stamp: SystemTime::now()
2751 .duration_since(UNIX_EPOCH)
2752 .unwrap_or_default()
2753 .as_millis() as u64,
2754 error: true,
2755 warning: false,
2756 exception: true,
2757 strict: false,
2758 private: false,
2759 },
2760 ));
2761 }
2762 }
2763 }
2764 }
2765
2766 pub(crate) fn resource_threads(&self) -> &ResourceThreads {
2768 &self.resource_threads
2769 }
2770
2771 pub(crate) fn core_resource_thread(&self) -> CoreResourceThread {
2773 self.resource_threads().sender()
2774 }
2775
2776 pub(crate) fn storage_threads(&self) -> &StorageThreads {
2778 &self.storage_threads
2779 }
2780
2781 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
2785 if let Some(window) = self.downcast::<Window>() {
2786 Some(window.event_loop_sender())
2787 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2788 dedicated.event_loop_sender()
2789 } else if let Some(service_worker) = self.downcast::<ServiceWorkerGlobalScope>() {
2790 Some(service_worker.event_loop_sender())
2791 } else {
2792 unreachable!(
2793 "Tried to access event loop sender for incompatible \
2794 GlobalScope (PaintWorklet or DissimilarOriginWindow)"
2795 );
2796 }
2797 }
2798
2799 pub(crate) fn task_manager(&self) -> &TaskManager {
2801 let shared_canceller = self
2802 .downcast::<WorkerGlobalScope>()
2803 .map(WorkerGlobalScope::shared_task_canceller);
2804 self.task_manager.get_or_init(|| {
2805 TaskManager::new(
2806 self.event_loop_sender(),
2807 self.pipeline_id(),
2808 shared_canceller,
2809 )
2810 })
2811 }
2812
2813 pub(crate) fn evaluate_js_on_global_with_result(
2815 &self,
2816 code: &str,
2817 rval: MutableHandleValue,
2818 fetch_options: ScriptFetchOptions,
2819 script_base_url: ServoUrl,
2820 can_gc: CanGc,
2821 introduction_type: Option<&'static CStr>,
2822 ) -> Result<(), JavaScriptEvaluationError> {
2823 let source_code = SourceCode::Text(Rc::new(DOMString::from_string((*code).to_string())));
2824 self.evaluate_script_on_global_with_result(
2825 &source_code,
2826 "",
2827 rval,
2828 1,
2829 fetch_options,
2830 script_base_url,
2831 can_gc,
2832 introduction_type,
2833 )
2834 }
2835
2836 #[allow(unsafe_code)]
2838 #[allow(clippy::too_many_arguments)]
2839 pub(crate) fn evaluate_script_on_global_with_result(
2840 &self,
2841 code: &SourceCode,
2842 filename: &str,
2843 rval: MutableHandleValue,
2844 line_number: u32,
2845 fetch_options: ScriptFetchOptions,
2846 script_base_url: ServoUrl,
2847 can_gc: CanGc,
2848 introduction_type: Option<&'static CStr>,
2849 ) -> Result<(), JavaScriptEvaluationError> {
2850 let cx = GlobalScope::get_cx();
2851
2852 let ar = enter_realm(self);
2853
2854 let _aes = AutoEntryScript::new(self);
2855
2856 unsafe {
2857 rooted!(in(*cx) let mut compiled_script = std::ptr::null_mut::<JSScript>());
2858 match code {
2859 SourceCode::Text(text_code) => {
2860 let mut options = CompileOptionsWrapper::new(*cx, filename, line_number);
2861 if let Some(introduction_type) = introduction_type {
2862 options.set_introduction_type(introduction_type);
2863 }
2864
2865 debug!("compiling dom string");
2866 compiled_script.set(Compile1(
2867 *cx,
2868 options.ptr,
2869 &mut transform_str_to_source_text(&text_code.str()),
2870 ));
2871
2872 if compiled_script.is_null() {
2873 debug!("error compiling Dom string");
2874 report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
2875 return Err(JavaScriptEvaluationError::CompilationFailure);
2876 }
2877 },
2878 SourceCode::Compiled(pre_compiled_script) => {
2879 let options = InstantiateOptions {
2880 skipFilenameValidation: false,
2881 hideScriptFromDebugger: false,
2882 deferDebugMetadata: false,
2883 eagerDelazificationStrategy_: DelazificationOption::OnDemandOnly,
2884 };
2885 let script = InstantiateGlobalStencil(
2886 *cx,
2887 &options,
2888 *pre_compiled_script.source_code,
2889 ptr::null_mut(),
2890 );
2891 compiled_script.set(script);
2892 },
2893 };
2894
2895 assert!(!compiled_script.is_null());
2896
2897 rooted!(in(*cx) let mut script_private = UndefinedValue());
2898 JS_GetScriptPrivate(*compiled_script, script_private.handle_mut());
2899
2900 if script_private.is_undefined() {
2903 debug!("Set script private for {}", script_base_url);
2904
2905 let module_script_data = Rc::new(ModuleScript::new(
2906 script_base_url,
2907 fetch_options,
2908 None,
2912 ));
2913
2914 SetScriptPrivate(
2915 *compiled_script,
2916 &PrivateValue(Rc::into_raw(module_script_data) as *const _),
2917 );
2918 }
2919
2920 let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval);
2921
2922 if !result {
2923 debug!("error evaluating Dom string");
2924 let error_info =
2925 take_and_report_pending_exception_for_api(cx, InRealm::Entered(&ar), can_gc);
2926 return Err(JavaScriptEvaluationError::EvaluationFailure(error_info));
2927 }
2928
2929 maybe_resume_unwind();
2930 Ok(())
2931 }
2932 }
2933
2934 pub(crate) fn schedule_callback(
2936 &self,
2937 callback: OneshotTimerCallback,
2938 duration: Duration,
2939 ) -> OneshotTimerHandle {
2940 self.timers()
2941 .schedule_callback(callback, duration, self.timer_source())
2942 }
2943
2944 pub(crate) fn unschedule_callback(&self, handle: OneshotTimerHandle) {
2945 self.timers().unschedule_callback(handle);
2946 }
2947
2948 pub(crate) fn set_timeout_or_interval(
2950 &self,
2951 callback: TimerCallback,
2952 arguments: Vec<HandleValue>,
2953 timeout: Duration,
2954 is_interval: IsInterval,
2955 can_gc: CanGc,
2956 ) -> Fallible<i32> {
2957 self.timers().set_timeout_or_interval(
2958 self,
2959 callback,
2960 arguments,
2961 timeout,
2962 is_interval,
2963 self.timer_source(),
2964 can_gc,
2965 )
2966 }
2967
2968 pub(crate) fn clear_timeout_or_interval(&self, handle: i32) {
2969 self.timers().clear_timeout_or_interval(self, handle);
2970 }
2971
2972 pub(crate) fn queue_function_as_microtask(&self, callback: Rc<VoidFunction>) {
2973 self.enqueue_microtask(Microtask::User(UserMicrotask {
2974 callback,
2975 pipeline: self.pipeline_id(),
2976 }))
2977 }
2978
2979 pub(crate) fn fire_timer(&self, handle: TimerEventId, can_gc: CanGc) {
2980 self.timers().fire_timer(handle, self, can_gc);
2981 }
2982
2983 pub(crate) fn resume(&self) {
2984 self.timers().resume();
2985 }
2986
2987 pub(crate) fn suspend(&self) {
2988 self.timers().suspend();
2989 }
2990
2991 pub(crate) fn slow_down_timers(&self) {
2992 self.timers().slow_down();
2993 }
2994
2995 pub(crate) fn speed_up_timers(&self) {
2996 self.timers().speed_up();
2997 }
2998
2999 fn timer_source(&self) -> TimerSource {
3000 if self.is::<Window>() {
3001 return TimerSource::FromWindow(self.pipeline_id());
3002 }
3003 if self.is::<WorkerGlobalScope>() {
3004 return TimerSource::FromWorker;
3005 }
3006 unreachable!();
3007 }
3008
3009 pub(crate) fn can_continue_running(&self) -> bool {
3012 if self.is::<Window>() {
3013 return ScriptThread::can_continue_running();
3014 }
3015 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3016 return !worker.is_closing();
3017 }
3018
3019 true
3021 }
3022
3023 pub(crate) fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3025 if self.can_continue_running() {
3027 self.microtask_queue.checkpoint(
3028 GlobalScope::get_cx(),
3029 |_| Some(DomRoot::from_ref(self)),
3030 vec![DomRoot::from_ref(self)],
3031 can_gc,
3032 );
3033 }
3034 }
3035
3036 pub(crate) fn enqueue_microtask(&self, job: Microtask) {
3038 self.microtask_queue.enqueue(job, GlobalScope::get_cx());
3039 }
3040
3041 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
3045 if let Some(window) = self.downcast::<Window>() {
3046 return window.new_script_pair();
3047 }
3048 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3049 return worker.new_script_pair();
3050 }
3051 unreachable!();
3052 }
3053
3054 pub(crate) fn microtask_queue(&self) -> &Rc<MicrotaskQueue> {
3056 &self.microtask_queue
3057 }
3058
3059 pub(crate) fn process_event(&self, msg: CommonScriptMsg) -> bool {
3063 if self.is::<Window>() {
3064 return ScriptThread::process_event(msg);
3065 }
3066 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3067 return worker.process_event(msg);
3068 }
3069 unreachable!();
3070 }
3071
3072 pub(crate) fn runtime_handle(&self) -> ParentRuntime {
3073 if self.is::<Window>() {
3074 ScriptThread::runtime_handle()
3075 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3076 worker.runtime_handle()
3077 } else {
3078 unreachable!()
3079 }
3080 }
3081
3082 #[allow(unsafe_code)]
3086 pub(crate) fn current() -> Option<DomRoot<Self>> {
3087 let cx = Runtime::get()?;
3088 unsafe {
3089 let global = CurrentGlobalOrNull(cx.as_ptr());
3090 if global.is_null() {
3091 None
3092 } else {
3093 Some(global_scope_from_global(global, cx.as_ptr()))
3094 }
3095 }
3096 }
3097
3098 pub(crate) fn entry() -> DomRoot<Self> {
3102 entry_global()
3103 }
3104
3105 pub(crate) fn incumbent() -> Option<DomRoot<Self>> {
3109 incumbent_global()
3110 }
3111
3112 pub(crate) fn performance(&self) -> DomRoot<Performance> {
3113 if let Some(window) = self.downcast::<Window>() {
3114 return window.Performance();
3115 }
3116 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3117 return worker.Performance();
3118 }
3119 unreachable!();
3120 }
3121
3122 pub(crate) fn supported_performance_entry_types(
3124 &self,
3125 cx: SafeJSContext,
3126 retval: MutableHandleValue,
3127 can_gc: CanGc,
3128 ) {
3129 self.frozen_supported_performance_entry_types.get_or_init(
3130 || {
3131 VALID_ENTRY_TYPES
3132 .iter()
3133 .map(|t| DOMString::from(t.to_string()))
3134 .collect()
3135 },
3136 cx,
3137 retval,
3138 can_gc,
3139 );
3140 }
3141
3142 pub(crate) fn get_https_state(&self) -> HttpsState {
3143 self.https_state.get()
3144 }
3145
3146 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
3147 self.https_state.set(https_state);
3148 }
3149
3150 pub(crate) fn is_secure_context(&self) -> bool {
3152 if Some(false) == self.inherited_secure_context {
3157 return false;
3158 }
3159 match self.top_level_creation_url() {
3162 None => {
3163 assert!(
3165 self.downcast::<WorkerGlobalScope>().is_some() ||
3166 self.downcast::<WorkletGlobalScope>().is_some()
3167 );
3168 true
3169 },
3170 Some(top_level_creation_url) => {
3171 assert!(self.downcast::<Window>().is_some());
3172 if top_level_creation_url.scheme() == "blob" &&
3176 Some(true) == self.inherited_secure_context
3177 {
3178 return true;
3179 }
3180 top_level_creation_url.is_potentially_trustworthy()
3181 },
3182 }
3183 }
3184
3185 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
3187 if self.downcast::<Window>().is_some() || self.downcast::<WorkerGlobalScope>().is_some() {
3188 return self.policy_container().csp_list;
3189 }
3190 None
3192 }
3193
3194 pub(crate) fn status_code(&self) -> Option<u16> {
3195 if let Some(window) = self.downcast::<Window>() {
3196 return window.Document().status_code();
3197 }
3198 None
3199 }
3200
3201 #[cfg(feature = "webgpu")]
3202 pub(crate) fn wgpu_id_hub(&self) -> Arc<IdentityHub> {
3203 self.gpu_id_hub.clone()
3204 }
3205
3206 #[cfg(feature = "webgpu")]
3207 pub(crate) fn add_gpu_device(&self, device: &GPUDevice) {
3208 self.gpu_devices
3209 .borrow_mut()
3210 .insert(device.id(), WeakRef::new(device));
3211 }
3212
3213 #[cfg(feature = "webgpu")]
3214 pub(crate) fn remove_gpu_device(&self, device: WebGPUDevice) {
3215 let device = self
3216 .gpu_devices
3217 .borrow_mut()
3218 .remove(&device)
3219 .expect("GPUDevice should still be in devices hashmap");
3220 assert!(device.root().is_none())
3221 }
3222
3223 #[cfg(feature = "webgpu")]
3224 pub(crate) fn gpu_device_lost(
3225 &self,
3226 device: WebGPUDevice,
3227 reason: DeviceLostReason,
3228 msg: String,
3229 ) {
3230 let reason = match reason {
3231 DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown,
3232 DeviceLostReason::Destroyed => GPUDeviceLostReason::Destroyed,
3233 };
3234 let _ac = enter_realm(self);
3235 if let Some(device) = self
3236 .gpu_devices
3237 .borrow_mut()
3238 .get_mut(&device)
3239 .expect("GPUDevice should still be in devices hashmap")
3240 .root()
3241 {
3242 device.lose(reason, msg);
3243 }
3244 }
3245
3246 #[cfg(feature = "webgpu")]
3247 pub(crate) fn handle_uncaptured_gpu_error(
3248 &self,
3249 device: WebGPUDevice,
3250 error: webgpu_traits::Error,
3251 ) {
3252 if let Some(gpu_device) = self
3253 .gpu_devices
3254 .borrow()
3255 .get(&device)
3256 .and_then(|device| device.root())
3257 {
3258 gpu_device.fire_uncaptured_error(error);
3259 } else {
3260 warn!("Recived error for lost GPUDevice!")
3261 }
3262 }
3263
3264 pub(crate) fn current_group_label(&self) -> Option<DOMString> {
3265 self.console_group_stack
3266 .borrow()
3267 .last()
3268 .map(|label| DOMString::from(format!("[{}]", label)))
3269 }
3270
3271 pub(crate) fn push_console_group(&self, group: DOMString) {
3272 self.console_group_stack.borrow_mut().push(group);
3273 }
3274
3275 pub(crate) fn pop_console_group(&self) {
3276 let _ = self.console_group_stack.borrow_mut().pop();
3277 }
3278
3279 pub(crate) fn increment_console_count(&self, label: &DOMString) -> usize {
3280 *self
3281 .console_count_map
3282 .borrow_mut()
3283 .entry(label.clone())
3284 .and_modify(|e| *e += 1)
3285 .or_insert(1)
3286 }
3287
3288 pub(crate) fn reset_console_count(&self, label: &DOMString) -> Result<(), ()> {
3289 match self.console_count_map.borrow_mut().get_mut(label) {
3290 Some(value) => {
3291 *value = 0;
3292 Ok(())
3293 },
3294 None => Err(()),
3295 }
3296 }
3297
3298 pub(crate) fn dynamic_module_list(&self) -> RefMut<'_, DynamicModuleList> {
3299 self.dynamic_modules.borrow_mut()
3300 }
3301
3302 pub(crate) fn structured_clone(
3303 &self,
3304 cx: SafeJSContext,
3305 value: HandleValue,
3306 options: RootedTraceableBox<StructuredSerializeOptions>,
3307 retval: MutableHandleValue,
3308 ) -> Fallible<()> {
3309 let mut rooted = CustomAutoRooter::new(
3310 options
3311 .transfer
3312 .iter()
3313 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
3314 .collect(),
3315 );
3316 let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
3317
3318 let data = structuredclone::write(cx, value, Some(guard))?;
3319
3320 structuredclone::read(self, data, retval)?;
3321
3322 Ok(())
3323 }
3324
3325 pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
3326 &self,
3327 request_builder: RequestBuilder,
3328 context: Arc<Mutex<Listener>>,
3329 task_source: SendableTaskSource,
3330 ) {
3331 let network_listener = NetworkListener {
3332 context,
3333 task_source,
3334 };
3335 self.fetch_with_network_listener(request_builder, network_listener);
3336 }
3337
3338 pub(crate) fn fetch_with_network_listener<
3339 Listener: FetchResponseListener + PreInvoke + Send + 'static,
3340 >(
3341 &self,
3342 request_builder: RequestBuilder,
3343 network_listener: NetworkListener<Listener>,
3344 ) {
3345 fetch_async(
3346 &self.core_resource_thread(),
3347 request_builder,
3348 None,
3349 network_listener.into_callback(),
3350 );
3351 }
3352
3353 pub(crate) fn unminified_js_dir(&self) -> Option<String> {
3354 self.unminified_js_dir.clone()
3355 }
3356
3357 pub(crate) fn set_byte_length_queuing_strategy_size(&self, function: Rc<Function>) {
3358 if self
3359 .byte_length_queuing_strategy_size_function
3360 .set(function)
3361 .is_err()
3362 {
3363 warn!("byte length queuing strategy size function is set twice.");
3364 };
3365 }
3366
3367 pub(crate) fn get_byte_length_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3368 self.byte_length_queuing_strategy_size_function
3369 .get()
3370 .cloned()
3371 }
3372
3373 pub(crate) fn set_count_queuing_strategy_size(&self, function: Rc<Function>) {
3374 if self
3375 .count_queuing_strategy_size_function
3376 .set(function)
3377 .is_err()
3378 {
3379 warn!("count queuing strategy size function is set twice.");
3380 };
3381 }
3382
3383 pub(crate) fn get_count_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3384 self.count_queuing_strategy_size_function.get().cloned()
3385 }
3386
3387 pub(crate) fn add_notification_permission_request_callback(
3388 &self,
3389 callback_id: String,
3390 callback: Rc<NotificationPermissionCallback>,
3391 ) {
3392 self.notification_permission_request_callback_map
3393 .borrow_mut()
3394 .insert(callback_id, callback.clone());
3395 }
3396
3397 pub(crate) fn remove_notification_permission_request_callback(
3398 &self,
3399 callback_id: String,
3400 ) -> Option<Rc<NotificationPermissionCallback>> {
3401 self.notification_permission_request_callback_map
3402 .borrow_mut()
3403 .remove(&callback_id)
3404 }
3405
3406 pub(crate) fn trusted_types(&self, can_gc: CanGc) -> DomRoot<TrustedTypePolicyFactory> {
3407 if let Some(window) = self.downcast::<Window>() {
3408 return window.TrustedTypes(can_gc);
3409 }
3410 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3411 return worker.TrustedTypes(can_gc);
3412 }
3413 unreachable!();
3414 }
3415
3416 pub(crate) fn append_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3417 if let Some(window) = self.downcast::<Window>() {
3418 return window.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3419 }
3420 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3421 return worker.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3422 }
3423 unreachable!();
3424 }
3425
3426 pub(crate) fn remove_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3427 if let Some(window) = self.downcast::<Window>() {
3428 return window.remove_reporting_observer(reporting_observer);
3429 }
3430 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3431 return worker.remove_reporting_observer(reporting_observer);
3432 }
3433 unreachable!();
3434 }
3435
3436 pub(crate) fn registered_reporting_observers(&self) -> Vec<DomRoot<ReportingObserver>> {
3437 if let Some(window) = self.downcast::<Window>() {
3438 return window.registered_reporting_observers();
3439 }
3440 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3441 return worker.registered_reporting_observers();
3442 }
3443 unreachable!();
3444 }
3445
3446 pub(crate) fn append_report(&self, report: Report) {
3447 if let Some(window) = self.downcast::<Window>() {
3448 return window.append_report(report);
3449 }
3450 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3451 return worker.append_report(report);
3452 }
3453 unreachable!();
3454 }
3455
3456 pub(crate) fn buffered_reports(&self) -> Vec<Report> {
3457 if let Some(window) = self.downcast::<Window>() {
3458 return window.buffered_reports();
3459 }
3460 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3461 return worker.buffered_reports();
3462 }
3463 unreachable!();
3464 }
3465
3466 pub(crate) fn import_map(&self) -> Ref<'_, ImportMap> {
3467 self.import_map.borrow()
3468 }
3469
3470 pub(crate) fn import_map_mut(&self) -> RefMut<'_, ImportMap> {
3471 self.import_map.borrow_mut()
3472 }
3473
3474 pub(crate) fn resolved_module_set(&self) -> Ref<'_, HashSet<ResolvedModule>> {
3475 self.resolved_module_set.borrow()
3476 }
3477
3478 pub(crate) fn resolved_module_set_mut(&self) -> RefMut<'_, HashSet<ResolvedModule>> {
3479 self.resolved_module_set.borrow_mut()
3480 }
3481
3482 pub(crate) fn add_module_to_resolved_module_set(
3484 &self,
3485 base_url: &str,
3486 specifier: &str,
3487 specifier_url: Option<ServoUrl>,
3488 ) {
3489 if self.is::<Window>() {
3492 let record =
3496 ResolvedModule::new(base_url.to_owned(), specifier.to_owned(), specifier_url);
3497 self.resolved_module_set.borrow_mut().insert(record);
3499 }
3500 }
3501}
3502
3503#[allow(unsafe_code)]
3505unsafe fn global_scope_from_global(
3506 global: *mut JSObject,
3507 cx: *mut JSContext,
3508) -> DomRoot<GlobalScope> {
3509 unsafe {
3510 assert!(!global.is_null());
3511 let clasp = get_object_class(global);
3512 assert_ne!(
3513 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3514 0
3515 );
3516 root_from_object(global, cx).unwrap()
3517 }
3518}
3519
3520#[allow(unsafe_code)]
3522unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<GlobalScope> {
3523 assert!(!global.is_null());
3524 let clasp = unsafe { get_object_class(global) };
3525
3526 unsafe {
3527 assert_ne!(
3528 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3529 0
3530 );
3531 }
3532
3533 root_from_object_static(global).unwrap()
3534}
3535
3536#[allow(unsafe_code)]
3537impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
3538 unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot<Self> {
3539 unsafe { GlobalScope::from_context(cx, realm) }
3540 }
3541
3542 fn get_cx() -> SafeJSContext {
3543 GlobalScope::get_cx()
3544 }
3545
3546 unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
3547 GlobalScope::from_object(obj)
3548 }
3549
3550 fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<Self> {
3551 GlobalScope::from_reflector(reflector, realm)
3552 }
3553
3554 fn origin(&self) -> &MutableOrigin {
3555 GlobalScope::origin(self)
3556 }
3557
3558 fn incumbent() -> Option<DomRoot<Self>> {
3559 GlobalScope::incumbent()
3560 }
3561
3562 fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3563 GlobalScope::perform_a_microtask_checkpoint(self, can_gc)
3564 }
3565
3566 fn get_url(&self) -> ServoUrl {
3567 self.get_url()
3568 }
3569
3570 fn is_secure_context(&self) -> bool {
3571 self.is_secure_context()
3572 }
3573}