base: Implement MallocSizeOf for some more types (#43858)

This implements MallocSizeOf for a couple more types and removes some
"ignore_malloc_size_of" throughout the codebase.
- std::path::PathBuf
- tokio::sync::oneshot::Sender
- http::HeaderMap (with a reasonable approximation of iterating over all
headers)
- data_url::Mime by looking at the inner type
- http::Method: Is an enum internally
- urlpattern::Urlpattern: Iterating over all public fields that are
strings as an approximation.

Testing: We cannot test if MallocSizeOf is correct currently.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
Narfinger
2026-04-02 16:13:08 +08:00
committed by GitHub
parent 5fdd425dd2
commit f7d77754ff
17 changed files with 59 additions and 56 deletions

1
Cargo.lock generated
View File

@@ -8024,6 +8024,7 @@ dependencies = [
"atomic_refcell",
"content-security-policy",
"crossbeam-channel",
"data-url",
"encoding_rs",
"euclid",
"http 1.4.0",

View File

@@ -18,6 +18,7 @@ app_units = { workspace = true }
atomic_refcell = { workspace = true }
content-security-policy = { workspace = true }
crossbeam-channel = { workspace = true }
data-url = { workspace = true }
encoding_rs = '0.8'
euclid = { workspace = true }
http = { workspace = true }

View File

@@ -59,7 +59,6 @@ use resvg::usvg::{self, tiny_skia_path};
use style::properties::ComputedValues;
use style::values::generics::length::GenericLengthPercentageOrAuto;
pub use stylo_malloc_size_of::MallocSizeOfOps;
use uuid::Uuid;
/// Trait for measuring the "deep" heap usage of a data structure. This is the
/// most commonly-used of the traits.
@@ -392,6 +391,13 @@ impl<T: MallocSizeOf> MallocSizeOf for std::collections::VecDeque<T> {
}
}
impl MallocSizeOf for std::path::PathBuf {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
// This should be an approximation of the actual size
self.as_os_str().as_encoded_bytes().len()
}
}
impl<A: smallvec::Array> MallocShallowSizeOf for smallvec::SmallVec<A> {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
if self.spilled() {
@@ -1073,6 +1079,12 @@ impl<T> MallocSizeOf for tokio::sync::mpsc::UnboundedSender<T> {
}
}
impl<T> MallocSizeOf for tokio::sync::oneshot::Sender<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
}
}
impl<T> MallocSizeOf for ipc_channel::ipc::IpcSender<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
@@ -1109,6 +1121,22 @@ impl MallocSizeOf for servo_arc::Arc<ComputedValues> {
}
}
impl MallocSizeOf for http::HeaderMap {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
// The headermap in http is more complicated than a simple hashmap
// However, this should give us a reasonable approximation.
self.iter()
.map(|entry| entry.0.size_of(ops) + entry.1.size_of(ops))
.sum()
}
}
impl MallocSizeOf for data_url::mime::Mime {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.type_.size_of(ops) + self.parameters.size_of(ops) + self.subtype.size_of(ops)
}
}
malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
@@ -1117,12 +1145,13 @@ malloc_size_of_is_0!(f32, f64);
malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
malloc_size_of_is_0!(Uuid);
malloc_size_of_is_0!(uuid::Uuid);
malloc_size_of_is_0!(app_units::Au);
malloc_size_of_is_0!(content_security_policy::Destination);
malloc_size_of_is_0!(content_security_policy::sandboxing_directive::SandboxingFlagSet);
malloc_size_of_is_0!(encoding_rs::Decoder);
malloc_size_of_is_0!(http::StatusCode);
malloc_size_of_is_0!(http::Method);
malloc_size_of_is_0!(keyboard_types::Code);
malloc_size_of_is_0!(keyboard_types::Modifiers);
malloc_size_of_is_0!(mime::Mime);
@@ -1154,9 +1183,22 @@ malloc_size_of_is_0!(taffy::Layout);
malloc_size_of_is_0!(time::Duration);
malloc_size_of_is_0!(unicode_bidi::Level);
malloc_size_of_is_0!(unicode_script::Script);
malloc_size_of_is_0!(urlpattern::UrlPattern);
malloc_size_of_is_0!(std::net::TcpStream);
impl MallocSizeOf for urlpattern::UrlPattern {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
// This is an approximation
self.protocol().len() +
self.username().len() +
self.password().len() +
self.hostname().len() +
self.port().len() +
self.pathname().len() +
self.search().len() +
self.hash().len()
}
}
impl<S: tendril::TendrilSink<tendril::fmt::UTF8, A>, A: tendril::Atomicity> MallocSizeOf
for tendril::stream::LossyDecoder<S, A>
{

View File

@@ -17,7 +17,7 @@ use headers::{
use http::header::HeaderValue;
use http::{HeaderMap, Method, StatusCode, header};
use log::{debug, error};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use malloc_size_of_derive::MallocSizeOf;
use net_traits::http_status::HttpStatus;
use net_traits::request::Request;
@@ -55,11 +55,15 @@ impl CacheKey {
}
/// A complete cached resource.
#[derive(Clone)]
#[derive(Clone, MallocSizeOf)]
pub struct CachedResource {
#[conditional_malloc_size_of]
request_headers: Arc<ParkingLotMutex<HeaderMap>>,
#[conditional_malloc_size_of]
body: Arc<ParkingLotMutex<ResponseBody>>,
#[conditional_malloc_size_of]
aborted: Arc<AtomicBool>,
#[conditional_malloc_size_of]
awaiting_body: Arc<ParkingLotMutex<Vec<TokioSender<Data>>>>,
metadata: CachedMetadata,
location_url: Option<Result<ServoUrl, String>>,
@@ -70,27 +74,11 @@ pub struct CachedResource {
last_validated: Instant,
}
impl MallocSizeOf for CachedResource {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
// TODO: self.request_headers.unconditional_size_of(ops) +
self.body.unconditional_size_of(ops) +
self.aborted.unconditional_size_of(ops) +
self.awaiting_body.unconditional_size_of(ops) +
self.metadata.size_of(ops) +
self.location_url.size_of(ops) +
self.https_state.size_of(ops) +
self.status.size_of(ops) +
self.url_list.size_of(ops) +
self.expires.size_of(ops) +
self.last_validated.size_of(ops)
}
}
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone, MallocSizeOf)]
struct CachedMetadata {
/// Headers
#[ignore_malloc_size_of = "Defined in `http` and has private members"]
#[conditional_malloc_size_of]
pub headers: Arc<ParkingLotMutex<HeaderMap>>,
/// Final URL after redirects.
pub final_url: ServoUrl,

View File

@@ -30,7 +30,6 @@ use crate::script_runtime::CanGc;
pub(crate) struct Headers {
reflector_: Reflector,
guard: Cell<Guard>,
#[ignore_malloc_size_of = "Defined in hyper"]
#[no_trace]
header_list: DomRefCell<HyperHeaders>,
}

View File

@@ -376,7 +376,6 @@ pub(crate) struct Window {
test_runner: MutNullableDom<TestRunner>,
/// A handle for communicating messages to the WebGL thread, if available.
#[ignore_malloc_size_of = "channels are hard"]
#[no_trace]
webgl_chan: Option<WebGLChan>,

View File

@@ -168,11 +168,9 @@ pub(crate) struct ServiceWorkerGlobalScope {
/// indicating the sw should stop running,
/// while still draining the task-queue
// and running all enqueued, and not cancelled, tasks.
#[ignore_malloc_size_of = "Defined in std"]
#[no_trace]
time_out_port: Receiver<Instant>,
#[ignore_malloc_size_of = "Defined in std"]
#[no_trace]
swmanager_sender: GenericSender<ServiceWorkerMsg>,

View File

@@ -208,20 +208,16 @@ pub(crate) struct XMLHttpRequest {
response_arraybuffer: HeapBufferSource<ArrayBufferU8>,
#[ignore_malloc_size_of = "Defined in rust-mozjs"]
response_json: Heap<JSVal>,
#[ignore_malloc_size_of = "Defined in hyper"]
#[no_trace]
response_headers: DomRefCell<HeaderMap>,
#[ignore_malloc_size_of = "Defined in hyper"]
#[no_trace]
override_mime_type: DomRefCell<Option<Mime>>,
// Associated concepts
#[ignore_malloc_size_of = "Defined in hyper"]
#[no_trace]
request_method: DomRefCell<Method>,
#[no_trace]
request_url: DomRefCell<Option<ServoUrl>>,
#[ignore_malloc_size_of = "Defined in hyper"]
#[no_trace]
request_headers: DomRefCell<HeaderMap>,
request_body_len: Cell<usize>,

View File

@@ -71,7 +71,7 @@ impl Kind {
/// <https://html.spec.whatwg.org/multipage/#drag-data-store-bitmap>
#[derive(MallocSizeOf)]
struct Bitmap {
#[ignore_malloc_size_of = "RasterImage"]
#[conditional_malloc_size_of]
image: Option<Arc<RasterImage>>,
x: i32,
y: i32,

View File

@@ -7,7 +7,6 @@ use std::sync::Arc;
use std::time::Duration;
use layout_api::AnimatingImages;
use malloc_size_of::MallocSizeOf;
use paint_api::ImageUpdate;
use parking_lot::RwLock;
use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods;
@@ -18,12 +17,13 @@ use crate::dom::node::Node;
use crate::dom::window::Window;
use crate::script_thread::with_script_thread;
#[derive(Clone, Default, JSTraceable)]
#[derive(Clone, Default, JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub struct ImageAnimationManager {
/// The set of [`AnimatingImages`] which is used to communicate the addition
/// and removal of animating images from layout.
#[no_trace]
#[conditional_malloc_size_of]
animating_images: Arc<RwLock<AnimatingImages>>,
/// The [`TimerId`] of the currently scheduled animated image update callback.
@@ -31,12 +31,6 @@ pub struct ImageAnimationManager {
callback_timer_id: Cell<Option<TimerId>>,
}
impl MallocSizeOf for ImageAnimationManager {
fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
(*self.animating_images.read()).size_of(ops)
}
}
impl ImageAnimationManager {
pub(crate) fn animating_images(&self) -> Arc<RwLock<AnimatingImages>> {
self.animating_images.clone()

View File

@@ -192,9 +192,7 @@ impl BroadcastClone for SerializableFileList {
/// File-based blob
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FileBlob {
#[ignore_malloc_size_of = "Uuid are hard(not really)"]
id: Uuid,
#[ignore_malloc_size_of = "PathBuf are hard"]
name: Option<PathBuf>,
cache: RefCell<Option<Vec<u8>>>,
size: u64,

View File

@@ -493,9 +493,7 @@ pub struct PageError {
#[derive(Debug, PartialEq, MallocSizeOf)]
pub struct HttpRequest {
pub url: ServoUrl,
#[ignore_malloc_size_of = "http type"]
pub method: Method,
#[ignore_malloc_size_of = "http type"]
pub headers: HeaderMap,
pub body: Option<DebugVec>,
pub pipeline_id: PipelineId,

View File

@@ -639,13 +639,11 @@ pub struct WebResourceRequest {
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub method: Method,
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
pub url: Url,
pub is_for_main_frame: bool,

View File

@@ -688,7 +688,7 @@ pub fn node_id_from_scroll_id(id: usize) -> usize {
#[derive(Clone, Debug, MallocSizeOf)]
pub struct ImageAnimationState {
#[ignore_malloc_size_of = "RasterImage"]
#[conditional_malloc_size_of]
pub image: Arc<RasterImage>,
pub active_frame: usize,
frame_start_time: f64,

View File

@@ -78,13 +78,11 @@ pub enum LoadContext {
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct CustomResponse {
#[ignore_malloc_size_of = "Defined in hyper"]
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
pub headers: HeaderMap,
#[ignore_malloc_size_of = "Defined in hyper"]
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"

View File

@@ -174,7 +174,6 @@ pub struct PreloadEntry {
/// <https://html.spec.whatwg.org/multipage/#preload-response>
pub response: Option<Response>,
/// <https://html.spec.whatwg.org/multipage/#preload-on-response-available>
#[ignore_malloc_size_of = "Channels are hard"]
pub on_response_available: Option<TokioSender<Response>>,
}
@@ -318,7 +317,7 @@ pub enum BodyChunkRequest {
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct RequestBody {
/// Net's channel to communicate with script re this body.
#[ignore_malloc_size_of = "Channels are hard"]
#[conditional_malloc_size_of]
body_chunk_request_channel: Arc<Mutex<Option<IpcSender<BodyChunkRequest>>>>,
/// <https://fetch.spec.whatwg.org/#concept-body-source>
source: BodySource,
@@ -427,7 +426,6 @@ pub struct RequestBuilder {
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub method: Method,
/// <https://fetch.spec.whatwg.org/#concept-request-url>
@@ -438,7 +436,6 @@ pub struct RequestBuilder {
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
/// <https://fetch.spec.whatwg.org/#unsafe-request-flag>
@@ -782,12 +779,10 @@ pub struct Request {
pub id: RequestId,
pub preload_id: Option<PreloadId>,
/// <https://fetch.spec.whatwg.org/#concept-request-method>
#[ignore_malloc_size_of = "Defined in hyper"]
pub method: Method,
/// <https://fetch.spec.whatwg.org/#local-urls-only-flag>
pub local_urls_only: bool,
/// <https://fetch.spec.whatwg.org/#concept-request-header-list>
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
/// <https://fetch.spec.whatwg.org/#unsafe-request-flag>
pub unsafe_request: bool,

View File

@@ -91,7 +91,6 @@ pub struct ResponseInit {
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
pub status_code: u16,
pub referrer: Option<ServoUrl>,
@@ -110,7 +109,6 @@ pub struct Response {
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
#[conditional_malloc_size_of]
pub body: Arc<Mutex<ResponseBody>>,