perf(metadata): omit empty constructorTokens slot (reader change) - #435
Merged
Conversation
57933 of 60589 methods carry no constructor tokens, yet every MethodMeta paid a 4-byte pointer for the field. It is the trailing field and MethodMeta has no subclass, so it can be left out entirely and gated on a flag. Also widens the member flag mask: it cleared bits 8 and up alongside the type bits, which would silently discard any member flag stored there. No member in the SDK sets bit 8 today, so this changes nothing on its own.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
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.
Description
Draft. Stacked on #434 (
feat/metadata-size) — review only the last commit; the base PR is generator-only, this one is for changes that also need the runtime reader to move.Sizes on a full iOS 26.2 simulator SDK run, same umbrella header throughout:
main)This commit accounts for −231,713 B.
Current behavior
Every
MethodMetastores a 4-byte pointer to its constructor-tokens string. 57,933 of 60,589 methods have no constructor tokens — the field points at the interned empty string. The string itself costs nothing (one shared copy), but the pointer is paid 60,589 times.New behavior
constructorTokensis the trailing field ofMethodMeta, andMethodMetahas no subclass, so the slot can simply be omitted. A new flag,MethodHasConstructorTokens(bit 9), says whether it is present;MethodMeta::constructorTokens()returns""without touching the slot when the flag is clear.PropertyMeta::savealready conditionally omits its getter/setter pointers, so this follows an existing precedent in the format.Method records are only ever reached through
ArrayOfPtrTo<MethodMeta>— arrays of offsets, never contiguous structs — so a variable-size record is safe; nothing does pointer arithmetic across them.Also in this commit: a latent flag-mask bug
serializeMembermasked with0b11111000, which clears the 3 type bits and everything from bit 8 up. That silently discards any member flag stored at bit 8 or above — includingHasDemangledName, whichserializeBasehad just set. It is widened to~0b111so only the type bits are cleared.This changes nothing on its own today: I checked all 29,561 methods and 20,603 properties in the SDK and none carries a demangled name, so bit 8 was always 0 for members. But the mask had to be fixed before bit 9 could be used at all.
Verification
Both files rendered to a canonical, offset-independent form — every entity with names, flags, type encodings and constructor tokens resolved, sorted — then diffed:
The renderer auto-detects which format a file uses (legacy always-present slot vs. flagged slot) and compares the resulting string, so a method with no tokens renders as
""under both. Flag bits 7/8/9 are excluded from the comparison because they describe how a record is stored rather than what it means — names and tokens are compared directly instead.Risk
The reader change is the load-bearing part: if
constructorTokens()ever reads the slot when the flag is clear, it reads whatever the generator emitted next in the heap. The accessor is the single point where that is decided, and it is the only place_constructorTokensis touched.Only consumer of the value is
ArgConverter.mm:645-647, which compares it against tokens built from a JS initializer object;""there behaves exactly as the interned empty string did.Note on the diff size
Roughly 85 of the ~95 changed lines are clang-format reindenting the
BinaryFlagsandMetaFlagsenum blocks from 4-space to 2-space. The pre-commit hook formats staged hunks, and adding one enumerator marks the whole enum as touched. The semantic change is about ten lines: one new flag in each enum, the conditionalpush_pointer, the flag assignment, the mask widening, and the accessor. Reviewing with whitespace ignored makes this much easier to read.Does your pull request have unit tests?
Not yet — draft. The device suite has not been run on this branch. Unlike #434 this one changes reader behavior, so it does need a suite run before it leaves draft.