1#![cfg_attr(crown, allow(crown::jscontext_first_arg))]
6
7use std::cell::RefCell;
8
9use devtools_traits::{
10 BlackboxCoverage, DebuggerValue, DevtoolScriptControlMsg, EvaluateJSReply,
11 GetEnvironmentRequest, ScriptToDevtoolsControlMsg, SourceInfo, WorkerId,
12};
13use dom_struct::dom_struct;
14use embedder_traits::ScriptToEmbedderChan;
15use embedder_traits::resources::{self, Resource};
16use js::context::JSContext;
17use js::rust::wrappers2::JS_DefineDebuggerObject;
18use net_traits::ResourceThreads;
19use profile_traits::{mem, time};
20use script_bindings::interfaces::HasOrigin;
21use script_bindings::reflector::DomObject;
22use servo_base::generic_channel::{GenericCallback, GenericSender, channel};
23use servo_base::id::{Index, PipelineId, PipelineNamespaceId};
24use servo_constellation_traits::ScriptToConstellationSender;
25use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
26use storage_traits::StorageThreads;
27
28use crate::dom::bindings::codegen::Bindings::DebuggerGetEnvironmentEventBinding::EnvironmentInfo;
29use crate::dom::bindings::codegen::Bindings::DebuggerGlobalScopeBinding;
30use crate::dom::bindings::codegen::Bindings::DebuggerInterruptEventBinding::{
31 FrameInfo, FrameOffset, PauseReason,
32};
33use crate::dom::bindings::codegen::GenericBindings::DebuggerEvalEventBinding::EvalResult;
34use crate::dom::bindings::codegen::GenericBindings::DebuggerGetPossibleBreakpointsEventBinding::RecommendedBreakpointLocation;
35use crate::dom::bindings::codegen::GenericBindings::DebuggerGlobalScopeBinding::{
36 DebuggerGlobalScopeMethods, NotifyNewSource, PipelineIdInit,
37};
38use crate::dom::bindings::inheritance::Castable;
39use crate::dom::bindings::root::DomRoot;
40use crate::dom::bindings::str::DOMString;
41use crate::dom::bindings::utils::define_all_exposed_interfaces;
42use crate::dom::debugger::debuggerblackboxevent::DebuggerBlackboxEvent;
43use crate::dom::debugger::debuggerclearbreakpointevent::DebuggerClearBreakpointEvent;
44use crate::dom::debugger::debuggerframeevent::DebuggerFrameEvent;
45use crate::dom::debugger::debuggergetenvironmentevent::DebuggerGetEnvironmentEvent;
46use crate::dom::debugger::debuggerinterruptevent::DebuggerInterruptEvent;
47use crate::dom::debugger::debuggerresumeevent::DebuggerResumeEvent;
48use crate::dom::debugger::debuggersetbreakpointevent::DebuggerSetBreakpointEvent;
49use crate::dom::debugger::debuggerunblackboxevent::DebuggerUnblackboxEvent;
50use crate::dom::globalscope::GlobalScope;
51use crate::dom::types::{
52 DebuggerAddDebuggeeEvent, DebuggerEvalEvent, DebuggerGetPossibleBreakpointsEvent, Event,
53};
54#[cfg(feature = "webgpu")]
55use crate::dom::webgpu::identityhub::IdentityHub;
56use crate::event_loop::script_thread::with_script_thread;
57use crate::realms::enter_auto_realm;
58use crate::runtime::script_runtime::IntroductionType;
59
60#[dom_struct]
61pub(crate) struct DebuggerGlobalScope {
65 global_scope: GlobalScope,
66 #[no_trace]
67 devtools_to_script_sender: GenericSender<DevtoolScriptControlMsg>,
68 #[no_trace]
69 get_possible_breakpoints_result_sender:
70 RefCell<Option<GenericSender<Vec<devtools_traits::RecommendedBreakpointLocation>>>>,
71 #[no_trace]
72 eval_result_sender: RefCell<Option<GenericSender<EvaluateJSReply>>>,
73 #[no_trace]
74 get_list_frame_result_sender: RefCell<Option<GenericSender<Vec<String>>>>,
75 #[no_trace]
76 get_environment_result_sender: RefCell<Option<GenericSender<String>>>,
77 #[no_trace]
78 pipeline_id: PipelineId,
79 #[no_trace]
80 origin: MutableOrigin,
81}
82
83impl DebuggerGlobalScope {
84 #[expect(unsafe_code, clippy::too_many_arguments)]
92 pub(crate) fn new(
93 debugger_pipeline_id: PipelineId,
94 script_to_devtools_sender: Option<GenericCallback<ScriptToDevtoolsControlMsg>>,
95 devtools_to_script_sender: GenericSender<DevtoolScriptControlMsg>,
96 mem_profiler_chan: mem::ProfilerChan,
97 time_profiler_chan: time::ProfilerChan,
98 script_to_constellation_sender: ScriptToConstellationSender,
99 script_to_embedder_chan: ScriptToEmbedderChan,
100 resource_threads: ResourceThreads,
101 storage_threads: StorageThreads,
102 #[cfg(feature = "webgpu")] gpu_id_hub: std::sync::Arc<IdentityHub>,
103 cx: &mut JSContext,
104 ) -> DomRoot<Self> {
105 let global = Box::new(Self {
106 global_scope: GlobalScope::new_inherited(
107 script_to_devtools_sender,
108 mem_profiler_chan,
109 time_profiler_chan,
110 script_to_constellation_sender,
111 script_to_embedder_chan,
112 resource_threads,
113 storage_threads,
114 ServoUrl::parse_with_base(None, "about:internal/debugger")
115 .expect("Guaranteed by argument"),
116 None,
117 #[cfg(feature = "webgpu")]
118 gpu_id_hub,
119 None,
120 false,
121 ),
122 devtools_to_script_sender,
123 get_possible_breakpoints_result_sender: RefCell::new(None),
124 get_list_frame_result_sender: RefCell::new(None),
125 get_environment_result_sender: RefCell::new(None),
126 eval_result_sender: RefCell::new(None),
127 pipeline_id: debugger_pipeline_id,
128 origin: MutableOrigin::new(ImmutableOrigin::new_opaque()),
129 });
130 let global =
131 DebuggerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, &global.origin(), global);
132
133 let mut realm = enter_auto_realm(cx, &*global);
134 let mut realm = realm.current_realm();
135 define_all_exposed_interfaces(&mut realm, global.upcast());
136 assert!(unsafe {
137 JS_DefineDebuggerObject(&mut realm, global.global_scope.reflector().get_jsobject())
139 });
140
141 global
142 }
143
144 pub(crate) fn origin(&self) -> MutableOrigin {
145 self.origin.clone()
146 }
147
148 pub(crate) fn as_global_scope(&self) -> &GlobalScope {
149 self.upcast::<GlobalScope>()
150 }
151
152 pub(crate) fn execute(&self, cx: &mut JSContext) {
153 let mut realm = enter_auto_realm(cx, self);
154 let cx = &mut realm.current_realm();
155
156 let _ = self.global_scope.evaluate_js_on_global(
157 cx,
158 resources::read_string(Resource::DebuggerJS).into(),
159 "",
160 None,
161 None,
162 );
163 }
164
165 pub(crate) fn fire_add_debuggee(
166 &self,
167 cx: &mut JSContext,
168 debuggee_global: &GlobalScope,
169 debuggee_pipeline_id: PipelineId,
170 debuggee_worker_id: Option<WorkerId>,
171 ) {
172 let mut realm = enter_auto_realm(cx, self);
173 let cx = &mut realm;
174 let debuggee_pipeline_id =
175 crate::dom::pipelineid::PipelineId::new(cx, self.upcast(), debuggee_pipeline_id);
176 let event = DomRoot::upcast::<Event>(DebuggerAddDebuggeeEvent::new(
177 cx,
178 self.upcast(),
179 debuggee_global,
180 &debuggee_pipeline_id,
181 debuggee_worker_id.map(|id| id.to_string().into()),
182 ));
183 assert!(
184 event.fire(cx, self.upcast()),
185 "Guaranteed by DebuggerAddDebuggeeEvent::new"
186 );
187 }
188
189 #[expect(clippy::too_many_arguments)]
190 pub(crate) fn fire_eval(
191 &self,
192 cx: &mut JSContext,
193 code: DOMString,
194 debuggee_pipeline_id: PipelineId,
195 debuggee_worker_id: Option<WorkerId>,
196 frame_actor_id: Option<String>,
197 eager: bool,
198 result_sender: GenericSender<EvaluateJSReply>,
199 ) {
200 assert!(
201 self.eval_result_sender
202 .replace(Some(result_sender))
203 .is_none()
204 );
205 let mut realm = enter_auto_realm(cx, self);
206 let cx = &mut realm;
207 let debuggee_pipeline_id =
208 crate::dom::pipelineid::PipelineId::new(cx, self.upcast(), debuggee_pipeline_id);
209 let event = DomRoot::upcast::<Event>(DebuggerEvalEvent::new(
210 cx,
211 self.upcast(),
212 code,
213 &debuggee_pipeline_id,
214 debuggee_worker_id.map(|id| id.to_string().into()),
215 frame_actor_id.map(|id| id.into()),
216 eager,
217 ));
218 assert!(
219 event.fire(cx, self.upcast()),
220 "Guaranteed by DebuggerEvalEvent::new"
221 );
222 }
223
224 pub(crate) fn fire_get_possible_breakpoints(
225 &self,
226 cx: &mut JSContext,
227 spidermonkey_id: u32,
228 result_sender: GenericSender<Vec<devtools_traits::RecommendedBreakpointLocation>>,
229 ) {
230 assert!(
231 self.get_possible_breakpoints_result_sender
232 .replace(Some(result_sender))
233 .is_none()
234 );
235 let mut realm = enter_auto_realm(cx, self);
236 let cx = &mut realm.current_realm();
237 let event = DomRoot::upcast::<Event>(DebuggerGetPossibleBreakpointsEvent::new(
238 cx,
239 self.upcast(),
240 spidermonkey_id,
241 ));
242 assert!(
243 event.fire(cx, self.upcast()),
244 "Guaranteed by DebuggerGetPossibleBreakpointsEvent::new"
245 );
246 }
247
248 pub(crate) fn fire_set_breakpoint(
249 &self,
250 cx: &mut JSContext,
251 spidermonkey_id: u32,
252 script_id: u32,
253 offset: u32,
254 ) {
255 let event = DomRoot::upcast::<Event>(DebuggerSetBreakpointEvent::new(
256 cx,
257 self.upcast(),
258 spidermonkey_id,
259 script_id,
260 offset,
261 ));
262 assert!(
263 event.fire(cx, self.upcast()),
264 "Guaranteed by DebuggerSetBreakpointEvent::new"
265 );
266 }
267
268 pub(crate) fn fire_interrupt(&self, cx: &mut js::context::JSContext) {
269 let event = DomRoot::upcast::<Event>(DebuggerInterruptEvent::new(cx, self.upcast()));
270 assert!(
271 event.fire(cx, self.upcast()),
272 "Guaranteed by DebuggerInterruptEvent::new"
273 );
274 }
275
276 pub(crate) fn fire_list_frames(
277 &self,
278 cx: &mut js::context::JSContext,
279 pipeline_id: PipelineId,
280 start: u32,
281 count: u32,
282 result_sender: GenericSender<Vec<String>>,
283 ) {
284 assert!(
285 self.get_list_frame_result_sender
286 .replace(Some(result_sender))
287 .is_none()
288 );
289 let mut realm = enter_auto_realm(cx, self);
290 let cx = &mut realm.current_realm();
291 let pipeline_id = crate::dom::pipelineid::PipelineId::new(cx, self.upcast(), pipeline_id);
292 let event = DomRoot::upcast::<Event>(DebuggerFrameEvent::new(
293 cx,
294 self.upcast(),
295 &pipeline_id,
296 start,
297 count,
298 ));
299 assert!(
300 event.fire(cx, self.upcast()),
301 "Guaranteed by DebuggerFrameEvent::new"
302 );
303 }
304
305 pub(crate) fn fire_get_environment(
306 &self,
307 cx: &mut JSContext,
308 request: GetEnvironmentRequest,
309 result_sender: GenericSender<String>,
310 ) {
311 assert!(
312 self.get_environment_result_sender
313 .replace(Some(result_sender))
314 .is_none()
315 );
316 let mut realm = enter_auto_realm(cx, self);
317 let cx = &mut realm.current_realm();
318
319 let event = DomRoot::upcast::<Event>(DebuggerGetEnvironmentEvent::new(cx, self, request));
320 assert!(
321 event.fire(cx, self.upcast()),
322 "Guaranteed by DebuggerGetEnvironmentEvent::new"
323 );
324 }
325
326 pub(crate) fn fire_resume(
327 &self,
328 cx: &mut JSContext,
329 resume_limit_type: Option<String>,
330 frame_actor_id: Option<String>,
331 ) {
332 let event = DomRoot::upcast::<Event>(DebuggerResumeEvent::new(
333 cx,
334 self.upcast(),
335 resume_limit_type.map(DOMString::from),
336 frame_actor_id.map(DOMString::from),
337 ));
338 assert!(
339 event.fire(cx, self.upcast()),
340 "Guaranteed by DebuggerResumeEvent::new"
341 );
342 }
343
344 pub(crate) fn fire_clear_breakpoint(
345 &self,
346 cx: &mut JSContext,
347 spidermonkey_id: u32,
348 script_id: u32,
349 offset: u32,
350 ) {
351 let event = DomRoot::upcast::<Event>(DebuggerClearBreakpointEvent::new(
352 cx,
353 self.upcast(),
354 spidermonkey_id,
355 script_id,
356 offset,
357 ));
358 assert!(
359 event.fire(cx, self.upcast()),
360 "Guaranteed by DebuggerClearBreakpointEvent::new"
361 );
362 }
363
364 pub(crate) fn fire_blackbox(
365 &self,
366 cx: &mut JSContext,
367 spidermonkey_id: u32,
368 coverage: BlackboxCoverage,
369 ) {
370 let event = DomRoot::upcast::<Event>(DebuggerBlackboxEvent::new(
371 cx,
372 self.upcast(),
373 spidermonkey_id,
374 coverage,
375 ));
376 assert!(
377 event.fire(cx, self.upcast()),
378 "Guaranteed by DebuggerBlackboxEvent::new"
379 );
380 }
381
382 pub(crate) fn fire_unblackbox(
383 &self,
384 cx: &mut JSContext,
385 spidermonkey_id: u32,
386 coverage: BlackboxCoverage,
387 ) {
388 let event = DomRoot::upcast::<Event>(DebuggerUnblackboxEvent::new(
389 cx,
390 self.upcast(),
391 spidermonkey_id,
392 coverage,
393 ));
394 assert!(
395 event.fire(cx, self.upcast()),
396 "Guaranteed by DebuggerUnblackboxEvent::new"
397 );
398 }
399
400 pub(crate) fn pipeline_id(&self) -> PipelineId {
401 self.pipeline_id
402 }
403}
404
405impl DebuggerGlobalScopeMethods<crate::DomTypeHolder> for DebuggerGlobalScope {
406 fn NotifyNewSource(&self, args: &NotifyNewSource) {
408 let Some(devtools_chan) = self.as_global_scope().devtools_chan() else {
409 return;
410 };
411 let pipeline_id = PipelineId {
412 namespace_id: PipelineNamespaceId(args.pipelineId.namespaceId),
413 index: Index::new(args.pipelineId.index).expect("`pipelineId.index` must not be zero"),
414 };
415
416 if let Some(introduction_type) = args.introductionType.as_ref() {
417 let url_original = args.url.str();
430 let url_original = ServoUrl::parse(&url_original).ok();
432
433 let url_override = args
438 .urlOverride
439 .as_ref()
440 .map(|url| url.str())
441 .and_then(|url| ServoUrl::parse_with_base(url_original.as_ref(), &url).ok());
443
444 if [
448 IntroductionType::INJECTED_SCRIPT_STR,
449 IntroductionType::EVAL_STR,
450 IntroductionType::DEBUGGER_EVAL_STR,
451 IntroductionType::FUNCTION_STR,
452 IntroductionType::JAVASCRIPT_URL_STR,
453 IntroductionType::EVENT_HANDLER_STR,
454 IntroductionType::DOM_TIMER_STR,
455 ]
456 .contains(&&*introduction_type.str()) &&
457 url_override.is_none()
458 {
459 debug!(
460 "Not creating debuggee: `introductionType` is `{introduction_type}` but no valid url"
461 );
462 return;
463 }
464
465 let inline = introduction_type.str() == "inlineScript" && url_override.is_none();
473 let Some(url) = url_override.or(url_original) else {
474 debug!("Not creating debuggee: no valid url");
475 return;
476 };
477
478 let worker_id = args.workerId.as_ref().map(|id| id.parse().unwrap());
479
480 let source_info = SourceInfo {
481 url,
482 introduction_type: introduction_type.str().to_owned(),
483 inline,
484 worker_id,
485 content: (!inline).then(|| args.text.to_string()),
486 content_type: None, spidermonkey_id: args.spidermonkeyId,
488 };
489 if let Err(error) = devtools_chan.send(ScriptToDevtoolsControlMsg::CreateSourceActor(
490 self.devtools_to_script_sender.clone(),
491 pipeline_id,
492 source_info,
493 )) {
494 warn!("Failed to send to devtools server: {error:?}");
495 }
496 } else {
497 debug!("Not creating debuggee for script with no `introductionType`");
498 }
499 }
500
501 fn GetPossibleBreakpointsResult(
502 &self,
503 event: &DebuggerGetPossibleBreakpointsEvent,
504 result: Vec<RecommendedBreakpointLocation>,
505 ) {
506 info!("GetPossibleBreakpointsResult: {event:?} {result:?}");
507 let sender = self
508 .get_possible_breakpoints_result_sender
509 .take()
510 .expect("Guaranteed by Self::fire_get_possible_breakpoints()");
511 let _ = sender.send(
512 result
513 .into_iter()
514 .map(|entry| devtools_traits::RecommendedBreakpointLocation {
515 script_id: entry.scriptId,
516 offset: entry.offset,
517 line_number: entry.lineNumber,
518 column_number: entry.columnNumber,
519 is_step_start: entry.isStepStart,
520 })
521 .collect(),
522 );
523 }
524
525 fn EvalResult(&self, _event: &DebuggerEvalEvent, result: &EvalResult) {
530 let sender = self
531 .eval_result_sender
532 .take()
533 .expect("Guaranteed by Self::fire_eval()");
534
535 let has_exception = result.hasException.unwrap_or(false);
536 let value = match serde_json::from_str::<devtools_traits::DebuggerValue>(
537 &result.serializedValue.str(),
538 ) {
539 Ok(value) => value,
540 Err(error) => {
541 warn!("Failed to parse serialized debugger eval value: {error}");
542 devtools_traits::DebuggerValue::StringValue(
543 "failed to parse eval result".to_string(),
544 )
545 },
546 };
547
548 let exception_message = result
549 .exceptionMessage
550 .as_ref()
551 .map(|message| message.str().to_string());
552
553 let reply = EvaluateJSReply {
554 value,
555 exception_message,
556 has_exception,
557 };
558
559 let _ = sender.send(reply);
560 }
561
562 fn RegisterObjectActor(&self, serialized_value: DOMString) -> Option<DOMString> {
563 let chan = self.upcast::<GlobalScope>().devtools_chan()?;
564 let (tx, rx) = channel::<String>().unwrap();
565
566 let value =
567 match serde_json::from_str::<devtools_traits::DebuggerValue>(&serialized_value.str()) {
568 Ok(value) => value,
569 Err(error) => {
570 warn!("Failed to parse serialized debugger object value: {error}");
571 return None;
572 },
573 };
574
575 let msg = ScriptToDevtoolsControlMsg::CreateObjectActor(tx, value);
576 let _ = chan.send(msg);
577
578 rx.recv().ok().map(DOMString::from)
579 }
580
581 fn PauseAndRespond(
582 &self,
583 pipeline_id: &PipelineIdInit,
584 frame_offset: &FrameOffset,
585 pause_reason: &PauseReason,
586 ) {
587 let pipeline_id = PipelineId {
588 namespace_id: PipelineNamespaceId(pipeline_id.namespaceId),
589 index: Index::new(pipeline_id.index).expect("`pipelineId.index` must not be zero"),
590 };
591
592 let frame_offset = devtools_traits::FrameOffset {
593 actor: frame_offset.frameActorId.clone().into(),
594 column: frame_offset.column,
595 line: frame_offset.line,
596 };
597
598 let pause_reason = devtools_traits::PauseReason {
599 type_: pause_reason.type_.clone().into(),
600 on_next: pause_reason.onNext,
601 };
602
603 if let Some(chan) = self.upcast::<GlobalScope>().devtools_chan() {
604 let msg =
605 ScriptToDevtoolsControlMsg::DebuggerPause(pipeline_id, frame_offset, pause_reason);
606 let _ = chan.send(msg);
607 }
608
609 with_script_thread(|script_thread| {
610 script_thread.enter_debugger_pause_loop();
611 });
612 }
613
614 fn RegisterFrameActor(
615 &self,
616 pipeline_id: &PipelineIdInit,
617 result: &FrameInfo,
618 ) -> Option<DOMString> {
619 let pipeline_id = PipelineId {
620 namespace_id: PipelineNamespaceId(pipeline_id.namespaceId),
621 index: Index::new(pipeline_id.index).expect("`pipelineId.index` must not be zero"),
622 };
623
624 let chan = self.upcast::<GlobalScope>().devtools_chan()?;
625 let (tx, rx) = channel::<String>().unwrap();
626
627 let this_value = match serde_json::from_str::<devtools_traits::DebuggerValue>(
628 &result.serializedThis.str(),
629 ) {
630 Ok(this_value) => this_value,
631 Err(error) => {
632 warn!("Failed to parse serialized debugger frame this value: {error}");
633 return None;
634 },
635 };
636
637 let frame = devtools_traits::FrameInfo {
638 display_name: result.displayName.clone().map(String::from),
639 on_stack: result.onStack,
640 oldest: result.oldest,
641 this_value,
642 terminated: result.terminated,
643 type_: result.type_.clone().into(),
644 url: result.url.clone().into(),
645 };
646 let msg = ScriptToDevtoolsControlMsg::CreateFrameActor(tx, pipeline_id, frame);
647 let _ = chan.send(msg);
648
649 rx.recv().ok().map(DOMString::from)
650 }
651
652 fn ListFramesResult(&self, frame_actor_ids: Vec<DOMString>) {
653 info!("ListFramesResult: {frame_actor_ids:?}");
654 let sender = self
655 .get_list_frame_result_sender
656 .take()
657 .expect("Guaranteed by Self::fire_list_frames()");
658
659 let _ = sender.send(frame_actor_ids.into_iter().map(|i| i.into()).collect());
660 }
661
662 fn RegisterEnvironmentActor(
663 &self,
664 environment: &EnvironmentInfo,
665 parent: Option<DOMString>,
666 actor: Option<DOMString>,
667 ) -> Option<DOMString> {
668 let chan = self.upcast::<GlobalScope>().devtools_chan()?;
669 let (tx, rx) = channel::<String>().unwrap();
670
671 let binding_variables = match serde_json::from_str::<Vec<devtools_traits::PropertyDescriptor>>(
672 &environment.serializedBindings.str(),
673 ) {
674 Ok(binding_variables) => binding_variables,
675 Err(error) => {
676 warn!("Failed to parse serialized debugger environment bindings: {error}");
677 return None;
678 },
679 };
680 let object = match environment.serializedObject.as_ref() {
681 Some(serialized_object) => {
682 match serde_json::from_str::<DebuggerValue>(&serialized_object.str()) {
683 Ok(object) => Some(object),
684 Err(error) => {
685 warn!("Failed to parse serialized debugger environment object: {error}");
686 return None;
687 },
688 }
689 },
690 None => None,
691 };
692 let environment = devtools_traits::EnvironmentInfo {
693 type_: environment.type_.clone().map(String::from),
694 scope_kind: environment.scopeKind.clone().map(String::from),
695 function_display_name: environment.functionDisplayName.clone().map(String::from),
696 object,
697 binding_variables,
698 };
699
700 let msg = ScriptToDevtoolsControlMsg::CreateEnvironmentActor(
701 tx,
702 environment,
703 parent.map(String::from),
704 actor.map(String::from),
705 );
706 let _ = chan.send(msg);
707
708 rx.recv().ok().map(DOMString::from)
709 }
710
711 fn GetEnvironmentResult(&self, environment_actor_id: DOMString) {
712 let sender = self
713 .get_environment_result_sender
714 .take()
715 .expect("Guaranteed by Self::fire_get_environment()");
716
717 let _ = sender.send(environment_actor_id.into());
718 }
719}
720
721impl HasOrigin for DebuggerGlobalScope {
722 fn origin(&self) -> MutableOrigin {
723 DebuggerGlobalScope::origin(self)
724 }
725}