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