diff --git a/Cargo.toml b/Cargo.toml index cd04c81..4db9245 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -258,7 +258,7 @@ opt-level = 3 inherits = "release" lto = true codegen-units = 1 -opt-level = 3 +opt-level = 3 [profile.production-stripped] inherits = "production" diff --git a/forkme.lock b/forkme.lock index 58b6092..780d62c 100644 --- a/forkme.lock +++ b/forkme.lock @@ -1 +1 @@ -217d76c83dc63f5ff91afcb80479ed638b6dce6e +b590c6c8487d3d682005a6b3469124909103d4d0 diff --git a/patches/components/constellation/constellation.rs.patch b/patches/components/constellation/constellation.rs.patch index 60d0a5a..6457a55 100644 --- a/patches/components/constellation/constellation.rs.patch +++ b/patches/components/constellation/constellation.rs.patch @@ -184,9 +184,9 @@ ScriptToConstellationMessage::MediaSessionEvent(pipeline_id, event) => { // Unlikely at this point, but we may receive events coming from // different media sessions, so we set the active media session based -@@ -2052,6 +2130,129 @@ - ScriptToConstellationMessage::RespondToScreenshotReadinessRequest(response) => { - self.handle_screenshot_readiness_response(source_pipeline_id, response); +@@ -2057,6 +2135,129 @@ + let _ = event_loop.send(ScriptThreadMessage::TriggerGarbageCollection); + } }, + ScriptToConstellationMessage::EmbeddedWebViewNotification(event) => { + self.handle_embedded_webview_notification(webview_id, event); @@ -314,7 +314,7 @@ } } -@@ -3164,6 +3365,13 @@ +@@ -3169,6 +3370,13 @@ /// fn handle_close_top_level_browsing_context(&mut self, webview_id: WebViewId) { debug!("{webview_id}: Closing"); @@ -328,7 +328,7 @@ let browsing_context_id = BrowsingContextId::from(webview_id); // Step 5. Remove traversable from the user agent's top-level traversable set. let browsing_context = -@@ -3440,8 +3648,27 @@ +@@ -3445,8 +3653,27 @@ opener_webview_id, opener_pipeline_id, response_sender, @@ -356,7 +356,7 @@ let Some((webview_id_sender, webview_id_receiver)) = generic_channel::channel() else { warn!("Failed to create channel"); let _ = response_sender.send(None); -@@ -3539,6 +3766,359 @@ +@@ -3544,6 +3771,359 @@ }); } @@ -716,7 +716,7 @@ #[servo_tracing::instrument(skip_all)] fn handle_refresh_cursor(&self, pipeline_id: PipelineId) { let Some(pipeline) = self.pipelines.get(&pipeline_id) else { -@@ -4665,7 +5245,7 @@ +@@ -4670,7 +5250,7 @@ } #[servo_tracing::instrument(skip_all)] @@ -725,7 +725,7 @@ // Send a flat projection of the history to embedder. // The final vector is a concatenation of the URLs of the past // entries, the current entry and the future entries. -@@ -4768,9 +5348,23 @@ +@@ -4773,9 +5353,23 @@ ); self.embedder_proxy.send(EmbedderMsg::HistoryChanged( webview_id, diff --git a/patches/components/constellation/tracing.rs.patch b/patches/components/constellation/tracing.rs.patch index 03606f9..4b2d50b 100644 --- a/patches/components/constellation/tracing.rs.patch +++ b/patches/components/constellation/tracing.rs.patch @@ -36,10 +36,10 @@ Self::ActivateDocument => target!("ActivateDocument"), Self::SetDocumentState(..) => target!("SetDocumentState"), Self::SetFinalUrl(..) => target!("SetFinalUrl"), -@@ -185,6 +193,35 @@ - Self::RespondToScreenshotReadinessRequest(..) => { +@@ -186,6 +194,35 @@ target!("RespondToScreenshotReadinessRequest") }, + Self::TriggerGarbageCollection => target!("TriggerGarbageCollection"), + Self::EmbeddedWebViewNotification(..) => { + target!("EmbeddedWebViewNotification") + }, diff --git a/patches/components/script/dom/debuggerglobalscope.rs.patch b/patches/components/script/dom/debuggerglobalscope.rs.patch index c25f67b..1ac6d40 100644 --- a/patches/components/script/dom/debuggerglobalscope.rs.patch +++ b/patches/components/script/dom/debuggerglobalscope.rs.patch @@ -1,6 +1,6 @@ --- original +++ modified -@@ -102,9 +102,11 @@ +@@ -101,9 +101,11 @@ None, #[cfg(feature = "webgpu")] gpu_id_hub, diff --git a/patches/components/script/dom/globalscope.rs.patch b/patches/components/script/dom/globalscope.rs.patch index ea7a0ce..f13026f 100644 --- a/patches/components/script/dom/globalscope.rs.patch +++ b/patches/components/script/dom/globalscope.rs.patch @@ -35,7 +35,7 @@ unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")), byte_length_queuing_strategy_size_function: OnceCell::new(), count_queuing_strategy_size_function: OnceCell::new(), -@@ -3101,6 +3115,16 @@ +@@ -3107,6 +3121,16 @@ self.inherited_secure_context } diff --git a/patches/components/script/dom/html/htmllinkelement.rs.patch b/patches/components/script/dom/html/htmllinkelement.rs.patch index 55a072d..9733023 100644 --- a/patches/components/script/dom/html/htmllinkelement.rs.patch +++ b/patches/components/script/dom/html/htmllinkelement.rs.patch @@ -1,6 +1,6 @@ --- original +++ modified -@@ -697,7 +697,7 @@ +@@ -693,7 +693,7 @@ if !window.is_top_level() { return; } diff --git a/patches/components/script/dom/servointernals.rs.patch b/patches/components/script/dom/servointernals.rs.patch index a91f790..d91977d 100644 --- a/patches/components/script/dom/servointernals.rs.patch +++ b/patches/components/script/dom/servointernals.rs.patch @@ -20,7 +20,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::realms::{AlreadyInRealm, InRealm}; -@@ -132,22 +134,38 @@ +@@ -141,22 +143,38 @@ /// fn GetBoolPreference(&self, name: USVString) -> Fallible { @@ -69,7 +69,7 @@ } Err(Error::TypeMismatch(None)) } -@@ -154,11 +172,19 @@ +@@ -163,11 +181,19 @@ /// fn GetStringPreference(&self, name: USVString) -> Fallible { @@ -94,7 +94,7 @@ } Err(Error::TypeMismatch(None)) } -@@ -165,23 +191,59 @@ +@@ -174,23 +200,59 @@ /// fn SetBoolPreference(&self, name: USVString, value: bool) { @@ -163,7 +163,7 @@ } } -@@ -197,7 +259,10 @@ +@@ -206,7 +268,10 @@ /// The navigator.servo api is exposed to about: pages except about:blank, as /// well as any URLs provided by embedders that register new protocol handlers. #[expect(unsafe_code)] diff --git a/patches/components/script/dom/window.rs.patch b/patches/components/script/dom/window.rs.patch index 288890e..6a41bc4 100644 --- a/patches/components/script/dom/window.rs.patch +++ b/patches/components/script/dom/window.rs.patch @@ -83,7 +83,7 @@ // Step 6: Let userPromptHandler be WebDriver BiDi user prompt opened with this, // "prompt", and message. // TODO: Add support for WebDriver BiDi. -@@ -3030,9 +3058,33 @@ +@@ -3027,9 +3055,33 @@ &self, input_event: &ConstellationInputEvent, ) -> Option { @@ -120,7 +120,7 @@ } #[expect(unsafe_code)] -@@ -3051,8 +3103,25 @@ +@@ -3048,8 +3100,25 @@ // SAFETY: This is safe because `Window::query_elements_from_point` has ensured that // layout has run and any OpaqueNodes that no longer refer to real nodes are gone. let address = UntrustedNodeAddress(result.node.0 as *const c_void); @@ -147,7 +147,7 @@ cursor: result.cursor, point_in_node: result.point_in_target, point_in_frame, -@@ -3733,6 +3802,8 @@ +@@ -3730,6 +3799,8 @@ player_context: WindowGLContext, #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, @@ -156,7 +156,7 @@ theme: Theme, weak_script_thread: Weak, ) -> DomRoot { -@@ -3759,6 +3830,8 @@ +@@ -3756,6 +3827,8 @@ gpu_id_hub, inherited_secure_context, unminify_js, diff --git a/patches/components/script/messaging.rs.patch b/patches/components/script/messaging.rs.patch index 0ef723a..6ad4618 100644 --- a/patches/components/script/messaging.rs.patch +++ b/patches/components/script/messaging.rs.patch @@ -1,9 +1,9 @@ --- original +++ modified -@@ -107,6 +107,8 @@ - ScriptThreadMessage::AccessibilityTreeUpdate(..) => None, +@@ -108,6 +108,8 @@ ScriptThreadMessage::UpdatePinchZoomInfos(id, _) => Some(*id), ScriptThreadMessage::SetAccessibilityActive(..) => None, + ScriptThreadMessage::TriggerGarbageCollection => None, + ScriptThreadMessage::DispatchEmbeddedWebViewEvent { parent, .. } => Some(*parent), + ScriptThreadMessage::DispatchServoError(..) => None, }, diff --git a/patches/components/script/script_thread.rs.patch b/patches/components/script/script_thread.rs.patch index 1ec9900..6422a14 100644 --- a/patches/components/script/script_thread.rs.patch +++ b/patches/components/script/script_thread.rs.patch @@ -59,9 +59,9 @@ }, ScriptThreadMessage::ForwardKeyboardScroll(pipeline_id, scroll) => { if let Some(document) = self.documents.borrow().find_document(pipeline_id) { -@@ -1970,6 +1982,16 @@ - ScriptThreadMessage::SetAccessibilityActive(active) => { - self.set_accessibility_active(active); +@@ -1973,6 +1985,16 @@ + ScriptThreadMessage::TriggerGarbageCollection => unsafe { + JS_GC(*GlobalScope::get_cx(), GCReason::API); }, + ScriptThreadMessage::DispatchEmbeddedWebViewEvent { + target, @@ -76,7 +76,7 @@ } } -@@ -3012,6 +3034,9 @@ +@@ -3015,6 +3037,9 @@ .documents .borrow() .find_iframe(parent_pipeline_id, browsing_context_id); @@ -86,7 +86,7 @@ if let Some(frame_element) = frame_element { frame_element.update_pipeline_id(new_pipeline_id, reason, cx); } -@@ -3031,6 +3056,7 @@ +@@ -3034,6 +3059,7 @@ // is no need to pass along existing opener information that // will be discarded. None, @@ -94,7 +94,7 @@ ); } } -@@ -3307,6 +3333,44 @@ +@@ -3310,6 +3336,44 @@ } } @@ -139,7 +139,7 @@ fn ask_constellation_for_top_level_info( &self, sender_webview_id: WebViewId, -@@ -3421,7 +3485,13 @@ +@@ -3424,7 +3488,13 @@ self.senders.pipeline_to_embedder_sender.clone(), self.senders.constellation_sender.clone(), incomplete.pipeline_id, @@ -154,7 +154,7 @@ incomplete.viewport_details, origin.clone(), final_url.clone(), -@@ -3443,6 +3513,8 @@ +@@ -3446,6 +3516,8 @@ #[cfg(feature = "webgpu")] self.gpu_id_hub.clone(), incomplete.load_data.inherited_secure_context, @@ -163,7 +163,7 @@ incomplete.theme, self.this.clone(), ); -@@ -3466,6 +3538,7 @@ +@@ -3469,6 +3541,7 @@ incomplete.webview_id, incomplete.parent_info, incomplete.opener, @@ -171,7 +171,7 @@ ); if window_proxy.parent().is_some() { // https://html.spec.whatwg.org/multipage/#navigating-across-documents:delaying-load-events-mode-2 -@@ -4197,6 +4270,24 @@ +@@ -4206,6 +4279,24 @@ document.event_handler().handle_refresh_cursor(); } diff --git a/patches/components/shared/constellation/from_script_message.rs.patch b/patches/components/shared/constellation/from_script_message.rs.patch index bfa935a..cef2691 100644 --- a/patches/components/shared/constellation/from_script_message.rs.patch +++ b/patches/components/shared/constellation/from_script_message.rs.patch @@ -119,10 +119,10 @@ /// Mark a new document as active ActivateDocument, /// Set the document state for a pipeline (used by screenshot / reftests) -@@ -724,6 +773,44 @@ - ForwardKeyboardScroll(PipelineId, KeyboardScroll), - /// Notify the Constellation of the screenshot readiness of a given pipeline. +@@ -726,6 +775,44 @@ RespondToScreenshotReadinessRequest(ScreenshotReadinessResponse), + /// Request the constellation to force garbage collection in all `ScriptThread`'s. + TriggerGarbageCollection, + /// Notification from an embedded webview to be forwarded to its parent iframe element. + /// The Constellation will forward this to the parent pipeline's script thread. + EmbeddedWebViewNotification(EmbeddedWebViewEventType), diff --git a/patches/components/shared/script/lib.rs.patch b/patches/components/shared/script/lib.rs.patch index e2d5e14..2f730e7 100644 --- a/patches/components/shared/script/lib.rs.patch +++ b/patches/components/shared/script/lib.rs.patch @@ -35,10 +35,10 @@ } /// When a pipeline is closed, should its browsing context be discarded too? -@@ -308,6 +316,19 @@ - UpdatePinchZoomInfos(PipelineId, PinchZoomInfos), - /// Activate or deactivate accessibility features. +@@ -310,6 +318,19 @@ SetAccessibilityActive(bool), + /// Force a garbage collection in this script thread. + TriggerGarbageCollection, + /// Dispatch an event on an embedded webview's iframe element. + /// This is sent from the constellation when it receives an `EmbeddedWebViewNotification` + /// from an embedded webview's script thread. diff --git a/resources/about-memory.html b/resources/about-memory.html index 7e6e4c1..8fa1de2 100644 --- a/resources/about-memory.html +++ b/resources/about-memory.html @@ -154,6 +154,12 @@ } function start() { + window.gcButton.onclick = async () => { + window.gcButton.disabled = true; + navigator.servo.garbageCollectAllContexts(); + window.gcButton.disabled = false; + }; + window.startButton.onclick = async () => { let content = await navigator.servo.reportMemory(); let reports = JSON.parse(content); @@ -211,6 +217,7 @@

Memory Reports

+