Fix crash when using builtin memory profiler (#35058)

* script: Don't store explicit global roots inside timer storage.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

* script: Expose hook for MallocConditionalSizeOf usage.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-01-18 23:39:31 -05:00 committed by GitHub
parent 9f4787f006
commit 94bca310f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 5 deletions

View file

@ -8,7 +8,8 @@
#![allow(dead_code)]
use core::ffi::c_char;
use std::cell::Cell;
use std::cell::{Cell, LazyCell, RefCell};
use std::collections::HashSet;
use std::ffi::CString;
use std::io::{stdout, Write};
use std::ops::Deref;
@ -811,6 +812,10 @@ fn in_range<T: PartialOrd + Copy>(val: T, min: T, max: T) -> Option<T> {
}
}
thread_local!(static SEEN_POINTERS: LazyCell<RefCell<HashSet<*const c_void>>> = const {
LazyCell::new(|| RefCell::new(HashSet::new()))
});
#[allow(unsafe_code)]
unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
match get_dom_class(obj) {
@ -820,7 +825,13 @@ unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
if dom_object.is_null() {
return 0;
}
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
let seen_pointer =
move |ptr| SEEN_POINTERS.with(|pointers| !pointers.borrow_mut().insert(ptr));
let mut ops = MallocSizeOfOps::new(
servo_allocator::usable_size,
None,
Some(Box::new(seen_pointer)),
);
(v.malloc_size_of)(&mut ops, dom_object)
},
Err(_e) => 0,
@ -946,6 +957,7 @@ impl JSContext {
#[allow(unsafe_code)]
pub(crate) fn get_reports(&self, path_seg: String) -> Vec<Report> {
SEEN_POINTERS.with(|pointers| pointers.borrow_mut().clear());
let stats = unsafe {
let mut stats = ::std::mem::zeroed();
if !CollectServoSizes(self.0, &mut stats, Some(get_size)) {

View file

@ -22,7 +22,7 @@ use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::root::Dom;
use crate::dom::bindings::str::DOMString;
use crate::dom::document::FakeRequestAnimationFrameCallback;
use crate::dom::eventsource::EventSourceTimeoutCallback;
@ -40,8 +40,9 @@ use crate::task_source::SendableTaskSource;
pub(crate) struct OneshotTimerHandle(i32);
#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct OneshotTimers {
global_scope: DomRoot<GlobalScope>,
global_scope: Dom<GlobalScope>,
js_timers: JsTimers,
next_timer_handle: Cell<OneshotTimerHandle>,
timers: DomRefCell<Vec<OneshotTimer>>,
@ -121,7 +122,7 @@ impl PartialEq for OneshotTimer {
impl OneshotTimers {
pub(crate) fn new(global_scope: &GlobalScope) -> OneshotTimers {
OneshotTimers {
global_scope: DomRoot::from_ref(global_scope),
global_scope: Dom::from_ref(global_scope),
js_timers: JsTimers::default(),
next_timer_handle: Cell::new(OneshotTimerHandle(1)),
timers: DomRefCell::new(Vec::new()),