Repository navigation
perf: plain struct values and cached namespace lookups (classic) - #26
Merged
Merged
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
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 was referenced Oct 17, 2026
Structs: values are plain JS objects built from a per-type template cached per isolate (new struct_value.rs), replacing per-value interceptor objects. - fixes a ~550 byte leak per struct returned from native - fixes every `new Rect(...)` sharing one buffer - nested struct and String fields are now read - spread, JSON, instanceof, toString and expando properties work - `new Rect()` zero-fills; wrong field types throw TypeError - Colors.Red.R: ~3100 -> ~760 ns; held field read: 55 -> ~1 ns Namespaces/enums: the interceptor is non-masking and resolved names become read-only own properties, so repeat lookups skip it. - Windows.UI.Xaml.Controls.Button: 355 -> 27 ns
TimedTextStyle has no Padding property, so the old test only round-tripped a JS expando. Use TimedTextRegion.Padding and assert no own property.
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.
Summary
Two changes to the classic (V8) engine.
1. Struct values are plain JS objects
WinRT structs were interceptor objects. Each one built a new
ObjectTemplateand boxed aDeclarationFFIthat was never freed. Now each struct type gets oneFunctionTemplateper isolate (runtime/src/struct_value.rs), and values are ordinary objects with one property per field. All values of a type share one V8 map and the constructor's prototype.WinRT structs are value types, so a value is a snapshot. Passing it back to native serializes its fields with the existing
append_struct_object_bytes.DeclarationFFI.struct_instanceis removed.Bugs fixed along the way:
new Rect(...)wrote into one buffer stored on the constructor, so creating a second struct changed the first.undefined(e.g.Duration.TimeSpan).{...s}gave{},JSON.stringify(new Rect(...))gave{},String(s)threw,instanceofwas false, and properties added in JS were dropped.new Rect()threw, andnew Rect({ X: 1 })produced a broken object. Missing fields are now zero, and wrong field types throw aTypeError.A
TypeNamevalue ({ Name, Kind }) passed to a method or property is serialized, andStringstruct fields are now written.2. Namespace and enum lookups are cached as real properties
The namespace/enum interceptor is now non-masking. Each resolved name is defined as a read-only, non-enumerable own property, so repeat lookups no longer go through the interceptor. Writes to a reserved name are ignored, and throw a
TypeErrorin strict mode, same as an already-resolved name.Gotcha:
define_own_propertygoes through the object's setter interceptor. A thread-local guard lets the define through, and the side store keeps a copy as a backup. Without that guard, every lookup rebuilt a constructor and a V8 template, which are never freed, and memory grew without limit.namespace_members.rschecksWindows.Foundation.Uri === Windows.Foundation.Urito catch this.Performance
Release build, ns per op over 1M iterations:
Windows.UI.Colors.Red.RWindows.Foundation.UriWindows.UI.Xaml.Controls.ButtonBehaviour changes
Object.keys(struct)lists fields in metadata order.Testing
integration-tests/tests/struct_values.rsandnamespace_members.rs.main(11 known UI-thread/environment failures).cargo checkpasses for the napi-only build (--no-default-features --features napi_engine) and for the combined build.Not in this PR
Windows.UI.ColorHelper.ToDisplayName(color)crashes with an access violation onmainas well; small structs passed by value need a separate look.