From 5649aed6d3223ec49c42416f242249eb0c4fd890 Mon Sep 17 00:00:00 2001 From: Kathy Gray Date: Wed, 17 Jan 2018 10:35:15 -0800 Subject: [PATCH] Move native accesses of array into one access instead of per-element Differential Revision: D6578349 fbshipit-source-id: 84ebd66ed791a845e9cc0fbc7e12a377534aa903 --- .../react/bridge/ReadableNativeArray.java | 139 ++++++++++++++++-- .../jni/react/jni/ReadableNativeArray.cpp | 71 +++++++-- .../main/jni/react/jni/ReadableNativeArray.h | 2 + 3 files changed, 194 insertions(+), 18 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.java index 6f799f2d0..9ed4c1ca9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.java @@ -13,6 +13,9 @@ import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import java.util.ArrayList; +import java.util.Arrays; +import com.facebook.infer.annotation.Assertions; +import javax.annotation.Nullable; /** * Implementation of a NativeArray that allows read-only access to its members. This will generally @@ -28,24 +31,142 @@ public class ReadableNativeArray extends NativeArray implements ReadableArray { super(hybridData); } + //WriteOnce but not in the constructor fields + private @Nullable Object[] mLocalArray; + private @Nullable ReadableType[] mLocalTypeArray; + + private static int jniPassCounter = 0; + private static boolean mUseNativeAccessor = false; + public static void setUseNativeAccessor(boolean useNativeAccessor) { + mUseNativeAccessor = useNativeAccessor; + } + public static int getJNIPassCounter() { + return jniPassCounter; + } + + private Object[] getLocalArray() { + // Fast, non blocking check for the common case + if (mLocalArray != null) { + return mLocalArray; + } + synchronized (this) { + // Make sure no concurrent call already updated + if (mLocalArray == null) { + jniPassCounter++; + mLocalArray = Assertions.assertNotNull(importArray()); + } + } + return mLocalArray; + } + private native Object[] importArray(); + + private ReadableType[] getLocalTypeArray() { + // Fast, non-blocking check for the common case + if (mLocalTypeArray != null) { + return mLocalTypeArray; + } + synchronized (this) { + // Make sure no concurrent call already updated + if (mLocalTypeArray == null) { + jniPassCounter++; + Object[] tempArray = Assertions.assertNotNull(importTypeArray()); + mLocalTypeArray = Arrays.copyOf(tempArray, tempArray.length, ReadableType[].class); + } + } + return mLocalTypeArray; + } + private native Object[] importTypeArray(); + @Override - public native int size(); + public int size() { + if (mUseNativeAccessor) { + jniPassCounter++; + return sizeNative(); + } + return getLocalArray().length; + } + private native int sizeNative(); + @Override - public native boolean isNull(int index); + public boolean isNull(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return isNullNative(index); + } + return getLocalArray()[index] == null; + } + private native boolean isNullNative(int index); + @Override - public native boolean getBoolean(int index); + public boolean getBoolean(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getBooleanNative(index); + } + return ((Boolean) getLocalArray()[index]).booleanValue(); + } + private native boolean getBooleanNative(int index); + @Override - public native double getDouble(int index); + public double getDouble(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getDoubleNative(index); + } + return ((Double) getLocalArray()[index]).doubleValue(); + } + private native double getDoubleNative(int index); + @Override - public native int getInt(int index); + public int getInt(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getIntNative(index); + } + return ((Double) getLocalArray()[index]).intValue(); + } + private native int getIntNative(int index); + @Override - public native String getString(int index); + public String getString(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getStringNative(index); + } + return (String) getLocalArray()[index]; + } + private native String getStringNative(int index); + @Override - public native ReadableNativeArray getArray(int index); + public ReadableNativeArray getArray(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getArrayNative(index); + } + return (ReadableNativeArray) getLocalArray()[index]; + } + private native ReadableNativeArray getArrayNative(int index); + @Override - public native ReadableNativeMap getMap(int index); + public ReadableNativeMap getMap(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getMapNative(index); + } + return (ReadableNativeMap) getLocalArray()[index]; + } + private native ReadableNativeMap getMapNative(int index); + @Override - public native ReadableType getType(int index); + public ReadableType getType(int index) { + if (mUseNativeAccessor) { + jniPassCounter++; + return getTypeNative(index); + } + return getLocalTypeArray()[index]; + } + + private native ReadableType getTypeNative(int index); @Override public Dynamic getDynamic(int index) { diff --git a/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp b/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp index bc445a493..51e8273d7 100644 --- a/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp +++ b/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp @@ -56,6 +56,48 @@ const char* ReadableNativeArray::getString(jint index) { return dyn.getString().c_str(); } +local_ref> ReadableNativeArray::importArray() { + jint size = array_.size(); + auto jarray = JArrayClass::newArray(size); + for (jint i = 0; i < size; i++) { + switch(array_.at(i).type()) { + case folly::dynamic::Type::NULLT: { + jarray->setElement(i, nullptr); + break; + } + case folly::dynamic::Type::BOOL: { + jarray-> + setElement(i, + JBoolean::valueOf(ReadableNativeArray::getBoolean(i)).release()); + break; + } + case folly::dynamic::Type::INT64: + case folly::dynamic::Type::DOUBLE: { + jarray->setElement(i, + JDouble::valueOf(ReadableNativeArray::getDouble(i)).release()); + break; + } + case folly::dynamic::Type::STRING: { + jarray-> + setElement(i, + make_jstring(ReadableNativeArray::getString(i)).release()); + break; + } + case folly::dynamic::Type::OBJECT: { + jarray->setElement(i,ReadableNativeArray::getMap(i).release()); + break; + } + case folly::dynamic::Type::ARRAY: { + jarray->setElement(i,ReadableNativeArray::getArray(i).release()); + break; + } + default: + break; + } + } + return jarray; +} + local_ref ReadableNativeArray::getArray(jint index) { auto& elem = array_.at(index); if (elem.isNull()) { @@ -69,6 +111,15 @@ local_ref ReadableNativeArray::getType(jint index) { return ReadableType::getType(array_.at(index).type()); } +local_ref> ReadableNativeArray::importTypeArray() { + jint size = array_.size(); + auto jarray = JArrayClass::newArray(size); + for (jint i = 0; i < size; i++) { + jarray->setElement(i, ReadableNativeArray::getType(i).release()); + } + return jarray; +} + local_ref ReadableNativeArray::getMap(jint index) { auto& elem = array_.at(index); return ReadableNativeMap::createWithContents(folly::dynamic(elem)); @@ -83,15 +134,17 @@ local_ref getMapFixed(alias_ref> importArray(); + jni::local_ref> importTypeArray(); jint getSize(); jboolean isNull(jint index); jboolean getBoolean(jint index);