LLSD: store scalar values inline instead of heap-allocating#308
Conversation
LLSD becomes a 16-byte tagged union: Boolean, Integer, Real and Date (as its F64) live directly in the value, so constructing, copying, assigning and destroying them does no allocation and no reference counting -- a copy is a struct copy. String, UUID, URI, Binary, Map and Array remain reference-counted heap impls with copy-on-write for containers; sharing semantics, reference stability of asBinary()/ asStringRef()/operator[] and the threading model are unchanged. type() is now an inline member load, and container operations static_cast to the concrete impl identified by the tag, so virtual dispatch survives only for cross-type conversions on heap values. ImplBoolean/ImplInteger/ImplReal/ImplDate, the undefined sentinel impl, safe() and the static-usage-count machinery are deleted. sizeof(LLSD) grows 8 -> 16 in exchange for scalar reads that never touch the heap. Allocation-count test goldens updated accordingly (integer ops now allocate zero impls). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR refactors LLSD's heap-backed implementation to remove per-impl type tagging and move inline scalar storage into the LLSD union, centralizing container mutability through static helpers and rewriting all accessors around mType-switch dispatch. ChangesLLSD Implementation Refactor
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Description
Follow-up to #307: LLSD scalar values no longer heap-allocate.
LLSDbecomes a 16-byte tagged union —{ union { Impl*; Boolean; Integer; Real }; Type }. Boolean, Integer, Real, and Date (stored as its F64 seconds-since-epoch) live inline in the value itself, so constructing, copying, assigning, and destroying them performs zero heap allocation and zero reference counting; a copy is a plain struct copy. String, UUID, URI, Binary, Map, and Array remain reference-counted heap impls with copy-on-write for containers — sharing semantics, reference stability ofasBinary()/asStringRef()/operator[], and the documented threading model are unchanged.Dispatch is restructured around the tag:
type()is now a header-inline member load, soisMap()/isArray()/type switches across the viewer compile to a load + compare with no call and no pointer chase.has/get/operator[]/size/iterators)static_castto the concrete impl identified by the tag; virtual dispatch survives only for cross-type conversions on heap values (e.g. String→Real).ImplBoolean/ImplInteger/ImplReal/ImplDate, the undefined sentinel impl,safe(), and theSTATIC_USAGE_COUNTmachinery are deleted outright. The unshared-impl in-place assignment optimization is preserved via anassignValuehelper.The allocation-count test goldens tell the story: "assign integer value" went 1→0 allocations, and the mixed map scenario went 9→4 (only the map, array, and two strings allocate; integers, reals, and undefs are free).
Related Issues
Issue Link: N/A — proactive performance work, continuation of #307.
Checklist
Please ensure the following before requesting review:
Additional Notes
Trade-off for reviewers:
sizeof(LLSD)grows 8→16, sovector<LLSD>payloads double and map nodes grow by 8 bytes — in exchange scalar reads never touch the heap (no allocator traffic, no refcount cache-line traffic, better locality). Self-assignment and self-move are handled explicitly.Observable behavior is unchanged: all 94 integration test suites (llcommon, llmessage, llcorehttp, llxml/settings, llinventory, llprimitive, and the newview-side tests) were rebuilt against the new layout and pass on Windows.
🤖 Generated with Claude Code