Don't run effects from dead recycled scopes (#3201)
* Don't run effects from dead recycled scopes * Fix scheduler
This commit is contained in:
1 parent
c1f3a6868e
commit
128608f3b2
2 files changed
+20
-21
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
use crate::arena::ElementRef;
|
use crate::arena::ElementRef;
|
||||||
use crate::innerlude::{DirtyTasks, Effect};
|
use crate::innerlude::{DirtyTasks, Effect};
|
||||||
use crate::nodes::VNodeMount;
|
use crate::nodes::VNodeMount;
|
||||||
|
use crate::scheduler::ScopeOrder;
|
||||||
use crate::scope_context::SuspenseLocation;
|
use crate::scope_context::SuspenseLocation;
|
||||||
use crate::{
|
use crate::{
|
||||||
innerlude::{LocalTask, SchedulerMsg},
|
innerlude::{LocalTask, SchedulerMsg},
|
||||||
@@ -129,6 +130,11 @@ impl Runtime {
|
|||||||
self.remove_task(id);
|
self.remove_task(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop all queued effects
|
||||||
|
self.pending_effects
|
||||||
|
.borrow_mut()
|
||||||
|
.remove(&ScopeOrder::new(scope.height, scope.id));
|
||||||
|
|
||||||
// Drop all hooks in reverse order in case a hook depends on another hook.
|
// Drop all hooks in reverse order in case a hook depends on another hook.
|
||||||
for hook in scope.hooks.take().drain(..).rev() {
|
for hook in scope.hooks.take().drain(..).rev() {
|
||||||
drop(hook);
|
drop(hook);
|
||||||
|
|||||||
@@ -148,13 +148,11 @@ impl VirtualDom {
|
|||||||
/// Take the top task from the highest scope
|
/// Take the top task from the highest scope
|
||||||
pub(crate) fn pop_task(&mut self) -> Option<Task> {
|
pub(crate) fn pop_task(&mut self) -> Option<Task> {
|
||||||
let mut dirty_tasks = self.runtime.dirty_tasks.borrow_mut();
|
let mut dirty_tasks = self.runtime.dirty_tasks.borrow_mut();
|
||||||
let mut tasks = dirty_tasks.first()?;
|
let tasks = dirty_tasks.first()?;
|
||||||
|
|
||||||
// If the scope doesn't exist for whatever reason, then we should skip it
|
// The scope that owns the effect should still exist. We can't just ignore the task if the scope doesn't exist
|
||||||
while !self.scopes.contains(tasks.order.id.0) {
|
// because the scope id may have been reallocated
|
||||||
dirty_tasks.pop_first();
|
debug_assert!(self.scopes.contains(tasks.order.id.0));
|
||||||
tasks = dirty_tasks.first()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tasks = tasks.tasks_queued.borrow_mut();
|
let mut tasks = tasks.tasks_queued.borrow_mut();
|
||||||
let task = tasks.pop_front()?;
|
let task = tasks.pop_front()?;
|
||||||
@@ -168,27 +166,22 @@ impl VirtualDom {
|
|||||||
/// Take any effects from the highest scope. This should only be called if there is no pending scope reruns or tasks
|
/// Take any effects from the highest scope. This should only be called if there is no pending scope reruns or tasks
|
||||||
pub(crate) fn pop_effect(&mut self) -> Option<Effect> {
|
pub(crate) fn pop_effect(&mut self) -> Option<Effect> {
|
||||||
let mut pending_effects = self.runtime.pending_effects.borrow_mut();
|
let mut pending_effects = self.runtime.pending_effects.borrow_mut();
|
||||||
let mut effect = pending_effects.pop_first()?;
|
let effect = pending_effects.pop_first()?;
|
||||||
|
|
||||||
// If the scope doesn't exist for whatever reason, then we should skip it
|
// The scope that owns the effect should still exist. We can't just ignore the effect if the scope doesn't exist
|
||||||
while !self.scopes.contains(effect.order.id.0) {
|
// because the scope id may have been reallocated
|
||||||
effect = pending_effects.pop_first()?;
|
debug_assert!(self.scopes.contains(effect.order.id.0));
|
||||||
}
|
|
||||||
|
|
||||||
Some(effect)
|
Some(effect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take any work from the highest scope. This may include rerunning the scope and/or running tasks
|
/// Take any work from the highest scope. This may include rerunning the scope and/or running tasks
|
||||||
pub(crate) fn pop_work(&mut self) -> Option<Work> {
|
pub(crate) fn pop_work(&mut self) -> Option<Work> {
|
||||||
let mut dirty_scope = self.dirty_scopes.first();
|
let dirty_scope = self.dirty_scopes.first();
|
||||||
// Pop any invalid scopes off of each dirty task;
|
// Make sure the top dirty scope is valid
|
||||||
while let Some(scope) = dirty_scope {
|
#[cfg(debug_assertions)]
|
||||||
if !self.scopes.contains(scope.id.0) {
|
if let Some(scope) = dirty_scope {
|
||||||
self.dirty_scopes.pop_first();
|
assert!(self.scopes.contains(scope.id.0));
|
||||||
dirty_scope = self.dirty_scopes.first();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the height of the highest dirty scope
|
// Find the height of the highest dirty scope
|
||||||
@@ -197,7 +190,7 @@ impl VirtualDom {
|
|||||||
let mut dirty_task = dirty_tasks.first();
|
let mut dirty_task = dirty_tasks.first();
|
||||||
// Pop any invalid tasks off of each dirty scope;
|
// Pop any invalid tasks off of each dirty scope;
|
||||||
while let Some(task) = dirty_task {
|
while let Some(task) = dirty_task {
|
||||||
if task.tasks_queued.borrow().is_empty() || !self.scopes.contains(task.order.id.0) {
|
if task.tasks_queued.borrow().is_empty() {
|
||||||
dirty_tasks.pop_first();
|
dirty_tasks.pop_first();
|
||||||
dirty_task = dirty_tasks.first()
|
dirty_task = dirty_tasks.first()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in new issue
Block a user