Dynamically check DOMRefCell access from layout in debug builds

This commit is contained in:
Keegan McAllister 2014-10-23 14:44:17 -07:00
parent 0162214b1f
commit 6ec0939a22
9 changed files with 150 additions and 30 deletions

View file

@ -5,13 +5,15 @@
use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};
use servo_util::task_state;
use std::cell::{Cell, UnsafeCell};
use std::kinds::marker;
/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations.
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
value: UnsafeCell<T>,
borrow: Cell<BorrowFlag>,
@ -27,8 +29,31 @@ impl<T> DOMRefCell<T> {
///
/// For use in the layout task only.
pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
debug_assert!(task_state::get().is_layout());
&*self.value.get()
}
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
debug_assert!(task_state::get().is_script());
match self.borrow.get() {
WRITING => None,
borrow => {
self.borrow.set(borrow + 1);
Some(Ref { _parent: self })
}
}
}
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
debug_assert!(task_state::get().is_script());
match self.borrow.get() {
UNUSED => {
self.borrow.set(WRITING);
Some(RefMut { _parent: self })
},
_ => None
}
}
}
impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
@ -63,16 +88,6 @@ impl<T> DOMRefCell<T> {
unsafe{self.value.unwrap()}
}
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match self.borrow.get() {
WRITING => None,
borrow => {
self.borrow.set(borrow + 1);
Some(Ref { _parent: self })
}
}
}
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
@ -80,16 +95,6 @@ impl<T> DOMRefCell<T> {
}
}
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow.get() {
UNUSED => {
self.borrow.set(WRITING);
Some(RefMut { _parent: self })
},
_ => None
}
}
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,

View file

@ -24,6 +24,8 @@ use script_task::WorkerPostMessage;
use script_task::StackRootTLS;
use servo_net::resource_task::{ResourceTask, load_whole_resource};
use servo_util::task_state;
use servo_util::task_state::{Script, InWorker};
use js::glue::JS_STRUCTURED_CLONE_VERSION;
use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_WriteStructuredClone, JS_ClearPendingException};
@ -90,6 +92,9 @@ impl DedicatedWorkerGlobalScope {
.native()
.named(format!("Web Worker at {}", worker_url.serialize()))
.spawn(proc() {
task_state::initialize(Script | InWorker);
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);

View file

@ -54,6 +54,7 @@ use servo_net::resource_task::ResourceTask;
use servo_util::geometry::to_frac_px;
use servo_util::smallvec::{SmallVec1, SmallVec};
use servo_util::task::spawn_named_with_send_on_failure;
use servo_util::task_state;
use geom::point::Point2D;
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
@ -262,7 +263,7 @@ impl ScriptTaskFactory for ScriptTask {
let ConstellationChan(const_chan) = constellation_chan.clone();
let (script_chan, script_port) = channel();
let layout_chan = LayoutChan(layout_chan.sender());
spawn_named_with_send_on_failure("ScriptTask", proc() {
spawn_named_with_send_on_failure("ScriptTask", task_state::Script, proc() {
let script_task = ScriptTask::new(id,
compositor as Box<ScriptListener>,
layout_chan,