mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Remove GC hazard when compiling inline event listeners. (#33965)
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
a01d66df53
commit
1d6ede7b48
1 changed files with 41 additions and 41 deletions
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -100,50 +101,49 @@ enum InlineEventListener {
|
||||||
Null,
|
Null,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineEventListener {
|
/// Get a compiled representation of this event handler, compiling it from its
|
||||||
/// Get a compiled representation of this event handler, compiling it from its
|
/// raw source if necessary.
|
||||||
/// raw source if necessary.
|
/// <https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler>
|
||||||
/// <https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler>
|
fn get_compiled_handler(
|
||||||
fn get_compiled_handler(
|
inline_listener: &RefCell<InlineEventListener>,
|
||||||
&mut self,
|
owner: &EventTarget,
|
||||||
owner: &EventTarget,
|
ty: &Atom,
|
||||||
ty: &Atom,
|
can_gc: CanGc,
|
||||||
can_gc: CanGc,
|
) -> Option<CommonEventHandler> {
|
||||||
) -> Option<CommonEventHandler> {
|
let listener = mem::replace(
|
||||||
match mem::replace(self, InlineEventListener::Null) {
|
&mut *inline_listener.borrow_mut(),
|
||||||
InlineEventListener::Null => None,
|
InlineEventListener::Null,
|
||||||
InlineEventListener::Uncompiled(handler) => {
|
);
|
||||||
let result = owner.get_compiled_event_handler(handler, ty, can_gc);
|
let compiled = match listener {
|
||||||
if let Some(ref compiled) = result {
|
InlineEventListener::Null => None,
|
||||||
*self = InlineEventListener::Compiled(compiled.clone());
|
InlineEventListener::Uncompiled(handler) => {
|
||||||
}
|
owner.get_compiled_event_handler(handler, ty, can_gc)
|
||||||
result
|
},
|
||||||
},
|
InlineEventListener::Compiled(handler) => Some(handler),
|
||||||
InlineEventListener::Compiled(handler) => {
|
};
|
||||||
*self = InlineEventListener::Compiled(handler.clone());
|
if let Some(ref compiled) = compiled {
|
||||||
Some(handler)
|
*inline_listener.borrow_mut() = InlineEventListener::Compiled(compiled.clone());
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
|
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
|
||||||
enum EventListenerType {
|
enum EventListenerType {
|
||||||
Additive(#[ignore_malloc_size_of = "Rc"] Rc<EventListener>),
|
Additive(#[ignore_malloc_size_of = "Rc"] Rc<EventListener>),
|
||||||
Inline(InlineEventListener),
|
Inline(RefCell<InlineEventListener>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventListenerType {
|
impl EventListenerType {
|
||||||
fn get_compiled_listener(
|
fn get_compiled_listener(
|
||||||
&mut self,
|
&self,
|
||||||
owner: &EventTarget,
|
owner: &EventTarget,
|
||||||
ty: &Atom,
|
ty: &Atom,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Option<CompiledEventListener> {
|
) -> Option<CompiledEventListener> {
|
||||||
match *self {
|
match *self {
|
||||||
EventListenerType::Inline(ref mut inline) => inline
|
EventListenerType::Inline(ref inline) => {
|
||||||
.get_compiled_handler(owner, ty, can_gc)
|
get_compiled_handler(inline, owner, ty, can_gc).map(CompiledEventListener::Handler)
|
||||||
.map(CompiledEventListener::Handler),
|
},
|
||||||
EventListenerType::Additive(ref listener) => {
|
EventListenerType::Additive(ref listener) => {
|
||||||
Some(CompiledEventListener::Listener(listener.clone()))
|
Some(CompiledEventListener::Listener(listener.clone()))
|
||||||
},
|
},
|
||||||
|
@ -308,15 +308,15 @@ impl DerefMut for EventListeners {
|
||||||
impl EventListeners {
|
impl EventListeners {
|
||||||
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
|
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
|
||||||
fn get_inline_listener(
|
fn get_inline_listener(
|
||||||
&mut self,
|
&self,
|
||||||
owner: &EventTarget,
|
owner: &EventTarget,
|
||||||
ty: &Atom,
|
ty: &Atom,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Option<CommonEventHandler> {
|
) -> Option<CommonEventHandler> {
|
||||||
for entry in &mut self.0 {
|
for entry in &self.0 {
|
||||||
if let EventListenerType::Inline(ref mut inline) = entry.listener {
|
if let EventListenerType::Inline(ref inline) = entry.listener {
|
||||||
// Step 1.1-1.8 and Step 2
|
// Step 1.1-1.8 and Step 2
|
||||||
return inline.get_compiled_handler(owner, ty, can_gc);
|
return get_compiled_handler(inline, owner, ty, can_gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,14 +326,14 @@ impl EventListeners {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
|
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
|
||||||
fn get_listeners(
|
fn get_listeners(
|
||||||
&mut self,
|
&self,
|
||||||
phase: Option<ListenerPhase>,
|
phase: Option<ListenerPhase>,
|
||||||
owner: &EventTarget,
|
owner: &EventTarget,
|
||||||
ty: &Atom,
|
ty: &Atom,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Vec<CompiledEventListener> {
|
) -> Vec<CompiledEventListener> {
|
||||||
self.0
|
self.0
|
||||||
.iter_mut()
|
.iter()
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
if phase.is_none() || Some(entry.phase) == phase {
|
if phase.is_none() || Some(entry.phase) == phase {
|
||||||
// Step 1.1-1.8, 2
|
// Step 1.1-1.8, 2
|
||||||
|
@ -395,8 +395,8 @@ impl EventTarget {
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Vec<CompiledEventListener> {
|
) -> Vec<CompiledEventListener> {
|
||||||
self.handlers
|
self.handlers
|
||||||
.borrow_mut()
|
.borrow()
|
||||||
.get_mut(type_)
|
.get(type_)
|
||||||
.map_or(vec![], |listeners| {
|
.map_or(vec![], |listeners| {
|
||||||
listeners.get_listeners(specific_phase, self, type_, can_gc)
|
listeners.get_listeners(specific_phase, self, type_, can_gc)
|
||||||
})
|
})
|
||||||
|
@ -427,7 +427,7 @@ impl EventTarget {
|
||||||
// Replace if there's something to replace with,
|
// Replace if there's something to replace with,
|
||||||
// but remove entirely if there isn't.
|
// but remove entirely if there isn't.
|
||||||
Some(listener) => {
|
Some(listener) => {
|
||||||
entries[idx].listener = EventListenerType::Inline(listener);
|
entries[idx].listener = EventListenerType::Inline(listener.into());
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
entries.remove(idx);
|
entries.remove(idx);
|
||||||
|
@ -437,7 +437,7 @@ impl EventTarget {
|
||||||
if let Some(listener) = listener {
|
if let Some(listener) = listener {
|
||||||
entries.push(EventListenerEntry {
|
entries.push(EventListenerEntry {
|
||||||
phase: ListenerPhase::Bubbling,
|
phase: ListenerPhase::Bubbling,
|
||||||
listener: EventListenerType::Inline(listener),
|
listener: EventListenerType::Inline(listener.into()),
|
||||||
once: false,
|
once: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -455,9 +455,9 @@ impl EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_inline_event_listener(&self, ty: &Atom, can_gc: CanGc) -> Option<CommonEventHandler> {
|
fn get_inline_event_listener(&self, ty: &Atom, can_gc: CanGc) -> Option<CommonEventHandler> {
|
||||||
let mut handlers = self.handlers.borrow_mut();
|
let handlers = self.handlers.borrow();
|
||||||
handlers
|
handlers
|
||||||
.get_mut(ty)
|
.get(ty)
|
||||||
.and_then(|entry| entry.get_inline_listener(self, ty, can_gc))
|
.and_then(|entry| entry.get_inline_listener(self, ty, can_gc))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue