From 40a0ecc65f89d6d34c910996168a3a0e6d5bdadb Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Wed, 19 May 2021 17:29:23 +0000 Subject: [PATCH] Bug 1709935 - Support XPCOM refcount logging with rust-xpcom, r=xpcom-reviewers,mccr8 Differential Revision: https://phabricator.services.mozilla.com/D115086 --- toolkit/library/rust/shared/Cargo.toml | 2 +- xpcom/rust/xpcom/Cargo.toml | 1 + xpcom/rust/xpcom/src/refptr.rs | 54 ++++++++++++++++++++++++ xpcom/rust/xpcom/xpcom_macros/src/lib.rs | 31 +++++++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 8b8486f77294..88fcb30cb8e8 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -85,7 +85,7 @@ cubeb-remoting = ["cubeb-sys", "audioipc-client", "audioipc-server"] cubeb_coreaudio_rust = ["cubeb-sys", "cubeb-coreaudio"] cubeb_pulse_rust = ["cubeb-sys", "cubeb-pulse"] gecko_debug = ["geckoservo/gecko_debug", "nsstring/gecko_debug"] -gecko_refcount_logging = ["geckoservo/gecko_refcount_logging"] +gecko_refcount_logging = ["geckoservo/gecko_refcount_logging", "xpcom/gecko_refcount_logging"] simd-accel = ["encoding_glue/simd-accel", "jsrust_shared/simd-accel"] moz_memory = [] moz_places = ["bookmark_sync"] diff --git a/xpcom/rust/xpcom/Cargo.toml b/xpcom/rust/xpcom/Cargo.toml index 8de17167b089..0c4566fefa68 100644 --- a/xpcom/rust/xpcom/Cargo.toml +++ b/xpcom/rust/xpcom/Cargo.toml @@ -15,3 +15,4 @@ thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } [features] thread_sanitizer = [] +gecko_refcount_logging = [] diff --git a/xpcom/rust/xpcom/src/refptr.rs b/xpcom/rust/xpcom/src/refptr.rs index 52bbe0821648..55ce0c6dc583 100644 --- a/xpcom/rust/xpcom/src/refptr.rs +++ b/xpcom/rust/xpcom/src/refptr.rs @@ -319,3 +319,57 @@ impl AtomicRefcnt { self.0.load(Ordering::Acquire) as nsrefcnt } } + +#[cfg(feature = "gecko_refcount_logging")] +pub mod trace_refcnt { + use crate::interfaces::nsrefcnt; + + extern "C" { + pub fn NS_LogCtor(aPtr: *mut libc::c_void, aTypeName: *const libc::c_char, aSize: u32); + pub fn NS_LogDtor(aPtr: *mut libc::c_void, aTypeName: *const libc::c_char, aSize: u32); + pub fn NS_LogAddRef( + aPtr: *mut libc::c_void, + aRefcnt: nsrefcnt, + aClass: *const libc::c_char, + aClassSize: u32, + ); + pub fn NS_LogRelease( + aPtr: *mut libc::c_void, + aRefcnt: nsrefcnt, + aClass: *const libc::c_char, + aClassSize: u32, + ); + } +} + +// stub inline methods for the refcount logging functions for when the feature +// is disabled. +#[cfg(not(feature = "gecko_refcount_logging"))] +pub mod trace_refcnt { + use crate::interfaces::nsrefcnt; + + #[inline] + #[allow(non_snake_case)] + pub unsafe extern "C" fn NS_LogCtor(_: *mut libc::c_void, _: *const libc::c_char, _: u32) {} + #[inline] + #[allow(non_snake_case)] + pub unsafe extern "C" fn NS_LogDtor(_: *mut libc::c_void, _: *const libc::c_char, _: u32) {} + #[inline] + #[allow(non_snake_case)] + pub unsafe extern "C" fn NS_LogAddRef( + _: *mut libc::c_void, + _: nsrefcnt, + _: *const libc::c_char, + _: u32, + ) { + } + #[inline] + #[allow(non_snake_case)] + pub unsafe extern "C" fn NS_LogRelease( + _: *mut libc::c_void, + _: nsrefcnt, + _: *const libc::c_char, + _: u32, + ) { + } +} diff --git a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs index aa5b76a18f94..e535d96e90ae 100644 --- a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs +++ b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs @@ -658,7 +658,23 @@ fn xpcom(init: DeriveInput) -> Result { coerce_impl.push(coerce); } + let size_for_logs = if real.generics.params.is_empty() { + quote!(::std::mem::size_of::() as u32) + } else { + // Refcount logging requires all types with the same name to have the + // same size, and generics aren't taken into account when creating our + // name string, so we need to make sure that all possible instantiations + // report the same size. To do that, we fake a size based on the number + // of vtable pointers and the known refcount field. + let fake_size_npointers = bases.len() + 1; + quote!((::std::mem::size_of::() * #fake_size_npointers) as u32) + }; + let (impl_generics, ty_generics, where_clause) = real.generics.split_for_impl(); + let name_for_logs = quote!( + concat!(module_path!(), "::", stringify!(#name #ty_generics), "\0").as_ptr() + as *const ::xpcom::reexports::libc::c_char + ); Ok(quote! { #real @@ -695,12 +711,25 @@ fn xpcom(init: DeriveInput) -> Result { /// Automatically generated implementation of AddRef for nsISupports. #vis unsafe fn AddRef(&self) -> ::xpcom::interfaces::nsrefcnt { - self.__refcnt.inc() + let new = self.__refcnt.inc(); + ::xpcom::trace_refcnt::NS_LogAddRef( + self as *const _ as *mut ::xpcom::reexports::libc::c_void, + new, + #name_for_logs, + #size_for_logs, + ); + new } /// Automatically generated implementation of Release for nsISupports. #vis unsafe fn Release(&self) -> ::xpcom::interfaces::nsrefcnt { let new = self.__refcnt.dec(); + ::xpcom::trace_refcnt::NS_LogRelease( + self as *const _ as *mut ::xpcom::reexports::libc::c_void, + new, + #name_for_logs, + #size_for_logs, + ); if new == 0 { // dealloc ::std::boxed::Box::from_raw(self as *const Self as *mut Self);