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