aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/script/dom/bindings/codegen/CodegenRust.py30
-rw-r--r--src/components/script/dom/bindings/utils.rs5
-rw-r--r--src/components/script/dom/browsercontext.rs5
-rw-r--r--src/components/script/script_task.rs165
m---------src/support/spidermonkey/rust-mozjs0
5 files changed, 118 insertions, 87 deletions
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py
index a6c984d2e02..3e86f722869 100644
--- a/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1755,22 +1755,26 @@ def CreateBindingJSObject(descriptor, parent=None):
create = " let mut raw: JS<%s> = JS::from_raw(&mut *aObject);\n" % descriptor.concreteType
if descriptor.proxy:
assert not descriptor.createGlobal
- handler = """
+ create += """
let js_info = aScope.deref().page().js_info();
let handler = js_info.get_ref().dom_static.proxy_handlers.deref().get(&(PrototypeList::id::%s as uint));
-""" % descriptor.name
- create += handler + """ let obj = NewProxyObject(aCx, *handler,
- &PrivateValue(squirrel_away_unique(aObject) as *libc::c_void),
- proto, %s,
- ptr::null(), ptr::null());
+ let private = PrivateValue(squirrel_away_unique(aObject) as *libc::c_void);
+ let obj = with_compartment(aCx, proto, || {
+ NewProxyObject(aCx, *handler,
+ &private,
+ proto, %s,
+ ptr::null(), ptr::null())
+ });
assert!(obj.is_not_null());
-""" % (parent)
+""" % (descriptor.name, parent)
else:
if descriptor.createGlobal:
create += " let obj = CreateDOMGlobal(aCx, &Class.base as *js::Class as *JSClass);\n"
else:
- create += " let obj = JS_NewObject(aCx, &Class.base as *js::Class as *JSClass, proto, %s);\n" % parent
+ create += (" let obj = with_compartment(aCx, proto, || {\n"
+ " JS_NewObject(aCx, &Class.base as *js::Class as *JSClass, proto, %s)\n"
+ " });\n" % parent)
create += """ assert!(obj.is_not_null());
JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
@@ -1797,8 +1801,7 @@ class CGWrapMethod(CGAbstractMethod):
assert!(scope.is_not_null());
assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0);
- //JSAutoCompartment ac(aCx, scope);
- let proto = GetProtoObject(aCx, scope, scope);
+ let proto = with_compartment(aCx, scope, || GetProtoObject(aCx, scope, scope));
assert!(proto.is_not_null());
%s
@@ -1809,8 +1812,10 @@ class CGWrapMethod(CGAbstractMethod):
else:
return """
%s
- let proto = GetProtoObject(aCx, obj, obj);
- JS_SetPrototype(aCx, obj, proto);
+ with_compartment(aCx, obj, || {
+ let proto = GetProtoObject(aCx, obj, obj);
+ JS_SetPrototype(aCx, obj, proto);
+ });
raw.mut_reflector().set_jsobject(obj);
return raw;""" % CreateBindingJSObject(self.descriptor)
@@ -4241,6 +4246,7 @@ class CGBindingRoot(CGThing):
'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
+ 'js::rust::with_compartment',
'dom::types::*',
'dom::bindings',
'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary}',
diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs
index a99189ae161..f5b0f08849e 100644
--- a/src/components/script/dom/bindings/utils.rs
+++ b/src/components/script/dom/bindings/utils.rs
@@ -41,6 +41,7 @@ use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
use js::jsval::JSVal;
use js::jsval::{PrivateValue, ObjectValue, NullValue, ObjectOrNullValue};
use js::jsval::{Int32Value, UInt32Value, DoubleValue, BooleanValue, UndefinedValue};
+use js::rust::with_compartment;
use js::{JSPROP_ENUMERATE, JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS};
use js::JSPROP_PERMANENT;
use js::{JSFUN_CONSTRUCTOR, JSPROP_READONLY};
@@ -583,7 +584,9 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
if obj.is_null() {
return ptr::null();
}
- JS_InitStandardClasses(cx, obj);
+ with_compartment(cx, obj, || {
+ JS_InitStandardClasses(cx, obj);
+ });
initialize_global(obj);
obj
}
diff --git a/src/components/script/dom/browsercontext.rs b/src/components/script/dom/browsercontext.rs
index fb282a2c945..f95e84ab02b 100644
--- a/src/components/script/dom/browsercontext.rs
+++ b/src/components/script/dom/browsercontext.rs
@@ -10,6 +10,7 @@ use dom::window::Window;
use js::jsapi::JSObject;
use js::glue::{WrapperNew, CreateWrapperProxyHandler, ProxyTraps};
+use js::rust::with_compartment;
use libc::c_void;
use std::ptr;
@@ -56,9 +57,9 @@ impl BrowserContext {
let parent = win.deref().reflector().get_jsobject();
let cx = js_info.get_ref().js_context.deref().deref().ptr;
- let wrapper = unsafe {
+ let wrapper = with_compartment(cx, parent, || unsafe {
WrapperNew(cx, parent, *handler.deref())
- };
+ });
assert!(wrapper.is_not_null());
wrapper
}
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index 09d9ee59aa6..724d5e194c7 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -35,10 +35,12 @@ use layout_interface;
use geom::point::Point2D;
use geom::size::Size2D;
use js::global::DEBUG_FNS;
-use js::jsapi::{JSObject, JS_CallFunctionValue, JS_DefineFunctions};
+use js::jsapi::{JS_CallFunctionValue, JS_DefineFunctions};
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ};
+use js::jsapi::{JSContext, JSRuntime};
use js::jsval::NullValue;
use js::rust::{Cx, RtUtils};
+use js::rust::with_compartment;
use js;
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout};
use servo_msg::compositor_msg::{ScriptListener};
@@ -426,21 +428,8 @@ impl Page {
}
}
- pub fn initialize_js_info(&self, js_context: Rc<Cx>, global: *JSObject) {
- assert!(global.is_not_null());
-
- // Note that the order that these variables are initialized is _not_ arbitrary. Switching
- // them around can -- and likely will -- lead to things breaking.
-
- unsafe {
- JS_SetGCZeal(js_context.deref().ptr, 0, JS_DEFAULT_ZEAL_FREQ);
- }
-
- js_context.set_default_options_and_version();
- js_context.set_logging_error_reporter();
-
- let mut js_info = self.mut_js_info();
- *js_info = Some(JSPageInfo {
+ pub fn initialize_js_info(&self, js_context: Rc<Cx>) {
+ *self.mut_js_info() = Some(JSPageInfo {
dom_static: GlobalStaticData(),
js_context: Untraceable::new(js_context),
});
@@ -548,6 +537,8 @@ pub struct ScriptTask {
/// The JavaScript runtime.
pub js_runtime: js::rust::rt,
+ /// The JSContext.
+ pub js_context: RefCell<Option<Rc<Cx>>>,
pub mouse_over_targets: RefCell<Option<Vec<JS<Node>>>>
}
@@ -581,6 +572,7 @@ impl<'a> Drop for ScriptMemoryFailsafe<'a> {
for page in page_tree.iter() {
*page.mut_js_info() = None;
}
+ *owner.js_context.borrow_mut() = None;
}
None => (),
}
@@ -599,15 +591,7 @@ impl ScriptTask {
img_cache_task: ImageCacheTask,
window_size: Size2D<uint>)
-> Rc<ScriptTask> {
- let js_runtime = js::rust::rt();
-
- unsafe {
- JS_SetWrapObjectCallbacks(js_runtime.deref().ptr,
- ptr::null(),
- wrap_for_same_compartment,
- ptr::null());
- }
-
+ let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
Rc::new(ScriptTask {
page_tree: RefCell::new(PageTree::new(id, layout_chan, window_size)),
@@ -620,10 +604,42 @@ impl ScriptTask {
compositor: compositor,
js_runtime: js_runtime,
+ js_context: RefCell::new(Some(js_context)),
mouse_over_targets: RefCell::new(None)
})
}
+ fn new_rt_and_cx() -> (js::rust::rt, Rc<Cx>) {
+ let js_runtime = js::rust::rt();
+ assert!({
+ let ptr: *JSRuntime = (*js_runtime).ptr;
+ ptr.is_not_null()
+ });
+ unsafe {
+ JS_SetWrapObjectCallbacks((*js_runtime).ptr,
+ ptr::null(),
+ wrap_for_same_compartment,
+ ptr::null());
+ }
+
+ let js_context = js_runtime.cx();
+ assert!({
+ let ptr: *JSContext = (*js_context).ptr;
+ ptr.is_not_null()
+ });
+ js_context.set_default_options_and_version();
+ js_context.set_logging_error_reporter();
+ unsafe {
+ JS_SetGCZeal((*js_context).ptr, 0, JS_DEFAULT_ZEAL_FREQ);
+ }
+
+ (js_runtime, js_context)
+ }
+
+ pub fn get_cx(&self) -> *JSContext {
+ (**self.js_context.borrow().get_ref()).ptr
+ }
+
/// Starts the script task. After calling this method, the script task will loop receiving
/// messages on its port.
pub fn start(&self) {
@@ -772,10 +788,9 @@ impl ScriptTask {
Some(timer_handle) => {
// TODO: Support extra arguments. This requires passing a `*JSVal` array as `argv`.
let rval = NullValue();
- let js_info = page.js_info();
- let cx = js_info.get_ref().js_context.deref().deref().ptr;
unsafe {
- JS_CallFunctionValue(cx, this_value, *timer_handle.data.funval,
+ JS_CallFunctionValue(self.get_cx(), this_value,
+ *timer_handle.data.funval,
0, ptr::null(), &rval);
}
@@ -844,20 +859,16 @@ impl ScriptTask {
// If root is being exited, shut down all pages
let mut page_tree = self.page_tree.borrow_mut();
if page_tree.page().id == id {
- for page in page_tree.iter() {
- debug!("shutting down layout for root page {:?}", page.id);
- shut_down_layout(&*page)
- }
+ debug!("shutting down layout for root page {:?}", id);
+ *self.js_context.borrow_mut() = None;
+ shut_down_layout(&mut *page_tree);
return true
}
// otherwise find just the matching page and exit all sub-pages
match page_tree.remove(id) {
Some(ref mut page_tree) => {
- for page in page_tree.iter() {
- debug!("shutting down layout for page {:?}", page.id);
- shut_down_layout(&*page)
- }
+ shut_down_layout(&mut *page_tree);
false
}
// TODO(tkuehn): pipeline closing is currently duplicated across
@@ -892,21 +903,22 @@ impl ScriptTask {
}
}
- let cx = self.js_runtime.cx();
+ let cx = self.js_context.borrow();
+ let cx = cx.get_ref();
// Create the window and document objects.
let mut window = Window::new(cx.deref().ptr,
page_tree.page.clone(),
self.chan.clone(),
self.compositor.dup(),
self.image_cache_task.clone()).root();
- page.initialize_js_info(cx.clone(), window.reflector().get_jsobject());
+ page.initialize_js_info(cx.clone());
let mut document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root();
window.deref_mut().init_browser_context(&*document);
- {
+ with_compartment((**cx).ptr, window.reflector().get_jsobject(), || {
let mut js_info = page.mut_js_info();
RegisterBindings::Register(&window.unrooted(), js_info.get_mut_ref());
- }
+ });
self.compositor.set_ready_state(Loading);
// Parse HTML.
@@ -980,23 +992,25 @@ impl ScriptTask {
let js_scripts = js_scripts.take_unwrap();
debug!("js_scripts: {:?}", js_scripts);
- // Define debug functions.
- unsafe {
- assert!(JS_DefineFunctions((*cx).ptr,
- window.reflector().get_jsobject(),
- DEBUG_FNS.as_ptr()) != 0);
- }
+ with_compartment((**cx).ptr, window.reflector().get_jsobject(), || {
+ // Define debug functions.
+ unsafe {
+ assert!(JS_DefineFunctions((**cx).ptr,
+ window.reflector().get_jsobject(),
+ DEBUG_FNS.as_ptr()) != 0);
+ }
- // Evaluate every script in the document.
- for file in js_scripts.iter() {
- let global_obj = window.reflector().get_jsobject();
- //FIXME: this should have some kind of error handling, or explicitly
- // drop an exception on the floor.
- match cx.evaluate_script(global_obj, file.data.clone(), file.url.to_str(), 1) {
- Ok(_) => (),
- Err(_) => println!("evaluate_script failed")
+ // Evaluate every script in the document.
+ for file in js_scripts.iter() {
+ let global_obj = window.reflector().get_jsobject();
+ //FIXME: this should have some kind of error handling, or explicitly
+ // drop an exception on the floor.
+ match cx.evaluate_script(global_obj, file.data.clone(), file.url.to_str(), 1) {
+ Ok(_) => (),
+ Err(_) => println!("evaluate_script failed")
+ }
}
- }
+ });
// We have no concept of a document loader right now, so just dispatch the
// "load" event as soon as we've finished executing all scripts parsed during
@@ -1221,25 +1235,32 @@ impl ScriptTask {
}
}
-/// Shuts down layout for the given page.
-fn shut_down_layout(page: &Page) {
- page.join_layout();
-
- // Tell the layout task to begin shutting down.
- let (response_chan, response_port) = channel();
- let LayoutChan(ref chan) = *page.layout_chan;
- chan.send(layout_interface::PrepareToExitMsg(response_chan));
- response_port.recv();
-
- // Destroy all nodes. Setting frame and js_info to None will trigger our
- // compartment to shutdown, run GC, etc.
+/// Shuts down layout for the given page tree.
+fn shut_down_layout(page_tree: &mut PageTree) {
+ for page in page_tree.iter() {
+ page.join_layout();
+
+ // Tell the layout task to begin shutting down, and wait until it
+ // processed this message.
+ let (response_chan, response_port) = channel();
+ let LayoutChan(ref chan) = *page.layout_chan;
+ chan.send(layout_interface::PrepareToExitMsg(response_chan));
+ response_port.recv();
+ }
- let mut js_info = page.mut_js_info();
+ // Remove our references to the DOM objects in this page tree.
+ for page in page_tree.iter() {
+ *page.mut_frame() = None;
+ }
- let mut frame = page.mut_frame();
- *frame = None;
- *js_info = None;
+ // Drop our references to the JSContext, potentially triggering a GC.
+ for page in page_tree.iter() {
+ *page.mut_js_info() = None;
+ }
// Destroy the layout task. If there were node leaks, layout will now crash safely.
- chan.send(layout_interface::ExitNowMsg);
+ for page in page_tree.iter() {
+ let LayoutChan(ref chan) = *page.layout_chan;
+ chan.send(layout_interface::ExitNowMsg);
+ }
}
diff --git a/src/support/spidermonkey/rust-mozjs b/src/support/spidermonkey/rust-mozjs
-Subproject 92d2979ff9656e6dcc018486bc3a7d1bcc63fd9
+Subproject 50365a556b51da2455de051bfe4697872f49d8d