Repository navigation
Use a virtual accessor instead of a dynamic_cast when building ShadowView layout metrics - #59290
hryhoriiK97 wants to merge 2 commits into
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
There's callers like https://github.com/software-mansion/react-native-svg/blob/main/common/cpp/react/renderer/components/rnsvg/RNSVGConcreteShadowNode.h#L31 which set this trait, while not being a ConcreteViewShadowNode. They happen to inherit from LayoutableShadowNode, but there's no strict enforcement here. |
`ViewKind` is only a convention: a component can set the trait without inheriting `ConcreteViewShadowNode`. Instead of relying on it, add a virtual `ShadowNode::asLayoutable()` that `LayoutableShadowNode` overrides, and use it in `layoutMetricsFromShadowNode` in place of the `dynamic_cast` for every node. Mark `LayoutableShadowNode::getDebugProps` as `override`, which clang requires once the class has another `override`, and add the new method to the C++ API snapshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@javache you're right, |
|
@javache has imported this pull request. If you are a Meta employee, you can view this in D126687891. |
|
This pull request was successfully merged by @hryhoriiK97 in 79a5629 When will my fix make it into a release? | How to file a pick request? |
Summary:
ShadowView's constructor reads the node's layout metrics throughlayoutMetricsFromShadowNode, which usesdynamic_cast<const LayoutableShadowNode *>to find out whether the node has layout. The differ builds aShadowViewfor every child it visits when it slices a node's children, so this runs for every visited node on every commit, including the per-frame commits that update a ScrollView's content offset.Current behavior. Every call pays for a
dynamic_cast, which walks the type's inheritance information at runtime; for aView, the node's type isConcreteViewShadowNode<...>, several levels belowLayoutableShadowNode. In Time Profiler traces of scrolling,__dynamic_casttook 19–21% of the differ's time.With this change.
ShadowNodegets a virtualasLayoutable()that returnsnullptr, andLayoutableShadowNodeoverrides it to returnthis.layoutMetricsFromShadowNodecalls it instead of thedynamic_cast, so every node, not only Views, gets its layout metrics without a runtime type check, and the compiler guarantees the result.LayoutableShadowNode::getDebugPropsis markedoverride, since clang requires it once the class has anotheroverride.Changelog:
[GENERAL] [CHANGED] - Building a
ShadowViewno longer uses adynamic_castto read a node's layout metricsTest Plan:
clang-formatpasses on the changed files. The C++ API snapshots inscripts/cxx-api/api-snapshotslist the new method.yarn fantom(full suite, with the tester rebuilt from this change): 3,289 tests pass (110 skipped by their configuration). In that run the tester crashed (SIGSEGV) in two other files,AnimatedBackend-itestandStaleEventHandlersFromInterruptedRender-itest; neither crashed in 30 runs each on their own, and the same kind of crash happens locally without this change.xcodebuildin Release and run on a physical iPhone 15 Pro (iOS 26.6.1). The two arms are the same binary with the change switched by a launch argument, in the order before, after, after, before. Interactions were driven by Argent on the physical iPhone. Timed: the diff phase of each mount transaction fromTransactionTelemetry, on the main thread.🤖 Generated with Claude Code