on master help sign in
Shrink the size of `NodeKind` by putting `ElementNode`s behind a ref

`ElementNode`s are not small, and by putting them behind a reference, then `NodeKind`'s size drops to three words and we avoid a bunch of `memcpy`ing. Additionally, use recursion in `EventsRegistry::remove_subtree` isntead of maintaining an explicit work stack. Recursion is faster and we don't need to worry about blowing the stack here since we already use recursion anyways in diffing.

commitbd2c84c174dfe3bfb7ac83a9d269d2572f6c07e7 authorNick Fitzgerald <fitzgen@gmail.com> dateFri 19 Apr 2019, 10:42 (8 years ago) parentfc6a13c
4 files changed+21−24
src/diff.rs+1−1 src/events.rs+8−13 src/node.rs+11−9 tests/web/main.rs+1−1
src/diff.rs+1−1
@@ -925,7 +925,7 @@ fn create(
925925 NodeKind::Text(TextNode { text }) => {
926926 change_list.create_text_node(text);
927927 }
928− NodeKind::Element(ElementNode {
928+ NodeKind::Element(&ElementNode {
929929 key: _,
930930 tag_name,
931931 listeners,
src/events.rs+8−13
@@ -19,7 +19,6 @@ cfg_if::cfg_if! {
1919 pub(crate) fn clear_active_listeners(&mut self) {}
2020 }
2121 } else {
22− use bumpalo::Bump;
2322 use crate::{
2423 node::{ElementNode, ListenerCallback, NodeKind},
2524 vdom::VdomWeak,
@@ -99,18 +98,14 @@ cfg_if::cfg_if! {
9998 }
10099
101100 pub(crate) fn remove_subtree(&mut self, node: &Node) {
102− let bump = Bump::new();
103− let mut stack = bumpalo::collections::Vec::with_capacity_in(64, &bump);
104− stack.push(node);
105−
106− while let Some(node) = stack.pop() {
107− match node.kind {
108− NodeKind::Cached(_) | NodeKind::Text(_) => continue,
109− NodeKind::Element(ElementNode {listeners, children, ..}) => {
110− for l in listeners {
111− self.remove(l);
112− }
113− stack.extend(children);
101+ match node.kind {
102+ NodeKind::Cached(_) | NodeKind::Text(_) => return,
103+ NodeKind::Element(&ElementNode {listeners, children, ..}) => {
104+ for l in listeners {
105+ self.remove(l);
106+ }
107+ for child in children {
108+ self.remove_subtree(child)
114109 }
115110 }
116111 }
src/node.rs+11−9
@@ -24,7 +24,7 @@ pub_unstable_internal! {
2424 Text(TextNode<'a>),
2525
2626 /// An element potentially with attributes and children.
27− Element(ElementNode<'a>),
27+ Element(&'a ElementNode<'a>),
2828
2929 /// A node in the vdom's `CachedSet`. This allows us to avoid
3030 /// re-rendering and re-diffing subtrees.
@@ -187,15 +187,17 @@ impl<'a> Node<'a> {
187187 let attributes: &'a Attributes = bump.alloc(attributes);
188188 let attributes: &'a [Attribute<'a>] = attributes.as_ref();
189189
190+ let element = bump.alloc_with(|| ElementNode {
191+ key,
192+ tag_name,
193+ listeners,
194+ attributes,
195+ children,
196+ namespace,
197+ });
198+
190199 Node {
191− kind: NodeKind::Element(ElementNode {
192− key,
193− tag_name,
194− listeners,
195− attributes,
196− children,
197− namespace,
198− }),
200+ kind: NodeKind::Element(element),
199201 }
200202 }
201203
tests/web/main.rs+1−1
@@ -89,7 +89,7 @@ pub fn assert_rendered<R: Render>(container: &web_sys::Element, r: &R) {
8989 "actual.text_content() == expected.text()"
9090 );
9191 }
92− NodeKind::Element(ElementNode {
92+ NodeKind::Element(&ElementNode {
9393 tag_name,
9494 attributes,
9595 children,