mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Reviewable per commits: As noted in https://github.com/servo/servo/pull/42180#discussion_r2749861902 transmuting `&Reflector<AssociatedMemory>` to `&Reflector<()>` will ignore AssociatedMemory information and thus it will not remove extra associated memory. By returning `&Reflector<Self::ReflectorType>` from `DomObject::reflector()` we will preserve this information and thus correctly handle cases with associated memory. We also do not need `overrideMemoryUsage` in bindings.conf anymore. 🎉 Instead of removing associated memory in drop code we should do it as part of finalizers, otherwise we have problems in nested (inherited) structs, where drop is run for both parent and child, but we only added associated memory for child (on init_reflector) which already included size of parent. The only exception here is promise, because it is RCed and not finalized. Testing: Tested locally that it fixes speedometer. Fixes #42269 --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
81 lines
2.8 KiB
Rust
81 lines
2.8 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
//! Generic finalizer implementations for DOM binding implementations.
|
|
|
|
use std::any::type_name;
|
|
use std::{mem, ptr};
|
|
|
|
use js::glue::JS_GetReservedSlot;
|
|
use js::jsapi::JSObject;
|
|
use js::jsval::UndefinedValue;
|
|
use js::rust::GCMethods;
|
|
|
|
use crate::DomObject;
|
|
use crate::codegen::PrototypeList::PROTO_OR_IFACE_LENGTH;
|
|
use crate::utils::{ProtoOrIfaceArray, get_proto_or_iface_array};
|
|
use crate::weakref::{DOM_WEAK_SLOT, WeakBox, WeakReferenceable};
|
|
|
|
/// Drop the resources held by reserved slots of a global object
|
|
unsafe fn do_finalize_global(obj: *mut JSObject) {
|
|
unsafe {
|
|
let protolist = get_proto_or_iface_array(obj);
|
|
let list = (*protolist).as_mut_ptr();
|
|
for idx in 0..PROTO_OR_IFACE_LENGTH as isize {
|
|
let entry = list.offset(idx);
|
|
let value = *entry;
|
|
<*mut JSObject>::post_barrier(entry, value, ptr::null_mut());
|
|
}
|
|
let _: Box<ProtoOrIfaceArray> = Box::from_raw(protolist);
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// `this` must point to a valid, non-null instance of T.
|
|
pub(crate) unsafe fn finalize_common<T: DomObject>(this: *const T) {
|
|
if !this.is_null() {
|
|
// The pointer can be null if the object is the unforgeable holder of that interface.
|
|
let this = unsafe { Box::from_raw(this as *mut T) };
|
|
this.reflector().drop_memory(&*this);
|
|
}
|
|
debug!("{} finalize: {:p}", type_name::<T>(), this);
|
|
}
|
|
|
|
/// # Safety
|
|
/// `obj` must point to a valid, non-null JS object.
|
|
/// `this` must point to a valid, non-null instance of T.
|
|
pub(crate) unsafe fn finalize_global<T: DomObject>(obj: *mut JSObject, this: *const T) {
|
|
unsafe {
|
|
do_finalize_global(obj);
|
|
finalize_common::<T>(this);
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// `obj` must point to a valid, non-null JS object.
|
|
/// `this` must point to a valid, non-null instance of T.
|
|
pub(crate) unsafe fn finalize_weak_referenceable<T: WeakReferenceable>(
|
|
obj: *mut JSObject,
|
|
this: *const T,
|
|
) {
|
|
let mut slot = UndefinedValue();
|
|
unsafe { JS_GetReservedSlot(obj, DOM_WEAK_SLOT, &mut slot) };
|
|
let weak_box_ptr = slot.to_private() as *mut WeakBox<T>;
|
|
if !weak_box_ptr.is_null() {
|
|
let count = {
|
|
let weak_box = unsafe { &*weak_box_ptr };
|
|
assert!(weak_box.value.get().is_some());
|
|
assert!(weak_box.count.get() > 0);
|
|
weak_box.value.set(None);
|
|
let count = weak_box.count.get() - 1;
|
|
weak_box.count.set(count);
|
|
count
|
|
};
|
|
if count == 0 {
|
|
mem::drop(unsafe { Box::from_raw(weak_box_ptr) });
|
|
}
|
|
}
|
|
unsafe { finalize_common::<T>(this) };
|
|
}
|