Speed up ScopedPrimitiveArrayRO

For small arrays <= 1024 elements, we use GetArrayRegion with stack
allocated backing storage instead of GetArrayElements. The speedup
comes from the fact that GetArrayRegion doesn't need to allocate a
copy of array.

Timing results for:
https://android-review.googlesource.com/#/c/169727/

BEFORE

Host:
Byte length=1 ns/op=452.2633712
Short length=1 ns/op=468.6469192
Int length=1 ns/op=422.5663486
Long length=1 ns/op=423.4946638
Byte length=8 ns/op=424.8546962
Short length=8 ns/op=424.3842626
Int length=8 ns/op=424.3816324
Long length=8 ns/op=452.9407552
Byte length=64 ns/op=441.674149
Short length=64 ns/op=472.2310028
Int length=64 ns/op=455.6142958
Long length=64 ns/op=487.6810328
Byte length=512 ns/op=454.0858634
Short length=512 ns/op=497.675829
Int length=512 ns/op=481.2103832
Long length=512 ns/op=507.4674306
Byte length=4096 ns/op=531.7923602
Short length=4096 ns/op=648.254466
Int length=4096 ns/op=578.0794842
Long length=4096 ns/op=563.3641424

N5:
Byte length=1 ns/op=3118.2292802
Short length=1 ns/op=3083.7797488
Int length=1 ns/op=3177.8996446
Long length=1 ns/op=3151.0892072
Byte length=8 ns/op=3287.7326966
Short length=8 ns/op=3126.5799676
Int length=8 ns/op=3197.3203112
Long length=8 ns/op=3201.0613218
Byte length=64 ns/op=3178.7730612
Short length=64 ns/op=3162.2255092
Int length=64 ns/op=3241.3191864
Long length=64 ns/op=3117.6674886
Byte length=512 ns/op=3106.540978
Short length=512 ns/op=3183.0501344
Int length=512 ns/op=3513.8142382
Long length=512 ns/op=3592.4372798
Byte length=4096 ns/op=3552.9428216
Short length=4096 ns/op=3997.586686
Int length=4096 ns/op=4545.2151442
Long length=4096 ns/op=4371.4996338

AFTER

Host:
Byte length=1 ns/op=261.764995
Short length=1 ns/op=238.6584262
Int length=1 ns/op=262.856902
Long length=1 ns/op=238.0286378
Byte length=8 ns/op=242.4962264
Short length=8 ns/op=247.8668746
Int length=8 ns/op=263.9420024
Long length=8 ns/op=243.3675294
Byte length=64 ns/op=243.3372902
Short length=64 ns/op=249.0408034
Int length=64 ns/op=250.2168296
Long length=64 ns/op=253.837053
Byte length=512 ns/op=252.8071526
Short length=512 ns/op=271.689653
Int length=512 ns/op=291.8933238
Long length=512 ns/op=341.6303746
Byte length=4096 ns/op=540.8749038
Short length=4096 ns/op=661.7068158
Int length=4096 ns/op=569.030217
Long length=4096 ns/op=565.0571702

N5:
Byte length=1 ns/op=1209.4042078
Short length=1 ns/op=1207.2498746
Int length=1 ns/op=1377.0557706
Long length=1 ns/op=1348.6359368
Byte length=8 ns/op=1260.0724162
Short length=8 ns/op=1229.6107912
Int length=8 ns/op=1414.1408952
Long length=8 ns/op=1394.1158746
Byte length=64 ns/op=1232.532947
Short length=64 ns/op=1228.1248122
Int length=64 ns/op=1468.2667912
Long length=64 ns/op=1404.232687
Byte length=512 ns/op=1256.976093
Short length=512 ns/op=1335.5540308
Int length=512 ns/op=1599.6927076
Long length=512 ns/op=1769.8866764
Byte length=4096 ns/op=3310.2486656
Short length=4096 ns/op=3956.6322484
Int length=4096 ns/op=4374.6221234
Long length=4096 ns/op=4256.71598

Bug: 19664826
Change-Id: I703d7346de732199be1feadbead021c6647a554a
diff --git a/include/nativehelper/ScopedPrimitiveArray.h b/include/nativehelper/ScopedPrimitiveArray.h
index b573bd6..b681b99 100644
--- a/include/nativehelper/ScopedPrimitiveArray.h
+++ b/include/nativehelper/ScopedPrimitiveArray.h
@@ -27,32 +27,44 @@
     class Scoped ## NAME ## ArrayRO { \
     public: \
         explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
-        : mEnv(env), mJavaArray(NULL), mRawArray(NULL) {} \
+        : mEnv(env), mJavaArray(NULL), mRawArray(NULL), mSize(0) {} \
         Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
-        : mEnv(env), mJavaArray(javaArray), mRawArray(NULL) { \
-            if (mJavaArray == NULL) { \
+        : mEnv(env) { \
+            if (javaArray == NULL) { \
+                mJavaArray = NULL; \
+                mSize = 0; \
+                mRawArray = NULL; \
                 jniThrowNullPointerException(mEnv, NULL); \
             } else { \
-                mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+                reset(javaArray); \
             } \
         } \
         ~Scoped ## NAME ## ArrayRO() { \
-            if (mRawArray) { \
+            if (mRawArray != NULL && mRawArray != mBuffer) { \
                 mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
             } \
         } \
         void reset(PRIMITIVE_TYPE ## Array javaArray) { \
             mJavaArray = javaArray; \
-            mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+            mSize = mEnv->GetArrayLength(mJavaArray); \
+            if (mSize <= buffer_size) { \
+                mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
+                mRawArray = mBuffer; \
+            } else { \
+                mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+            } \
         } \
         const PRIMITIVE_TYPE* get() const { return mRawArray; } \
         PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
         const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
-        size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
+        size_t size() const { return mSize; } \
     private: \
+        static const jsize buffer_size = 1024; \
         JNIEnv* const mEnv; \
         PRIMITIVE_TYPE ## Array mJavaArray; \
         PRIMITIVE_TYPE* mRawArray; \
+        jsize mSize; \
+        PRIMITIVE_TYPE mBuffer[buffer_size]; \
         DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
     }