fix(native): one resolved-style cache key per distinct input set - #1
Draft
YevheniiKotyrlo wants to merge 1 commit into
Draft
YevheniiKotyrlo wants to merge 1 commit into
YevheniiKotyrlo wants to merge 1 commit into
Conversation
`generateStateHash` keys the resolved-style cache on weak-key identity, so it shares only when equal inputs arrive as one object. Three defects break that. **The config is minted per instance.** `styled()` derives it once at module scope; `useCssElement` derives one per instance from a module constant — same value, fresh identity, so N identical elements each hold their own entry, sorted rule array and observable. `getRuleVariation`'s rule clone is keyed on that identity too, so it was per element rather than per mapping. Deriving through `weakFamily` keys the config on the mapping. A mapping that is not an object is refused by name rather than through the `Invalid value used as weak map key` a primitive would otherwise raise from inside `reactivity`; the predicate is narrower than that WeakMap contract, since a function is a valid weak key and still not a mapping. **`family` and `weakFamily` cache on truthiness.** A factory returning `0` is re-run on every lookup, and `hashKeyFamily` hands out `hashKeyCount++` — so the first weak key hashed never settles. Of twelve call sites it is the only one whose result can be falsy, so caching on presence changes nothing else. **The key is lossy.** Folding N numbers into one and printing it base-36 is a digest, and `family` returns the entry it holds while ignoring the rules the second caller brought — so a collision renders one element's styles on another. Over one config plus one rule, the commonest shape, the fold collides 31.99% of the time. Sorting and joining is exact and keeps order-independence. The numbers are collected into a `Float64Array` so the sort is native: ordering them with `Array.prototype.sort` needs a comparator, and that callback is most of what ordering costs on Hermes — 1.10x the fold at the median key count against 1.64x. Float64 rather than Int32 because the key counter is unbounded and an int32 wraps silently at 2^31. Two inherited lines go with the fold: `generateStateHash`'s empty-string sentinel — unreachable, and collidable once the key is a join — together with the two parameters no caller passes, and the loop's `if (!key) continue`, which erased a member from a value whose whole point is that it erases nothing. `family` gains `size()` so the invariant is assertable. It reaches `rootVariables` and `universalVariables`, which are `family` instances published through `./native-internal` — additive, beside the `delete` and `clear` already on them. 50 identical elements: 50 entries before, 1 after. A 150-control screen on a physical Android device: 1785 → 270-271. Re-entering a screen grew the cache without limit (2, 4, 6 …) and is now flat; entries are still never released on unmount, which is a separate defect. 19 tests across five files, each red first.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Base layer of a stack. The submission is upstream: nativewind#434 — review and comment there.
This PR exists so the layer above it (#2) shows only its own six commits instead of seven. Nothing is merged in this fork.