mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement RootedVec<T>
This commit is contained in:
parent
4cf76d65ba
commit
e8a1e9eabb
5 changed files with 168 additions and 27 deletions
|
@ -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};
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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();
|
||||
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.iter().map(|rect| rect.r()).collect())
|
||||
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,15 +28,13 @@ 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);
|
||||
|
||||
|
@ -43,6 +42,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
|
|||
|
||||
/* 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());
|
||||
|
|
|
@ -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};
|
||||
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue