Skip to content

perf(wasm): cache container kind() on JS wrappers - #1085

Open
zxch3n wants to merge 1 commit into
fix/wasm-handle-walk-memoryfrom
perf/wasm-kind-cache
Open

perf(wasm): cache container kind() on JS wrappers#1085
zxch3n wants to merge 1 commit into
fix/wasm-handle-walk-memoryfrom
perf/wasm-kind-cache

Conversation

@zxch3n

@zxch3n zxch3n commented Sep 3, 2026

Copy link
Copy Markdown
Member

Stack: 2/6 — merge order: #1093#1085#1086#1087#1090#1091

Summary

kind() on container wrappers (LoroMap/LoroList/LoroText/LoroTree/LoroMovableList/LoroCounter) returns a constant string per class, but every call crossed into WASM and allocated a fresh JS string via getStringFromWasm0. On a real document with ~70k containers, loro-mirror-style traversal called kind() 230k times per full read (and id 333k times; the id cache already landed in #1073).

This extends the existing container_id_cache_patch.js mechanism with a class-level memo for kind(). Reads after free() still raise wasm-bindgen's null-pointer error (the memo is bypassed for a zero __wbg_ptr), and Rust-side kind() reads in js_to_container share the same memo.

Measured (scripts/measure-container-id.cjs, 1M repeated reads of one wrapper)

case before after
same-wrapper-repeated-kind 164.5 ms, 1,000,000 string decodes ~1.0 ms, 0 decodes
mirror-reuse-wrapper (id + kind + toJSON, 20k containers) 51.1 ms, 63,333 decodes 42.4 ms, 23,333 decodes

Tests

  • tests/container_id_cache.test.ts: repeated kind() calls return the same string with zero additional wasm string decodes; at most one decode per container class; post-free() reads still throw.
  • Full wasm suite: 26 files / 349 tests pass; tsc --noEmit clean.

Wasm binary size

No change — this is a pure JS-glue patch.

Part 1 of the bulk-read series; the follow-up (per-container/range deep reads) stacks on this branch.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

WASM Size Report

  • Original size: 3107.72 KB
  • Gzipped size: 1028.48 KB
  • Brotli size: 721.49 KB

kind() returns a constant string per container class but the wasm-bindgen
glue crossed into WASM and allocated a fresh JS string on every call.
Memoize it once per class next to the existing per-wrapper id cache.

Measured with scripts/measure-container-id.cjs (1M repeated reads):
164.5 ms -> 1.0 ms, wasm string decodes 1,000,000 -> 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant