Use JSTraceable everywhere

This commit is contained in:
Manish Goregaokar 2014-09-24 03:01:03 +05:30
parent 85f79290a6
commit cc44a3b064
133 changed files with 325 additions and 278 deletions

View file

@ -11,57 +11,51 @@
//! 1. The GC calls `_trace` defined in `FooBinding` during the marking
//! phase. (This happens through `JSClass.trace` for non-proxy bindings, and
//! through `ProxyTraps.trace` otherwise.)
//! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`,
//! defined in `InheritTypes.rs`).
//! 3. `Foo::trace()` calls `Foo::encode()` (an implementation of `Encodable`).
//! This implementation is typically derived by a `#[deriving(Encodable)]`
//! annotation on the Rust struct.
//! 4. For all fields (except those wrapped in `Untraceable`), `Foo::encode()`
//! calls `encode()` on the field.
//!
//! For example, for fields of type `JS<T>`, `JS<T>::encode()` calls
//! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`).
//! This is typically derived via a #[jstraceable] annotation
//! 4. For all fields (except those wrapped in `Untraceable`), `Foo::trace()`
//! calls `trace()` on the field.
//! For example, for fields of type `JS<T>`, `JS<T>::trace()` calls
//! `trace_reflector()`.
//! 6. `trace_reflector()` calls `trace_object()` with the `JSObject` for the
//! reflector.
//! 7. `trace_object()` calls `JS_CallTracer()` to notify the GC, which will
//! add the object to the graph, and will trace that object as well.
//!
//! The untraceable!() macro adds an empty implementation of JSTraceable to
//! a datatype.
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};
use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;
use libc;
use url::Url;
use std::mem;
use std::num;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Encoder};
use url::Url;
use servo_util::atom::Atom;
use servo_util::namespace::Namespace;
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use net::image_cache_task::ImageCacheTask;
use script_traits::ScriptControlChan;
use std::collections::hashmap::HashMap;
use collections::hash::Hash;
use style::PropertyDeclarationBlock;
// IMPORTANT: We rely on the fact that we never attempt to encode DOM objects using
// any encoder but JSTracer. Since we derive trace hooks automatically,
// we are unfortunately required to use generic types everywhere and
// unsafely cast to the concrete JSTracer we actually require.
fn get_jstracer<'a, S: Encoder<E>, E>(s: &'a mut S) -> &'a mut JSTracer {
unsafe {
mem::transmute(s)
impl<T: Reflectable> JSTraceable for JS<T> {
fn trace(&self, trc: *mut JSTracer) {
trace_reflector(trc, "", self.reflector());
}
}
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for JS<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
trace_reflector(get_jstracer(s), "", self.reflector());
Ok(())
}
}
impl<S: Encoder<E>, E> Encodable<S, E> for Reflector {
fn encode(&self, _s: &mut S) -> Result<(), E> {
Ok(())
}
}
untraceable!(Reflector)
/// A trait to allow tracing (only) DOM objects.
pub trait JSTraceable {
@ -122,12 +116,6 @@ impl<T> Untraceable<T> {
}
}
impl<S: Encoder<E>, E, T> Encodable<S, E> for Untraceable<T> {
fn encode(&self, _s: &mut S) -> Result<(), E> {
Ok(())
}
}
impl<T> Deref<T> for Untraceable<T> {
fn deref<'a>(&'a self) -> &'a T {
&self.inner
@ -167,28 +155,88 @@ impl<T> Deref<T> for Traceable<T> {
}
}
impl<S: Encoder<E>, E, T: Encodable<S, E>> Encodable<S, E> for Traceable<RefCell<T>> {
fn encode(&self, s: &mut S) -> Result<(), E> {
self.borrow().encode(s)
impl<T: JSTraceable> JSTraceable for RefCell<T> {
fn trace(&self, trc: *mut JSTracer) {
self.borrow().trace(trc)
}
}
impl<S: Encoder<E>, E, T: Encodable<S, E>+Copy> Encodable<S, E> for Traceable<Cell<T>> {
fn encode(&self, s: &mut S) -> Result<(), E> {
self.deref().get().encode(s)
impl<T: JSTraceable> JSTraceable for Rc<T> {
fn trace(&self, trc: *mut JSTracer) {
self.trace(trc)
}
}
impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*mut JSObject> {
fn encode(&self, s: &mut S) -> Result<(), E> {
trace_object(get_jstracer(s), "object", **self);
Ok(())
impl<T: JSTraceable> JSTraceable for Box<T> {
fn trace(&self, trc: *mut JSTracer) {
self.trace(trc)
}
}
impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
fn encode(&self, s: &mut S) -> Result<(), E> {
trace_jsval(get_jstracer(s), "val", **self);
Ok(())
impl<T: JSTraceable+Copy> JSTraceable for Traceable<Cell<T>> {
fn trace(&self, trc: *mut JSTracer) {
self.deref().get().trace(trc)
}
}
impl<T: JSTraceable+Copy> JSTraceable for Cell<T> {
fn trace(&self, trc: *mut JSTracer) {
self.get().trace(trc)
}
}
impl JSTraceable for Traceable<*mut JSObject> {
fn trace(&self, trc: *mut JSTracer) {
trace_object(trc, "object", **self);
}
}
impl JSTraceable for Traceable<JSVal> {
fn trace(&self, trc: *mut JSTracer) {
trace_jsval(trc, "val", **self);
}
}
// XXXManishearth Check if the following three are optimized to no-ops
// if e.trace() is a no-op (e.g it is an untraceable type)
impl<T: JSTraceable> JSTraceable for Vec<T> {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
e.trace(trc);
}
}
}
impl<T: JSTraceable> JSTraceable for Option<T> {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
self.as_ref().map(|e| e.trace(trc));
}
}
impl<K: Eq+Hash, V: JSTraceable> JSTraceable for HashMap<K, V> {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
e.val1().trace(trc);
}
}
}
untraceable!(bool, f32, f64, String, Url)
untraceable!(SubpageId, WindowSizeData, PipelineId)
untraceable!(uint, u8, u16, u32, u64)
untraceable!(int, i8, i16, i32, i64)
untraceable!(Untraceable<T>)
untraceable!(ImageCacheTask, ScriptControlChan)
untraceable!(Atom, Namespace)
untraceable!(PropertyDeclarationBlock)
impl<'a> JSTraceable for &'a str {
#[inline]
fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}