mirror of
https://github.com/servo/servo.git
synced 2025-07-31 03:00:29 +01:00
Avoid accessing node global during Node's destructor.
This commit is contained in:
parent
3e95efdea6
commit
1449bac0e1
3 changed files with 42 additions and 13 deletions
|
@ -67,6 +67,7 @@ use crate::dom::window::Window;
|
||||||
use crate::script_runtime::JSContext;
|
use crate::script_runtime::JSContext;
|
||||||
use crate::script_thread::ScriptThread;
|
use crate::script_thread::ScriptThread;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use crossbeam_channel::Sender;
|
||||||
use devtools_traits::NodeInfo;
|
use devtools_traits::NodeInfo;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
|
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
|
||||||
|
@ -209,7 +210,9 @@ impl NodeFlags {
|
||||||
impl Drop for Node {
|
impl Drop for Node {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.style_and_layout_data.get().map(|d| self.dispose(d));
|
if let Some(data) = self.style_and_layout_data.get() {
|
||||||
|
self.dispose(data, ScriptThread::get_any_layout_chan().as_ref());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,15 +227,16 @@ enum SuppressObserver {
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
|
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
|
||||||
pub fn dispose(&self, data: OpaqueStyleAndLayoutData) {
|
pub(crate) fn dispose(
|
||||||
|
&self,
|
||||||
|
data: OpaqueStyleAndLayoutData,
|
||||||
|
layout_chan: Option<&Sender<Msg>>,
|
||||||
|
) {
|
||||||
debug_assert!(thread_state::get().is_script());
|
debug_assert!(thread_state::get().is_script());
|
||||||
let win = window_from_node(self);
|
|
||||||
self.style_and_layout_data.set(None);
|
self.style_and_layout_data.set(None);
|
||||||
if win
|
if layout_chan.map_or(false, |chan| {
|
||||||
.layout_chan()
|
chan.send(Msg::ReapStyleAndLayoutData(data)).is_err()
|
||||||
.send(Msg::ReapStyleAndLayoutData(data))
|
}) {
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
warn!("layout thread unreachable - leaking layout data");
|
warn!("layout thread unreachable - leaking layout data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,12 +319,16 @@ impl Node {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let window = window_from_node(root);
|
||||||
|
let layout_chan = window.layout_chan();
|
||||||
for node in root.traverse_preorder(ShadowIncluding::Yes) {
|
for node in root.traverse_preorder(ShadowIncluding::Yes) {
|
||||||
// This needs to be in its own loop, because unbind_from_tree may
|
// This needs to be in its own loop, because unbind_from_tree may
|
||||||
// rely on the state of IS_IN_DOC of the context node's descendants,
|
// rely on the state of IS_IN_DOC of the context node's descendants,
|
||||||
// e.g. when removing a <form>.
|
// e.g. when removing a <form>.
|
||||||
vtable_for(&&*node).unbind_from_tree(&context);
|
vtable_for(&&*node).unbind_from_tree(&context);
|
||||||
node.style_and_layout_data.get().map(|d| node.dispose(d));
|
if let Some(data) = node.style_and_layout_data.get() {
|
||||||
|
node.dispose(data, Some(layout_chan));
|
||||||
|
}
|
||||||
// https://dom.spec.whatwg.org/#concept-node-remove step 14
|
// https://dom.spec.whatwg.org/#concept-node-remove step 14
|
||||||
if let Some(element) = node.as_custom_element() {
|
if let Some(element) = node.as_custom_element() {
|
||||||
ScriptThread::enqueue_callback_reaction(
|
ScriptThread::enqueue_callback_reaction(
|
||||||
|
@ -481,10 +489,12 @@ impl<'a> Iterator for QuerySelectorIterator {
|
||||||
impl Node {
|
impl Node {
|
||||||
impl_rare_data!(NodeRareData);
|
impl_rare_data!(NodeRareData);
|
||||||
|
|
||||||
pub fn teardown(&self) {
|
pub(crate) fn teardown(&self, layout_chan: &Sender<Msg>) {
|
||||||
self.style_and_layout_data.get().map(|d| self.dispose(d));
|
if let Some(data) = self.style_and_layout_data.get() {
|
||||||
|
self.dispose(data, Some(layout_chan));
|
||||||
|
}
|
||||||
for kid in self.children() {
|
for kid in self.children() {
|
||||||
kid.teardown();
|
kid.teardown(layout_chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1403,7 +1403,9 @@ impl Window {
|
||||||
// We tear down the active document, which causes all the attached
|
// We tear down the active document, which causes all the attached
|
||||||
// nodes to dispose of their layout data. This messages the layout
|
// nodes to dispose of their layout data. This messages the layout
|
||||||
// thread, informing it that it can safely free the memory.
|
// thread, informing it that it can safely free the memory.
|
||||||
self.Document().upcast::<Node>().teardown();
|
self.Document()
|
||||||
|
.upcast::<Node>()
|
||||||
|
.teardown(self.layout_chan());
|
||||||
|
|
||||||
// Tell the constellation to drop the sender to our message-port router, if there is any.
|
// Tell the constellation to drop the sender to our message-port router, if there is any.
|
||||||
self.upcast::<GlobalScope>().remove_message_ports_router();
|
self.upcast::<GlobalScope>().remove_message_ports_router();
|
||||||
|
|
|
@ -821,6 +821,23 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptThread {
|
impl ScriptThread {
|
||||||
|
pub(crate) fn get_any_layout_chan() -> Option<Sender<Msg>> {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
|
let script_thread = match root.get() {
|
||||||
|
Some(s) => unsafe { &*s },
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
script_thread
|
||||||
|
.documents
|
||||||
|
.borrow()
|
||||||
|
.map
|
||||||
|
.values()
|
||||||
|
.next()
|
||||||
|
.map(|d| d.window().layout_chan())
|
||||||
|
.cloned()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn runtime_handle() -> ParentRuntime {
|
pub fn runtime_handle() -> ParentRuntime {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
let script_thread = unsafe { &*root.get().unwrap() };
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue