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 all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -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,134 @@ 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.iter() {
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);
});
}
@@ -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;
@@ -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)
}
@@ -25,7 +25,8 @@ use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
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;
@@ -1061,17 +1062,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
@@ -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};
@@ -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());
@@ -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());
@@ -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};
@@ -386,6 +387,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
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.