aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/script_task.rs
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2014-04-21 17:13:22 -0400
committerbors-servo <release+servo@mozilla.com>2014-04-21 17:13:22 -0400
commitc6bdc7b7f2d39b522be5767f09f88b1b4ca5577a (patch)
tree6f40dae2705bb6341af86dba8f65c13d6bf8de9b /src/components/script/script_task.rs
parent3c175c7ac0815b6c2e2e63806317366f56b38e58 (diff)
parent3078f580550870156a985fb002f429b6dc35b381 (diff)
downloadservo-c6bdc7b7f2d39b522be5767f09f88b1b4ca5577a.tar.gz
servo-c6bdc7b7f2d39b522be5767f09f88b1b4ca5577a.zip
auto merge of #2202 : jdm/servo/scriptleak, r=Ms2ger
....
Diffstat (limited to 'src/components/script/script_task.rs')
-rw-r--r--src/components/script/script_task.rs43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index 4e7a30705b0..f8e7d230420 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -485,6 +485,45 @@ pub struct ScriptTask {
mouse_over_targets: RefCell<Option<~[JS<Node>]>>
}
+/// In the event of task failure, all data on the stack runs its destructor. However, there
+/// are no reachable, owning pointers to the DOM memory, so it never gets freed by default
+/// when the script task fails. The ScriptMemoryFailsafe uses the destructor bomb pattern
+/// to forcibly tear down the JS compartments for pages associated with the failing ScriptTask.
+struct ScriptMemoryFailsafe<'a> {
+ owner: Option<&'a ScriptTask>,
+}
+
+impl<'a> ScriptMemoryFailsafe<'a> {
+ fn neuter(&mut self) {
+ self.owner = None;
+ }
+
+ fn new(owner: &'a ScriptTask) -> ScriptMemoryFailsafe<'a> {
+ ScriptMemoryFailsafe {
+ owner: Some(owner),
+ }
+ }
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for ScriptMemoryFailsafe<'a> {
+ fn drop(&mut self) {
+ match self.owner {
+ Some(owner) => {
+ let mut page_tree = owner.page_tree.borrow_mut();
+ for page in page_tree.iter() {
+ let mut js_info = page.mut_js_info();
+ unsafe {
+ JS_AllowGC(js_info.get_ref().js_context.deref().deref().ptr);
+ }
+ *js_info = None;
+ }
+ }
+ None => (),
+ }
+ }
+}
+
impl ScriptTask {
/// Creates a new script task.
pub fn new(id: PipelineId,
@@ -547,7 +586,11 @@ impl ScriptTask {
resource_task,
image_cache_task,
window_size);
+ let mut failsafe = ScriptMemoryFailsafe::new(&*script_task);
script_task.start();
+
+ // This must always be the very last operation performed before the task completes
+ failsafe.neuter();
});
}