diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java deleted file mode 100644 index e2241e847ea..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import static com.facebook.react.fabric.FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT; -import static com.facebook.react.fabric.mounting.mountitems.FabricNameComponentMapping.getFabricComponentName; - -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Nullsafe; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.ReactMarker; -import com.facebook.react.bridge.ReactMarkerConstants; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.fabric.events.EventEmitterWrapper; -import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.react.fabric.mounting.SurfaceMountingManager; -import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; -import com.facebook.react.uimanager.StateWrapper; -import com.facebook.systrace.Systrace; -import java.util.Locale; - -/** - * This class represents a batch of {@link MountItem}s, represented directly as int buffers to - * remove the need for actual MountItem instances. - * - *

An IntBufferBatchMountItem batch contains an array of ints, indicating the mount actions that - * should be taken, and a size; as well as an array of Objects, and a corresponding array size, for - * any data that cannot be passed as a raw int. - * - *

The purpose of encapsulating the array of MountItems this way, is to reduce the amount of - * allocations in C++ and JNI round-trips. - */ -@DoNotStrip -@Nullsafe(Nullsafe.Mode.LOCAL) -final class IntBufferBatchMountItem implements BatchMountItem { - static final String TAG = IntBufferBatchMountItem.class.getSimpleName(); - - static final int INSTRUCTION_FLAG_MULTIPLE = 1; - - static final int INSTRUCTION_CREATE = 2; - static final int INSTRUCTION_DELETE = 4; - static final int INSTRUCTION_INSERT = 8; - static final int INSTRUCTION_REMOVE = 16; - static final int INSTRUCTION_UPDATE_PROPS = 32; - static final int INSTRUCTION_UPDATE_STATE = 64; - static final int INSTRUCTION_UPDATE_LAYOUT = 128; - static final int INSTRUCTION_UPDATE_EVENT_EMITTER = 256; - static final int INSTRUCTION_UPDATE_PADDING = 512; - static final int INSTRUCTION_UPDATE_OVERFLOW_INSET = 1024; - - private final int mSurfaceId; - private final int mCommitNumber; - - private final int[] mIntBuffer; - private final Object[] mObjBuffer; - - private final int mIntBufferLen; - private final int mObjBufferLen; - - IntBufferBatchMountItem(int surfaceId, int[] intBuf, Object[] objBuf, int commitNumber) { - mSurfaceId = surfaceId; - mCommitNumber = commitNumber; - - mIntBuffer = intBuf; - mObjBuffer = objBuf; - - mIntBufferLen = mIntBuffer.length; - mObjBufferLen = mObjBuffer.length; - } - - private void beginMarkers(String reason) { - Systrace.beginSection(Systrace.TRACE_TAG_REACT, "IntBufferBatchMountItem::" + reason); - - if (mCommitNumber > 0) { - ReactMarker.logFabricMarker( - ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, mCommitNumber); - } - } - - private void endMarkers() { - if (mCommitNumber > 0) { - ReactMarker.logFabricMarker( - ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, mCommitNumber); - } - - Systrace.endSection(Systrace.TRACE_TAG_REACT); - } - - @Override - public void execute(MountingManager mountingManager) { - SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(mSurfaceId); - if (surfaceMountingManager == null) { - FLog.e( - TAG, - "Skipping batch of MountItems; no SurfaceMountingManager found for [%d].", - mSurfaceId); - return; - } - if (surfaceMountingManager.isStopped()) { - FLog.e(TAG, "Skipping batch of MountItems; was stopped [%d].", mSurfaceId); - return; - } - if (ReactNativeFeatureFlags.enableFabricLogs()) { - FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", mSurfaceId); - } - - beginMarkers("mountViews"); - int i = 0, j = 0; - while (i < mIntBufferLen) { - int rawType = mIntBuffer[i++]; - int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE; - int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1); - - String[] args = {"numInstructions", String.valueOf(numInstructions)}; - - Systrace.beginSection( - Systrace.TRACE_TAG_REACT, - "IntBufferBatchMountItem::mountInstructions::" + nameForInstructionString(type), - args, - args.length); - for (int k = 0; k < numInstructions; k++) { - if (type == INSTRUCTION_CREATE) { - String componentName = getFabricComponentName((String) mObjBuffer[j++]); - surfaceMountingManager.createView( - componentName, - mIntBuffer[i++], - (ReadableMap) mObjBuffer[j++], - (StateWrapper) mObjBuffer[j++], - (EventEmitterWrapper) mObjBuffer[j++], - mIntBuffer[i++] == 1); - } else if (type == INSTRUCTION_DELETE) { - surfaceMountingManager.deleteView(mIntBuffer[i++]); - } else if (type == INSTRUCTION_INSERT) { - int tag = mIntBuffer[i++]; - int parentTag = mIntBuffer[i++]; - surfaceMountingManager.addViewAt(parentTag, tag, mIntBuffer[i++]); - } else if (type == INSTRUCTION_REMOVE) { - surfaceMountingManager.removeViewAt(mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); - } else if (type == INSTRUCTION_UPDATE_PROPS) { - surfaceMountingManager.updateProps(mIntBuffer[i++], (ReadableMap) mObjBuffer[j++]); - } else if (type == INSTRUCTION_UPDATE_STATE) { - surfaceMountingManager.updateState(mIntBuffer[i++], (StateWrapper) mObjBuffer[j++]); - } else if (type == INSTRUCTION_UPDATE_LAYOUT) { - int reactTag = mIntBuffer[i++]; - int parentTag = mIntBuffer[i++]; - int x = mIntBuffer[i++]; - int y = mIntBuffer[i++]; - int width = mIntBuffer[i++]; - int height = mIntBuffer[i++]; - int displayType = mIntBuffer[i++]; - int layoutDirection = mIntBuffer[i++]; - surfaceMountingManager.updateLayout( - reactTag, parentTag, x, y, width, height, displayType, layoutDirection); - } else if (type == INSTRUCTION_UPDATE_PADDING) { - surfaceMountingManager.updatePadding( - mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); - } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { - int reactTag = mIntBuffer[i++]; - int overflowInsetLeft = mIntBuffer[i++]; - int overflowInsetTop = mIntBuffer[i++]; - int overflowInsetRight = mIntBuffer[i++]; - int overflowInsetBottom = mIntBuffer[i++]; - - surfaceMountingManager.updateOverflowInset( - reactTag, - overflowInsetLeft, - overflowInsetTop, - overflowInsetRight, - overflowInsetBottom); - } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { - surfaceMountingManager.updateEventEmitter( - mIntBuffer[i++], (EventEmitterWrapper) mObjBuffer[j++]); - } else { - throw new IllegalArgumentException( - "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i); - } - } - Systrace.endSection(Systrace.TRACE_TAG_REACT); - } - endMarkers(); - } - - @Override - public int getSurfaceId() { - return mSurfaceId; - } - - @Override - public boolean isBatchEmpty() { - return mIntBufferLen == 0; - } - - @Override - public String toString() { - try { - StringBuilder s = new StringBuilder(); - s.append(String.format(Locale.ROOT, "IntBufferBatchMountItem [surface:%d]:\n", mSurfaceId)); - int i = 0, j = 0; - while (i < mIntBufferLen) { - int rawType = mIntBuffer[i++]; - int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE; - int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1); - for (int k = 0; k < numInstructions; k++) { - if (type == INSTRUCTION_CREATE) { - String componentName = getFabricComponentName((String) mObjBuffer[j++]); - j += 3; - s.append( - String.format( - Locale.ROOT, - "CREATE [%d] - layoutable:%d - %s\n", - mIntBuffer[i++], - mIntBuffer[i++], - componentName)); - } else if (type == INSTRUCTION_DELETE) { - s.append(String.format(Locale.ROOT, "DELETE [%d]\n", mIntBuffer[i++])); - } else if (type == INSTRUCTION_INSERT) { - s.append( - String.format( - Locale.ROOT, - "INSERT [%d]->[%d] @%d\n", - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++])); - } else if (type == INSTRUCTION_REMOVE) { - s.append( - String.format( - Locale.ROOT, - "REMOVE [%d]->[%d] @%d\n", - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++])); - } else if (type == INSTRUCTION_UPDATE_PROPS) { - Object props = mObjBuffer[j++]; - String propsString = - IS_DEVELOPMENT_ENVIRONMENT - ? (props != null ? props.toString() : "") - : ""; - s.append( - String.format( - Locale.ROOT, "UPDATE PROPS [%d]: %s\n", mIntBuffer[i++], propsString)); - } else if (type == INSTRUCTION_UPDATE_STATE) { - StateWrapper state = (StateWrapper) mObjBuffer[j++]; - String stateString = - IS_DEVELOPMENT_ENVIRONMENT - ? (state != null ? state.toString() : "") - : ""; - s.append( - String.format( - Locale.ROOT, "UPDATE STATE [%d]: %s\n", mIntBuffer[i++], stateString)); - } else if (type == INSTRUCTION_UPDATE_LAYOUT) { - s.append( - String.format( - Locale.ROOT, - "UPDATE LAYOUT [%d]->[%d]: x:%d y:%d w:%d h:%d displayType:%d" - + " layoutDirection:%d\n", - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++])); - } else if (type == INSTRUCTION_UPDATE_PADDING) { - s.append( - String.format( - Locale.ROOT, - "UPDATE PADDING [%d]: top:%d right:%d bottom:%d left:%d\n", - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++])); - } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { - s.append( - String.format( - Locale.ROOT, - "UPDATE OVERFLOWINSET [%d]: left:%d top:%d right:%d bottom:%d\n", - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++], - mIntBuffer[i++])); - } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { - j += 1; - s.append(String.format(Locale.ROOT, "UPDATE EVENTEMITTER [%d]\n", mIntBuffer[i++])); - } else { - FLog.e(TAG, "String so far: " + s.toString()); - throw new IllegalArgumentException( - "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i); - } - } - } - return s.toString(); - } catch (Exception e) { - // Generally, this only happens during development when a malformed buffer is sent through. - // In these cases, we print the buffers to assist in debugging. - // This should never happen in production, but if it does... it'd still be helpful to know. - FLog.e(TAG, "Caught exception trying to print", e); - - StringBuilder ss = new StringBuilder(); - for (int ii = 0; ii < mIntBufferLen; ii++) { - ss.append(mIntBuffer[ii]); - ss.append(", "); - } - FLog.e(TAG, ss.toString()); - - for (int jj = 0; jj < mObjBufferLen; jj++) { - FLog.e(TAG, mObjBuffer[jj] != null ? mObjBuffer[jj].toString() : "null"); - } - - return ""; - } - } - - private static String nameForInstructionString(int type) { - if (type == INSTRUCTION_CREATE) { - return "CREATE"; - } else if (type == INSTRUCTION_DELETE) { - return "DELETE"; - } else if (type == INSTRUCTION_INSERT) { - return "INSERT"; - } else if (type == INSTRUCTION_REMOVE) { - return "REMOVE"; - } else if (type == INSTRUCTION_UPDATE_PROPS) { - return "UPDATE_PROPS"; - } else if (type == INSTRUCTION_UPDATE_STATE) { - return "UPDATE_STATE"; - } else if (type == INSTRUCTION_UPDATE_LAYOUT) { - return "UPDATE_LAYOUT"; - } else if (type == INSTRUCTION_UPDATE_PADDING) { - return "UPDATE_PADDING"; - } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) { - return "UPDATE_OVERFLOW_INSET"; - } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) { - return "UPDATE_EVENT_EMITTER"; - } else { - return "UNKNOWN"; - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.kt new file mode 100644 index 00000000000..75ffb391a60 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.kt @@ -0,0 +1,335 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.fabric.mounting.mountitems + +import com.facebook.common.logging.FLog +import com.facebook.proguard.annotations.DoNotStripAny +import com.facebook.react.bridge.ReactMarker +import com.facebook.react.bridge.ReactMarkerConstants +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.fabric.FabricUIManager +import com.facebook.react.fabric.events.EventEmitterWrapper +import com.facebook.react.fabric.mounting.MountingManager +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags +import com.facebook.react.uimanager.StateWrapper +import com.facebook.systrace.Systrace +import java.util.Locale + +/** + * This class represents a batch of [MountItem]s, represented directly as int buffers to remove the + * need for actual MountItem instances. + * + * An IntBufferBatchMountItem batch contains an array of ints, indicating the mount actions that + * should be taken, and a size; as well as an array of Objects, and a corresponding array size, for + * any data that cannot be passed as a raw int. + * + * The purpose of encapsulating the array of MountItems this way, is to reduce the amount of + * allocations in C++ and JNI round-trips. + */ +@DoNotStripAny +internal class IntBufferBatchMountItem( + private val surfaceId: Int, + private val intBuffer: IntArray, + private val objBuffer: Array, + private val commitNumber: Int +) : BatchMountItem { + private val intBufferLen = intBuffer.size + private val objBufferLen = objBuffer.size + + private fun beginMarkers(reason: String) { + Systrace.beginSection(Systrace.TRACE_TAG_REACT, "IntBufferBatchMountItem::$reason") + + if (commitNumber > 0) { + ReactMarker.logFabricMarker( + ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, commitNumber) + } + } + + private fun endMarkers() { + if (commitNumber > 0) { + ReactMarker.logFabricMarker( + ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, commitNumber) + } + + Systrace.endSection(Systrace.TRACE_TAG_REACT) + } + + override fun execute(mountingManager: MountingManager) { + val surfaceMountingManager = mountingManager.getSurfaceManager(surfaceId) + if (surfaceMountingManager == null) { + FLog.e( + TAG, "Skipping batch of MountItems; no SurfaceMountingManager found for [%d].", surfaceId) + return + } + if (surfaceMountingManager.isStopped()) { + FLog.e(TAG, "Skipping batch of MountItems; was stopped [%d].", surfaceId) + return + } + if (ReactNativeFeatureFlags.enableFabricLogs()) { + FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", surfaceId) + } + + beginMarkers("mountViews") + var i = 0 + var j = 0 + while (i < intBufferLen) { + val rawType = intBuffer[i++] + val type = rawType and INSTRUCTION_FLAG_MULTIPLE.inv() + val numInstructions = + (if ((rawType and INSTRUCTION_FLAG_MULTIPLE) != 0) intBuffer[i++] else 1) + + val args = arrayOf("numInstructions", numInstructions.toString()) + + Systrace.beginSection( + Systrace.TRACE_TAG_REACT, + "IntBufferBatchMountItem::mountInstructions::" + nameForInstructionString(type), + args, + args.size) + for (k in 0 until numInstructions) { + when (type) { + INSTRUCTION_CREATE -> { + val componentName = (objBuffer[j++] as String?).orEmpty() + val fabricComponentName = + FabricNameComponentMapping.getFabricComponentName(componentName) + surfaceMountingManager.createView( + fabricComponentName, + intBuffer[i++], + objBuffer[j++] as ReadableMap?, + objBuffer[j++] as StateWrapper?, + objBuffer[j++] as EventEmitterWrapper?, + intBuffer[i++] == 1) + } + INSTRUCTION_DELETE -> surfaceMountingManager.deleteView(intBuffer[i++]) + INSTRUCTION_INSERT -> { + val tag = intBuffer[i++] + val parentTag = intBuffer[i++] + surfaceMountingManager.addViewAt(parentTag, tag, intBuffer[i++]) + } + INSTRUCTION_REMOVE -> + surfaceMountingManager.removeViewAt(intBuffer[i++], intBuffer[i++], intBuffer[i++]) + INSTRUCTION_UPDATE_PROPS -> + surfaceMountingManager.updateProps(intBuffer[i++], objBuffer[j++] as ReadableMap?) + INSTRUCTION_UPDATE_STATE -> + surfaceMountingManager.updateState(intBuffer[i++], objBuffer[j++] as StateWrapper?) + INSTRUCTION_UPDATE_LAYOUT -> { + val reactTag = intBuffer[i++] + val parentTag = intBuffer[i++] + val x = intBuffer[i++] + val y = intBuffer[i++] + val width = intBuffer[i++] + val height = intBuffer[i++] + val displayType = intBuffer[i++] + val layoutDirection = intBuffer[i++] + surfaceMountingManager.updateLayout( + reactTag, parentTag, x, y, width, height, displayType, layoutDirection) + } + INSTRUCTION_UPDATE_PADDING -> + surfaceMountingManager.updatePadding( + intBuffer[i++], intBuffer[i++], intBuffer[i++], intBuffer[i++], intBuffer[i++]) + INSTRUCTION_UPDATE_OVERFLOW_INSET -> { + val reactTag = intBuffer[i++] + val overflowInsetLeft = intBuffer[i++] + val overflowInsetTop = intBuffer[i++] + val overflowInsetRight = intBuffer[i++] + val overflowInsetBottom = intBuffer[i++] + + surfaceMountingManager.updateOverflowInset( + reactTag, + overflowInsetLeft, + overflowInsetTop, + overflowInsetRight, + overflowInsetBottom) + } + INSTRUCTION_UPDATE_EVENT_EMITTER -> { + val eventEmitterWrapper = objBuffer[j++] as EventEmitterWrapper? + if (eventEmitterWrapper != null) { + surfaceMountingManager.updateEventEmitter(intBuffer[i++], eventEmitterWrapper) + } + } + else -> { + throw IllegalArgumentException( + "Invalid type argument to IntBufferBatchMountItem: $type at index: $i") + } + } + } + Systrace.endSection(Systrace.TRACE_TAG_REACT) + } + endMarkers() + } + + override fun getSurfaceId(): Int = surfaceId + + override fun isBatchEmpty(): Boolean = intBufferLen == 0 + + override fun toString(): String { + try { + val s = StringBuilder() + s.append(String.format(Locale.ROOT, "IntBufferBatchMountItem [surface:%d]:\n", surfaceId)) + var i = 0 + var j = 0 + while (i < intBufferLen) { + val rawType = intBuffer[i++] + val type = rawType and INSTRUCTION_FLAG_MULTIPLE.inv() + val numInstructions = + (if ((rawType and INSTRUCTION_FLAG_MULTIPLE) != 0) intBuffer[i++] else 1) + for (k in 0 until numInstructions) { + when (type) { + INSTRUCTION_CREATE -> { + val componentName = (objBuffer[j++] as String?).orEmpty() + val fabricComponentName = + FabricNameComponentMapping.getFabricComponentName(componentName) + + j += 3 + s.append( + String.format( + Locale.ROOT, + "CREATE [%d] - layoutable:%d - %s\n", + intBuffer[i++], + intBuffer[i++], + fabricComponentName)) + } + INSTRUCTION_DELETE -> + s.append(String.format(Locale.ROOT, "DELETE [%d]\n", intBuffer[i++])) + INSTRUCTION_INSERT -> + s.append( + String.format( + Locale.ROOT, + "INSERT [%d]->[%d] @%d\n", + intBuffer[i++], + intBuffer[i++], + intBuffer[i++])) + INSTRUCTION_REMOVE -> + s.append( + String.format( + Locale.ROOT, + "REMOVE [%d]->[%d] @%d\n", + intBuffer[i++], + intBuffer[i++], + intBuffer[i++])) + INSTRUCTION_UPDATE_PROPS -> { + val props = objBuffer[j++] + val propsString = + if (FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT) (props?.toString() ?: "") + else "" + s.append( + String.format( + Locale.ROOT, "UPDATE PROPS [%d]: %s\n", intBuffer[i++], propsString)) + } + INSTRUCTION_UPDATE_STATE -> { + val state: StateWrapper? = objBuffer[j++] as StateWrapper? + val stateString = + if (FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT) (state?.toString() ?: "") + else "" + s.append( + String.format( + Locale.ROOT, "UPDATE STATE [%d]: %s\n", intBuffer[i++], stateString)) + } + INSTRUCTION_UPDATE_LAYOUT -> + s.append( + String.format( + Locale.ROOT, + "UPDATE LAYOUT [%d]->[%d]: x:%d y:%d w:%d h:%d displayType:%d" + + " layoutDirection:%d\n", + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++])) + INSTRUCTION_UPDATE_PADDING -> + s.append( + String.format( + Locale.ROOT, + "UPDATE PADDING [%d]: top:%d right:%d bottom:%d left:%d\n", + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++])) + INSTRUCTION_UPDATE_OVERFLOW_INSET -> + s.append( + String.format( + Locale.ROOT, + "UPDATE OVERFLOWINSET [%d]: left:%d top:%d right:%d bottom:%d\n", + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++], + intBuffer[i++])) + INSTRUCTION_UPDATE_EVENT_EMITTER -> { + j += 1 + s.append(String.format(Locale.ROOT, "UPDATE EVENTEMITTER [%d]\n", intBuffer[i++])) + } + else -> { + FLog.e(TAG, "String so far: $s") + throw IllegalArgumentException( + "Invalid type argument to IntBufferBatchMountItem: $type at index: $i") + } + } + } + } + return s.toString() + } catch (e: Exception) { + // Generally, this only happens during development when a malformed buffer is sent through. + // In these cases, we print the buffers to assist in debugging. + // This should never happen in production, but if it does... it'd still be helpful to know. + FLog.e(TAG, "Caught exception trying to print", e) + + val ss = StringBuilder() + var ii = 0 + while (ii < intBufferLen) { + ss.append(intBuffer[ii]) + ss.append(", ") + ii++ + } + FLog.e(TAG, ss.toString()) + + var jj = 0 + while (jj < objBufferLen) { + FLog.e(TAG, if (objBuffer[jj] != null) objBuffer[jj].toString() else "null") + jj++ + } + + return "" + } + } + + companion object { + val TAG: String = IntBufferBatchMountItem::class.java.simpleName + + const val INSTRUCTION_FLAG_MULTIPLE: Int = 1 + + const val INSTRUCTION_CREATE: Int = 2 + const val INSTRUCTION_DELETE: Int = 4 + const val INSTRUCTION_INSERT: Int = 8 + const val INSTRUCTION_REMOVE: Int = 16 + const val INSTRUCTION_UPDATE_PROPS: Int = 32 + const val INSTRUCTION_UPDATE_STATE: Int = 64 + const val INSTRUCTION_UPDATE_LAYOUT: Int = 128 + const val INSTRUCTION_UPDATE_EVENT_EMITTER: Int = 256 + const val INSTRUCTION_UPDATE_PADDING: Int = 512 + const val INSTRUCTION_UPDATE_OVERFLOW_INSET: Int = 1024 + + private fun nameForInstructionString(type: Int): String = + when (type) { + INSTRUCTION_CREATE -> "CREATE" + INSTRUCTION_DELETE -> "DELETE" + INSTRUCTION_INSERT -> "INSERT" + INSTRUCTION_REMOVE -> "REMOVE" + INSTRUCTION_UPDATE_PROPS -> "UPDATE_PROPS" + INSTRUCTION_UPDATE_STATE -> "UPDATE_STATE" + INSTRUCTION_UPDATE_LAYOUT -> "UPDATE_LAYOUT" + INSTRUCTION_UPDATE_PADDING -> "UPDATE_PADDING" + INSTRUCTION_UPDATE_OVERFLOW_INSET -> "UPDATE_OVERFLOW_INSET" + INSTRUCTION_UPDATE_EVENT_EMITTER -> "UPDATE_EVENT_EMITTER" + else -> "UNKNOWN" + } + } +}