From d5e41805f6e56bfe87ee8750d002c855ccf32ec6 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Fri, 21 Aug 2026 13:14:41 +0800 Subject: [PATCH] refactor(renderer): bind document task capabilities atomically --- .../src/document_runtime/lifecycle.rs | 25 ++++++++++++++++--- .../main_parser_continuation.rs | 2 +- .../src/document_runtime/runtime_core.rs | 6 +++-- moli-renderer-v8/src/host/scripts.rs | 19 ++++++-------- .../src/native_bridge/context_host/core.rs | 25 ++++++------------- .../page_task_queue/main_document_runtime.rs | 4 +++ moli-renderer-v8/src/script_vm.rs | 8 ++---- 7 files changed, 48 insertions(+), 41 deletions(-) diff --git a/moli-renderer-v8/src/document_runtime/lifecycle.rs b/moli-renderer-v8/src/document_runtime/lifecycle.rs index ca04f73588..8173c287e7 100644 --- a/moli-renderer-v8/src/document_runtime/lifecycle.rs +++ b/moli-renderer-v8/src/document_runtime/lifecycle.rs @@ -44,7 +44,7 @@ impl DocumentRuntime { self.main_document_script_preloads = store; } - pub(crate) fn bind_main_document_runtime_producer( + pub(super) fn bind_main_document_runtime_producer( &mut self, owner: crate::frame_owner_model::FrameDocumentTaskOwner, ) -> bool { @@ -59,7 +59,7 @@ impl DocumentRuntime { .has_main_document_runtime_route() } - pub(crate) fn bind_stylesheet_task_producer( + pub(super) fn bind_stylesheet_task_producer( &mut self, owner: crate::frame_owner_model::FrameDocumentTaskOwner, ) { @@ -74,6 +74,24 @@ impl DocumentRuntime { self.stylesheet_lifecycle.task_producer = Some(producer); } + /// Installs every Page task capability for one exact main Document as one + /// synchronous owner transaction. Callers cannot publish work while only + /// a subset of the runtime, stylesheet, and parser routes has advanced. + pub(crate) fn replace_main_document_task_capabilities( + &mut self, + owner: crate::frame_owner_model::FrameDocumentTaskOwner, + ) -> bool { + assert_eq!( + self.main_frame_document_task_owner(), + Some(owner), + "main Document task capabilities must match the runtime incarnation" + ); + let main_runtime_route_bound = self.bind_main_document_runtime_producer(owner); + self.bind_stylesheet_task_producer(owner); + self.bind_main_parser_continuation_producer(owner); + main_runtime_route_bound + } + pub(crate) fn enqueue_main_document_completion_recheck( &mut self, owner: crate::frame_owner_model::FrameDocumentTaskOwner, @@ -280,7 +298,7 @@ impl DocumentRuntime { } /// Completes the exact owner transaction started by [`Self::open_document`]. - pub(crate) fn commit_main_document_open(&mut self, owner: FrameDocumentTaskOwner) { + pub(crate) fn commit_main_document_open(&mut self, owner: FrameDocumentTaskOwner) -> bool { assert!( matches!( self.document_incarnation, @@ -289,6 +307,7 @@ impl DocumentRuntime { "main Document open must invalidate its retired incarnation before commit" ); self.document_incarnation = DocumentRuntimeIncarnationIdentity::MainFrame(owner); + self.replace_main_document_task_capabilities(owner) } pub(crate) fn parser_module_scripts(&self) -> &ModuleScriptContinuationStore { diff --git a/moli-renderer-v8/src/document_runtime/main_parser_continuation.rs b/moli-renderer-v8/src/document_runtime/main_parser_continuation.rs index 90782c3973..613cb72f6c 100644 --- a/moli-renderer-v8/src/document_runtime/main_parser_continuation.rs +++ b/moli-renderer-v8/src/document_runtime/main_parser_continuation.rs @@ -39,7 +39,7 @@ impl MainParserContinuationState { } impl DocumentRuntime { - pub(crate) fn bind_main_parser_continuation_producer(&mut self, owner: FrameDocumentTaskOwner) { + pub(super) fn bind_main_parser_continuation_producer(&mut self, owner: FrameDocumentTaskOwner) { self.main_parser_continuation.producer = Some(self.main_parser_continuation.sender.bind_producer(owner)); self.main_parser_continuation.admitted = false; diff --git a/moli-renderer-v8/src/document_runtime/runtime_core.rs b/moli-renderer-v8/src/document_runtime/runtime_core.rs index a7c9517245..6130faf61f 100644 --- a/moli-renderer-v8/src/document_runtime/runtime_core.rs +++ b/moli-renderer-v8/src/document_runtime/runtime_core.rs @@ -22,14 +22,16 @@ impl DocumentRuntime { stylesheet_task_sender: crate::page_task_queue::RendererPageStylesheetTaskSender, main_parser_continuation_sender: crate::page_task_queue::RendererPageMainParserContinuationSender, ) -> Self { - Self::from_dom_host_with_incarnation( + let mut runtime = Self::from_dom_host_with_incarnation( dom_host, DocumentRuntimeIncarnationIdentity::MainFrame(main_document_owner), page_task_tx, page_task_parser_boundary_injection_tx, stylesheet_task_sender, main_parser_continuation_sender, - ) + ); + runtime.replace_main_document_task_capabilities(main_document_owner); + runtime } pub(crate) fn main_frame_document_task_owner( diff --git a/moli-renderer-v8/src/host/scripts.rs b/moli-renderer-v8/src/host/scripts.rs index ec7f33f552..1fdd687a80 100644 --- a/moli-renderer-v8/src/host/scripts.rs +++ b/moli-renderer-v8/src/host/scripts.rs @@ -54,7 +54,6 @@ pub(crate) struct HostScriptScheduler { pending_failed_dynamic_scripts: VecDeque, page_task_tx: Option, main_document_runtime_producer: Option, - main_document_runtime_target: Option, main_document_completion_recheck_turn_queued: bool, dynamic_module_job_turn_queued: bool, native_module_owner_event_turn_queued: bool, @@ -301,7 +300,6 @@ impl Default for HostScriptScheduler { pending_failed_dynamic_scripts: VecDeque::new(), page_task_tx: None, main_document_runtime_producer: None, - main_document_runtime_target: None, main_document_completion_recheck_turn_queued: false, dynamic_module_job_turn_queued: false, native_module_owner_event_turn_queued: false, @@ -424,7 +422,6 @@ impl HostScriptScheduler { self.pending_failed_dynamic_scripts.clear(); } self.main_document_runtime_producer = None; - self.main_document_runtime_target = None; self.main_document_completion_recheck_turn_queued = false; self.dynamic_module_job_turn_queued = false; self.native_module_owner_event_turn_queued = false; @@ -1227,18 +1224,17 @@ impl HostScriptScheduler { &mut self, owner: crate::frame_owner_model::FrameDocumentTaskOwner, ) -> bool { - let next_target = owner; - if self.main_document_runtime_target != Some(next_target) { + if self + .main_document_runtime_producer + .as_ref() + .is_none_or(|producer| producer.document_owner() != owner) + { self.main_document_completion_recheck_turn_queued = false; } self.main_document_runtime_producer = self .page_task_tx .as_ref() .map(|tx| tx.bind_main_document_runtime_producer(owner)); - self.main_document_runtime_target = self - .main_document_runtime_producer - .as_ref() - .map(|_| next_target); self.dynamic_module_job_turn_queued = false; self.native_module_owner_event_turn_queued = false; self.admit_ready_dynamic_module_job(); @@ -1312,8 +1308,9 @@ impl HostScriptScheduler { owner: crate::frame_owner_model::FrameDocumentTaskOwner, ) -> bool { if self - .main_document_runtime_target - .is_none_or(|target_owner| target_owner != owner) + .main_document_runtime_producer + .as_ref() + .is_none_or(|producer| producer.document_owner() != owner) { return false; } diff --git a/moli-renderer-v8/src/native_bridge/context_host/core.rs b/moli-renderer-v8/src/native_bridge/context_host/core.rs index bc06ed0b6e..b5d2fb2dcf 100644 --- a/moli-renderer-v8/src/native_bridge/context_host/core.rs +++ b/moli-renderer-v8/src/native_bridge/context_host/core.rs @@ -515,29 +515,18 @@ impl JsContextHost { .expect("main document owner must exist before document.open() replacement"); { let runtime: &mut DocumentRuntime = self; - runtime.commit_main_document_open(transition.current_owner()); + let main_runtime_route_bound = + runtime.commit_main_document_open(transition.current_owner()); + assert_eq!( + main_runtime_route_bound, + runtime.has_main_document_runtime_route(), + "document.open() must replace every main Document task capability" + ); runtime.start_root_document_parser_stream(); } self.dom_agent_state .reset_for_document_replacement(transition.current_owner().document_id); self.replace_main_document_resource_loader(transition); - let main_runtime_route_expected = { - let runtime: &DocumentRuntime = self; - runtime.has_main_document_runtime_route() - }; - let main_runtime_route_bound = { - let runtime: &mut DocumentRuntime = self; - runtime.bind_main_document_runtime_producer(transition.current_owner()) - }; - assert_eq!( - main_runtime_route_bound, main_runtime_route_expected, - "document.open() must replace the exact main runtime producer with the owner transaction" - ); - { - let runtime: &mut DocumentRuntime = self; - runtime.bind_stylesheet_task_producer(transition.current_owner()); - runtime.bind_main_parser_continuation_producer(transition.current_owner()); - } let rebound_meta_refresh = { let runtime: &mut DocumentRuntime = self; runtime.rebind_top_level_meta_refresh_after_document_open(transition.current_owner()) diff --git a/moli-renderer-v8/src/page_task_queue/main_document_runtime.rs b/moli-renderer-v8/src/page_task_queue/main_document_runtime.rs index 556e0e6056..df1fd7e8aa 100644 --- a/moli-renderer-v8/src/page_task_queue/main_document_runtime.rs +++ b/moli-renderer-v8/src/page_task_queue/main_document_runtime.rs @@ -227,6 +227,10 @@ pub(crate) struct RendererPageMainDocumentRuntimeProducer { } impl RendererPageMainDocumentRuntimeProducer { + pub(crate) const fn document_owner(&self) -> FrameDocumentTaskOwner { + self.document_owner + } + fn send_action( &self, action: RendererPageMainDocumentRuntimeAction, diff --git a/moli-renderer-v8/src/script_vm.rs b/moli-renderer-v8/src/script_vm.rs index ba3f8c3374..b7dcd56385 100644 --- a/moli-renderer-v8/src/script_vm.rs +++ b/moli-renderer-v8/src/script_vm.rs @@ -1941,14 +1941,10 @@ impl ScriptVmPageRealmBootstrap { .borrow_mut() .register_main_document_resource_loader(&initial_document_loader); document_runtime.set_cookie_store(initial_document_loader.request_client().cookie_store()); - let main_runtime_route_bound = - document_runtime.bind_main_document_runtime_producer(main_document_owner); - document_runtime.bind_stylesheet_task_producer(main_document_owner); - document_runtime.bind_main_parser_continuation_producer(main_document_owner); assert_eq!( - main_runtime_route_bound, + document_runtime.has_main_document_runtime_route(), page_runtime_wake_tx.has_main_document_runtime_route(), - "main Document runtime producer binding must match the PageVm route capability" + "main Document runtime construction must match the PageVm route capability" ); { let context_host = context_host.borrow();