1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cmath>
18 #include <vector>
19
20 #include <fbjni/fbjni.h>
21
22 #include "expect.h"
23
24 using namespace facebook::jni;
25
testMakeBoolArray(alias_ref<jclass>,jint size)26 local_ref<jbooleanArray> testMakeBoolArray(alias_ref<jclass>, jint size) {
27 return make_boolean_array(size);
28 }
29
testMakeByteArray(alias_ref<jclass>,jint size)30 local_ref<jbyteArray> testMakeByteArray(alias_ref<jclass>, jint size) {
31 return make_byte_array(size);
32 }
33
testMakeCharArray(alias_ref<jclass>,jint size)34 local_ref<jcharArray> testMakeCharArray(alias_ref<jclass>, jint size) {
35 return make_char_array(size);
36 }
37
testMakeShortArray(alias_ref<jclass>,jint size)38 local_ref<jshortArray> testMakeShortArray(alias_ref<jclass>, jint size) {
39 return make_short_array(size);
40 }
41
testMakeIntArray(alias_ref<jclass>,jint size)42 local_ref<jintArray> testMakeIntArray(alias_ref<jclass>, jint size) {
43 return make_int_array(size);
44 }
45
testMakeLongArray(alias_ref<jclass>,jint size)46 local_ref<jlongArray> testMakeLongArray(alias_ref<jclass>, jint size) {
47 return make_long_array(size);
48 }
49
testMakeFloatArray(alias_ref<jclass>,jint size)50 local_ref<jfloatArray> testMakeFloatArray(alias_ref<jclass>, jint size) {
51 return make_float_array(size);
52 }
53
testMakeDoubleArray(alias_ref<jclass>,jint size)54 local_ref<jdoubleArray> testMakeDoubleArray(alias_ref<jclass>, jint size) {
55 return make_double_array(size);
56 }
57
testGetSetBooleanArray(alias_ref<jclass>,alias_ref<jbooleanArray> array)58 jboolean testGetSetBooleanArray(
59 alias_ref<jclass>,
60 alias_ref<jbooleanArray> array) {
61 EXPECT(array);
62
63 auto n = array->size();
64 EXPECT(n == 2);
65
66 auto vec = std::vector<jboolean>(n);
67 array->getRegion(0, n, vec.data());
68 auto smartbuf = array->getRegion(0, n);
69
70 EXPECT(!vec[0] && vec[1]);
71 EXPECT(!smartbuf[0] && smartbuf[1]);
72
73 for (auto i = 0u; i < n; ++i) {
74 smartbuf[i] = !smartbuf[i];
75 }
76
77 array->setRegion(0, n, smartbuf.get());
78
79 return JNI_TRUE;
80 }
81
testPinBooleanArray(alias_ref<jclass>,alias_ref<jbooleanArray> array)82 jboolean testPinBooleanArray(
83 alias_ref<jclass>,
84 alias_ref<jbooleanArray> array) {
85 EXPECT(array);
86
87 auto n = static_cast<jboolean>(array->size());
88 auto pinned = array->pin();
89
90 EXPECT(!pinned[0] && pinned[1]);
91
92 for (auto i = 0; i < n; ++i) {
93 pinned[i] = !pinned[i];
94 }
95
96 return JNI_TRUE;
97 }
98
99 constexpr double kEps = 1e-3;
100
101 template <typename JArrayType>
testGetSetArray(alias_ref<jclass>,alias_ref<JArrayType> array)102 jboolean testGetSetArray(alias_ref<jclass>, alias_ref<JArrayType> array) {
103 EXPECT(array);
104 int n = array->size();
105 auto vec = std::vector<typename jtype_traits<JArrayType>::entry_type>(n);
106 array->getRegion(0, n, vec.data());
107 auto smartbuf = array->getRegion(0, n);
108
109 for (auto i = 0; i < n; ++i) {
110 EXPECT(std::abs(static_cast<double>(vec[i] - i)) < kEps);
111 EXPECT(std::abs(static_cast<double>(smartbuf[i] - i)) < kEps);
112 }
113
114 for (auto i = 0; i < n; ++i) {
115 smartbuf[i] *= 2;
116 }
117
118 array->setRegion(0, n, smartbuf.get());
119
120 return JNI_TRUE;
121 }
122
123 template <typename JArrayType>
testPinArray(alias_ref<jclass>,alias_ref<JArrayType> array)124 jboolean testPinArray(alias_ref<jclass>, alias_ref<JArrayType> array) {
125 EXPECT(array);
126
127 int n = array->size();
128 auto pinned = array->pin();
129
130 for (auto i = 0; i < n; ++i) {
131 EXPECT(std::abs(static_cast<double>(pinned[i] - i)) < kEps);
132 }
133
134 for (auto i = 0; i < n; ++i) {
135 pinned[i] *= 2;
136 }
137
138 return JNI_TRUE;
139 }
140
141 template <typename JArrayType>
testPinArrayRegion(alias_ref<jclass>,alias_ref<JArrayType> array)142 jboolean testPinArrayRegion(alias_ref<jclass>, alias_ref<JArrayType> array) {
143 EXPECT(array);
144 EXPECT(array->size() > 5);
145
146 int splits[] = {0, 1, 3, static_cast<int>(array->size())};
147 for (int i = 0; i < 3; i++) {
148 auto pinned = array->pinRegion(splits[i], splits[i + 1] - splits[i]);
149 for (int j = 0; j < static_cast<int>(pinned.size()); j++) {
150 EXPECT(std::abs(static_cast<double>(pinned[j] - j - splits[i])) < kEps);
151 pinned[j] *= 2;
152 }
153 }
154 return JNI_TRUE;
155 }
156
157 template <typename JArrayType>
testPinArrayCritical(alias_ref<jclass>,alias_ref<JArrayType> array)158 jboolean testPinArrayCritical(alias_ref<jclass>, alias_ref<JArrayType> array) {
159 EXPECT(array);
160
161 int n = array->size();
162 auto pinned = array->pinCritical();
163
164 for (auto i = 0; i < n; ++i) {
165 EXPECT(std::abs(static_cast<double>(pinned[i] - i)) < kEps);
166 }
167
168 for (auto i = 0; i < n; ++i) {
169 pinned[i] *= 2;
170 }
171
172 return JNI_TRUE;
173 }
174
testIndexOutOfBoundsInRegions(alias_ref<jclass>)175 jboolean testIndexOutOfBoundsInRegions(alias_ref<jclass>) {
176 constexpr auto N = 7;
177 constexpr auto TOO_MUCH = 10;
178 constexpr auto NEGATIVE = -1;
179
180 auto array = make_int_array(N);
181
182 try {
183 auto buf = array->getRegion(TOO_MUCH, N);
184 EXPECT(false);
185 } catch (JniException&) {
186 }
187
188 try {
189 auto buf = array->getRegion(NEGATIVE, N);
190 EXPECT(false);
191 } catch (JniException&) {
192 }
193
194 try {
195 auto vec = std::vector<jint>(TOO_MUCH);
196 array->setRegion(0, vec.size(), vec.data());
197 EXPECT(false);
198 } catch (JniException&) {
199 }
200
201 try {
202 auto vec = std::vector<jint>(1);
203 array->setRegion(NEGATIVE, vec.size(), vec.data());
204 EXPECT(false);
205 } catch (JniException&) {
206 }
207
208 return JNI_TRUE;
209 }
210
TestBooleanArrayIndexing(alias_ref<jobject> self,alias_ref<jbooleanArray> input,jint idx)211 jboolean TestBooleanArrayIndexing(
212 alias_ref<jobject> self,
213 alias_ref<jbooleanArray> input,
214 jint idx) {
215 auto array = input->pin();
216 jboolean value = array[idx];
217 return value;
218 }
219
TestIntegerArrayIndexing(alias_ref<jobject> self,alias_ref<jintArray> input,jint idx)220 jint TestIntegerArrayIndexing(
221 alias_ref<jobject> self,
222 alias_ref<jintArray> input,
223 jint idx) {
224 auto array = input->pin();
225 jint value = array[idx];
226 return value;
227 }
228
TestIntegerArraySize(alias_ref<jobject> self,alias_ref<jintArray> input)229 jsize TestIntegerArraySize(
230 alias_ref<jobject> self,
231 alias_ref<jintArray> input) {
232 auto array = input->pin();
233 jsize size = array.size();
234 return size;
235 }
236
TestIntegerArrayIncrement(alias_ref<jobject> self,alias_ref<jintArray> input)237 alias_ref<jintArray> TestIntegerArrayIncrement(
238 alias_ref<jobject> self,
239 alias_ref<jintArray> input) {
240 auto array = input->pin();
241 for (size_t ii = 0; ii < array.size(); ii++) {
242 array[ii]++;
243 }
244 return input;
245 }
246
TestIntegerArrayMoveAssignment(alias_ref<jobject> self,alias_ref<jintArray> input)247 void TestIntegerArrayMoveAssignment(
248 alias_ref<jobject> self,
249 alias_ref<jintArray> input) {
250 auto array = input->pin();
251 array[0] = 0;
252 array.release();
253 }
254
isPinnedArrayACopy(alias_ref<jobject>,alias_ref<jintArray> input)255 jboolean isPinnedArrayACopy(alias_ref<jobject>, alias_ref<jintArray> input) {
256 return input->pin().isCopy();
257 }
258
testCopiedPinnedArray(alias_ref<jobject>,alias_ref<jintArray> input)259 jboolean testCopiedPinnedArray(alias_ref<jobject>, alias_ref<jintArray> input) {
260 EXPECT(input->size() > 0);
261 input->pin()[0] = 100;
262 auto pin = input->pin();
263 EXPECT(pin.isCopy());
264 EXPECT(pin[0] == input->pin()[0]);
265
266 pin[0] = 200;
267 EXPECT(input->pin()[0] == 100);
268
269 pin.commit();
270 EXPECT(input->pin()[0] == 200);
271 pin[0] = 300;
272 EXPECT(input->pin()[0] == 200);
273 pin.abort();
274 EXPECT(input->pin()[0] == 200);
275 pin = input->pin();
276 pin[0] = 400;
277 pin.release();
278 EXPECT(input->pin()[0] == 400);
279 return JNI_TRUE;
280 }
281
testNonCopiedPinnedArray(alias_ref<jobject>,alias_ref<jintArray> input)282 jboolean testNonCopiedPinnedArray(
283 alias_ref<jobject>,
284 alias_ref<jintArray> input) {
285 EXPECT(input->size() > 0);
286 auto pin = input->pin();
287 EXPECT(!pin.isCopy());
288 EXPECT(pin[0] == input->pin()[0]);
289 pin.commit();
290 EXPECT(pin[0] == input->pin()[0]);
291 pin[0] = 100;
292 EXPECT(pin[0] == input->pin()[0]);
293 input->pin()[0] = 200;
294 EXPECT(pin[0] == input->pin()[0]);
295 pin.abort();
296 return JNI_TRUE;
297 }
298
RegisterPrimitiveArrayTests()299 void RegisterPrimitiveArrayTests() {
300 registerNatives(
301 "com/facebook/jni/PrimitiveArrayTests",
302 {
303 makeNativeMethod("nativeTestMakeBooleanArray", testMakeBoolArray),
304 makeNativeMethod("nativeTestMakeByteArray", testMakeByteArray),
305 makeNativeMethod("nativeTestMakeCharArray", testMakeCharArray),
306 makeNativeMethod("nativeTestMakeShortArray", testMakeShortArray),
307 makeNativeMethod("nativeTestMakeIntArray", testMakeIntArray),
308 makeNativeMethod("nativeTestMakeLongArray", testMakeLongArray),
309 makeNativeMethod("nativeTestMakeFloatArray", testMakeFloatArray),
310 makeNativeMethod("nativeTestMakeDoubleArray", testMakeDoubleArray),
311
312 makeNativeMethod(
313 "nativeTestGetSetBooleanArray", testGetSetBooleanArray),
314 makeNativeMethod(
315 "nativeTestGetSetByteArray", testGetSetArray<jbyteArray>),
316 makeNativeMethod(
317 "nativeTestGetSetCharArray", testGetSetArray<jcharArray>),
318 makeNativeMethod(
319 "nativeTestGetSetShortArray", testGetSetArray<jshortArray>),
320 makeNativeMethod(
321 "nativeTestGetSetIntArray", testGetSetArray<jintArray>),
322 makeNativeMethod(
323 "nativeTestGetSetLongArray", testGetSetArray<jlongArray>),
324 makeNativeMethod(
325 "nativeTestGetSetFloatArray", testGetSetArray<jfloatArray>),
326 makeNativeMethod(
327 "nativeTestGetSetDoubleArray", testGetSetArray<jdoubleArray>),
328
329 makeNativeMethod("nativeTestPinBooleanArray", testPinBooleanArray),
330 makeNativeMethod("nativeTestPinByteArray", testPinArray<jbyteArray>),
331 makeNativeMethod("nativeTestPinCharArray", testPinArray<jcharArray>),
332 makeNativeMethod(
333 "nativeTestPinShortArray", testPinArray<jshortArray>),
334 makeNativeMethod("nativeTestPinIntArray", testPinArray<jintArray>),
335 makeNativeMethod("nativeTestPinLongArray", testPinArray<jlongArray>),
336 makeNativeMethod(
337 "nativeTestPinFloatArray", testPinArray<jfloatArray>),
338 makeNativeMethod(
339 "nativeTestPinDoubleArray", testPinArray<jdoubleArray>),
340
341 makeNativeMethod(
342 "nativeTestPinByteArrayRegion", testPinArrayRegion<jbyteArray>),
343 makeNativeMethod(
344 "nativeTestPinCharArrayRegion", testPinArrayRegion<jcharArray>),
345 makeNativeMethod(
346 "nativeTestPinShortArrayRegion", testPinArrayRegion<jshortArray>),
347 makeNativeMethod(
348 "nativeTestPinIntArrayRegion", testPinArrayRegion<jintArray>),
349 makeNativeMethod(
350 "nativeTestPinLongArrayRegion", testPinArrayRegion<jlongArray>),
351 makeNativeMethod(
352 "nativeTestPinFloatArrayRegion", testPinArrayRegion<jfloatArray>),
353 makeNativeMethod(
354 "nativeTestPinDoubleArrayRegion",
355 testPinArrayRegion<jdoubleArray>),
356
357 makeNativeMethod(
358 "nativeTestPinByteArrayCritical",
359 testPinArrayCritical<jbyteArray>),
360 makeNativeMethod(
361 "nativeTestPinCharArrayCritical",
362 testPinArrayCritical<jcharArray>),
363 makeNativeMethod(
364 "nativeTestPinShortArrayCritical",
365 testPinArrayCritical<jshortArray>),
366 makeNativeMethod(
367 "nativeTestPinIntArrayCritical", testPinArrayCritical<jintArray>),
368 makeNativeMethod(
369 "nativeTestPinLongArrayCritical",
370 testPinArrayCritical<jlongArray>),
371 makeNativeMethod(
372 "nativeTestPinFloatArrayCritical",
373 testPinArrayCritical<jfloatArray>),
374 makeNativeMethod(
375 "nativeTestPinDoubleArrayCritical",
376 testPinArrayCritical<jdoubleArray>),
377
378 makeNativeMethod(
379 "nativeTestIndexOutOfBoundsInRegions",
380 testIndexOutOfBoundsInRegions),
381
382 makeNativeMethod(
383 "nativeTestBooleanArrayIndexing", TestBooleanArrayIndexing),
384 makeNativeMethod(
385 "nativeTestIntegerArrayIndexing", TestIntegerArrayIndexing),
386 makeNativeMethod("nativeTestIntegerArraySize", TestIntegerArraySize),
387 makeNativeMethod(
388 "nativeTestIntegerArrayIncrement", TestIntegerArrayIncrement),
389 makeNativeMethod(
390 "nativeTestIntegerArrayMoveAssignment",
391 TestIntegerArrayMoveAssignment),
392
393 makeNativeMethod("nativeIsPinnedArrayACopy", isPinnedArrayACopy),
394 makeNativeMethod(
395 "nativeTestCopiedPinnedArray", testCopiedPinnedArray),
396 makeNativeMethod(
397 "nativeTestNonCopiedPinnedArray", testNonCopiedPinnedArray),
398 });
399 }
400