Skip to content

Commit

Permalink
Implement RootedVec<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
mukilan authored and Ms2ger committed Mar 29, 2015
1 parent 4cf76d6 commit e8a1e9e
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 28 deletions.
136 changes: 135 additions & 1 deletion components/script/dom/bindings/trace.rs
Expand Up @@ -57,11 +57,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};
Expand Down Expand Up @@ -291,3 +293,135 @@ 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 RootedVec<()>>>
}

/// 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: &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 *const _ 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: &HashSet<*const RootedVec<()>>) {
for collection in collections {
let collection: *const RootedVec<()> = *collection;
let collection = collection as *const RootedVec<T>;
unsafe {
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::<JSVal>(tracer, &self.set[CollectionType::JSVals as uint]);
trace_collection_type::<*mut JSObject>(tracer, &self.set[CollectionType::JSObjects as uint]);
}
}


/// 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> {
unsafe {
RootedCollectionSet::add::<T>(&*(return_address() as *const _));
}
RootedVec::<T> { v: vec!() }
}

}

#[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);
});
}
8 changes: 4 additions & 4 deletions components/script/dom/domrectlist.rs
Expand Up @@ -6,6 +6,7 @@ use dom::bindings::codegen::Bindings::DOMRectListBinding;
use dom::bindings::codegen::Bindings::DOMRectListBinding::DOMRectListMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::trace::RootedVec;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::domrect::DOMRect;
use dom::window::Window;
Expand All @@ -19,17 +20,16 @@ pub struct DOMRectList {

impl DOMRectList {
fn new_inherited(window: JSRef<Window>,
rects: Vec<JSRef<DOMRect>>) -> DOMRectList {
let rects = rects.iter().map(|rect| JS::from_rooted(*rect)).collect();
rects: &RootedVec<JS<DOMRect>>) -> DOMRectList {
DOMRectList {
reflector_: Reflector::new(),
rects: rects,
rects: (**rects).clone(),
window: JS::from_rooted(window),
}
}

pub fn new(window: JSRef<Window>,
rects: Vec<JSRef<DOMRect>>) -> Temporary<DOMRectList> {
rects: &RootedVec<JS<DOMRect>>) -> Temporary<DOMRectList> {
reflect_dom_object(box DOMRectList::new_inherited(window, rects),
GlobalRef::Window(window), DOMRectListBinding::Wrap)
}
Expand Down
26 changes: 14 additions & 12 deletions components/script/dom/element.rs
Expand Up @@ -28,7 +28,8 @@ use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived;
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{NamespaceError, InvalidCharacter, Syntax};
use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalRootable, Root};
use dom::bindings::js::OptionalRootable;
use dom::bindings::trace::RootedVec;
use dom::bindings::utils::xml_name_type;
use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName};
use dom::create::create_element;
Expand Down Expand Up @@ -1114,17 +1115,18 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
fn GetClientRects(self) -> Temporary<DOMRectList> {
let win = window_from_node(self).root();
let node: JSRef<Node> = NodeCast::from_ref(self);
let rects = node.get_content_boxes();
let rects: Vec<Root<DOMRect>> = rects.iter().map(|r| {
DOMRect::new(
win.r(),
r.origin.y,
r.origin.y + r.size.height,
r.origin.x,
r.origin.x + r.size.width).root()
}).collect();

DOMRectList::new(win.r(), rects.iter().map(|rect| rect.r()).collect())
let raw_rects = node.get_content_boxes();
let mut rects = RootedVec::new();
for rect in raw_rects.iter() {
let rect = DOMRect::new(win.r(),
rect.origin.y,
rect.origin.y + rect.size.height,
rect.origin.x,
rect.origin.x + rect.size.width);
rects.push(JS::from_rooted(rect));
}

DOMRectList::new(win.r(), &rects)
}

// http://dev.w3.org/csswg/cssom-view/#dom-element-getboundingclientrect
Expand Down
21 changes: 11 additions & 10 deletions components/script/dom/eventdispatcher.rs
Expand Up @@ -4,8 +4,9 @@

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, NodeDerived};
use dom::bindings::js::{JS, JSRef, OptionalRootable, Root};
use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast};
use dom::bindings::js::{JS, JSRef, OptionalRootable};
use dom::bindings::trace::RootedVec;
use dom::eventtarget::{EventTarget, ListenerPhase};
use dom::event::{Event, EventPhase};
use dom::node::{Node, NodeHelpers};
Expand All @@ -27,22 +28,21 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
let type_ = event.Type();

//TODO: no chain if not participating in a tree
let mut chain: Vec<Root<EventTarget>> = if target.is_node() {
let target_node: JSRef<Node> = NodeCast::to_ref(target).unwrap();
target_node.ancestors().map(|ancestor| {
let mut chain: RootedVec<JS<EventTarget>> = RootedVec::new();
if let Some(target_node) = NodeCast::to_ref(target) {
for ancestor in target_node.ancestors() {
let ancestor_target: JSRef<EventTarget> = EventTargetCast::from_ref(ancestor);
JS::from_rooted(ancestor_target).root()
}).collect()
} else {
vec!()
};
chain.push(JS::from_rooted(ancestor_target))
}
}

event.set_phase(EventPhase::Capturing);

//FIXME: The "callback this value" should be currentTarget

/* capturing */
for cur_target in chain.as_slice().iter().rev() {
let cur_target = cur_target.root();
let stopped = match cur_target.r().get_listeners_for(type_.as_slice(), ListenerPhase::Capturing) {
Some(listeners) => {
event.set_current_target(cur_target.r());
Expand Down Expand Up @@ -88,6 +88,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
event.set_phase(EventPhase::Bubbling);

for cur_target in chain.iter() {
let cur_target = cur_target.root();
let stopped = match cur_target.r().get_listeners_for(type_.as_slice(), ListenerPhase::Bubbling) {
Some(listeners) => {
event.set_current_target(cur_target.r());
Expand Down
6 changes: 5 additions & 1 deletion components/script/script_task.rs
Expand Up @@ -28,7 +28,7 @@ use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, RootedReference}
use dom::bindings::js::{RootCollection, RootCollectionPtr, Unrooted};
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};
Expand Down Expand Up @@ -461,6 +461,10 @@ impl ScriptTask {
!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
Expand Down

12 comments on commit e8a1e9e

@Ms2ger
Copy link
Contributor

@Ms2ger Ms2ger commented on e8a1e9e Mar 29, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+

@Ms2ger
Copy link
Contributor

@Ms2ger Ms2ger commented on e8a1e9e Mar 29, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=jdm

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from Ms2ger, jdm
at e8a1e9e

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging servo/servo/rooted-vec = e8a1e9e into auto

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

servo/servo/rooted-vec = e8a1e9e merged ok, testing candidate = 08e8ab8

@Ms2ger
Copy link
Contributor

@Ms2ger Ms2ger commented on e8a1e9e Mar 29, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from Ms2ger, jdm
at e8a1e9e

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging servo/servo/rooted-vec = e8a1e9e into auto

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

servo/servo/rooted-vec = e8a1e9e merged ok, testing candidate = 1282850

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 1282850

Please sign in to comment.