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_NewStringCopyUTF8N, 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_str = trusted_script.data().str();
495 let s = js::conversions::Utf8Chars::from(&*script_str);
496 let new_string = JS_NewStringCopyUTF8N(*cx, &*s as *const _);
497 code_for_eval.set(new_string);
498 }
499 true
500}
501
502#[allow(unsafe_code)]
503unsafe extern "C" fn content_security_policy_allows(
504 cx: *mut RawJSContext,
505 runtime_code: RuntimeCode,
506 code_string: HandleString,
507 compilation_type: CompilationType,
508 parameter_strings: RawHandle<StackGCVector<*mut JSString>>,
509 body_string: HandleString,
510 parameter_args: RawHandle<StackGCVector<JSVal>>,
511 body_arg: RawHandleValue,
512 can_compile_strings: *mut bool,
513) -> bool {
514 let mut allowed = false;
515 let cx = JSContext::from_ptr(cx);
516 wrap_panic(&mut || {
517 let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
519 let global = &GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
520 let csp_list = global.get_csp_list();
521
522 allowed = csp_list.is_none() ||
524 match runtime_code {
525 RuntimeCode::JS => {
526 let parameter_strings = Handle::from_raw(parameter_strings);
527 let parameter_strings_length = parameter_strings.len();
528 let mut parameter_strings_vec =
529 Vec::with_capacity(parameter_strings_length as usize);
530
531 for i in 0..parameter_strings_length {
532 let Some(str_) = parameter_strings.at(i) else {
533 unreachable!();
534 };
535 parameter_strings_vec.push(safely_convert_null_to_string(cx, str_.into()));
536 }
537
538 let parameter_args = Handle::from_raw(parameter_args);
539 let parameter_args_length = parameter_args.len();
540 let mut parameter_args_vec = Vec::with_capacity(parameter_args_length as usize);
541
542 for i in 0..parameter_args_length {
543 let Some(arg) = parameter_args.at(i) else {
544 unreachable!();
545 };
546 let value = arg.into_handle().get();
547 if value.is_object() {
548 if let Ok(trusted_script) =
549 root_from_object::<TrustedScript>(value.to_object(), *cx)
550 {
551 parameter_args_vec
552 .push(TrustedScriptOrString::TrustedScript(trusted_script));
553 } else {
554 parameter_args_vec
558 .push(TrustedScriptOrString::String(DOMString::new()));
559 }
560 } else if value.is_string() {
561 parameter_args_vec
563 .push(TrustedScriptOrString::String(DOMString::new()));
564 } else {
565 unreachable!();
566 }
567 }
568
569 TrustedScript::can_compile_string_with_trusted_type(
570 cx,
571 global,
572 safely_convert_null_to_string(cx, code_string),
573 compilation_type,
574 parameter_strings_vec,
575 safely_convert_null_to_string(cx, body_string),
576 parameter_args_vec,
577 HandleValue::from_raw(body_arg),
578 CanGc::note(),
579 )
580 },
581 RuntimeCode::WASM => global.get_csp_list().is_wasm_evaluation_allowed(global),
582 };
583 });
584 *can_compile_strings = allowed;
585 true
586}
587
588#[allow(unsafe_code)]
589#[cfg_attr(crown, allow(crown::unrooted_must_root))]
590pub(crate) fn notify_about_rejected_promises(global: &GlobalScope) {
592 let cx = GlobalScope::get_cx();
593 unsafe {
594 if !global.get_uncaught_rejections().borrow().is_empty() {
596 let uncaught_rejections: Vec<TrustedPromise> = global
598 .get_uncaught_rejections()
599 .borrow()
600 .iter()
601 .map(|promise| {
602 let promise =
603 Promise::new_with_js_promise(Handle::from_raw(promise.handle()), cx);
604
605 TrustedPromise::new(promise)
606 })
607 .collect();
608
609 global.get_uncaught_rejections().borrow_mut().clear();
611
612 let target = Trusted::new(global.upcast::<EventTarget>());
613
614 global.task_manager().dom_manipulation_task_source().queue(
616 task!(unhandled_rejection_event: move || {
617 let target = target.root();
618 let cx = GlobalScope::get_cx();
619
620 for promise in uncaught_rejections {
621 let promise = promise.root();
622
623 let promise_is_handled = GetPromiseIsHandled(promise.reflector().get_jsobject());
625 if promise_is_handled {
626 continue;
627 }
628
629 rooted!(in(*cx) let mut reason = UndefinedValue());
631 JS_GetPromiseResult(promise.reflector().get_jsobject(), reason.handle_mut());
632
633 let event = PromiseRejectionEvent::new(
634 &target.global(),
635 atom!("unhandledrejection"),
636 EventBubbles::DoesNotBubble,
637 EventCancelable::Cancelable,
638 promise.clone(),
639 reason.handle(),
640 CanGc::note()
641 );
642
643 let not_canceled = event.upcast::<Event>().fire(&target, CanGc::note());
644
645 if not_canceled {
648 }
650
651 if !promise_is_handled {
653 target.global().add_consumed_rejection(promise.reflector().get_jsobject().into_handle());
654 }
655 }
656 })
657 );
658 }
659 }
660}
661
662#[derive(JSTraceable, MallocSizeOf)]
663pub(crate) struct Runtime {
664 #[ignore_malloc_size_of = "Type from mozjs"]
665 rt: RustRuntime,
666 #[conditional_malloc_size_of]
668 pub(crate) microtask_queue: Rc<MicrotaskQueue>,
669 #[ignore_malloc_size_of = "Type from mozjs"]
670 job_queue: *mut JobQueue,
671 networking_task_src: Option<Box<SendableTaskSource>>,
672}
673
674impl Runtime {
675 #[allow(unsafe_code)]
685 pub(crate) fn new(networking_task_source: Option<SendableTaskSource>) -> Runtime {
686 unsafe { Self::new_with_parent(None, networking_task_source) }
687 }
688
689 #[allow(unsafe_code)]
702 pub(crate) unsafe fn new_with_parent(
703 parent: Option<ParentRuntime>,
704 networking_task_source: Option<SendableTaskSource>,
705 ) -> Runtime {
706 let (cx, runtime) = if let Some(parent) = parent {
707 let runtime = RustRuntime::create_with_parent(parent);
708 let cx = runtime.cx();
709 (cx, runtime)
710 } else {
711 let runtime = RustRuntime::new(JS_ENGINE.lock().unwrap().as_ref().unwrap().clone());
712 (runtime.cx(), runtime)
713 };
714
715 JS_AddExtraGCRootsTracer(cx, Some(trace_rust_roots), ptr::null_mut());
716
717 JS_SetSecurityCallbacks(cx, &SECURITY_CALLBACKS);
718
719 JS_InitDestroyPrincipalsCallback(cx, Some(principals::destroy_servo_jsprincipal));
720 JS_InitReadPrincipalsCallback(cx, Some(principals::read_jsprincipal));
721
722 if cfg!(debug_assertions) {
724 JS_SetGCCallback(cx, Some(debug_gc_callback), ptr::null_mut());
725 }
726
727 if opts::get().debug.gc_profile {
728 SetGCSliceCallback(cx, Some(gc_slice_callback));
729 }
730
731 unsafe extern "C" fn empty_wrapper_callback(_: *mut RawJSContext, _: HandleObject) -> bool {
732 true
733 }
734 unsafe extern "C" fn empty_has_released_callback(_: HandleObject) -> bool {
735 false
737 }
738 SetDOMCallbacks(cx, &DOM_CALLBACKS);
739 SetPreserveWrapperCallbacks(
740 cx,
741 Some(empty_wrapper_callback),
742 Some(empty_has_released_callback),
743 );
744 JS_SetGCParameter(cx, JSGCParamKey::JSGC_INCREMENTAL_GC_ENABLED, 0);
746
747 unsafe extern "C" fn dispatch_to_event_loop(
748 closure: *mut c_void,
749 dispatchable: *mut DispatchablePointer,
750 ) -> bool {
751 let networking_task_src: &SendableTaskSource = &*(closure as *mut SendableTaskSource);
752 let runnable = Runnable(dispatchable);
753 let task = task!(dispatch_to_event_loop_message: move || {
754 if let Some(cx) = RustRuntime::get() {
755 runnable.run(cx.as_ptr(), Dispatchable_MaybeShuttingDown::NotShuttingDown);
756 }
757 });
758
759 networking_task_src.queue_unconditionally(task);
760 true
761 }
762
763 let mut networking_task_src_ptr = std::ptr::null_mut();
764 if let Some(source) = networking_task_source {
765 networking_task_src_ptr = Box::into_raw(Box::new(source));
766 SetUpEventLoopDispatch(
767 cx,
768 Some(dispatch_to_event_loop),
769 networking_task_src_ptr as *mut c_void,
770 );
771 }
772
773 InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error));
774
775 let microtask_queue = Rc::new(MicrotaskQueue::default());
776
777 let interrupt_queues: Box<Vec<Rc<MicrotaskQueue>>> = Box::default();
781
782 let job_queue = CreateJobQueue(
783 &JOB_QUEUE_TRAPS,
784 &*microtask_queue as *const _ as *const c_void,
785 Box::into_raw(interrupt_queues) as *mut c_void,
786 );
787 SetJobQueue(cx, job_queue);
788 SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut());
789
790 EnsureModuleHooksInitialized(runtime.rt());
791
792 set_gc_zeal_options(cx);
793
794 let cx_opts = &mut *ContextOptionsRef(cx);
796 JS_SetGlobalJitCompilerOption(
797 cx,
798 JSJitCompilerOption::JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE,
799 pref!(js_baseline_interpreter_enabled) as u32,
800 );
801 JS_SetGlobalJitCompilerOption(
802 cx,
803 JSJitCompilerOption::JSJITCOMPILER_BASELINE_ENABLE,
804 pref!(js_baseline_jit_enabled) as u32,
805 );
806 JS_SetGlobalJitCompilerOption(
807 cx,
808 JSJitCompilerOption::JSJITCOMPILER_ION_ENABLE,
809 pref!(js_ion_enabled) as u32,
810 );
811 cx_opts.compileOptions_.asmJSOption_ = if pref!(js_asmjs_enabled) {
812 AsmJSOption::Enabled
813 } else {
814 AsmJSOption::DisabledByAsmJSPref
815 };
816 let wasm_enabled = pref!(js_wasm_enabled);
817 cx_opts.set_wasm_(wasm_enabled);
818 if wasm_enabled {
819 SetProcessBuildIdOp(Some(servo_build_id));
823 }
824 cx_opts.set_wasmBaseline_(pref!(js_wasm_baseline_enabled));
825 cx_opts.set_wasmIon_(pref!(js_wasm_ion_enabled));
826 JS_SetGlobalJitCompilerOption(
828 cx,
829 JSJitCompilerOption::JSJITCOMPILER_NATIVE_REGEXP_ENABLE,
830 pref!(js_native_regex_enabled) as u32,
831 );
832 JS_SetOffthreadIonCompilationEnabled(cx, pref!(js_offthread_compilation_enabled));
833 JS_SetGlobalJitCompilerOption(
834 cx,
835 JSJitCompilerOption::JSJITCOMPILER_BASELINE_WARMUP_TRIGGER,
836 if pref!(js_baseline_jit_unsafe_eager_compilation_enabled) {
837 0
838 } else {
839 u32::MAX
840 },
841 );
842 JS_SetGlobalJitCompilerOption(
843 cx,
844 JSJitCompilerOption::JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER,
845 if pref!(js_ion_unsafe_eager_compilation_enabled) {
846 0
847 } else {
848 u32::MAX
849 },
850 );
851 JS_SetGCParameter(
857 cx,
858 JSGCParamKey::JSGC_MAX_BYTES,
859 in_range(pref!(js_mem_max), 1, 0x100)
860 .map(|val| (val * 1024 * 1024) as u32)
861 .unwrap_or(u32::MAX),
862 );
863 JS_SetGCParameter(
865 cx,
866 JSGCParamKey::JSGC_INCREMENTAL_GC_ENABLED,
867 pref!(js_mem_gc_incremental_enabled) as u32,
868 );
869 JS_SetGCParameter(
870 cx,
871 JSGCParamKey::JSGC_PER_ZONE_GC_ENABLED,
872 pref!(js_mem_gc_per_zone_enabled) as u32,
873 );
874 if let Some(val) = in_range(pref!(js_mem_gc_incremental_slice_ms), 0, 100_000) {
875 JS_SetGCParameter(cx, JSGCParamKey::JSGC_SLICE_TIME_BUDGET_MS, val as u32);
876 }
877 JS_SetGCParameter(
878 cx,
879 JSGCParamKey::JSGC_COMPACTING_ENABLED,
880 pref!(js_mem_gc_compacting_enabled) as u32,
881 );
882
883 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_time_limit_ms), 0, 10_000) {
884 JS_SetGCParameter(cx, JSGCParamKey::JSGC_HIGH_FREQUENCY_TIME_LIMIT, val as u32);
885 }
886 if let Some(val) = in_range(pref!(js_mem_gc_low_frequency_heap_growth), 0, 10_000) {
887 JS_SetGCParameter(cx, JSGCParamKey::JSGC_LOW_FREQUENCY_HEAP_GROWTH, val as u32);
888 }
889 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_heap_growth_min), 0, 10_000) {
890 JS_SetGCParameter(
891 cx,
892 JSGCParamKey::JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH,
893 val as u32,
894 );
895 }
896 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_heap_growth_max), 0, 10_000) {
897 JS_SetGCParameter(
898 cx,
899 JSGCParamKey::JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH,
900 val as u32,
901 );
902 }
903 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_low_limit_mb), 0, 10_000) {
904 JS_SetGCParameter(cx, JSGCParamKey::JSGC_SMALL_HEAP_SIZE_MAX, val as u32);
905 }
906 if let Some(val) = in_range(pref!(js_mem_gc_high_frequency_high_limit_mb), 0, 10_000) {
907 JS_SetGCParameter(cx, JSGCParamKey::JSGC_LARGE_HEAP_SIZE_MIN, val as u32);
908 }
909 if let Some(val) = in_range(pref!(js_mem_gc_empty_chunk_count_min), 0, 10_000) {
920 JS_SetGCParameter(cx, JSGCParamKey::JSGC_MIN_EMPTY_CHUNK_COUNT, val as u32);
921 }
922
923 Runtime {
924 rt: runtime,
925 microtask_queue,
926 job_queue,
927 networking_task_src: (!networking_task_src_ptr.is_null())
928 .then(|| Box::from_raw(networking_task_src_ptr)),
929 }
930 }
931
932 pub(crate) fn thread_safe_js_context(&self) -> ThreadSafeJSContext {
933 self.rt.thread_safe_js_context()
934 }
935}
936
937impl Drop for Runtime {
938 #[allow(unsafe_code)]
939 fn drop(&mut self) {
940 self.microtask_queue.clear();
942
943 unsafe {
945 DeleteJobQueue(self.job_queue);
946 }
947 LiveDOMReferences::destruct();
948 mark_runtime_dead();
949 }
950}
951
952impl Deref for Runtime {
953 type Target = RustRuntime;
954 fn deref(&self) -> &RustRuntime {
955 &self.rt
956 }
957}
958
959pub struct JSEngineSetup(JSEngine);
960
961impl Default for JSEngineSetup {
962 fn default() -> Self {
963 let engine = JSEngine::init().unwrap();
964 *JS_ENGINE.lock().unwrap() = Some(engine.handle());
965 Self(engine)
966 }
967}
968
969impl Drop for JSEngineSetup {
970 fn drop(&mut self) {
971 *JS_ENGINE.lock().unwrap() = None;
972
973 while !self.0.can_shutdown() {
974 thread::sleep(Duration::from_millis(50));
975 }
976 }
977}
978
979static JS_ENGINE: Mutex<Option<JSEngineHandle>> = Mutex::new(None);
980
981fn in_range<T: PartialOrd + Copy>(val: T, min: T, max: T) -> Option<T> {
982 if val < min || val >= max {
983 None
984 } else {
985 Some(val)
986 }
987}
988
989thread_local!(static MALLOC_SIZE_OF_OPS: Cell<*mut MallocSizeOfOps> = const { Cell::new(ptr::null_mut()) });
990
991#[allow(unsafe_code)]
992unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
993 match get_dom_class(obj) {
994 Ok(v) => {
995 let dom_object = private_from_object(obj) as *const c_void;
996
997 if dom_object.is_null() {
998 return 0;
999 }
1000 let ops = MALLOC_SIZE_OF_OPS.get();
1001 (v.malloc_size_of)(&mut *ops, dom_object)
1002 },
1003 Err(_e) => 0,
1004 }
1005}
1006
1007thread_local!(static GC_CYCLE_START: Cell<Option<Instant>> = const { Cell::new(None) });
1008thread_local!(static GC_SLICE_START: Cell<Option<Instant>> = const { Cell::new(None) });
1009
1010#[allow(unsafe_code)]
1011unsafe extern "C" fn gc_slice_callback(
1012 _cx: *mut RawJSContext,
1013 progress: GCProgress,
1014 desc: *const GCDescription,
1015) {
1016 match progress {
1017 GCProgress::GC_CYCLE_BEGIN => GC_CYCLE_START.with(|start| {
1018 start.set(Some(Instant::now()));
1019 println!("GC cycle began");
1020 }),
1021 GCProgress::GC_SLICE_BEGIN => GC_SLICE_START.with(|start| {
1022 start.set(Some(Instant::now()));
1023 println!("GC slice began");
1024 }),
1025 GCProgress::GC_SLICE_END => GC_SLICE_START.with(|start| {
1026 let duration = start.get().unwrap().elapsed();
1027 start.set(None);
1028 println!("GC slice ended: duration={:?}", duration);
1029 }),
1030 GCProgress::GC_CYCLE_END => GC_CYCLE_START.with(|start| {
1031 let duration = start.get().unwrap().elapsed();
1032 start.set(None);
1033 println!("GC cycle ended: duration={:?}", duration);
1034 }),
1035 };
1036 if !desc.is_null() {
1037 let desc: &GCDescription = &*desc;
1038 let options = match desc.options_ {
1039 GCOptions::Normal => "Normal",
1040 GCOptions::Shrink => "Shrink",
1041 GCOptions::Shutdown => "Shutdown",
1042 };
1043 println!(" isZone={}, options={}", desc.isZone_, options);
1044 }
1045 let _ = stdout().flush();
1046}
1047
1048#[allow(unsafe_code)]
1049unsafe extern "C" fn debug_gc_callback(
1050 _cx: *mut RawJSContext,
1051 status: JSGCStatus,
1052 _reason: GCReason,
1053 _data: *mut os::raw::c_void,
1054) {
1055 match status {
1056 JSGCStatus::JSGC_BEGIN => thread_state::enter(ThreadState::IN_GC),
1057 JSGCStatus::JSGC_END => thread_state::exit(ThreadState::IN_GC),
1058 }
1059}
1060
1061#[allow(unsafe_code)]
1062unsafe extern "C" fn trace_rust_roots(tr: *mut JSTracer, _data: *mut os::raw::c_void) {
1063 if !runtime_is_alive() {
1064 return;
1065 }
1066 trace!("starting custom root handler");
1067 trace_thread(tr);
1068 trace_roots(tr);
1069 trace_refcounted_objects(tr);
1070 settings_stack::trace(tr);
1071 trace!("done custom root handler");
1072}
1073
1074#[allow(unsafe_code)]
1075unsafe extern "C" fn servo_build_id(build_id: *mut BuildIdCharVector) -> bool {
1076 let servo_id = b"Servo\0";
1077 SetBuildId(build_id, servo_id[0] as *const c_char, servo_id.len())
1078}
1079
1080#[allow(unsafe_code)]
1081#[cfg(feature = "debugmozjs")]
1082unsafe fn set_gc_zeal_options(cx: *mut RawJSContext) {
1083 use js::jsapi::SetGCZeal;
1084
1085 let level = match pref!(js_mem_gc_zeal_level) {
1086 level @ 0..=14 => level as u8,
1087 _ => return,
1088 };
1089 let frequency = match pref!(js_mem_gc_zeal_frequency) {
1090 frequency if frequency >= 0 => frequency as u32,
1091 _ => 5000,
1093 };
1094 SetGCZeal(cx, level, frequency);
1095}
1096
1097#[allow(unsafe_code)]
1098#[cfg(not(feature = "debugmozjs"))]
1099unsafe fn set_gc_zeal_options(_: *mut RawJSContext) {}
1100
1101pub(crate) use script_bindings::script_runtime::JSContext;
1102
1103pub(crate) trait JSContextHelper {
1106 fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report>;
1107}
1108
1109impl JSContextHelper for JSContext {
1110 #[allow(unsafe_code)]
1111 fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report> {
1112 MALLOC_SIZE_OF_OPS.with(|ops_tls| ops_tls.set(ops));
1113 let stats = unsafe {
1114 let mut stats = ::std::mem::zeroed();
1115 if !CollectServoSizes(**self, &mut stats, Some(get_size)) {
1116 return vec![];
1117 }
1118 stats
1119 };
1120 MALLOC_SIZE_OF_OPS.with(|ops| ops.set(ptr::null_mut()));
1121
1122 let mut reports = vec![];
1123 let mut report = |mut path_suffix, kind, size| {
1124 let mut path = path![path_seg, "js"];
1125 path.append(&mut path_suffix);
1126 reports.push(Report { path, kind, size })
1127 };
1128
1129 report(
1133 path!["gc-heap", "used"],
1134 ReportKind::ExplicitNonHeapSize,
1135 stats.gcHeapUsed,
1136 );
1137
1138 report(
1139 path!["gc-heap", "unused"],
1140 ReportKind::ExplicitNonHeapSize,
1141 stats.gcHeapUnused,
1142 );
1143
1144 report(
1145 path!["gc-heap", "admin"],
1146 ReportKind::ExplicitNonHeapSize,
1147 stats.gcHeapAdmin,
1148 );
1149
1150 report(
1151 path!["gc-heap", "decommitted"],
1152 ReportKind::ExplicitNonHeapSize,
1153 stats.gcHeapDecommitted,
1154 );
1155
1156 report(
1158 path!["malloc-heap"],
1159 ReportKind::ExplicitSystemHeapSize,
1160 stats.mallocHeap,
1161 );
1162
1163 report(
1164 path!["non-heap"],
1165 ReportKind::ExplicitNonHeapSize,
1166 stats.nonHeap,
1167 );
1168 reports
1169 }
1170}
1171
1172pub(crate) struct StreamConsumer(*mut JSStreamConsumer);
1173
1174#[allow(unsafe_code)]
1175impl StreamConsumer {
1176 pub(crate) fn consume_chunk(&self, stream: &[u8]) -> bool {
1177 unsafe {
1178 let stream_ptr = stream.as_ptr();
1179 StreamConsumerConsumeChunk(self.0, stream_ptr, stream.len())
1180 }
1181 }
1182
1183 pub(crate) fn stream_end(&self) {
1184 unsafe {
1185 StreamConsumerStreamEnd(self.0);
1186 }
1187 }
1188
1189 pub(crate) fn stream_error(&self, error_code: usize) {
1190 unsafe {
1191 StreamConsumerStreamError(self.0, error_code);
1192 }
1193 }
1194
1195 pub(crate) fn note_response_urls(
1196 &self,
1197 maybe_url: Option<String>,
1198 maybe_source_map_url: Option<String>,
1199 ) {
1200 unsafe {
1201 let maybe_url = maybe_url.map(|url| CString::new(url).unwrap());
1202 let maybe_source_map_url = maybe_source_map_url.map(|url| CString::new(url).unwrap());
1203
1204 let maybe_url_param = match maybe_url.as_ref() {
1205 Some(url) => url.as_ptr(),
1206 None => ptr::null(),
1207 };
1208 let maybe_source_map_url_param = match maybe_source_map_url.as_ref() {
1209 Some(url) => url.as_ptr(),
1210 None => ptr::null(),
1211 };
1212
1213 StreamConsumerNoteResponseURLs(self.0, maybe_url_param, maybe_source_map_url_param);
1214 }
1215 }
1216}
1217
1218#[allow(unsafe_code)]
1221unsafe extern "C" fn consume_stream(
1222 _cx: *mut RawJSContext,
1223 obj: HandleObject,
1224 _mime_type: MimeType,
1225 _consumer: *mut JSStreamConsumer,
1226) -> bool {
1227 let cx = JSContext::from_ptr(_cx);
1228 let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
1229 let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
1230
1231 if let Ok(unwrapped_source) =
1233 root_from_handleobject::<Response>(RustHandleObject::from_raw(obj), *cx)
1234 {
1235 let mimetype = unwrapped_source.Headers(CanGc::note()).extract_mime_type();
1237
1238 if !&mimetype[..].eq_ignore_ascii_case(b"application/wasm") {
1240 throw_dom_exception(
1241 cx,
1242 &global,
1243 Error::Type("Response has unsupported MIME type".to_string()),
1244 CanGc::note(),
1245 );
1246 return false;
1247 }
1248
1249 match unwrapped_source.Type() {
1251 DOMResponseType::Basic | DOMResponseType::Cors | DOMResponseType::Default => {},
1252 _ => {
1253 throw_dom_exception(
1254 cx,
1255 &global,
1256 Error::Type("Response.type must be 'basic', 'cors' or 'default'".to_string()),
1257 CanGc::note(),
1258 );
1259 return false;
1260 },
1261 }
1262
1263 if !unwrapped_source.Ok() {
1265 throw_dom_exception(
1266 cx,
1267 &global,
1268 Error::Type("Response does not have ok status".to_string()),
1269 CanGc::note(),
1270 );
1271 return false;
1272 }
1273
1274 if unwrapped_source.is_locked() {
1276 throw_dom_exception(
1277 cx,
1278 &global,
1279 Error::Type("There was an error consuming the Response".to_string()),
1280 CanGc::note(),
1281 );
1282 return false;
1283 }
1284
1285 if unwrapped_source.is_disturbed() {
1287 throw_dom_exception(
1288 cx,
1289 &global,
1290 Error::Type("Response already consumed".to_string()),
1291 CanGc::note(),
1292 );
1293 return false;
1294 }
1295 unwrapped_source.set_stream_consumer(Some(StreamConsumer(_consumer)));
1296 } else {
1297 throw_dom_exception(
1299 cx,
1300 &global,
1301 Error::Type("expected Response or Promise resolving to Response".to_string()),
1302 CanGc::note(),
1303 );
1304 return false;
1305 }
1306 true
1307}
1308
1309#[allow(unsafe_code)]
1310unsafe extern "C" fn report_stream_error(_cx: *mut RawJSContext, error_code: usize) {
1311 error!(
1312 "Error initializing StreamConsumer: {:?}",
1313 RUST_js_GetErrorMessage(ptr::null_mut(), error_code as u32)
1314 );
1315}
1316
1317pub(crate) struct Runnable(*mut DispatchablePointer);
1318
1319#[allow(unsafe_code)]
1320unsafe impl Sync for Runnable {}
1321#[allow(unsafe_code)]
1322unsafe impl Send for Runnable {}
1323
1324#[allow(unsafe_code)]
1325impl Runnable {
1326 fn run(&self, cx: *mut RawJSContext, maybe_shutting_down: Dispatchable_MaybeShuttingDown) {
1327 unsafe {
1328 DispatchableRun(cx, self.0, maybe_shutting_down);
1329 }
1330 }
1331}
1332
1333pub(crate) use script_bindings::script_runtime::CanGc;
1334
1335pub(crate) struct IntroductionType;
1341impl IntroductionType {
1342 pub const EVAL: &CStr = c"eval";
1344 pub const EVAL_STR: &str = "eval";
1345
1346 pub const DEBUGGER_EVAL: &CStr = c"debugger eval";
1349 pub const DEBUGGER_EVAL_STR: &str = "debugger eval";
1350
1351 pub const FUNCTION: &CStr = c"Function";
1353 pub const FUNCTION_STR: &str = "Function";
1354
1355 pub const WORKLET: &CStr = c"Worklet";
1357 pub const WORKLET_STR: &str = "Worklet";
1358
1359 pub const EVENT_HANDLER: &CStr = c"eventHandler";
1361 pub const EVENT_HANDLER_STR: &str = "eventHandler";
1362
1363 pub const SRC_SCRIPT: &CStr = c"srcScript";
1366 pub const SRC_SCRIPT_STR: &str = "srcScript";
1367
1368 pub const INLINE_SCRIPT: &CStr = c"inlineScript";
1371 pub const INLINE_SCRIPT_STR: &str = "inlineScript";
1372
1373 pub const INJECTED_SCRIPT: &CStr = c"injectedScript";
1379 pub const INJECTED_SCRIPT_STR: &str = "injectedScript";
1380
1381 pub const IMPORTED_MODULE: &CStr = c"importedModule";
1384 pub const IMPORTED_MODULE_STR: &str = "importedModule";
1385
1386 pub const JAVASCRIPT_URL: &CStr = c"javascriptURL";
1388 pub const JAVASCRIPT_URL_STR: &str = "javascriptURL";
1389
1390 pub const DOM_TIMER: &CStr = c"domTimer";
1392 pub const DOM_TIMER_STR: &str = "domTimer";
1393
1394 pub const WORKER: &CStr = c"Worker";
1398 pub const WORKER_STR: &str = "Worker";
1399}