perf(runtime): reject non-private property names without validating UTF-8 (read −10.5%) - #8970
Conversation
…TF-8 private_member_storage_name runs at the top of both the generic property read and the generic write, so every property operation pays it — and it reached its verdict by UTF-8-validating the entire key before the prefix compare could reject it. Measured at ~7.5% self time in a computed-key read loop (plus its share of from_utf8), all of it spent proving that "k123" does not start with '#'. A length compare plus one byte settles it for every ordinary key. Keys that pass the filter still take the original path, so private members and '#'-prefixed ordinary keys behave exactly as before. Claude-Session: https://claude.ai/code/session_01Ay8VyLkKbm8Hkc1xmvTEsP
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review. 📝 WalkthroughWalkthroughThe generic property path now rejects ordinary keys with a length and first-byte check before UTF-8 validation. Private-member handling remains unchanged for keys that pass the filter. The shared prefix is now a constant, and the changelog records benchmark results. ChangesPrivate member name filtering
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This localized optimization avoids unnecessary UTF-8 validation for ordinary property names while preserving the existing path for private-member keys, with passing tests and equivalent differential results. No actionable merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Description checkExplanation The description is detailed and directly addresses the change, motivation, benchmarks, correctness validation, test results, and related pre-existing issues. It does not use the repository template headings or checklist, but it provides the required substantive information. Full details: Docstring CoverageExplanation Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 1 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
Merged. The reasoning holds and the implementation is careful in the two places it had to be:
Nice to see it reuse Validation — runtime 2779/0, codegen 1341/0 ( The −10.5% is not re-measured here. |
private_member_storage_nameruns at the top of both the generic property read (js_object_get_field_by_name) and the generic write (field_set_by_name), so every property operation in the program pays it. It reached its verdict viastr_from_string_header, which UTF-8-validates the entire key before the prefix compare can reject it.In a computed-key read loop that is ~7.5% self time (plus its share of
from_utf8) — all of it spent proving that"k123"does not begin with#.A private-member storage name always starts with
#and is longer than the#<perry:private-member:prefix, so a length compare plus one byte settles it for every ordinary key, with no validation and no slice. Keys that pass the filter still take the original path, so private members and#-prefixed ordinary keys are untouched.Measurement
Interleaved A/B pairs, min-of-15, quiet load (~1.9), 16-core Linux host:
Means move the same direction on all three (45→43, 93→85, 47→46). An earlier 6-pair run was inconclusive — the spread exceeded the effect — so this is the tightened measurement.
Correctness
perry-runtime: 2779 passed / 0 failed.static #instances, private methods, private getters,#x in obj, subclassing, and an ordinary property literally named#<perry:private-member:1:x>— is byte-identical, including on the cases where perry currently diverges from node.byte_len, then the payload's first byte via the sharedstring_header_payloadhelper).Note
Building that differential surfaced three pre-existing correctness bugs in private class members on
main(compound assignment on a private field yieldsNaN; private fields are enumerable own properties; an ordinary key matching the internal prefix is silently dropped). They are not affected by this PR — same output before and after — and are filed separately as #8969.https://claude.ai/code/session_01Ay8VyLkKbm8Hkc1xmvTEsP
Summary by CodeRabbit