From 508b1526d9a7bf935ded23c91c7ee4f288ebbcdd Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 2 Jul 2025 17:26:48 -0700 Subject: [PATCH] Avoid array copies on every MapBuffer read (#52386) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52386 Enum `values()` function makes a copy of an underlying array on each call. This happens in a hot path, and seems to show up during profiling. Let's cache it. Changelog: [Internal] Reviewed By: lenaic Differential Revision: D77623705 fbshipit-source-id: 5a33425822f477f63fe104ca9e5ed474385a2022 --- .../react/common/mapbuffer/ReadableMapBuffer.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/ReadableMapBuffer.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/ReadableMapBuffer.kt index d246ffba26b..0984d77764c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/ReadableMapBuffer.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/ReadableMapBuffer.kt @@ -11,6 +11,7 @@ import com.facebook.jni.HybridClassBase import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.common.annotations.StableReactNativeAPI import com.facebook.react.common.mapbuffer.MapBuffer.Companion.KEY_RANGE +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import java.lang.StringBuilder import java.nio.ByteBuffer import java.nio.ByteOrder @@ -86,7 +87,11 @@ private constructor( private fun readDataType(bucketIndex: Int): MapBuffer.DataType { val value = readUnsignedShort(getKeyOffsetForBucketIndex(bucketIndex) + TYPE_OFFSET).toInt() - return MapBuffer.DataType.values()[value] + return if (ReactNativeFeatureFlags.enableAndroidTextMeasurementOptimizations()) { + DATA_TYPES[value] + } else { + MapBuffer.DataType.values()[value] + } } private fun getTypedValueOffsetForKey(key: Int, expected: MapBuffer.DataType): Int { @@ -264,7 +269,12 @@ private constructor( get() = readUnsignedShort(bucketOffset).toInt() override val type: MapBuffer.DataType - get() = MapBuffer.DataType.values()[readUnsignedShort(bucketOffset + TYPE_OFFSET).toInt()] + get() = + if (ReactNativeFeatureFlags.enableAndroidTextMeasurementOptimizations()) { + DATA_TYPES[readUnsignedShort(bucketOffset + TYPE_OFFSET).toInt()] + } else { + MapBuffer.DataType.values()[readUnsignedShort(bucketOffset + TYPE_OFFSET).toInt()] + } override val doubleValue: Double get() { @@ -318,5 +328,7 @@ private constructor( // 4 bytes = 2 (key) + 2 (type) private const val VALUE_OFFSET = 4 + + private val DATA_TYPES = MapBuffer.DataType.values() } }