Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a replacement for Vec<Root<T>> #4620

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Implement RootedVec<T>

  • Loading branch information
mukilan authored and jdm committed Mar 1, 2015
commit 0891ceeee61b50f4bd2a48b6e6a6e480341ea706
@@ -54,11 +54,13 @@ use msg::constellation_msg::ConstellationChan;
use util::smallvec::{SmallVec1, SmallVec};
use util::str::{LengthOrPercentageOrAuto};
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::collections::hash_state::HashState;
use std::ffi::CString;
use std::hash::{Hash, Hasher};
use std::intrinsics::return_address;
use std::old_io::timer::Timer;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender};
use string_cache::{Atom, Namespace};
@@ -262,3 +264,136 @@ impl JSTraceable for Box<LayoutRPC+'static> {
// Do nothing
}
}

/// Holds a set of vectors that need to be rooted
pub struct RootedCollectionSet {
set: Vec<HashSet<*const ()>>
}

/// TLV Holds a set of vectors that need to be rooted
thread_local!(pub static ROOTED_COLLECTIONS: Rc<RefCell<RootedCollectionSet>> =
Rc::new(RefCell::new(RootedCollectionSet::new())));

enum CollectionType {
DOMObjects,
JSVals,
JSObjects,
}


impl RootedCollectionSet {
fn new() -> RootedCollectionSet {
RootedCollectionSet {
set: vec!(HashSet::new(), HashSet::new(), HashSet::new())
}
}

fn remove<T: VecRootableType>(collection: &mut RootedVec<T>) {
ROOTED_COLLECTIONS.with(|ref collections| {
let type_ = VecRootableType::tag(None::<T>);
let mut collections = collections.borrow_mut();
assert!(collections.set[type_ as uint].remove(&(collection as *mut _ as *const _)));
});
}

fn add<T: VecRootableType>(collection: &RootedVec<T>) {
ROOTED_COLLECTIONS.with(|ref collections| {
let type_ = VecRootableType::tag(None::<T>);
let mut collections = collections.borrow_mut();
collections.set[type_ as uint].insert(collection as *const _ as *const _);
})
}

unsafe fn trace(&self, tracer: *mut JSTracer) {
fn trace_collection_type<T: JSTraceable>(tracer: *mut JSTracer,
collections: *const HashSet<*const RootedVec<T>>) {
unsafe {
for collection in (*collections).iter() {
let _ = (**collection).trace(tracer);
}
}
}

let dom_collections = &self.set[CollectionType::DOMObjects as uint] as *const _ as *const HashSet<*const RootedVec<*const Reflector>>;
for dom_collection in (*dom_collections).iter() {
for reflector in (**dom_collection).iter() {
trace_reflector(tracer, "", &**reflector);
}
}

trace_collection_type(tracer,
&self.set[CollectionType::JSVals as uint] as *const _ as *const HashSet<*const RootedVec<JSVal>>);
trace_collection_type(tracer,
&self.set[CollectionType::JSObjects as uint] as *const _ as *const HashSet<*const RootedVec<*mut JSObject>>);
}
}


/// Trait implemented by all types that can be used with RootedVec
trait VecRootableType {
/// Return the type tag used to determine how to trace RootedVec
fn tag(_a: Option<Self>) -> CollectionType;
}

impl<T: Reflectable> VecRootableType for JS<T> {
fn tag(_a: Option<JS<T>>) -> CollectionType { CollectionType::DOMObjects }
}

impl VecRootableType for JSVal {
fn tag(_a: Option<JSVal>) -> CollectionType { CollectionType::JSVals }
}

impl VecRootableType for *mut JSObject {
fn tag(_a: Option<*mut JSObject>) -> CollectionType { CollectionType::JSObjects }
}

/// A vector of items that are rooted for the lifetime
/// of this struct
#[allow(unrooted_must_root)]
#[jstraceable]
pub struct RootedVec<T> {
v: Vec<T>
}


impl<T: VecRootableType> RootedVec<T> {
/// Create a vector of items of type T that is rooted for
/// the lifetime of this struct
pub fn new() -> RootedVec<T> {
let ret = RootedVec::<T> { v: vec!() };
unsafe {
RootedCollectionSet::add::<T>(&*(return_address() as *const _));
}
ret
}

}

#[unsafe_destructor]
impl<T: VecRootableType> Drop for RootedVec<T> {
fn drop(&mut self) {
RootedCollectionSet::remove(self);
}
}

impl<T> Deref for RootedVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> {
&self.v
}
}

impl<T> DerefMut for RootedVec<T> {
fn deref_mut(&mut self) -> &mut Vec<T> {
&mut self.v
}
}


/// SM Callback that traces the rooted collections
pub unsafe extern fn trace_collections(tracer: *mut JSTracer, _data: *mut libc::c_void) {
ROOTED_COLLECTIONS.with(|ref collections| {
let collections = collections.borrow();
collections.trace(tracer);
});
}
@@ -16,7 +16,7 @@ use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, RootedReference}
use dom::bindings::js::{RootCollection, RootCollectionPtr};
use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference};
use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::trace::JSTraceable;
use dom::bindings::trace::{JSTraceable, trace_collections};
use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap};
use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressHandler, DocumentProgressTask, DocumentSource};
use dom::element::{Element, AttributeHandlers};
@@ -63,7 +63,7 @@ use geom::point::Point2D;
use hyper::header::{LastModified, Headers};
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
use js::jsapi::{JSContext, JSRuntime, JSObject};
use js::jsapi::{JS_SetGCParameter, JSGC_MAX_BYTES};
use js::jsapi::{JS_SetExtraGCRootsTracer, JS_SetGCParameter, JSGC_MAX_BYTES};
use js::jsapi::{JS_SetGCCallback, JSGCStatus, JSGC_BEGIN, JSGC_END};
use js::rust::{Cx, RtUtils};
use js;
@@ -75,6 +75,7 @@ use std::borrow::ToOwned;
use std::cell::Cell;
use std::mem::replace;
use std::num::ToPrimitive;
use std::ptr;
use std::rc::Rc;
use std::result::Result;
use std::sync::mpsc::{channel, Sender, Receiver, Select};
@@ -380,12 +381,17 @@ impl ScriptTask {

pub fn new_rt_and_cx() -> (js::rust::rt, Rc<Cx>) {
LiveDOMReferences::initialize();

let js_runtime = js::rust::rt();
assert!({
let ptr: *mut JSRuntime = (*js_runtime).ptr;
!ptr.is_null()
});


unsafe {
JS_SetExtraGCRootsTracer((*js_runtime).ptr, Some(trace_collections), ptr::null_mut());
}
// Unconstrain the runtime's threshold on nominal heap size, to avoid
// triggering GC too often if operating continuously near an arbitrary
// finite threshold. This leaves the maximum-JS_malloc-bytes threshold
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.