From 770089c0ca7dbfcee71245556b371ed93cabe33a Mon Sep 17 00:00:00 2001 From: BREW <81044362+b-re-w@users.noreply.github.com> Date: Tue, 10 Nov 2026 04:31:13 +0900 Subject: [PATCH] Fix: Read browser memory in place in the tab strip, app window and browser readers The tab strip's, the app window's and the browser access layer's readers made a system call for every word of browser memory, as the second view's did. Memory already known readable is now read in place, with ReadProcessMemory kept for the rest. The top bar's own repaint traces its steps when it takes 2 ms or more. Co-Authored-By: Claude Opus 5.5 --- rivet/runtime/windows/src/browser/chromium.rs | 4 ++++ rivet/runtime/windows/src/features/app_window.rs | 3 +++ rivet/runtime/windows/src/features/tab_strip.rs | 5 +++++ rivet/runtime/windows/src/frame.rs | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/rivet/runtime/windows/src/browser/chromium.rs b/rivet/runtime/windows/src/browser/chromium.rs index 59ffa51..f5131c5 100644 --- a/rivet/runtime/windows/src/browser/chromium.rs +++ b/rivet/runtime/windows/src/browser/chromium.rs @@ -104,6 +104,10 @@ impl TabMoves for Chromium { fn read_word(address: usize) -> Option { use windows_sys::Win32::System::Diagnostics::Debug::ReadProcessMemory; use windows_sys::Win32::System::Threading::GetCurrentProcess; + // A word known readable is read in place, without a system call. + if let Some(value) = crate::chromium::memory::read_word(address) { + return Some(value); + } let mut value = 0usize; let mut done = 0usize; // ReadProcessMemory fails, instead of faulting, on an address that is not mapped. diff --git a/rivet/runtime/windows/src/features/app_window.rs b/rivet/runtime/windows/src/features/app_window.rs index 26b60bd..87dd96e 100644 --- a/rivet/runtime/windows/src/features/app_window.rs +++ b/rivet/runtime/windows/src/features/app_window.rs @@ -402,6 +402,9 @@ pub(crate) unsafe fn flip_new_tab(window: HWND, offsets: &[usize]) -> bool { unsafe fn safe_word(address: usize) -> Option { use windows_sys::Win32::System::Diagnostics::Debug::ReadProcessMemory; use windows_sys::Win32::System::Threading::GetCurrentProcess; + if let Some(value) = crate::chromium::memory::read_word(address) { + return Some(value); + } let mut value = 0usize; let mut done = 0usize; let ok = ReadProcessMemory( diff --git a/rivet/runtime/windows/src/features/tab_strip.rs b/rivet/runtime/windows/src/features/tab_strip.rs index c8e37cd..cd156af 100644 --- a/rivet/runtime/windows/src/features/tab_strip.rs +++ b/rivet/runtime/windows/src/features/tab_strip.rs @@ -147,6 +147,11 @@ const BOUNDS: usize = 0x1C0; /// A word of memory that may not belong to a view, read so that a wrong guess cannot fault. unsafe fn read(address: usize, bytes: usize, out: *mut u8) -> bool { use windows_sys::Win32::System::Diagnostics::Debug::ReadProcessMemory; + // Memory known readable is copied in place, without a system call for every word. + if address > 0x10000 && crate::chromium::memory::readable(address, bytes) { + std::ptr::copy_nonoverlapping(address as *const u8, out, bytes); + return true; + } address > 0x10000 && ReadProcessMemory( windows_sys::Win32::System::Threading::GetCurrentProcess(), diff --git a/rivet/runtime/windows/src/frame.rs b/rivet/runtime/windows/src/frame.rs index 0f6f243..8dc07c3 100644 --- a/rivet/runtime/windows/src/frame.rs +++ b/rivet/runtime/windows/src/frame.rs @@ -3125,12 +3125,14 @@ pub(crate) unsafe fn update_top_bar(window: HWND) { if crate::features::address_bar::busy() { return; } + let mut laps = Laps::start(); let dpi = layout_dpi(window); let top_bar = if framed(window) { crate::features::address_bar::view(window) } else { None }; + laps.mark("view"); APPBARS.with(|appbars| { if let Some(appbar) = appbars.borrow_mut().get_mut(&(window as isize)) { if let Err(error) = appbar.update_address(window as isize, top_bar.as_ref(), dpi) { @@ -3138,6 +3140,10 @@ pub(crate) unsafe fn update_top_bar(window: HWND) { } } }); + laps.mark("paint"); + if laps.total_us() >= SLOW_UPDATE_US && crate::trace::tracing() { + crate::trace::trace(&laps.line().replacen("appbar:", "top bar:", 1)); + } } /// The steps of one surface update and how long each took, in microseconds.