feat: it works with a new bump each time!!

This commit is contained in:
Jonathan Kelley committed 2021-12-20 23:31:33 -05:00
1 parent e2e4d431e1
commit 78d9056e35
4 files changed
+121 -111

No files matched your search

+85 -63
View File
@@ -91,15 +91,18 @@ impl ScopeArena {
container: ElementId,
subtree: u32,
) -> ScopeId {
// Increment the ScopeId system. ScopeIDs are never reused
let new_scope_id = ScopeId(self.scope_counter.get());
self.scope_counter.set(self.scope_counter.get() + 1);
let parent_scope = parent_scope.map(|f| self.get_scope_raw(f)).flatten();
// Get the height of the scope
let height = parent_scope
.as_ref()
.map(|f| unsafe { &**f })
.map(|f| f.height + 1)
.map(|id| self.get_scope(id).map(|scope| scope.height))
.flatten()
.unwrap_or_default();
let parent_scope = parent_scope.map(|f| self.get_scope_raw(f)).flatten();
/*
This scopearena aggressively reuse old scopes when possible.
We try to minimize the new allocations for props/arenas.
@@ -107,60 +110,39 @@ impl ScopeArena {
However, this will probably lead to some sort of fragmentation.
I'm not exactly sure how to improve this today.
*/
match self.free_scopes.borrow_mut().pop() {
// No free scope, make a new scope
None => {
let (node_capacity, hook_capacity) = self
.heuristics
.borrow()
.get(&fc_ptr)
.map(|h| (h.node_arena_size, h.hook_arena_size))
.unwrap_or_default();
if let Some(old_scope) = self.free_scopes.borrow_mut().pop() {
// reuse the old scope
let scope = unsafe { &mut *old_scope };
scope.props.get_mut().replace(vcomp);
scope.parent_scope = parent_scope;
scope.height = height;
scope.subtree.set(subtree);
scope.our_arena_idx = new_scope_id;
scope.container = container;
let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
debug_assert!(any_item.is_none());
} else {
// else create a new scope
let (node_capacity, hook_capacity) = self
.heuristics
.borrow()
.get(&fc_ptr)
.map(|h| (h.node_arena_size, h.hook_arena_size))
.unwrap_or_default();
let frames = [BumpFrame::new(node_capacity), BumpFrame::new(node_capacity)];
let scope = self.bump.alloc(ScopeState {
sender: self.sender.clone(),
container,
our_arena_idx: new_scope_id,
parent_scope,
self.scopes.borrow_mut().insert(
new_scope_id,
self.bump.alloc(ScopeState::new(
height,
frames,
subtree: Cell::new(subtree),
is_subtree_root: Cell::new(false),
props: vcomp,
generation: 0.into(),
shared_contexts: Default::default(),
items: RefCell::new(SelfReferentialItems {
listeners: Default::default(),
borrowed_props: Default::default(),
tasks: Default::default(),
}),
hook_arena: Bump::new(),
hook_vals: RefCell::new(Vec::with_capacity(hook_capacity)),
hook_idx: Default::default(),
});
let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
debug_assert!(any_item.is_none());
}
// Reuse a free scope
Some(old_scope) => {
let scope = unsafe { &mut *old_scope };
scope.props.set(vcomp);
scope.parent_scope = parent_scope;
scope.height = height;
scope.subtree = Cell::new(subtree);
scope.our_arena_idx = new_scope_id;
scope.container = container;
let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
debug_assert!(any_item.is_none());
}
container,
new_scope_id,
self.sender.clone(),
parent_scope,
vcomp,
node_capacity,
hook_capacity,
)),
);
}
new_scope_id
@@ -176,9 +158,6 @@ impl ScopeArena {
let scope = unsafe { &mut *self.scopes.borrow_mut().remove(&id).unwrap() };
scope.reset();
todo!("drop");
// unsafe { &*scope.render.get() }.release();
self.free_scopes.borrow_mut().push(scope);
Some(())
@@ -230,8 +209,7 @@ impl ScopeArena {
self.ensure_drop_safety(scope_id);
let g = comp.props.take();
// comp.props.release();
drop(comp.props.take());
});
// Now that all the references are gone, we can safely drop our own references in our listeners.
@@ -285,7 +263,10 @@ impl ScopeArena {
Also, the way we implement hooks allows us to cut rendering short before the next hook is recalled.
I'm not sure if React lets you abort the component early, but we let you do that.
*/
if let Some(node) = scope.props.render(scope) {
let props = scope.props.borrow();
let render = props.as_ref().unwrap();
if let Some(node) = render.render(scope) {
if !scope.items.borrow().tasks.is_empty() {
self.pending_futures.borrow_mut().insert(id);
}
@@ -425,7 +406,7 @@ pub struct ScopeState {
pub(crate) is_subtree_root: Cell<bool>,
pub(crate) subtree: Cell<u32>,
pub(crate) props: Option<RefCell<Box<dyn AnyProps>>>,
pub(crate) props: RefCell<Option<Box<dyn AnyProps>>>,
// nodes, items
pub(crate) frames: [BumpFrame; 2],
@@ -449,6 +430,47 @@ pub struct SelfReferentialItems<'a> {
// Public methods exposed to libraries and components
impl ScopeState {
fn new(
height: u32,
container: ElementId,
our_arena_idx: ScopeId,
sender: UnboundedSender<SchedulerMsg>,
parent_scope: Option<*mut ScopeState>,
vcomp: Box<dyn AnyProps>,
node_capacity: usize,
hook_capacity: usize,
) -> Self {
let frames = [BumpFrame::new(node_capacity), BumpFrame::new(node_capacity)];
ScopeState {
sender,
container,
our_arena_idx,
parent_scope,
props: RefCell::new(Some(vcomp)),
height,
frames,
// todo: subtrees
subtree: Cell::new(0),
is_subtree_root: Cell::new(false),
generation: 0.into(),
shared_contexts: Default::default(),
items: RefCell::new(SelfReferentialItems {
listeners: Default::default(),
borrowed_props: Default::default(),
tasks: Default::default(),
}),
hook_arena: Bump::new(),
hook_vals: RefCell::new(Vec::with_capacity(hook_capacity)),
hook_idx: Default::default(),
}
}
/// Get the subtree ID that this scope belongs to.
///
/// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route