on master help sign in
Merge pull request #36 from fitzgen/string-cache

String cache

commit7134c897bdf194546ff012222616e9cf94d81eca authorNick Fitzgerald <fitzgen@gmail.com> dateMon 11 Mar 2019, 13:18 (8 years ago) parent5b90826a0a1e50
5 files changed+175−82
Cargo.lock+26−8 Cargo.toml+1 js/change-list.js+45−21 src/change_list.rs+95−48 src/vdom.rs+8−5
Cargo.lock+26−8
@@ -1,3 +1,5 @@
1+# This file is automatically @generated by Cargo.
2+# It is not intended for manual editing.
13[[package]]
24name = "aho-corasick"
35version = "0.6.10"
@@ -48,6 +50,11 @@ name = "bumpalo"
4850version = "2.1.0"
4951source = "registry+https://github.com/rust-lang/crates.io-index"
5052
53+[[package]]
54+name = "byteorder"
55+version = "1.3.1"
56+source = "registry+https://github.com/rust-lang/crates.io-index"
57+
5158[[package]]
5259name = "cc"
5360version = "1.0.30"
@@ -85,6 +92,7 @@ dependencies = [
8592 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
8693 "dodrio-js-api 0.1.0",
8794 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
95+ "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
8896 "js-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
8997 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
9098 "wasm-bindgen 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -230,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
230238dependencies = [
231239 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
232240 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
233− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
241+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
234242 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
235243]
236244
@@ -239,6 +247,14 @@ name = "futures"
239247version = "0.1.25"
240248source = "registry+https://github.com/rust-lang/crates.io-index"
241249
250+[[package]]
251+name = "fxhash"
252+version = "0.2.1"
253+source = "registry+https://github.com/rust-lang/crates.io-index"
254+dependencies = [
255+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
256+]
257+
242258[[package]]
243259name = "heck"
244260version = "0.3.1"
@@ -384,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
384400dependencies = [
385401 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
386402 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
387− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
403+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
388404]
389405
390406[[package]]
@@ -404,7 +420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
404420
405421[[package]]
406422name = "syn"
407−version = "0.15.28"
423+version = "0.15.29"
408424source = "registry+https://github.com/rust-lang/crates.io-index"
409425dependencies = [
410426 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -419,7 +435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
419435dependencies = [
420436 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
421437 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
422− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
438+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
423439 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
424440]
425441
@@ -491,7 +507,7 @@ dependencies = [
491507 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
492508 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
493509 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
494− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
510+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
495511 "wasm-bindgen-shared 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
496512]
497513
@@ -521,7 +537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
521537dependencies = [
522538 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
523539 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
524− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
540+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
525541 "wasm-bindgen-backend 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
526542 "wasm-bindgen-shared 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
527543]
@@ -564,7 +580,7 @@ dependencies = [
564580 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
565581 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
566582 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
567− "syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)",
583+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
568584 "wasm-bindgen-backend 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
569585 "weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
570586]
@@ -633,6 +649,7 @@ dependencies = [
633649"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
634650"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
635651"checksum bumpalo 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef2109240a377370f55ea3ef0b486b46d7b5c0f7455ab0ec676d73f875d58a"
652+"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
636653"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"
637654"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
638655"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
@@ -641,6 +658,7 @@ dependencies = [
641658"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
642659"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
643660"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
661+"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
644662"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
645663"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
646664"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
@@ -664,7 +682,7 @@ dependencies = [
664682"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c"
665683"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
666684"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
667−"checksum syn 0.15.28 (registry+https://github.com/rust-lang/crates.io-index)" = "218aa5a01ab9805df6e9e48074c8d88f317cc9660b1ad6c3dabac2d627d185d6"
685+"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
668686"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
669687"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
670688"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
Cargo.toml+1
@@ -11,6 +11,7 @@ futures = "0.1.25"
1111wasm-bindgen = "0.2.38"
1212wasm-bindgen-futures = "0.3.15"
1313js-sys = "0.3.15"
14+fxhash = "0.2.1"
1415log = { version = "0.4.6", optional = true }
1516
1617[dependencies.web-sys]
js/change-list.js+45−21
@@ -43,12 +43,10 @@ const OP_TABLE = [
4343
4444 // 3
4545 function setAttribute(changeList, mem8, mem32, i) {
46− const pointer1 = mem32[i++];
47− const length1 = mem32[i++];
48− const name = string(mem8, pointer1, length1);
49− const pointer2 = mem32[i++];
50− const length2 = mem32[i++];
51− const value = string(mem8, pointer2, length2);
46+ const nameId = mem32[i++];
47+ const valueId = mem32[i++];
48+ const name = changeList.getString(nameId);
49+ const value = changeList.getString(valueId);
5250 const node = top(changeList.stack);
5351 node.setAttribute(name, value);
5452
@@ -68,9 +66,8 @@ const OP_TABLE = [
6866
6967 // 4
7068 function removeAttribute(changeList, mem8, mem32, i) {
71− const pointer = mem32[i++];
72− const length = mem32[i++];
73− const name = string(mem8, pointer, length);
69+ const nameId = mem32[i++];
70+ const name = changeList.getString(nameId);
7471 const node = top(changeList.stack);
7572 node.removeAttribute(name);
7673
@@ -125,18 +122,16 @@ const OP_TABLE = [
125122
126123 // 10
127124 function createElement(changeList, mem8, mem32, i) {
128− const pointer = mem32[i++];
129− const length = mem32[i++];
130− const tagName = string(mem8, pointer, length);
125+ const tagNameId = mem32[i++];
126+ const tagName = changeList.getString(tagNameId);
131127 changeList.stack.push(document.createElement(tagName));
132128 return i;
133129 },
134130
135131 // 11
136132 function newEventListener(changeList, mem8, mem32, i) {
137− const pointer = mem32[i++];
138− const length = mem32[i++];
139− const eventType = string(mem8, pointer, length);
133+ const eventId = mem32[i++];
134+ const eventType = changeList.getString(eventId);
140135 const a = mem32[i++];
141136 const b = mem32[i++];
142137 const el = top(changeList.stack);
@@ -149,9 +144,8 @@ const OP_TABLE = [
149144
150145 // 12
151146 function updateEventListener(changeList, mem8, mem32, i) {
152− const pointer = mem32[i++];
153− const length = mem32[i++];
154− const eventType = string(mem8, pointer, length);
147+ const eventId = mem32[i++];
148+ const eventType = changeList.getString(eventId);
155149 const el = top(changeList.stack);
156150 const listener = el[`dodrio-${eventType}`];
157151 listener.a = mem32[i++];
@@ -161,14 +155,30 @@ const OP_TABLE = [
161155
162156 // 13
163157 function removeEventListener(changeList, mem8, mem32, i) {
164− const pointer = mem32[i++];
165− const length = mem32[i++];
166− const eventType = string(mem8, pointer, length);
158+ const eventId = mem32[i++];
159+ const eventType = changeList.getString(eventId);
167160 const el = top(changeList.stack);
168161 const listener = el[`dodrio-${eventType}`];
169162 el.removeEventListener(eventType, listener.callback);
170163 changeList.listeners.delete(listener);
171164 return i;
165+ },
166+
167+ // 14
168+ function addString(changeList, mem8, mem32, i) {
169+ const pointer = mem32[i++];
170+ const length = mem32[i++];
171+ const id = mem32[i++];
172+ const str = string(mem8, pointer, length);
173+ changeList.addString(str, id);
174+ return i;
175+ },
176+
177+ // 15
178+ function dropString(changeList, mem8, mem32, i) {
179+ const id = mem32[i++];
180+ changeList.dropString(id);
181+ return i;
172182 }
173183];
174184
@@ -195,6 +205,7 @@ class ChangeList {
195205 this.container = container;
196206 this.ranges = [];
197207 this.stack = [];
208+ this.strings = new Map();
198209 }
199210
200211 unmount() {
@@ -214,6 +225,7 @@ class ChangeList {
214225 this.container = null;
215226 this.ranges = null;
216227 this.stack = null;
228+ this.strings = null;
217229 }
218230
219231 addChangeListRange(start, len) {
@@ -248,6 +260,18 @@ class ChangeList {
248260 }
249261 }
250262
263+ addString(str, id) {
264+ this.strings.set(id, str);
265+ }
266+
267+ dropString(id) {
268+ this.strings.delete(id);
269+ }
270+
271+ getString(id) {
272+ return this.strings.get(id);
273+ }
274+
251275 initEventsTrampoline(trampoline) {
252276 this.eventsTrampoline = (...args) => {
253277 trampoline(...args);
src/change_list.rs+95−48
@@ -1,5 +1,6 @@
11use crate::Listener;
22use bumpalo::Bump;
3+use fxhash::FxHashMap;
34use std::fmt;
45use std::sync::Once;
56use wasm_bindgen::prelude::*;
@@ -32,8 +33,15 @@ pub mod js {
3233 }
3334}
3435
36+struct StringsCacheEntry {
37+ key: u32,
38+ used: bool,
39+}
40+
3541pub(crate) struct ChangeList {
3642 bump: Bump,
43+ strings_cache: FxHashMap<String, StringsCacheEntry>,
44+ next_string_key: u32,
3745 js: js::ChangeList,
3846 events_trampoline: Option<Closure<Fn(web_sys::Event, u32, u32)>>,
3947}
@@ -69,9 +77,12 @@ impl ChangeList {
6977 });
7078
7179 let bump = Bump::new();
80+ let strings_cache = FxHashMap::default();
7281 let js = js::ChangeList::new(container);
7382 ChangeList {
7483 bump,
84+ strings_cache,
85+ next_string_key: 0,
7586 js,
7687 events_trampoline: None,
7788 }
@@ -238,6 +249,24 @@ enum ChangeDiscriminant {
238249 /// stack.top().removeEventListener(String(pointer, length));
239250 /// ```
240251 RemoveEventListener = 13,
252+
253+ /// Immediates: `(pointer, length, id)`
254+ ///
255+ /// Stack: `[...] -> [...]`
256+ ///
257+ /// ```text
258+ /// addString(String(pointer, length), id);
259+ /// ```
260+ AddString = 14,
261+
262+ /// Immediates: `(id)`
263+ ///
264+ /// Stack: `[...] -> [...]`
265+ ///
266+ /// ```text
267+ /// dropString(id);
268+ /// ```
269+ DropString = 15,
241270}
242271
243272// Allocation utilities to ensure that we only allocation sequences of `u32`s
@@ -249,22 +278,63 @@ impl ChangeList {
249278 self.bump.alloc(discriminant as u32);
250279 }
251280
252− // Note: no 1-immediate opcodes at this time.
281+ // Allocate an opcode with one immediate.
282+ fn op1(&self, discriminant: ChangeDiscriminant, a: u32) {
283+ self.bump.alloc([discriminant as u32, a]);
284+ }
253285
254286 // Allocate an opcode with two immediates.
255287 fn op2(&self, discriminant: ChangeDiscriminant, a: u32, b: u32) {
256288 self.bump.alloc([discriminant as u32, a, b]);
257289 }
258290
259− // Note: no 3-immediate opcodes at this time.
260−
261− // Allocate an opcode with four immediates.
262− fn op4(&self, discriminant: ChangeDiscriminant, a: u32, b: u32, c: u32, d: u32) {
263− self.bump.alloc([discriminant as u32, a, b, c, d]);
291+ // Allocate an opcode with three immediates.
292+ fn op3(&self, discriminant: ChangeDiscriminant, a: u32, b: u32, c: u32) {
293+ self.bump.alloc([discriminant as u32, a, b, c]);
264294 }
295+
296+ // Note: no 4-immediate opcodes at this time.
265297}
266298
267299impl ChangeList {
300+ fn ensure_string(&mut self, string: &str) -> u32 {
301+ if let Some(entry) = self.strings_cache.get_mut(string) {
302+ entry.used = true;
303+ entry.key
304+ } else {
305+ let key = self.next_string_key;
306+ self.next_string_key += 1;
307+ let entry = StringsCacheEntry { key, used: true };
308+ self.strings_cache.insert(string.to_string(), entry);
309+ self.op3(
310+ ChangeDiscriminant::AddString,
311+ string.as_ptr() as u32,
312+ string.len() as u32,
313+ key,
314+ );
315+ key
316+ }
317+ }
318+
319+ pub(crate) fn drop_unused_strings(&mut self) {
320+ debug!("drop_unused_strings()");
321+ let mut new_cache = FxHashMap::default();
322+ for (key, val) in self.strings_cache.iter() {
323+ if val.used {
324+ new_cache.insert(
325+ key.clone(),
326+ StringsCacheEntry {
327+ key: val.key,
328+ used: false,
329+ },
330+ );
331+ } else {
332+ self.op1(ChangeDiscriminant::DropString, val.key);
333+ }
334+ }
335+ self.strings_cache = new_cache;
336+ }
337+
268338 pub(crate) fn emit_set_text(&self, text: &str) {
269339 debug!("emit_set_text({:?})", text);
270340 self.op2(
@@ -284,24 +354,17 @@ impl ChangeList {
284354 self.op0(ChangeDiscriminant::ReplaceWith);
285355 }
286356
287− pub(crate) fn emit_set_attribute(&self, name: &str, value: &str) {
357+ pub(crate) fn emit_set_attribute(&mut self, name: &str, value: &str) {
288358 debug!("emit_set_attribute({:?}, {:?})", name, value);
289− self.op4(
290− ChangeDiscriminant::SetAttribute,
291− name.as_ptr() as u32,
292− name.len() as u32,
293− value.as_ptr() as u32,
294− value.len() as u32,
295− );
359+ let name_id = self.ensure_string(name);
360+ let value_id = self.ensure_string(value);
361+ self.op2(ChangeDiscriminant::SetAttribute, name_id, value_id);
296362 }
297363
298− pub(crate) fn emit_remove_attribute(&self, name: &str) {
364+ pub(crate) fn emit_remove_attribute(&mut self, name: &str) {
299365 debug!("emit_remove_attribute({:?})", name);
300− self.op2(
301− ChangeDiscriminant::RemoveAttribute,
302− name.as_ptr() as u32,
303− name.len() as u32,
304− );
366+ let name_id = self.ensure_string(name);
367+ self.op1(ChangeDiscriminant::RemoveAttribute, name_id);
305368 }
306369
307370 pub(crate) fn emit_push_first_child(&self) {
@@ -333,47 +396,31 @@ impl ChangeList {
333396 );
334397 }
335398
336− pub(crate) fn emit_create_element(&self, tag_name: &str) {
399+ pub(crate) fn emit_create_element(&mut self, tag_name: &str) {
337400 debug!("emit_create_element({:?})", tag_name);
338− self.op2(
339− ChangeDiscriminant::CreateElement,
340− tag_name.as_ptr() as u32,
341− tag_name.len() as u32,
342− );
401+ let tag_name_id = self.ensure_string(tag_name);
402+ self.op1(ChangeDiscriminant::CreateElement, tag_name_id);
343403 }
344404
345− pub(crate) fn emit_new_event_listener(&self, listener: &Listener) {
405+ pub(crate) fn emit_new_event_listener(&mut self, listener: &Listener) {
346406 debug!("emit_new_event_listener({:?})", listener);
347407 let (a, b) = listener.get_callback_parts();
348408 debug_assert!(a != 0);
349− self.op4(
350− ChangeDiscriminant::NewEventListener,
351− listener.event.as_ptr() as u32,
352− listener.event.len() as u32,
353− a,
354− b,
355− );
409+ let event_id = self.ensure_string(listener.event);
410+ self.op3(ChangeDiscriminant::NewEventListener, event_id, a, b);
356411 }
357412
358− pub(crate) fn emit_update_event_listener(&self, listener: &Listener) {
413+ pub(crate) fn emit_update_event_listener(&mut self, listener: &Listener) {
359414 debug!("emit_update_event_listener({:?})", listener);
360415 let (a, b) = listener.get_callback_parts();
361416 debug_assert!(a != 0);
362− self.op4(
363− ChangeDiscriminant::UpdateEventListener,
364− listener.event.as_ptr() as u32,
365− listener.event.len() as u32,
366− a,
367− b,
368− );
417+ let event_id = self.ensure_string(listener.event);
418+ self.op3(ChangeDiscriminant::UpdateEventListener, event_id, a, b);
369419 }
370420
371− pub(crate) fn emit_remove_event_listener(&self, event: &str) {
421+ pub(crate) fn emit_remove_event_listener(&mut self, event: &str) {
372422 debug!("emit_remove_event_listener({:?})", event);
373− self.op2(
374− ChangeDiscriminant::RemoveEventListener,
375− event.as_ptr() as u32,
376− event.len() as u32,
377− );
423+ let event_id = self.ensure_string(event);
424+ self.op1(ChangeDiscriminant::RemoveEventListener, event_id);
378425 }
379426}
src/vdom.rs+8−5
@@ -256,6 +256,9 @@ impl VdomInnerExclusive {
256256
257257 self.events_registry = Some(events_registry);
258258
259+ // Find and drop cached strings that aren't in use anymore.
260+ self.change_list.drop_unused_strings();
261+
259262 // Tell JS to apply our diff-generated changes to the physical DOM!
260263 self.change_list.apply_changes();
261264 }
@@ -271,7 +274,7 @@ impl VdomInnerExclusive {
271274 self.current_root = Some(current);
272275 }
273276
274− fn diff<'a>(&self, registry: &mut EventsRegistry, old: Node<'a>, new: Node<'a>) {
277+ fn diff<'a>(&mut self, registry: &mut EventsRegistry, old: Node<'a>, new: Node<'a>) {
275278 // debug!("---------------------------------------------------------");
276279 // debug!("dodrio::Vdom::diff");
277280 // debug!(" old = {:#?}", old);
@@ -323,7 +326,7 @@ impl VdomInnerExclusive {
323326 }
324327
325328 fn diff_listeners<'a>(
326− &self,
329+ &mut self,
327330 registry: &mut EventsRegistry,
328331 old: &'a [Listener<'a>],
329332 new: &'a [Listener<'a>],
@@ -357,7 +360,7 @@ impl VdomInnerExclusive {
357360 }
358361 }
359362
360− fn diff_attributes(&self, old: &[Attribute], new: &[Attribute]) {
363+ fn diff_attributes(&mut self, old: &[Attribute], new: &[Attribute]) {
361364 debug!(" updating attributes");
362365
363366 // Do O(n^2) passes to add/update and remove attributes, since
@@ -392,7 +395,7 @@ impl VdomInnerExclusive {
392395 }
393396
394397 fn diff_children<'a>(
395− &self,
398+ &mut self,
396399 registry: &mut EventsRegistry,
397400 old: &'a [Node<'a>],
398401 new: &'a [Node<'a>],
@@ -449,7 +452,7 @@ impl VdomInnerExclusive {
449452 }
450453 }
451454
452− fn create<'a>(&self, registry: &mut EventsRegistry, node: Node<'a>) {
455+ fn create<'a>(&mut self, registry: &mut EventsRegistry, node: Node<'a>) {
453456 match node {
454457 Node::Text(TextNode { text }) => {
455458 self.change_list.emit_create_text_node(text);