Preserve lazy ViewManager initialization in UIManager - #58097
Conversation
Copy UIManager implementation property descriptors instead of spreading UIManagerImpl, so Bridgeless initialization does not eagerly invoke lazy ViewManager getters or trigger unnecessary getConstantsForViewManager calls. Add regression coverage verifying that ViewManager descriptors remain lazy, own, and enumerable, and that each getter is evaluated only once on first access.
UIManager lazy ViewManager initialization optimizationTest environment:
Metric definitions:
1. Temporary ReactInstance instrumentationThe following debug-only instrumentation was added locally to import android.util.Log
private fun createConstants(
viewManagers: List<ViewManager<in Nothing, in Nothing>>,
customDirectEvents: MutableMap<String, Any>?,
): MutableMap<String, Any> {
val startNanos = System.nanoTime()
// Existing implementation...
try {
return UIManagerModuleConstantsHelper.createConstants(
viewManagers,
null,
customDirectEvents,
)
} finally {
// Existing marker cleanup...
if (BuildConfig.DEBUG) {
Log.d(
"RNUIManagerPerf",
"getConstants(eagerViewManagers=${viewManagers.size}) took ${(System.nanoTime() - startNanos) / 1_000_000.0}ms",
)
}
}
}
private fun getConstantsForViewManager(
viewManager: ViewManager<*, *>,
customDirectEvents: MutableMap<String, Any>,
): NativeMap {
val startNanos = System.nanoTime()
// Existing implementation...
try {
val viewManagerConstants =
UIManagerModuleConstantsHelper.createConstantsForViewManager(
viewManager,
null,
null,
null,
customDirectEvents,
)
return Arguments.makeNativeMap(viewManagerConstants)
} finally {
// Existing trace cleanup...
if (BuildConfig.DEBUG) {
Log.d(
"RNUIManagerPerf",
"getConstantsForViewManager(${viewManager.name}) took ${(System.nanoTime() - startNanos) / 1_000_000.0}ms",
)
}
}
}2. Before/after logsBefore: object spreadWith The 20 Startup timing from the same run: After: property descriptor compositionAfter preserving the lazy property descriptors instead of reading their values, startup no longer calls Result:
Startup timing from the same run: The marker timings above are one cold-start sample and are included as supporting evidence. The deterministic regression signal is the removal of all 20 synchronous |
Summary:
Changelog:
[ANDROID] [FIXED] - Avoid unnecessary getConstantsForViewManager calls during UIManager initialization.
Test Plan:
yarn flow-checkyarn test packages/react-native/Libraries/ReactNative --runInBandyarn lint --quietyarn format-check