1#![allow(dead_code)]
9
10use core::ffi::c_char;
11use std::cell::Cell;
12use std::ffi::{CStr, CString};
13use std::io::{Write, stdout};
14use std::ops::Deref;
15use std::os::raw::c_void;
16use std::rc::Rc;
17use std::sync::Mutex;
18use std::time::{Duration, Instant};
19use std::{os, ptr, thread};
20
21use background_hang_monitor_api::ScriptHangAnnotation;
22use js::conversions::jsstr_to_string;
23use js::gc::StackGCVector;
24use js::glue::{
25 CollectServoSizes, CreateJobQueue, DeleteJobQueue, DispatchablePointer, DispatchableRun,
26 JS_GetReservedSlot, JobQueueTraps, RUST_js_GetErrorMessage, SetBuildId, SetUpEventLoopDispatch,
27 StreamConsumerConsumeChunk, StreamConsumerNoteResponseURLs, StreamConsumerStreamEnd,
28 StreamConsumerStreamError,
29};
30use js::jsapi::{
31 AsmJSOption, BuildIdCharVector, CompilationType, ContextOptionsRef,
32 Dispatchable_MaybeShuttingDown, GCDescription, GCOptions, GCProgress, GCReason,
33 GetPromiseUserInputEventHandlingState, Handle as RawHandle, HandleObject, HandleString,
34 HandleValue as RawHandleValue, Heap, InitConsumeStreamCallback, JS_AddExtraGCRootsTracer,
35 JS_InitDestroyPrincipalsCallback, JS_InitReadPrincipalsCallback, JS_NewObject,
36 JS_NewStringCopyN, JS_SetGCCallback, JS_SetGCParameter, JS_SetGlobalJitCompilerOption,
37 JS_SetOffthreadIonCompilationEnabled, JS_SetReservedSlot, JS_SetSecurityCallbacks,
38 JSCLASS_RESERVED_SLOTS_MASK, JSCLASS_RESERVED_SLOTS_SHIFT, JSClass, JSClassOps,
39 JSContext as RawJSContext, JSGCParamKey, JSGCStatus, JSJitCompilerOption, JSObject,
40 JSSecurityCallbacks, JSString, JSTracer, JobQueue, MimeType, MutableHandleObject,
41 MutableHandleString, PromiseRejectionHandlingState, PromiseUserInputEventHandlingState,
42 RuntimeCode, SetDOMCallbacks, SetGCSliceCallback, SetJobQueue, SetPreserveWrapperCallbacks,
43 SetProcessBuildIdOp, SetPromiseRejectionTrackerCallback, StreamConsumer as JSStreamConsumer,
44};
45use js::jsval::{JSVal, ObjectValue, UndefinedValue};
46use js::panic::wrap_panic;
47pub(crate) use js::rust::ThreadSafeJSContext;
48use js::rust::wrappers::{GetPromiseIsHandled, JS_GetPromiseResult};
49use js::rust::{
50 Handle, HandleObject as RustHandleObject, HandleValue, IntoHandle, JSEngine, JSEngineHandle,
51 ParentRuntime, Runtime as RustRuntime,
52};
53use malloc_size_of::MallocSizeOfOps;
54use malloc_size_of_derive::MallocSizeOf;
55use profile_traits::mem::{Report, ReportKind};
56use profile_traits::path;
57use profile_traits::time::ProfilerCategory;
58use script_bindings::script_runtime::{mark_runtime_dead, runtime_is_alive};
59use servo_config::{opts, pref};
60use style::thread_state::{self, ThreadState};
61
62use crate::dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
63use crate::dom::bindings::codegen::Bindings::ResponseBinding::Response_Binding::ResponseMethods;
64use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
65use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString;
66use crate::dom::bindings::conversions::{
67 get_dom_class, private_from_object, root_from_handleobject, root_from_object,
68};
69use crate::dom::bindings::error::{Error, throw_dom_exception};
70use crate::dom::bindings::inheritance::Castable;
71use crate::dom::bindings::refcounted::{
72 LiveDOMReferences, Trusted, TrustedPromise, trace_refcounted_objects,
73};
74use crate::dom::bindings::reflector::{DomGlobal, DomObject};
75use crate::dom::bindings::root::trace_roots;
76use crate::dom::bindings::str::DOMString;
77use crate::dom::bindings::utils::DOM_CALLBACKS;
78use crate::dom::bindings::{principals, settings_stack};
79use crate::dom::csp::CspReporting;
80use crate::dom::event::{Event, EventBubbles, EventCancelable};
81use crate::dom::eventtarget::EventTarget;
82use crate::dom::globalscope::GlobalScope;
83use crate::dom::promise::Promise;
84use crate::dom::promiserejectionevent::PromiseRejectionEvent;
85use crate::dom::response::Response;
86use crate::dom::trustedscript::TrustedScript;
87use crate::microtask::{EnqueuedPromiseCallback, Microtask, MicrotaskQueue};
88use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
89use crate::script_module::EnsureModuleHooksInitialized;
90use crate::script_thread::trace_thread;
91use crate::task_source::SendableTaskSource;
92
93static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps {
94 getHostDefinedData: Some(get_host_defined_data),
95 enqueuePromiseJob: Some(enqueue_promise_job),
96 runJobs: Some(run_jobs),
97 empty: Some(empty),
98 pushNewInterruptQueue: Some(push_new_interrupt_queue),
99 popInterruptQueue: Some(pop_interrupt_queue),
100 dropInterruptQueues: Some(drop_interrupt_queues),
101};
102
103static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks {
104 contentSecurityPolicyAllows: Some(content_security_policy_allows),
105 codeForEvalGets: Some(code_for_eval_gets),
106 subsumes: Some(principals::subsumes),
107};
108
109#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq)]
110pub(crate) enum ScriptThreadEventCategory {
111 AttachLayout,
112 ConstellationMsg,
113 DatabaseAccessEvent,
114 DevtoolsMsg,
115 DocumentEvent,
116 FileRead,
117 FontLoading,
118 FormPlannedNavigation,
119 GeolocationEvent,
120 HistoryEvent,
121 ImageCacheMsg,
122 InputEvent,
123 NetworkEvent,
124 PortMessage,
125 Rendering,
126 Resize,
127 ScriptEvent,
128 SetScrollState,
129 SetViewport,
130 StylesheetLoad,
131 TimerEvent,
132 UpdateReplacedElement,
133 WebSocketEvent,
134 WorkerEvent,
135 WorkletEvent,
136 ServiceWorkerEvent,
137 EnterFullscreen,
138 ExitFullscreen,
139 PerformanceTimelineTask,
140 #[cfg(feature = "webgpu")]
141 WebGPUMsg,
142}
143
144impl From<ScriptThreadEventCategory> for ProfilerCategory {
145 fn from(category: ScriptThreadEventCategory) -> Self {
146 match category {
147 ScriptThreadEventCategory::AttachLayout => ProfilerCategory::ScriptAttachLayout,
148 ScriptThreadEventCategory::ConstellationMsg => ProfilerCategory::ScriptConstellationMsg,
149 ScriptThreadEventCategory::DatabaseAccessEvent => {
150 ProfilerCategory::ScriptDatabaseAccessEvent
151 },
152 ScriptThreadEventCategory::DevtoolsMsg => ProfilerCategory::ScriptDevtoolsMsg,
153 ScriptThreadEventCategory::DocumentEvent => ProfilerCategory::ScriptDocumentEvent,
154 ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
155 ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen,
156 ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead,
157 ScriptThreadEventCategory::FontLoading => ProfilerCategory::ScriptFontLoading,
158 ScriptThreadEventCategory::FormPlannedNavigation => {
159 ProfilerCategory::ScriptPlannedNavigation
160 },
161 ScriptThreadEventCategory::GeolocationEvent => ProfilerCategory::ScriptGeolocationEvent,
162 ScriptThreadEventCategory::HistoryEvent => ProfilerCategory::ScriptHistoryEvent,
163 ScriptThreadEventCategory::ImageCacheMsg => ProfilerCategory::ScriptImageCacheMsg,
164 ScriptThreadEventCategory::InputEvent => ProfilerCategory::ScriptInputEvent,
165 ScriptThreadEventCategory::NetworkEvent => ProfilerCategory::ScriptNetworkEvent,
166 ScriptThreadEventCategory::PerformanceTimelineTask => {
167 ProfilerCategory::ScriptPerformanceEvent
168 },
169 ScriptThreadEventCategory::PortMessage => ProfilerCategory::ScriptPortMessage,
170 ScriptThreadEventCategory::Resize => ProfilerCategory::ScriptResize,
171 ScriptThreadEventCategory::Rendering => ProfilerCategory::ScriptRendering,
172 ScriptThreadEventCategory::ScriptEvent => ProfilerCategory::ScriptEvent,
173 ScriptThreadEventCategory::ServiceWorkerEvent => {
174 ProfilerCategory::ScriptServiceWorkerEvent
175 },
176 ScriptThreadEventCategory::SetScrollState => ProfilerCategory::ScriptSetScrollState,
177 ScriptThreadEventCategory::SetViewport => ProfilerCategory::ScriptSetViewport,
178 ScriptThreadEventCategory::StylesheetLoad => ProfilerCategory::ScriptStylesheetLoad,
179 ScriptThreadEventCategory::TimerEvent => ProfilerCategory::ScriptTimerEvent,
180 ScriptThreadEventCategory::UpdateReplacedElement => {
181 ProfilerCategory::ScriptUpdateReplacedElement
182 },
183 ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
184 ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
185 ScriptThreadEventCategory::WorkletEvent => ProfilerCategory::ScriptWorkletEvent,
186 #[cfg(feature = "webgpu")]
187 ScriptThreadEventCategory::WebGPUMsg => ProfilerCategory::ScriptWebGPUMsg,
188 }
189 }
190}
191
192impl From<ScriptThreadEventCategory> for ScriptHangAnnotation {
193 fn from(category: ScriptThreadEventCategory) -> Self {
194 match category {
195 ScriptThreadEventCategory::AttachLayout => ScriptHangAnnotation::AttachLayout,
196 ScriptThreadEventCategory::ConstellationMsg => ScriptHangAnnotation::ConstellationMsg,
197 ScriptThreadEventCategory::DatabaseAccessEvent => {
198 ScriptHangAnnotation::DatabaseAccessEvent
199 },
200 ScriptThreadEventCategory::DevtoolsMsg => ScriptHangAnnotation::DevtoolsMsg,
201 ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent,
202 ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent,
203 ScriptThreadEventCategory::FileRead => ScriptHangAnnotation::FileRead,
204 ScriptThreadEventCategory::FontLoading => ScriptHangAnnotation::FontLoading,
205 ScriptThreadEventCategory::FormPlannedNavigation => {
206 ScriptHangAnnotation::FormPlannedNavigation
207 },
208 ScriptThreadEventCategory::GeolocationEvent => ScriptHangAnnotation::GeolocationEvent,
209 ScriptThreadEventCategory::HistoryEvent => ScriptHangAnnotation::HistoryEvent,
210 ScriptThreadEventCategory::ImageCacheMsg => ScriptHangAnnotation::ImageCacheMsg,
211 ScriptThreadEventCategory::NetworkEvent => ScriptHangAnnotation::NetworkEvent,
212 ScriptThreadEventCategory::Rendering => ScriptHangAnnotation::Rendering,
213 ScriptThreadEventCategory::Resize => ScriptHangAnnotation::Resize,
214 ScriptThreadEventCategory::ScriptEvent => ScriptHangAnnotation::ScriptEvent,
215 ScriptThreadEventCategory::SetScrollState => ScriptHangAnnotation::SetScrollState,
216 ScriptThreadEventCategory::SetViewport => ScriptHangAnnotation::SetViewport,
217 ScriptThreadEventCategory::StylesheetLoad => ScriptHangAnnotation::StylesheetLoad,
218 ScriptThreadEventCategory::TimerEvent => ScriptHangAnnotation::TimerEvent,
219 ScriptThreadEventCategory::UpdateReplacedElement => {
220 ScriptHangAnnotation::UpdateReplacedElement
221 },
222 ScriptThreadEventCategory::WebSocketEvent => ScriptHangAnnotation::WebSocketEvent,
223 ScriptThreadEventCategory::WorkerEvent => ScriptHangAnnotation::WorkerEvent,
224 ScriptThreadEventCategory::WorkletEvent => ScriptHangAnnotation::WorkletEvent,
225 ScriptThreadEventCategory::ServiceWorkerEvent => {
226 ScriptHangAnnotation::ServiceWorkerEvent
227 },
228 ScriptThreadEventCategory::EnterFullscreen => ScriptHangAnnotation::EnterFullscreen,
229 ScriptThreadEventCategory::ExitFullscreen => ScriptHangAnnotation::ExitFullscreen,
230 ScriptThreadEventCategory::PerformanceTimelineTask => {
231 ScriptHangAnnotation::PerformanceTimelineTask
232 },
233 ScriptThreadEventCategory::PortMessage => ScriptHangAnnotation::PortMessage,
234 #[cfg(feature = "webgpu")]
235 ScriptThreadEventCategory::WebGPUMsg => ScriptHangAnnotation::WebGPUMsg,
236 }
237 }
238}
239
240static HOST_DEFINED_DATA: JSClassOps = JSClassOps {
241 addProperty: None,
242 delProperty: None,
243 enumerate: None,
244 newEnumerate: None,
245 resolve: None,
246 mayResolve: None,
247 finalize: None,
248 call: None,
249 construct: None,
250 trace: None,
251};
252
253static HOST_DEFINED_DATA_CLASS: JSClass = JSClass {
254 name: c"HostDefinedData".as_ptr(),
255 flags: (HOST_DEFINED_DATA_SLOTS & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT,
256 cOps: &HOST_DEFINED_DATA,
257 spec: ptr::null(),
258 ext: ptr::null(),
259 oOps: ptr::null(),
260};
261
262const INCUMBENT_SETTING_SLOT: u32 = 0;
263const HOST_DEFINED_DATA_SLOTS: u32 = 1;
264
265#[allow(unsafe_code)]
267unsafe extern "C" fn get_host_defined_data(
268 _: *const c_void,
269 cx: *mut RawJSContext,
270 data: MutableHandleObject,
271) -> bool {
272 wrap_panic(&mut || {
273 let Some(incumbent_global) = GlobalScope::incumbent() else {
274 data.set(ptr::null_mut());
275 return;
276 };
277
278 let _realm = enter_realm(&*incumbent_global);
279
280 rooted!(in(cx) let result = JS_NewObject(cx, &HOST_DEFINED_DATA_CLASS));
281 assert!(!result.is_null());
282
283 JS_SetReservedSlot(
284 *result,
285 INCUMBENT_SETTING_SLOT,
286 &ObjectValue(*incumbent_global.reflector().get_jsobject()),
287 );
288
289 data.set(result.get());
290 });
291 true
292}
293
294#[allow(unsafe_code)]
295unsafe extern "C" fn run_jobs(microtask_queue: *const c_void, cx: *mut RawJSContext) {
296 let cx = JSContext::from_ptr(cx);
297 wrap_panic(&mut || {
298 let microtask_queue = &*(microtask_queue as *const MicrotaskQueue);
299 microtask_queue.checkpoint(cx, |_| None, vec![], CanGc::note());
302 });
303}
304
305#[allow(unsafe_code)]
306unsafe extern "C" fn empty(extra: *const c_void) -> bool {
307 let mut result = false;
308 wrap_panic(&mut || {
309 let microtask_queue = &*(extra as *const MicrotaskQueue);
310 result = microtask_queue.empty()
311 });
312 result
313}
314
315#[allow(unsafe_code)]
316unsafe extern "C" fn push_new_interrupt_queue(interrupt_queues: *mut c_void) -> *const c_void {
317 let mut result = std::ptr::null();
318 wrap_panic(&mut || {
319 let mut interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec<Rc<MicrotaskQueue>>);
320 let new_queue = Rc::new(MicrotaskQueue::default());
321 result = Rc::as_ptr(&new_queue) as *const c_void;
322 interrupt_queues.push(new_queue.clone());
323 std::mem::forget(interrupt_queues);
324 });
325 result
326}
327
328#[allow(unsafe_code)]
329unsafe extern "C" fn pop_interrupt_queue(interrupt_queues: *mut c_void) -> *const c_void {
330 let mut result = std::ptr::null();
331 wrap_panic(&mut || {
332 let mut interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec<Rc<MicrotaskQueue>>);
333 let popped_queue: Rc<MicrotaskQueue> =
334 interrupt_queues.pop().expect("Guaranteed by SpiderMonkey?");
335 result = Rc::as_ptr(&popped_queue) as *const c_void;
337 std::mem::forget(interrupt_queues);
338 });
339 result
340}
341
342#[allow(unsafe_code)]
343unsafe extern "C" fn drop_interrupt_queues(interrupt_queues: *mut c_void) {
344 wrap_panic(&mut || {
345 let interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec<Rc<MicrotaskQueue>>);
346 drop(interrupt_queues);
347 });
348}
349
350#[allow(unsafe_code)]
354unsafe extern "C" fn enqueue_promise_job(
355 extra: *const c_void,
356 cx: *mut RawJSContext,
357 promise: HandleObject,
358 job: HandleObject,
359 _allocation_site: HandleObject,
360 host_defined_data: HandleObject,
361) -> bool {
362 let cx = JSContext::from_ptr(cx);
363 let mut result = false;
364 wrap_panic(&mut || {
365 let microtask_queue = &*(extra as *const MicrotaskQueue);
366 let global = if !host_defined_data.is_null() {
367 let mut incumbent_global = UndefinedValue();
368 JS_GetReservedSlot(
369 host_defined_data.get(),
370 INCUMBENT_SETTING_SLOT,
371 &mut incumbent_global,
372 );
373 GlobalScope::from_object(incumbent_global.to_object())
374 } else {
375 let realm = AlreadyInRealm::assert_for_cx(cx);
376 GlobalScope::from_context(*cx, InRealm::already(&realm))
377 };
378 let pipeline = global.pipeline_id();
379 let interaction = if promise.get().is_null() {
380 PromiseUserInputEventHandlingState::DontCare
381 } else {
382 GetPromiseUserInputEventHandlingState(promise)
383 };
384 let is_user_interacting =
385 interaction == PromiseUserInputEventHandlingState::HadUserInteractionAtCreation;
386 microtask_queue.enqueue(
387 Microtask::Promise(EnqueuedPromiseCallback {
388 callback: PromiseJobCallback::new(cx, job.get()),
389 pipeline,
390 is_user_interacting,
391 }),
392 cx,
393 );
394 result = true
395 });
396 result
397}
398
399#[allow(unsafe_code)]
400#[cfg_attr(crown, allow(crown::unrooted_must_root))]
401unsafe extern "C" fn promise_rejection_tracker(
403 cx: *mut RawJSContext,
404 _muted_errors: bool,
405 promise: HandleObject,
406 state: PromiseRejectionHandlingState,
407 _data: *mut c_void,
408) {
409 let cx = JSContext::from_ptr(cx);
413 let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
414 let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
415
416 wrap_panic(&mut || {
417 match state {
418 PromiseRejectionHandlingState::Unhandled => {
420 global.add_uncaught_rejection(promise);
421 },
422 PromiseRejectionHandlingState::Handled => {
424 if global
426 .get_uncaught_rejections()
427 .borrow()
428 .contains(&Heap::boxed(promise.get()))
429 {
430 global.remove_uncaught_rejection(promise);
431 return;
432 }
433
434 if !global
436 .get_consumed_rejections()
437 .borrow()
438 .contains(&Heap::boxed(promise.get()))
439 {
440 return;
441 }
442
443 global.remove_consumed_rejection(promise);
445
446 let target = Trusted::new(global.upcast::<EventTarget>());
447 let promise = Promise::new_with_js_promise(Handle::from_raw(promise), cx);
448 let trusted_promise = TrustedPromise::new(promise.clone());
449
450 global.task_manager().dom_manipulation_task_source().queue(
452 task!(rejection_handled_event: move || {
453 let target = target.root();
454 let cx = GlobalScope::get_cx();
455 let root_promise = trusted_promise.root();
456
457 rooted!(in(*cx) let mut reason = UndefinedValue());
458 JS_GetPromiseResult(root_promise.reflector().get_jsobject(), reason.handle_mut());
459
460 let event = PromiseRejectionEvent::new(
461 &target.global(),
462 atom!("rejectionhandled"),
463 EventBubbles::DoesNotBubble,
464 EventCancelable::Cancelable,
465 root_promise,
466 reason.handle(),
467 CanGc::note()
468 );
469
470 event.upcast::<Event>().fire(&target, CanGc::note());
471 })
472 );
473 },
474 };
475 })
476}
477
478#[allow(unsafe_code)]
479fn safely_convert_null_to_string(cx: JSContext, str_: HandleString) -> DOMString {
480 DOMString::from(match std::ptr::NonNull::new(*str_) {
481 None => "".to_owned(),
482 Some(str_) => unsafe { jsstr_to_string(*cx, str_) },
483 })
484}
485
486#[allow(unsafe_code)]
487unsafe extern "C" fn code_for_eval_gets(
488 cx: *mut RawJSContext,
489 code: HandleObject,
490 code_for_eval: MutableHandleString,
491) -> bool {
492 let cx = JSContext::from_ptr(cx);
493 if let Ok(trusted_script) = root_from_object::<TrustedScript>(code.get(), *cx) {
494 let script_string = trusted_script.data();
495 let new_string = JS_NewStringCopyN(
496 *cx,
497 script_string.str().as_ptr() as *const libc::c_char,
498 script_string.len(),
499 );
500 code_for_eval.set(new_string);
501 }
502 true
503}
504
505#[allow(unsafe_code)]
506unsafe extern "C" fn content_security_policy_allows(
507 cx: *mut RawJSContext,
508 runtime_code: RuntimeCode,
509 code_string: HandleString,
510 compilation_type: CompilationType,
511 parameter_strings: RawHandle<StackGCVector<*mut JSString>>,
512 body_string: HandleString,
513 parameter_args: RawHandle<StackGCVector<JSVal>>,
514 body_arg: RawHandleValue,
515 can_compile_strings: *mut bool,
516) -> bool {
517 let mut allowed = false;
518 let cx = JSContext::from_ptr(cx);
519 wrap_panic(&mut || {
520 let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
522 let global = &GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
523 let csp_list = global.get_csp_list();
524
525 allowed = csp_list.is_none() ||
527 match runtime_code {
528 RuntimeCode::JS => {
529 let parameter_strings = Handle::from_raw(parameter_strings);
530 let parameter_strings_length = parameter_strings.len();
531 let mut parameter_strings_vec =
532 Vec::with_capacity(parameter_strings_length as usize);
533
534 for i in 0..parameter_strings_length {
535 let Some(str_) = parameter_strings.at(i) else {
536 unreachable!();
537 };
538 parameter_strings_vec.push(safely_convert_null_to_string(cx, str_.into()));
539 }
540
541 let parameter_args = Handle::from_raw(parameter_args);
542 let parameter_args_length = parameter_args.len();
543 let mut parameter_args_vec = Vec::with_capacity(parameter_args_length as usize);
544
545 for i in 0..parameter_args_length {
546 let Some(arg) = parameter_args.at(i) else {
547 unreachable!();
548 };
549 let value = arg.into_handle().get();
550 if value.is_object() {
551 if let Ok(trusted_script) =
552 root_from_object::<TrustedScript>(value.to_object(), *cx)
553 {
554 parameter_args_vec
555 .push(TrustedScriptOrString::TrustedScript(trusted_script));
556 } else {
557 parameter_args_vec
561 .push(TrustedScriptOrString::String(DOMString::new()));
562 }
563 } else if value.is_string() {
564 parameter_args_vec
566 .push(TrustedScriptOrString::String(DOMString::new()));
567 } else {
568 unreachable!();
569 }
570 }
571
572 TrustedScript::can_compile_string_with_trusted_type(
573 cx,
574 global,
575 safely_convert_null_to_string(cx, code_string),
576 compilation_type,
577 parameter_strings_vec,
578 safely_convert_null_to_string(cx, body_string),
579 parameter_args_vec,
580 HandleValue::from_raw(body_arg),
581 CanGc::note(),
582 )
583 },
584 RuntimeCode::WASM => global.get_csp_list().is_wasm_evaluation_allowed(global),
585 };
586 });
587 *can_compile_strings = allowed;
588 true
589}
590
591#[allow(unsafe_code)]
592#[cfg_attr(crown, allow(crown::unrooted_must_root))]
593pub(crate) fn notify_about_rejected_promises(global: &GlobalScope) {
595 let cx = GlobalScope::get_cx();
596 unsafe {
597 if !global.get_uncaught_rejections().borrow().is_empty() {
599 let uncaught_rejections: Vec<TrustedPromise> = global
601 .get_uncaught_rejections()
602 .borrow()
603 .iter()
604 .map(|promise| {
605 let promise =
606 Promise::new_with_js_promise(Handle::from_raw(promise.handle()), cx);
607
608 TrustedPromise::new(promise)
609 })
610 .collect();
611
612 global.get_uncaught_rejections().borrow_mut().clear();
614
615 let target = Trusted::new(global.upcast::<EventTarget>());
616
617 global.task_manager().dom_manipulation_task_source().queue(
619 task!(unhandled_rejection_event: move || {
620 let target = target.root();
621 let cx = GlobalScope::get_cx();
622
623 for promise in uncaught_rejections {
624 let promise = promise.root();
625
626 let promise_is_handled = GetPromiseIsHandled(promise.reflector().get_jsobject());
628 if promise_is_handled {
629 continue;
630 }
631
632 rooted!(in(*cx) let mut reason = UndefinedValue());
634 JS_GetPromiseResult(promise.reflector().get_jsobject(), reason.handle_mut());
635
636 let event = PromiseRejectionEvent::new(
637 &target.global(),
638 atom!("unhandledrejection"),
639 EventBubbles::DoesNotBubble,
640 EventCancelable::Cancelable,
641 promise.clone(),
642 reason.handle(),
643 CanGc::note()
644 );
645
646 let not_canceled = event.upcast::<Event>().fire(&target, CanGc::note());
647
648 if not_canceled {
651 }
653
654 if !promise_is_handled {
656 target.global().add_consumed_rejection(promise.reflector().get_jsobject().into_handle());
657 }
658 }
659 })
660 );
661 }
662 }
663}
664
665#[derive(JSTraceable, MallocSizeOf)]
666pub(crate) struct Runtime {
667 #[ignore_malloc_size_of = "Type from mozjs"]
668 rt: RustRuntime,
669 #[conditional_malloc_size_of]
671 pub(crate) microtask_queue: Rc<MicrotaskQueue>,
672 #[ignore_malloc_size_of = "Type from mozjs"]
673 job_queue: *mut JobQueue,
674 networking_task_src: Option<Box<SendableTaskSource>>,
675}
676
677impl Runtime {
678 #[allow(unsafe_code)]
688 pub(crate) fn new(networking_task_source: Option<SendableTaskSource>) -> Runtime {
689 unsafe { Self::new_with_parent(None, networking_task_source) }
690 }
691
692 #[allow(unsafe_code)]
705 pub(crate) unsafe fn new_with_parent(
706 parent: Option<ParentRuntime>,
707 networking_task_source: Option<SendableTaskSource>,
708 ) -> Runtime {
709 let (cx, runtime) = if let Some(parent) = parent {
710 let runtime = RustRuntime::create_with_parent(parent);
711 let cx = runtime.cx();
712 (cx, runtime)
713 } else {
714 let runtime = RustRuntime::new(JS_ENGINE.lock().unwrap().as_ref().unwrap().clone());
715 (runtime.cx(), runtime)
716 };
717
718 JS_AddExtraGCRootsTracer(cx, Some(trace_rust_roots), ptr::null_mut());
719
720 JS_SetSecurityCallbacks(cx, &SECURITY_CALLBACKS);
721
722 JS_InitDestroyPrincipalsCallback(cx, Some(principals::destroy_servo_jsprincipal));
723 JS_InitReadPrincipalsCallback(cx, Some(principals::read_jsprincipal));
724
725 if cfg!(debug_assertions) {
727 JS_SetGCCallback(cx, Some(debug_gc_callback), ptr::null_mut());
728 }
729
730 if opts::get().debug.gc_profile {
731 SetGCSliceCallback(cx, Some(gc_slice_callback));
732 }
733
734 unsafe extern "C" fn empty_wrapper_callback(_: *mut RawJSContext, _: HandleObject) -> bool {
735 true
736 }
737 unsafe extern "C" fn empty_has_released_callback(_: HandleObject) -> bool {
738 false
740 }
741 SetDOMCallbacks(cx, &DOM_CALLBACKS);
742 SetPreserveWrapperCallbacks(
743 cx,
744 Some(empty_wrapper_callback),
745 Some(empty_has_released_callback),
746 );
747 JS_SetGCParameter(cx, JSGCParamKey::JSGC_INCREMENTAL_GC_ENABLED, 0);
749
750 unsafe extern "C" fn dispatch_to_event_loop(
751 closure: *mut c_void,
752 dispatchable: *mut DispatchablePointer,
753 ) -> bool {
754 let networking_task_src: &SendableTaskSource = &*(closure as *mut SendableTaskSource);
755 let runnable = Runnable(dispatchable);
756 let task = task!(dispatch_to_event_loop_message: move || {
757 if let Some(cx) = RustRuntime::get() {
758 runnable.run(cx.as_ptr(), Dispatchable_MaybeShuttingDown::NotShuttingDown);
759 }
760 });
761
762 networking_task_src.queue_unconditionally(task);
763 true
764 }
765
766 let mut networking_task_src_ptr = std::ptr::null_mut();
767 if let Some(source) = networking_task_source {
768 networking_task_src_ptr = Box::into_raw(Box::new(source));
769 SetUpEventLoopDispatch(
770 cx,
771 Some(dispatch_to_event_loop),
772 networking_task_src_ptr as *mut c_void,
773 );
774 }
775
776 InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error));
777
778 let microtask_queue = Rc::new(MicrotaskQueue::default());
779
780 let interrupt_queues: Box<Vec<Rc<MicrotaskQueue>>> = Box::default();
784
785 let job_queue = CreateJobQueue(
786 &JOB_QUEUE_TRAPS,
787 &*microtask_queue as *const _ as *const c_void,
788 Box::into_raw(interrupt_queues) as *mut c_void,
789 );
790 SetJobQueue(cx, job_queue);
791 SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut());
792
793 EnsureModuleHooksInitialized(runtime.rt());
794
795 set_gc_zeal_options(cx);
796
797 let cx_opts = &mut *ContextOptionsRef(cx);
799 JS_SetGlobalJitCompilerOption(
800 cx,
801 JSJitCompilerOption::JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE,
802 pref!(js_baseline_interpreter_enabled) as u32,
803 );
804 JS_SetGlobalJitCompilerOption(
805 cx,
806 JSJitCompilerOption::JSJITCOMPILER_BASELINE_ENABLE,
807 pref!(js_baseline_jit_enabled) as u32,
808 );
809 JS_SetGlobalJitCompilerOption(
810 cx,
811 JSJitCompilerOption::JSJITCOMPILER_ION_ENABLE,
812 pref!(js_ion_enabled) as u32,
813 );
814 cx_opts.compileOptions_.asmJSOption_ = if pref!(js_asmjs_enabled) {
815 AsmJSOption::Enabled
816 } else {
817 AsmJSOption::DisabledByAsmJSPref
818 };
819 let wasm_enabled = pref!(js_wasm_enabled);
820 cx_opts.set_wasm_(wasm_enabled);
821 if wasm_enabled {
822 SetProcessBuildIdOp(Some(servo_build_id));
826 }
827 cx_opts.set_wasmBaseline_(pref!(js_wasm_baseline_enabled));
828 cx_opts.set_wasmIon_(pref!(js_wasm_ion_enabled));
829 JS_SetGlobalJitCompilerOption(
831 cx,
832 JSJitCompilerOption::JSJITCOMPILER_NATIVE_REGEXP_ENABLE,
833 pref!(js_native_regex_enabled) as u32,
834 );
835 JS_SetOffthreadIonCompilationEnabled(cx, pref!(js_offthread_compilation_enabled));
836 JS_SetGlobalJitCompilerOption(
837 cx,
838 JSJitCompilerOption::JSJITCOMPILER_BASELINE_WARMUP_TRIGGER,
839 if pref!(js_baseline_jit_unsafe_eager_compilation_enabled) {
840 0
841 } else {
842 u32::MAX
843 },
844 );
845 JS_SetGlobalJitCompilerOption(
846 cx,
847 JSJitCompilerOption::JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER,
848 if pref!(js_ion_unsafe_eager_compilation_enabled) {
849 0
850 } else {
851 u32::MAX
852 },
853 );
854 JS_SetGCParameter(
860 cx,
861 JSGCParamKey::JSGC_MAX_BYTES,
862 in_range(pref!(js_mem_max), 1, 0x100)
863 .map(|val| (val * 1024 * 1024) as u32)
864 .unwrap_or(u32::MAX),
865 );
866 JS_SetGCParameter(
868 cx,
869 JSGCParamKey::JSGC_INCREMENTAL_GC_ENABLED,
870 pref!(js_mem_gc_incremental_enabled) as u32,
871 );
872 JS_SetGCParameter(
873 cx,
874 JSGCParamKey::JSGC_PER_ZONE_GC_ENABLED,
875 pref!(js_mem_gc_per_zone_enabled) as u32,
876 );
877 if let Some(val) = in_range(pref!(js_mem_gc_incremental_slice_ms), 0, 100_000) {
878 JS_SetGCParameter(cx, JSGCParamKey::JSGC_SLICE_TIME_BUDGET_MS, val as u32);
879 }
880 JS_SetGCParameter(
881 cx,
882 JSGCParamKey::JSGC_COMPACTING_ENABLED,
883 pref!(js_mem_gc_compacting_enabled) as u32,
884 );
885
886 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_time_limit_ms), 0, 10_000) {
887 JS_SetGCParameter(cx, JSGCParamKey::JSGC_HIGH_FREQUENCY_TIME_LIMIT, val as u32);
888 }
889 if let Some(val) = in_range(pref!(js_mem_gc_low_frequency_heap_growth), 0, 10_000) {
890 JS_SetGCParameter(cx, JSGCParamKey::JSGC_LOW_FREQUENCY_HEAP_GROWTH, val as u32);
891 }
892 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_heap_growth_min), 0, 10_000) {
893 JS_SetGCParameter(
894 cx,
895 JSGCParamKey::JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH,
896 val as u32,
897 );
898 }
899 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_heap_growth_max), 0, 10_000) {
900 JS_SetGCParameter(
901 cx,
902 JSGCParamKey::JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH,
903 val as u32,
904 );
905 }
906 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_low_limit_mb), 0, 10_000) {
907 JS_SetGCParameter(cx, JSGCParamKey::JSGC_SMALL_HEAP_SIZE_MAX, val as u32);
908 }
909 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_high_limit_mb), 0, 10_000) {
910 JS_SetGCParameter(cx, JSGCParamKey::JSGC_LARGE_HEAP_SIZE_MIN, val as u32);
911 }
912 if let Some(val) = in_range(pref!(js_mem_gc_empty_chunk_count_min), 0, 10_000) {
923 JS_SetGCParameter(cx, JSGCParamKey::JSGC_MIN_EMPTY_CHUNK_COUNT, val as u32);
924 }
925
926 Runtime {
927 rt: runtime,
928 microtask_queue,
929 job_queue,
930 networking_task_src: (!networking_task_src_ptr.is_null())
931 .then(|| Box::from_raw(networking_task_src_ptr)),
932 }
933 }
934
935 pub(crate) fn thread_safe_js_context(&self) -> ThreadSafeJSContext {
936 self.rt.thread_safe_js_context()
937 }
938}
939
940impl Drop for Runtime {
941 #[allow(unsafe_code)]
942 fn drop(&mut self) {
943 self.microtask_queue.clear();
945
946 unsafe {
948 DeleteJobQueue(self.job_queue);
949 }
950 LiveDOMReferences::destruct();
951 mark_runtime_dead();
952 }
953}
954
955impl Deref for Runtime {
956 type Target = RustRuntime;
957 fn deref(&self) -> &RustRuntime {
958 &self.rt
959 }
960}
961
962pub struct JSEngineSetup(JSEngine);
963
964impl Default for JSEngineSetup {
965 fn default() -> Self {
966 let engine = JSEngine::init().unwrap();
967 *JS_ENGINE.lock().unwrap() = Some(engine.handle());
968 Self(engine)
969 }
970}
971
972impl Drop for JSEngineSetup {
973 fn drop(&mut self) {
974 *JS_ENGINE.lock().unwrap() = None;
975
976 while !self.0.can_shutdown() {
977 thread::sleep(Duration::from_millis(50));
978 }
979 }
980}
981
982static JS_ENGINE: Mutex<Option<JSEngineHandle>> = Mutex::new(None);
983
984fn in_range<T: PartialOrd + Copy>(val: T, min: T, max: T) -> Option<T> {
985 if val < min || val >= max {
986 None
987 } else {
988 Some(val)
989 }
990}
991
992thread_local!(static MALLOC_SIZE_OF_OPS: Cell<*mut MallocSizeOfOps> = const { Cell::new(ptr::null_mut()) });
993
994#[allow(unsafe_code)]
995unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
996 match get_dom_class(obj) {
997 Ok(v) => {
998 let dom_object = private_from_object(obj) as *const c_void;
999
1000 if dom_object.is_null() {
1001 return 0;
1002 }
1003 let ops = MALLOC_SIZE_OF_OPS.get();
1004 (v.malloc_size_of)(&mut *ops, dom_object)
1005 },
1006 Err(_e) => 0,
1007 }
1008}
1009
1010thread_local!(static GC_CYCLE_START: Cell<Option<Instant>> = const { Cell::new(None) });
1011thread_local!(static GC_SLICE_START: Cell<Option<Instant>> = const { Cell::new(None) });
1012
1013#[allow(unsafe_code)]
1014unsafe extern "C" fn gc_slice_callback(
1015 _cx: *mut RawJSContext,
1016 progress: GCProgress,
1017 desc: *const GCDescription,
1018) {
1019 match progress {
1020 GCProgress::GC_CYCLE_BEGIN => GC_CYCLE_START.with(|start| {
1021 start.set(Some(Instant::now()));
1022 println!("GC cycle began");
1023 }),
1024 GCProgress::GC_SLICE_BEGIN => GC_SLICE_START.with(|start| {
1025 start.set(Some(Instant::now()));
1026 println!("GC slice began");
1027 }),
1028 GCProgress::GC_SLICE_END => GC_SLICE_START.with(|start| {
1029 let duration = start.get().unwrap().elapsed();
1030 start.set(None);
1031 println!("GC slice ended: duration={:?}", duration);
1032 }),
1033 GCProgress::GC_CYCLE_END => GC_CYCLE_START.with(|start| {
1034 let duration = start.get().unwrap().elapsed();
1035 start.set(None);
1036 println!("GC cycle ended: duration={:?}", duration);
1037 }),
1038 };
1039 if !desc.is_null() {
1040 let desc: &GCDescription = &*desc;
1041 let options = match desc.options_ {
1042 GCOptions::Normal => "Normal",
1043 GCOptions::Shrink => "Shrink",
1044 GCOptions::Shutdown => "Shutdown",
1045 };
1046 println!(" isZone={}, options={}", desc.isZone_, options);
1047 }
1048 let _ = stdout().flush();
1049}
1050
1051#[allow(unsafe_code)]
1052unsafe extern "C" fn debug_gc_callback(
1053 _cx: *mut RawJSContext,
1054 status: JSGCStatus,
1055 _reason: GCReason,
1056 _data: *mut os::raw::c_void,
1057) {
1058 match status {
1059 JSGCStatus::JSGC_BEGIN => thread_state::enter(ThreadState::IN_GC),
1060 JSGCStatus::JSGC_END => thread_state::exit(ThreadState::IN_GC),
1061 }
1062}
1063
1064#[allow(unsafe_code)]
1065unsafe extern "C" fn trace_rust_roots(tr: *mut JSTracer, _data: *mut os::raw::c_void) {
1066 if !runtime_is_alive() {
1067 return;
1068 }
1069 trace!("starting custom root handler");
1070 trace_thread(tr);
1071 trace_roots(tr);
1072 trace_refcounted_objects(tr);
1073 settings_stack::trace(tr);
1074 trace!("done custom root handler");
1075}
1076
1077#[allow(unsafe_code)]
1078unsafe extern "C" fn servo_build_id(build_id: *mut BuildIdCharVector) -> bool {
1079 let servo_id = b"Servo\0";
1080 SetBuildId(build_id, servo_id[0] as *const c_char, servo_id.len())
1081}
1082
1083#[allow(unsafe_code)]
1084#[cfg(feature = "debugmozjs")]
1085unsafe fn set_gc_zeal_options(cx: *mut RawJSContext) {
1086 use js::jsapi::SetGCZeal;
1087
1088 let level = match pref!(js_mem_gc_zeal_level) {
1089 level @ 0..=14 => level as u8,
1090 _ => return,
1091 };
1092 let frequency = match pref!(js_mem_gc_zeal_frequency) {
1093 frequency if frequency >= 0 => frequency as u32,
1094 _ => 5000,
1096 };
1097 SetGCZeal(cx, level, frequency);
1098}
1099
1100#[allow(unsafe_code)]
1101#[cfg(not(feature = "debugmozjs"))]
1102unsafe fn set_gc_zeal_options(_: *mut RawJSContext) {}
1103
1104pub(crate) use script_bindings::script_runtime::JSContext;
1105
1106pub(crate) trait JSContextHelper {
1109 fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report>;
1110}
1111
1112impl JSContextHelper for JSContext {
1113 #[allow(unsafe_code)]
1114 fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report> {
1115 MALLOC_SIZE_OF_OPS.with(|ops_tls| ops_tls.set(ops));
1116 let stats = unsafe {
1117 let mut stats = ::std::mem::zeroed();
1118 if !CollectServoSizes(**self, &mut stats, Some(get_size)) {
1119 return vec![];
1120 }
1121 stats
1122 };
1123 MALLOC_SIZE_OF_OPS.with(|ops| ops.set(ptr::null_mut()));
1124
1125 let mut reports = vec![];
1126 let mut report = |mut path_suffix, kind, size| {
1127 let mut path = path![path_seg, "js"];
1128 path.append(&mut path_suffix);
1129 reports.push(Report { path, kind, size })
1130 };
1131
1132 report(
1136 path!["gc-heap", "used"],
1137 ReportKind::ExplicitNonHeapSize,
1138 stats.gcHeapUsed,
1139 );
1140
1141 report(
1142 path!["gc-heap", "unused"],
1143 ReportKind::ExplicitNonHeapSize,
1144 stats.gcHeapUnused,
1145 );
1146
1147 report(
1148 path!["gc-heap", "admin"],
1149 ReportKind::ExplicitNonHeapSize,
1150 stats.gcHeapAdmin,
1151 );
1152
1153 report(
1154 path!["gc-heap", "decommitted"],
1155 ReportKind::ExplicitNonHeapSize,
1156 stats.gcHeapDecommitted,
1157 );
1158
1159 report(
1161 path!["malloc-heap"],
1162 ReportKind::ExplicitSystemHeapSize,
1163 stats.mallocHeap,
1164 );
1165
1166 report(
1167 path!["non-heap"],
1168 ReportKind::ExplicitNonHeapSize,
1169 stats.nonHeap,
1170 );
1171 reports
1172 }
1173}
1174
1175pub(crate) struct StreamConsumer(*mut JSStreamConsumer);
1176
1177#[allow(unsafe_code)]
1178impl StreamConsumer {
1179 pub(crate) fn consume_chunk(&self, stream: &[u8]) -> bool {
1180 unsafe {
1181 let stream_ptr = stream.as_ptr();
1182 StreamConsumerConsumeChunk(self.0, stream_ptr, stream.len())
1183 }
1184 }
1185
1186 pub(crate) fn stream_end(&self) {
1187 unsafe {
1188 StreamConsumerStreamEnd(self.0);
1189 }
1190 }
1191
1192 pub(crate) fn stream_error(&self, error_code: usize) {
1193 unsafe {
1194 StreamConsumerStreamError(self.0, error_code);
1195 }
1196 }
1197
1198 pub(crate) fn note_response_urls(
1199 &self,
1200 maybe_url: Option<String>,
1201 maybe_source_map_url: Option<String>,
1202 ) {
1203 unsafe {
1204 let maybe_url = maybe_url.map(|url| CString::new(url).unwrap());
1205 let maybe_source_map_url = maybe_source_map_url.map(|url| CString::new(url).unwrap());
1206
1207 let maybe_url_param = match maybe_url.as_ref() {
1208 Some(url) => url.as_ptr(),
1209 None => ptr::null(),
1210 };
1211 let maybe_source_map_url_param = match maybe_source_map_url.as_ref() {
1212 Some(url) => url.as_ptr(),
1213 None => ptr::null(),
1214 };
1215
1216 StreamConsumerNoteResponseURLs(self.0, maybe_url_param, maybe_source_map_url_param);
1217 }
1218 }
1219}
1220
1221#[allow(unsafe_code)]
1224unsafe extern "C" fn consume_stream(
1225 _cx: *mut RawJSContext,
1226 obj: HandleObject,
1227 _mime_type: MimeType,
1228 _consumer: *mut JSStreamConsumer,
1229) -> bool {
1230 let cx = JSContext::from_ptr(_cx);
1231 let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
1232 let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
1233
1234 if let Ok(unwrapped_source) =
1236 root_from_handleobject::<Response>(RustHandleObject::from_raw(obj), *cx)
1237 {
1238 let mimetype = unwrapped_source.Headers(CanGc::note()).extract_mime_type();
1240
1241 if !&mimetype[..].eq_ignore_ascii_case(b"application/wasm") {
1243 throw_dom_exception(
1244 cx,
1245 &global,
1246 Error::Type("Response has unsupported MIME type".to_string()),
1247 CanGc::note(),
1248 );
1249 return false;
1250 }
1251
1252 match unwrapped_source.Type() {
1254 DOMResponseType::Basic | DOMResponseType::Cors | DOMResponseType::Default => {},
1255 _ => {
1256 throw_dom_exception(
1257 cx,
1258 &global,
1259 Error::Type("Response.type must be 'basic', 'cors' or 'default'".to_string()),
1260 CanGc::note(),
1261 );
1262 return false;
1263 },
1264 }
1265
1266 if !unwrapped_source.Ok() {
1268 throw_dom_exception(
1269 cx,
1270 &global,
1271 Error::Type("Response does not have ok status".to_string()),
1272 CanGc::note(),
1273 );
1274 return false;
1275 }
1276
1277 if unwrapped_source.is_locked() {
1279 throw_dom_exception(
1280 cx,
1281 &global,
1282 Error::Type("There was an error consuming the Response".to_string()),
1283 CanGc::note(),
1284 );
1285 return false;
1286 }
1287
1288 if unwrapped_source.is_disturbed() {
1290 throw_dom_exception(
1291 cx,
1292 &global,
1293 Error::Type("Response already consumed".to_string()),
1294 CanGc::note(),
1295 );
1296 return false;
1297 }
1298 unwrapped_source.set_stream_consumer(Some(StreamConsumer(_consumer)));
1299 } else {
1300 throw_dom_exception(
1302 cx,
1303 &global,
1304 Error::Type("expected Response or Promise resolving to Response".to_string()),
1305 CanGc::note(),
1306 );
1307 return false;
1308 }
1309 true
1310}
1311
1312#[allow(unsafe_code)]
1313unsafe extern "C" fn report_stream_error(_cx: *mut RawJSContext, error_code: usize) {
1314 error!(
1315 "Error initializing StreamConsumer: {:?}",
1316 RUST_js_GetErrorMessage(ptr::null_mut(), error_code as u32)
1317 );
1318}
1319
1320pub(crate) struct Runnable(*mut DispatchablePointer);
1321
1322#[allow(unsafe_code)]
1323unsafe impl Sync for Runnable {}
1324#[allow(unsafe_code)]
1325unsafe impl Send for Runnable {}
1326
1327#[allow(unsafe_code)]
1328impl Runnable {
1329 fn run(&self, cx: *mut RawJSContext, maybe_shutting_down: Dispatchable_MaybeShuttingDown) {
1330 unsafe {
1331 DispatchableRun(cx, self.0, maybe_shutting_down);
1332 }
1333 }
1334}
1335
1336pub(crate) use script_bindings::script_runtime::CanGc;
1337
1338pub(crate) struct IntroductionType;
1344impl IntroductionType {
1345 pub const EVAL: &CStr = c"eval";
1347 pub const EVAL_STR: &str = "eval";
1348
1349 pub const DEBUGGER_EVAL: &CStr = c"debugger eval";
1352 pub const DEBUGGER_EVAL_STR: &str = "debugger eval";
1353
1354 pub const FUNCTION: &CStr = c"Function";
1356 pub const FUNCTION_STR: &str = "Function";
1357
1358 pub const WORKLET: &CStr = c"Worklet";
1360 pub const WORKLET_STR: &str = "Worklet";
1361
1362 pub const EVENT_HANDLER: &CStr = c"eventHandler";
1364 pub const EVENT_HANDLER_STR: &str = "eventHandler";
1365
1366 pub const SRC_SCRIPT: &CStr = c"srcScript";
1369 pub const SRC_SCRIPT_STR: &str = "srcScript";
1370
1371 pub const INLINE_SCRIPT: &CStr = c"inlineScript";
1374 pub const INLINE_SCRIPT_STR: &str = "inlineScript";
1375
1376 pub const INJECTED_SCRIPT: &CStr = c"injectedScript";
1382 pub const INJECTED_SCRIPT_STR: &str = "injectedScript";
1383
1384 pub const IMPORTED_MODULE: &CStr = c"importedModule";
1387 pub const IMPORTED_MODULE_STR: &str = "importedModule";
1388
1389 pub const JAVASCRIPT_URL: &CStr = c"javascriptURL";
1391 pub const JAVASCRIPT_URL_STR: &str = "javascriptURL";
1392
1393 pub const DOM_TIMER: &CStr = c"domTimer";
1395 pub const DOM_TIMER_STR: &str = "domTimer";
1396
1397 pub const WORKER: &CStr = c"Worker";
1401 pub const WORKER_STR: &str = "Worker";
1402}