mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +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_thread::ScriptThread;
|
||||
use app_units::Au;
|
||||
use crossbeam_channel::Sender;
|
||||
use devtools_traits::NodeInfo;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
|
||||
|
@ -209,7 +210,9 @@ impl NodeFlags {
|
|||
impl Drop for Node {
|
||||
#[allow(unsafe_code)]
|
||||
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 {
|
||||
/// 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());
|
||||
let win = window_from_node(self);
|
||||
self.style_and_layout_data.set(None);
|
||||
if win
|
||||
.layout_chan()
|
||||
.send(Msg::ReapStyleAndLayoutData(data))
|
||||
.is_err()
|
||||
{
|
||||
if layout_chan.map_or(false, |chan| {
|
||||
chan.send(Msg::ReapStyleAndLayoutData(data)).is_err()
|
||||
}) {
|
||||
warn!("layout thread unreachable - leaking layout data");
|
||||
}
|
||||
}
|
||||
|
@ -315,12 +319,16 @@ impl Node {
|
|||
false,
|
||||
);
|
||||
}
|
||||
let window = window_from_node(root);
|
||||
let layout_chan = window.layout_chan();
|
||||
for node in root.traverse_preorder(ShadowIncluding::Yes) {
|
||||
// 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,
|
||||
// e.g. when removing a <form>.
|
||||
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
|
||||
if let Some(element) = node.as_custom_element() {
|
||||
ScriptThread::enqueue_callback_reaction(
|
||||
|
@ -481,10 +489,12 @@ impl<'a> Iterator for QuerySelectorIterator {
|
|||
impl Node {
|
||||
impl_rare_data!(NodeRareData);
|
||||
|
||||
pub fn teardown(&self) {
|
||||
self.style_and_layout_data.get().map(|d| self.dispose(d));
|
||||
pub(crate) fn teardown(&self, layout_chan: &Sender<Msg>) {
|
||||
if let Some(data) = self.style_and_layout_data.get() {
|
||||
self.dispose(data, Some(layout_chan));
|
||||
}
|
||||
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
|
||||
// nodes to dispose of their layout data. This messages the layout
|
||||
// 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.
|
||||
self.upcast::<GlobalScope>().remove_message_ports_router();
|
||||
|
|
|
@ -821,6 +821,23 @@ impl ScriptThreadFactory for 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 {
|
||||
SCRIPT_THREAD_ROOT.with(|root| {
|
||||
let script_thread = unsafe { &*root.get().unwrap() };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue