diff options
Diffstat (limited to 'components/script_bindings/finalize.rs')
-rw-r--r-- | components/script_bindings/finalize.rs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/components/script_bindings/finalize.rs b/components/script_bindings/finalize.rs new file mode 100644 index 00000000000..fa1079b5624 --- /dev/null +++ b/components/script_bindings/finalize.rs @@ -0,0 +1,74 @@ +/* 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::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) { + 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 unsafe fn finalize_common<T>(this: *const T) { + if !this.is_null() { + // The pointer can be null if the object is the unforgeable holder of that interface. + let _ = Box::from_raw(this as *mut T); + } + 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 unsafe fn finalize_global<T>(obj: *mut JSObject, this: *const T) { + 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 unsafe fn finalize_weak_referenceable<T: WeakReferenceable>( + obj: *mut JSObject, + this: *const T, +) { + let mut slot = UndefinedValue(); + 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 = &*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(Box::from_raw(weak_box_ptr)); + } + } + finalize_common::<T>(this); +} |