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 <chrono>
18 #include <ios>
19 #include <stdexcept>
20 #include <system_error>
21 #include <thread>
22
23 #include <fbjni/JThread.h>
24 #include <fbjni/fbjni.h>
25
26 #include "expect.h"
27 #include "no_rtti.h"
28
29 #include "inter_dso_exception_test_2/Test.h"
30
31 #define EXPECT_SAME(A, B, C) EXPECT((A) == (B) && (B) == (C) && (C) == (A))
32
33 // A lot of the functions here are just confirming that compilation works.
34 #pragma GCC diagnostic ignored "-Wunused-function"
35
36 using namespace facebook::jni;
37
38 namespace {
39
40 struct Callbacks : public facebook::jni::JavaClass<Callbacks> {
41 constexpr static auto kJavaDescriptor =
42 "Lcom/facebook/jni/FBJniTests$Callbacks;";
43 };
44
45 struct TestThing : public JavaClass<TestThing> {
46 constexpr static auto kJavaDescriptor =
47 "Lcom/facebook/jni/FBJniTests$TestThing;";
48 };
49
50 // Yes, sloppy and does not handle conversions correctly but does it's job here
ToString(JNIEnv * env,jstring java_string)51 static std::string ToString(JNIEnv* env, jstring java_string) {
52 auto chars = env->GetStringUTFChars(java_string, nullptr);
53 if (chars == nullptr) {
54 throw std::runtime_error{"Couldn't get UTF chars"};
55 }
56
57 std::string string{chars};
58 env->ReleaseStringUTFChars(java_string, chars);
59
60 return string;
61 }
62
TestClassResolution(JNIEnv * env,jobject self,jstring class_name)63 jboolean TestClassResolution(JNIEnv* env, jobject self, jstring class_name) {
64 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
65 return resolved_class.get() != nullptr ? JNI_TRUE : JNI_FALSE;
66 }
67
68 jboolean
TestLazyClassResolution(JNIEnv * env,jobject self,jstring class_name)69 TestLazyClassResolution(JNIEnv* env, jobject self, jstring class_name) {
70 auto resolved_class = alias_ref<jclass>{};
71 resolved_class = findClassLocal(ToString(env, class_name).c_str());
72 return resolved_class.get() != nullptr ? JNI_TRUE : JNI_FALSE;
73 }
74
TestCreateInstanceOf(JNIEnv * env,jobject self,jstring class_name)75 jobject TestCreateInstanceOf(JNIEnv* env, jobject self, jstring class_name) {
76 auto clazz = findClassLocal(ToString(env, class_name).c_str());
77 auto constructor = clazz->getConstructor<jobject(jstring)>();
78 return clazz->newObject(constructor, class_name).release();
79 }
80
TestTypeDescriptors(JNIEnv * env,jobject self)81 jboolean TestTypeDescriptors(JNIEnv* env, jobject self) {
82 #define FIXED_STRING_EXPECT_EQ(actual, expected) \
83 static_assert((actual) == (expected), "descriptor mismatch")
84
85 FIXED_STRING_EXPECT_EQ(jtype_traits<jboolean>::kDescriptor, "Z");
86 FIXED_STRING_EXPECT_EQ(jtype_traits<jbyte>::kDescriptor, "B");
87 FIXED_STRING_EXPECT_EQ(jtype_traits<jchar>::kDescriptor, "C");
88 FIXED_STRING_EXPECT_EQ(jtype_traits<jdouble>::kDescriptor, "D");
89 FIXED_STRING_EXPECT_EQ(jtype_traits<jfloat>::kDescriptor, "F");
90 FIXED_STRING_EXPECT_EQ(jtype_traits<jint>::kDescriptor, "I");
91 FIXED_STRING_EXPECT_EQ(jtype_traits<jlong>::kDescriptor, "J");
92 FIXED_STRING_EXPECT_EQ(jtype_traits<jshort>::kDescriptor, "S");
93
94 FIXED_STRING_EXPECT_EQ(
95 jtype_traits<jstring>::kDescriptor, "Ljava/lang/String;");
96 FIXED_STRING_EXPECT_EQ(
97 jtype_traits<jobject>::kDescriptor, "Ljava/lang/Object;");
98
99 FIXED_STRING_EXPECT_EQ(jtype_traits<jintArray>::kDescriptor, "[I");
100 FIXED_STRING_EXPECT_EQ(
101 jtype_traits<jtypeArray<jstring>>::kDescriptor, "[Ljava/lang/String;");
102 FIXED_STRING_EXPECT_EQ(
103 jtype_traits<jtypeArray<jtypeArray<jstring>>>::kDescriptor,
104 "[[Ljava/lang/String;");
105 FIXED_STRING_EXPECT_EQ(
106 jtype_traits<jtypeArray<jintArray>>::kDescriptor, "[[I");
107
108 // base_name() is meaningless for primitive types.
109 FIXED_STRING_EXPECT_EQ(jtype_traits<jstring>::kBaseName, "java/lang/String");
110 FIXED_STRING_EXPECT_EQ(jtype_traits<jobject>::kBaseName, "java/lang/Object");
111
112 FIXED_STRING_EXPECT_EQ(jtype_traits<jintArray>::kBaseName, "[I");
113 FIXED_STRING_EXPECT_EQ(
114 jtype_traits<jtypeArray<jstring>>::kBaseName, "[Ljava/lang/String;");
115 FIXED_STRING_EXPECT_EQ(
116 jtype_traits<jtypeArray<jtypeArray<jstring>>>::kBaseName,
117 "[[Ljava/lang/String;");
118 FIXED_STRING_EXPECT_EQ(jtype_traits<jtypeArray<jintArray>>::kBaseName, "[[I");
119
120 return JNI_TRUE;
121 }
122
TestVirtualMethodResolution_I(JNIEnv * env,jobject self,jstring class_name,jstring method_name)123 jboolean TestVirtualMethodResolution_I(
124 JNIEnv* env,
125 jobject self,
126 jstring class_name,
127 jstring method_name) {
128 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
129 auto resolved_method =
130 resolved_class->getMethod<jint()>(ToString(env, method_name).c_str());
131 return static_cast<bool>(resolved_method);
132 }
133
TestVirtualMethodResolution_arrB(JNIEnv * env,jobject self,jstring class_name,jstring method_name)134 jboolean TestVirtualMethodResolution_arrB(
135 JNIEnv* env,
136 jobject self,
137 jstring class_name,
138 jstring method_name) {
139 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
140 auto resolved_method = resolved_class->getMethod<jbyteArray()>(
141 ToString(env, method_name).c_str());
142 return static_cast<bool>(resolved_method);
143 }
144
TestVirtualMethodResolution_S_arrS(JNIEnv * env,jobject self,jstring class_name,jstring method_name)145 jboolean TestVirtualMethodResolution_S_arrS(
146 JNIEnv* env,
147 jobject self,
148 jstring class_name,
149 jstring method_name) {
150 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
151 auto resolved_method =
152 resolved_class->getMethod<jtypeArray<jstring>(jstring)>(
153 ToString(env, method_name).c_str());
154 return static_cast<bool>(resolved_method);
155 }
156
TestVirtualMethodResolution_arrarrS(JNIEnv * env,jobject self,jstring class_name,jstring method_name)157 jboolean TestVirtualMethodResolution_arrarrS(
158 JNIEnv* env,
159 jobject self,
160 jstring class_name,
161 jstring method_name) {
162 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
163 auto resolved_method =
164 resolved_class->getStaticMethod<jtypeArray<jtypeArray<jstring>>()>(
165 ToString(env, method_name).c_str());
166 return static_cast<bool>(resolved_method);
167 }
168
TestVirtualMethodResolution_arrarrI(JNIEnv * env,jobject self,jstring class_name,jstring method_name)169 jboolean TestVirtualMethodResolution_arrarrI(
170 JNIEnv* env,
171 jobject self,
172 jstring class_name,
173 jstring method_name) {
174 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
175 auto resolved_method =
176 resolved_class->getStaticMethod<jtypeArray<jintArray>()>(
177 ToString(env, method_name).c_str());
178 return static_cast<bool>(resolved_method);
179 }
180
TestLazyVirtualMethodResolution_I(JNIEnv * env,jobject self,jstring class_name,jstring method_name)181 jboolean TestLazyVirtualMethodResolution_I(
182 JNIEnv* env,
183 jobject self,
184 jstring class_name,
185 jstring method_name) {
186 auto resolved_class = findClassLocal(ToString(env, class_name).c_str());
187 auto resolved_method = JMethod<jint()>{};
188 resolved_method =
189 resolved_class->getMethod<jint()>(ToString(env, method_name).c_str());
190 return static_cast<bool>(resolved_method);
191 }
192
TestJMethodCallbacks(JNIEnv * env,jobject self,Callbacks::javaobject callbacks)193 void TestJMethodCallbacks(
194 JNIEnv* env,
195 jobject self,
196 Callbacks::javaobject callbacks) {
197 static const auto callbacks_class = Callbacks::javaClassStatic();
198
199 static const auto void_foo = callbacks_class->getMethod<void()>("voidFoo");
200 void_foo(callbacks);
201
202 static const auto boolean_foo =
203 callbacks_class->getMethod<jboolean()>("booleanFoo");
204 boolean_foo(callbacks);
205
206 static const auto byte_foo = callbacks_class->getMethod<jbyte()>("byteFoo");
207 byte_foo(callbacks);
208
209 static const auto char_foo = callbacks_class->getMethod<jchar()>("charFoo");
210 char_foo(callbacks);
211
212 static const auto short_foo =
213 callbacks_class->getMethod<jshort()>("shortFoo");
214 short_foo(callbacks);
215
216 static const auto int_foo = callbacks_class->getMethod<jint()>("intFoo");
217 int_foo(callbacks);
218
219 static const auto long_foo = callbacks_class->getMethod<jlong()>("longFoo");
220 long_foo(callbacks);
221
222 static const auto float_foo =
223 callbacks_class->getMethod<jfloat()>("floatFoo");
224 float_foo(callbacks);
225
226 static const auto double_foo =
227 callbacks_class->getMethod<jdouble()>("doubleFoo");
228 double_foo(callbacks);
229
230 static const auto object_foo =
231 callbacks_class->getMethod<jobject()>("objectFoo");
232 object_foo(callbacks);
233
234 static const auto string_foo =
235 callbacks_class->getMethod<jstring()>("stringFoo");
236 string_foo(callbacks);
237 }
238
239 // Try to test the static functions
TestJStaticMethodCallbacks(JNIEnv * env,jobject self)240 void TestJStaticMethodCallbacks(JNIEnv* env, jobject self) {
241 // static auto callbacks_class = findClassStatic(callbacks_class_name);
242 auto cls = findClassLocal("com/facebook/jni/FBJniTests");
243 jclass jcls = env->FindClass("com/facebook/jni/FBJniTests");
244
245 static const auto void_foo_static =
246 cls->getStaticMethod<void()>("voidFooStatic");
247 void_foo_static(jcls);
248
249 static const auto boolean_foo_static =
250 cls->getStaticMethod<jboolean()>("booleanFooStatic");
251 boolean_foo_static(jcls);
252
253 static const auto byte_foo_static =
254 cls->getStaticMethod<jbyte()>("byteFooStatic");
255 byte_foo_static(jcls);
256
257 static const auto char_foo_static =
258 cls->getStaticMethod<jchar(jchar, jint)>("charFooStatic");
259 char_foo_static(jcls, 'c', 5);
260
261 static const auto short_foo_static =
262 cls->getStaticMethod<jshort(jshort, jshort)>("shortFooStatic");
263 short_foo_static(jcls, 17, 42);
264
265 static const auto int_foo_static =
266 cls->getStaticMethod<jint(jint)>("intFooStatic");
267 int_foo_static(jcls, 5);
268
269 static const auto long_foo_static =
270 cls->getStaticMethod<jlong()>("longFooStatic");
271 long_foo_static(jcls);
272
273 static const auto float_foo_static =
274 cls->getStaticMethod<jfloat()>("floatFooStatic");
275 float_foo_static(jcls);
276
277 static const auto double_foo_static =
278 cls->getStaticMethod<jdouble()>("doubleFooStatic");
279 double_foo_static(jcls);
280
281 static const auto object_foo_static =
282 cls->getStaticMethod<jobject()>("objectFooStatic");
283 object_foo_static(jcls);
284
285 static const auto string_foo_static =
286 cls->getStaticMethod<jstring()>("stringFooStatic");
287 string_foo_static(jcls);
288 }
289
290 jboolean
TestIsAssignableFrom(JNIEnv * env,jobject self,jclass cls1,jclass cls2)291 TestIsAssignableFrom(JNIEnv* env, jobject self, jclass cls1, jclass cls2) {
292 return adopt_local(cls1)->isAssignableFrom(cls2);
293 }
294
295 jboolean
TestIsInstanceOf(JNIEnv * env,jobject self,jobject test_object,jclass cls)296 TestIsInstanceOf(JNIEnv* env, jobject self, jobject test_object, jclass cls) {
297 auto clsref = adopt_local(test_object);
298 return clsref->isInstanceOf(cls);
299 }
300
TestIsSameObject(JNIEnv * env,jobject self,jobject a,jobject b)301 jboolean TestIsSameObject(JNIEnv* env, jobject self, jobject a, jobject b) {
302 return isSameObject(a, b);
303 }
304
TestGetSuperclass(JNIEnv * env,jobject self,jclass test_class,jclass super_class)305 jboolean TestGetSuperclass(
306 JNIEnv* env,
307 jobject self,
308 jclass test_class,
309 jclass super_class) {
310 return isSameObject(
311 adopt_local(test_class)->getSuperclass().get(), super_class);
312 }
313
314 jboolean
StaticCastAliasRefToString(JNIEnv *,jobject,jobject string_as_object)315 StaticCastAliasRefToString(JNIEnv*, jobject, jobject string_as_object) {
316 alias_ref<jobject> string_as_object_alias_ref{string_as_object};
317 alias_ref<jstring> string_alias_ref =
318 static_ref_cast<jstring>(string_as_object_alias_ref);
319 return isSameObject(string_alias_ref.get(), string_as_object_alias_ref.get());
320 }
321
DynamicCastAliasRefToThrowable(JNIEnv *,jobject,jobject might_actually_be_throwable)322 jboolean DynamicCastAliasRefToThrowable(
323 JNIEnv*,
324 jobject,
325 jobject might_actually_be_throwable) {
326 alias_ref<jobject> might_actually_be_throwable_alias_ref{
327 might_actually_be_throwable};
328 // If the next line fails, it will throw an exception.
329 alias_ref<jthrowable> throwable_alias_ref =
330 dynamic_ref_cast<jthrowable>(might_actually_be_throwable_alias_ref);
331 return isSameObject(
332 throwable_alias_ref.get(), might_actually_be_throwable_alias_ref.get());
333 }
334
335 jboolean
StaticCastLocalRefToString(JNIEnv *,jobject,jobject string_as_object)336 StaticCastLocalRefToString(JNIEnv*, jobject, jobject string_as_object) {
337 local_ref<jobject> string_as_object_local_ref = adopt_local(string_as_object);
338 local_ref<jstring> string_local_ref =
339 static_ref_cast<jstring>(string_as_object_local_ref);
340 return isSameObject(string_local_ref.get(), string_as_object_local_ref.get());
341 }
342
DynamicCastLocalRefToString(JNIEnv *,jobject,jobject might_actually_be_string)343 jboolean DynamicCastLocalRefToString(
344 JNIEnv*,
345 jobject,
346 jobject might_actually_be_string) {
347 local_ref<jobject> might_actually_be_string_local_ref =
348 adopt_local(might_actually_be_string);
349 // If the next line fails, it will throw an exception.
350 local_ref<jstring> string_local_ref =
351 dynamic_ref_cast<jstring>(might_actually_be_string_local_ref);
352 return isSameObject(
353 string_local_ref.get(), might_actually_be_string_local_ref.get());
354 }
355
356 jboolean
StaticCastGlobalRefToString(JNIEnv *,jobject,jobject string_as_object)357 StaticCastGlobalRefToString(JNIEnv*, jobject, jobject string_as_object) {
358 global_ref<jobject> string_as_object_global_ref =
359 make_global(string_as_object);
360 global_ref<jstring> string_global_ref =
361 static_ref_cast<jstring>(string_as_object_global_ref);
362 return isSameObject(
363 string_global_ref.get(), string_as_object_global_ref.get());
364 }
365
DynamicCastGlobalRefToString(JNIEnv *,jobject,jobject might_actually_be_string)366 jboolean DynamicCastGlobalRefToString(
367 JNIEnv*,
368 jobject,
369 jobject might_actually_be_string) {
370 global_ref<jobject> might_actually_be_string_global_ref =
371 make_global(might_actually_be_string);
372 // If the next line fails, it will throw an exception.
373 global_ref<jstring> string_global_ref =
374 dynamic_ref_cast<jstring>(might_actually_be_string_global_ref);
375 return isSameObject(
376 string_global_ref.get(), might_actually_be_string_global_ref.get());
377 }
378
379 template <typename... Args>
Use(Args &&...args)380 static void Use(Args&&... args) {}
381
TestWeakRefs(JNIEnv *,jobject self)382 jboolean TestWeakRefs(JNIEnv*, jobject self) {
383 using facebook::jni::internal::g_reference_stats;
384
385 g_reference_stats.reset();
386 {
387 // Wrapping existing local that should be deleted (locals = 1)
388 auto local = adopt_local(self);
389 // Make new local (locals = 2)
390 auto local2 = make_local(local);
391 // Make weak (weaks = 1)
392 auto weak = make_weak(local);
393 // Make global (globals = 1)
394 auto global = weak.lockGlobal();
395 // No new refs
396 auto banana = std::move(weak);
397 // No new refs
398 auto& binini = banana;
399 // Create a global of the local (keeping the local) (globals = 2)
400 auto dubglob = make_global(local);
401 // Create a weak (weaks = 2)
402 auto dupweak = make_weak(local);
403 // No new refs
404 swap(local, local2);
405
406 Use(binini);
407 }
408
409 FBJNI_LOGE("locals: %d", g_reference_stats.locals_deleted.load());
410 FBJNI_LOGE("globals: %d", g_reference_stats.globals_deleted.load());
411 FBJNI_LOGE("weaks: %d", g_reference_stats.weaks_deleted.load());
412
413 return (g_reference_stats.locals_deleted == 2 &&
414 g_reference_stats.globals_deleted == 2 &&
415 g_reference_stats.weaks_deleted == 2)
416 ? JNI_TRUE
417 : JNI_FALSE;
418 }
419
TestAlias(JNIEnv * env,jobject self)420 jboolean TestAlias(JNIEnv* env, jobject self) {
421 auto ref = alias_ref<jobject>{self};
422 return ref->isInstanceOf(findClassLocal("java/lang/Object"));
423 }
424
testAliasRefConversions(JNIEnv *,jobject self)425 jboolean testAliasRefConversions(JNIEnv*, jobject self) {
426 auto aLocalString = make_jstring("foo");
427 alias_ref<jstring> aString = aLocalString;
428 alias_ref<jobject> anObject = aLocalString;
429 anObject = (jstring) nullptr;
430 anObject = aString;
431 // aString = anObject; // Shouldn't compile
432
433 return isSameObject(aString, anObject) ? JNI_TRUE : JNI_FALSE;
434 }
435
TestAutoAliasRefReturningVoid(facebook::jni::alias_ref<jobject> self)436 void TestAutoAliasRefReturningVoid(facebook::jni::alias_ref<jobject> self) {
437 // If this compiles, it succeeds.
438 }
439
testNullJString(JNIEnv *,jobject)440 jboolean testNullJString(JNIEnv*, jobject) {
441 auto aNullJString = make_jstring(nullptr);
442 EXPECT(aNullJString.get() == (jstring) nullptr);
443 return JNI_TRUE;
444 }
445
testSwap(JNIEnv *,jobject self,jobject other)446 jboolean testSwap(JNIEnv*, jobject self, jobject other) {
447 auto selfAlias = wrap_alias(self);
448 auto otherAlias = wrap_alias(other);
449
450 swap(selfAlias, otherAlias);
451 EXPECT(self == otherAlias);
452 EXPECT(other == selfAlias);
453 EXPECT(self != selfAlias);
454 EXPECT(other != otherAlias);
455
456 auto selfLocal = make_local(self);
457 auto otherLocal = make_local(other);
458 swap(selfLocal, otherLocal);
459 EXPECT(self == otherLocal);
460 EXPECT(other == selfLocal);
461 EXPECT(self != selfLocal);
462 EXPECT(other != otherLocal);
463
464 auto selfGlobal = make_global(self);
465 auto otherGlobal = make_global(other);
466 swap(selfGlobal, otherGlobal);
467 EXPECT(self == otherGlobal);
468 EXPECT(other == selfGlobal);
469 EXPECT(self != selfGlobal);
470 EXPECT(other != otherGlobal);
471
472 auto selfWeak = make_weak(self);
473 auto otherWeak = make_weak(other);
474 swap(selfWeak, otherWeak);
475 auto selfLockedWeak = selfWeak.lockLocal();
476 auto otherLockedWeak = otherWeak.lockLocal();
477 EXPECT(self == otherLockedWeak);
478 EXPECT(other == selfLockedWeak);
479 EXPECT(self != selfLockedWeak);
480 EXPECT(other != otherLockedWeak);
481
482 return JNI_TRUE;
483 }
484
testEqualOperator(JNIEnv *,jobject self,jobject other)485 jboolean testEqualOperator(JNIEnv*, jobject self, jobject other) {
486 auto selfAlias = wrap_alias(self);
487 auto otherAlias = wrap_alias(other);
488 auto selfLocal = adopt_local(self);
489 auto otherLocal = adopt_local(other);
490 auto selfGlobal = make_global(self);
491 auto otherGlobal = make_global(other);
492 auto selfWeak = make_weak(self);
493 auto otherWeak = make_weak(other);
494 auto selfLockedWeak = selfWeak.lockLocal();
495 auto otherLockedWeak = otherWeak.lockLocal();
496
497 EXPECT(self == selfAlias);
498 EXPECT(selfAlias == selfLocal);
499 EXPECT(selfLocal == selfGlobal);
500 EXPECT(selfGlobal == selfLockedWeak);
501 EXPECT(self != other);
502 EXPECT(self != otherAlias);
503 EXPECT(self != otherLocal);
504 EXPECT(self != otherGlobal);
505 EXPECT(self != otherLockedWeak);
506 EXPECT(selfAlias != nullptr);
507 EXPECT(!(selfAlias == nullptr));
508 EXPECT(nullptr != selfLocal);
509 EXPECT(!(nullptr == selfGlobal));
510
511 return JNI_TRUE;
512 }
513
testReleaseAlias(JNIEnv *,jobject self)514 jboolean testReleaseAlias(JNIEnv*, jobject self) {
515 auto local = adopt_local(self);
516 auto alias = local.releaseAlias();
517
518 EXPECT(typeid(alias) == typeid(alias_ref<jobject>));
519 EXPECT(isSameObject(self, alias.get()));
520
521 return JNI_TRUE;
522 }
523
testLockingWeakReferences(JNIEnv *,jobject self)524 jboolean testLockingWeakReferences(JNIEnv*, jobject self) {
525 auto weak = make_weak(self);
526 auto local = weak.lockLocal();
527 auto global = weak.lockGlobal();
528
529 EXPECT(typeid(local) == typeid(local_ref<jobject>));
530 EXPECT(typeid(global) == typeid(global_ref<jobject>));
531 EXPECT(self == local);
532 EXPECT(self == global);
533
534 return JNI_TRUE;
535 }
536
TestFieldAccess(alias_ref<jobject> self,const std::string & field_name,jint oldval,jint newval)537 jboolean TestFieldAccess(
538 alias_ref<jobject> self,
539 const std::string& field_name,
540 jint oldval,
541 jint newval) {
542 auto cls = self->getClass();
543 auto fld = cls->getField<jint>(field_name.c_str());
544 auto method = cls->getMethod<jint(jdouble)>("bar");
545
546 if (method(self.get(), 17) != 42) {
547 return JNI_FALSE;
548 }
549
550 if (method(self, 17) != 42) {
551 return JNI_FALSE;
552 }
553
554 if (self->getFieldValue(fld) != oldval) {
555 return JNI_FALSE;
556 }
557
558 self->setFieldValue(fld, newval);
559
560 return JNI_TRUE;
561 }
562
TestStringFieldAccess(JNIEnv * env,jobject self,jstring field_name,jstring oldval,jstring newval)563 jboolean TestStringFieldAccess(
564 JNIEnv* env,
565 jobject self,
566 jstring field_name,
567 jstring oldval,
568 jstring newval) {
569 auto me = adopt_local(self);
570 auto cls = me->getClass();
571 auto fld = cls->getField<jstring>(ToString(env, field_name).c_str());
572 auto oldvalStr = adopt_local(oldval)->toStdString();
573
574 auto curvalRef = me->getFieldValue(fld);
575 if (curvalRef->toStdString() != oldvalStr) {
576 return JNI_FALSE;
577 }
578
579 const alias_ref<jobject> cme = me;
580 if (cme->getFieldValue(fld)->toStdString() != oldvalStr) {
581 return JNI_FALSE;
582 }
583
584 me->setFieldValue(fld, newval);
585
586 return JNI_TRUE;
587 }
588
TestReferenceFieldAccess(alias_ref<jobject> self,std::string const & field_name,jobject oldval,jobject newval,jboolean useWrapper)589 jboolean TestReferenceFieldAccess(
590 alias_ref<jobject> self,
591 std::string const& field_name,
592 jobject oldval,
593 jobject newval,
594 jboolean useWrapper) {
595 auto cls = self->getClass();
596 auto rawfld =
597 cls->getField<jobject>(field_name.c_str(), TestThing::kJavaDescriptor);
598
599 if (self->getFieldValue(rawfld) != oldval) {
600 return JNI_FALSE;
601 }
602
603 alias_ref<jobject> const cself = self;
604 if (cself->getFieldValue(rawfld) != oldval) {
605 return JNI_FALSE;
606 }
607
608 if (useWrapper) {
609 auto newvalRef = adopt_local(static_cast<TestThing::javaobject>(newval));
610 auto fld = cls->getField<TestThing::javaobject>(field_name.c_str());
611 self->setFieldValue<TestThing::javaobject>(fld, newvalRef);
612 } else {
613 self->setFieldValue(rawfld, newval);
614 }
615
616 return JNI_TRUE;
617 }
618
TestStaticFieldAccess(JNIEnv * env,jobject self,jstring field_name,jint oldval,jint newval)619 jboolean TestStaticFieldAccess(
620 JNIEnv* env,
621 jobject self,
622 jstring field_name,
623 jint oldval,
624 jint newval) {
625 auto me = adopt_local(self);
626 auto cls = me->getClass();
627 auto fld = cls->getStaticField<jint>(ToString(env, field_name).c_str());
628
629 if (cls->getStaticFieldValue(fld) != oldval) {
630 return JNI_FALSE;
631 }
632 cls->setStaticFieldValue(fld, newval);
633 return JNI_TRUE;
634 }
635
TestStaticStringFieldAccess(JNIEnv * env,jobject self,jstring field_name,jstring oldval,jstring newval)636 jboolean TestStaticStringFieldAccess(
637 JNIEnv* env,
638 jobject self,
639 jstring field_name,
640 jstring oldval,
641 jstring newval) {
642 auto me = adopt_local(self);
643 auto cls = me->getClass();
644 auto fld = cls->getStaticField<jstring>(ToString(env, field_name).c_str());
645
646 auto curvalRef = cls->getStaticFieldValue(fld);
647 if (curvalRef->toStdString() != adopt_local(oldval)->toStdString()) {
648 return JNI_FALSE;
649 }
650 cls->setStaticFieldValue(fld, newval);
651 return JNI_TRUE;
652 }
653
TestStaticReferenceFieldAccess(alias_ref<jobject> self,std::string const & field_name,jobject oldval,jobject newval,jboolean useWrapper)654 jboolean TestStaticReferenceFieldAccess(
655 alias_ref<jobject> self,
656 std::string const& field_name,
657 jobject oldval,
658 jobject newval,
659 jboolean useWrapper) {
660 auto cls = self->getClass();
661 auto rawfld = cls->getStaticField<jobject>(
662 field_name.c_str(), TestThing::kJavaDescriptor);
663
664 auto curvalRef = cls->getStaticFieldValue(rawfld);
665 if (curvalRef != oldval) {
666 return JNI_FALSE;
667 }
668
669 if (useWrapper) {
670 auto newvalRef = adopt_local(static_cast<TestThing::javaobject>(newval));
671 auto fld = cls->getStaticField<TestThing::javaobject>(field_name.c_str());
672 cls->setStaticFieldValue<TestThing::javaobject>(fld, newvalRef);
673 } else {
674 cls->setStaticFieldValue(rawfld, newval);
675 }
676
677 return JNI_TRUE;
678 }
679
TestNonVirtualMethod(JNIEnv * env,jobject self,jboolean s)680 jboolean TestNonVirtualMethod(JNIEnv* env, jobject self, jboolean s) {
681 auto me = adopt_local(self);
682 if (!me) {
683 return JNI_FALSE;
684 }
685
686 auto cls = me->getClass();
687 if (!cls) {
688 return JNI_FALSE;
689 }
690 auto method =
691 cls->getNonvirtualMethod<jboolean(jboolean)>("nonVirtualMethod");
692
693 jclass jcls = env->FindClass("com/facebook/jni/FBJniTests");
694
695 return method(self, jcls, s);
696 }
697
TestArrayCreation(JNIEnv * env,jobject self,jstring s0,jstring s1,jstring s2)698 jtypeArray<jstring> TestArrayCreation(
699 JNIEnv* env,
700 jobject self,
701 jstring s0,
702 jstring s1,
703 jstring s2) {
704 auto array = JArrayClass<jstring>::newArray(3);
705 array->setElement(0, s0);
706 array->setElement(1, s1);
707 array->setElement(2, s2);
708 return static_cast<jtypeArray<jstring>>(array.release());
709 }
710
TestMultidimensionalObjectArray(JNIEnv * env,jobject self,jstring s0,jstring s1,jstring s2)711 jtypeArray<jtypeArray<jstring>> TestMultidimensionalObjectArray(
712 JNIEnv* env,
713 jobject self,
714 jstring s0,
715 jstring s1,
716 jstring s2) {
717 auto array = JArrayClass<jtypeArray<jstring>>::newArray(2);
718 auto row = JArrayClass<jstring>::newArray(2);
719 row->setElement(0, s0);
720 row->setElement(1, s1);
721 (*array)[0] = row;
722 row = JArrayClass<jstring>::newArray(1);
723 row->setElement(0, s2);
724 (*array)[1] = row;
725 return array.release();
726 }
727
TestMultidimensionalPrimitiveArray(JNIEnv * env,jobject self,jint i0,jint i1,jint i2)728 jtypeArray<jintArray> TestMultidimensionalPrimitiveArray(
729 JNIEnv* env,
730 jobject self,
731 jint i0,
732 jint i1,
733 jint i2) {
734 auto array = JArrayClass<jintArray>::newArray(2);
735 auto row = JArrayInt::newArray(2);
736 row->setRegion(0, 1, &i0);
737 row->setRegion(1, 1, &i1);
738 (*array)[0] = row;
739 row = JArrayInt::newArray(1);
740 row->setRegion(0, 1, &i2);
741 (*array)[1] = row;
742 return array.release();
743 }
744
745 jstring
TestBuildStringArray(JNIEnv * env,jobject self,jtypeArray<jstring> input)746 TestBuildStringArray(JNIEnv* env, jobject self, jtypeArray<jstring> input) {
747 auto me = adopt_local(self);
748 auto cls = me->getClass();
749 auto method =
750 cls->getMethod<jstring(jtypeArray<jstring>)>("captureStringArray");
751
752 auto niceInput = adopt_local_array<jstring>(input);
753 auto length = niceInput->size();
754 auto inputCopy = JArrayClass<jstring>::newArray(length);
755 for (size_t idx = 0; idx < length; idx++) {
756 switch (idx % 3) {
757 case 0: {
758 // Verify that assignment from a T works.
759 jstring value = (jstring)env->GetObjectArrayElement(input, idx);
760 (*inputCopy)[idx] = value; // Assignment from actual type.
761 env->DeleteLocalRef(value);
762 break;
763 }
764 case 1: {
765 // Verify that direct assignment from an ElementProxy works.
766 (*inputCopy)[idx] = (*niceInput)[idx];
767 break;
768 }
769 case 2:
770 default: {
771 // Verify that assignment from a smart reference works.
772 auto smartRef = adopt_local((*niceInput)[idx]);
773 (*inputCopy)[idx] = smartRef;
774 break;
775 }
776 }
777 }
778
779 return method(self, inputCopy.get()).release();
780 }
781
782 template <typename F, typename... Args>
tryResolveMethodWithCxxTypes(std::string sig,alias_ref<jobject> me,std::string methodName,Args...args)783 void tryResolveMethodWithCxxTypes(
784 std::string sig,
785 alias_ref<jobject> me,
786 std::string methodName,
787 Args... args) {
788 auto cls = me->getClass();
789 auto method = cls->getMethod<F>(methodName.c_str());
790 if (!method)
791 throw std::runtime_error("method lookup failed with signature=" + sig);
792 try {
793 method(me, args...);
794 } catch (std::exception&) {
795 throw std::runtime_error("calling method failed with signature=" + sig);
796 }
797
798 auto nonVirtualMethod = cls->getNonvirtualMethod<F>(methodName.c_str());
799 if (!nonVirtualMethod)
800 throw std::runtime_error("method lookup failed with signature=" + sig);
801 try {
802 nonVirtualMethod(me, cls.get(), args...);
803 } catch (std::exception&) {
804 throw std::runtime_error("calling method failed with signature=" + sig);
805 }
806
807 auto staticMethod = cls->getStaticMethod<F>((methodName + "Static").c_str());
808 if (!staticMethod)
809 throw std::runtime_error(
810 "static method lookup failed with signature=" + sig);
811 try {
812 staticMethod(cls, args...);
813 } catch (std::exception&) {
814 throw std::runtime_error(
815 "calling static method failed with signature=" + sig);
816 }
817 }
818
819 // Simple utility to give us a good error message.
820 #define runTest(sig, ...) \
821 tryResolveMethodWithCxxTypes<sig>(#sig, self, method, __VA_ARGS__);
822
TestMethodResolutionWithCxxTypes(alias_ref<jobject> self,alias_ref<jstring> jmethod,alias_ref<jstring> str,jlong v)823 void TestMethodResolutionWithCxxTypes(
824 alias_ref<jobject> self,
825 alias_ref<jstring> jmethod,
826 alias_ref<jstring> str,
827 jlong v) {
828 auto method = jmethod->toStdString();
829 runTest(jobject(jstring, jlong), str.get(), v);
830 runTest(local_ref<jobject>(jstring, jlong), str.get(), v);
831
832 runTest(jobject(local_ref<jstring>, jlong), make_local(str), v);
833 runTest(jobject(alias_ref<jstring>, jlong), str, v);
834
835 runTest(jobject(alias_ref<jstring>, int64_t), str, (int64_t)v);
836 runTest(jobject(alias_ref<jstring>, long long), str, (long long)v);
837
838 runTest(
839 jobject(const char*, int64_t), str->toStdString().c_str(), (int64_t)v);
840
841 method = jmethod->toStdString() + "Void";
842 runTest(void(jstring, int64_t), str.get(), v);
843
844 method = jmethod->toStdString() + "Int";
845 runTest(jint(jstring, int64_t), str.get(), v);
846 }
847
848 #undef runTest
849
TestHandleJavaCustomException(JNIEnv * env,jobject self)850 void TestHandleJavaCustomException(JNIEnv* env, jobject self) {
851 auto me = adopt_local(self);
852 auto cls = me->getClass();
853 auto method = cls->getMethod<void()>("customExceptionThrower");
854
855 method(self);
856 }
857
TestHandleNullExceptionMessage(JNIEnv * env,jobject self)858 void TestHandleNullExceptionMessage(JNIEnv* env, jobject self) {
859 auto me = adopt_local(self);
860 auto cls = me->getClass();
861 auto method = cls->getMethod<void()>("nullMessageThrower");
862
863 try {
864 method(self);
865 } catch (const std::exception& ex) {
866 ex.what();
867 }
868 }
869
TestHandleNestedException(JNIEnv * env,jobject self)870 void TestHandleNestedException(JNIEnv* env, jobject self) {
871 auto me = adopt_local(self);
872 auto cls = me->getClass();
873 auto method = cls->getMethod<void()>("customExceptionThrower");
874
875 try {
876 try {
877 method(self);
878 } catch (...) {
879 std::throw_with_nested(std::runtime_error("middle"));
880 }
881 } catch (...) {
882 std::throw_with_nested(std::out_of_range("outer"));
883 }
884 }
885
TestHandleNoRttiException(JNIEnv * env,jobject self)886 void TestHandleNoRttiException(JNIEnv* env, jobject self) {
887 nortti::throwException();
888 }
889
TestCopyConstructor(JNIEnv * env,jobject self)890 jstring TestCopyConstructor(JNIEnv* env, jobject self) {
891 auto me = adopt_local(self);
892 auto cls = me->getClass();
893 auto method = cls->getMethod<void()>("customExceptionThrower");
894
895 try {
896 method(self);
897 return env->NewStringUTF("method did not throw");
898 } catch (JniException ex) { // No & -- we're intentionally invoking the copy
899 // constructor.
900 return env->NewStringUTF(ex.what());
901 }
902 }
903
TestMoveConstructorWithEmptyWhat(JNIEnv * env,jobject self)904 jstring TestMoveConstructorWithEmptyWhat(JNIEnv* env, jobject self) {
905 auto me = adopt_local(self);
906 auto cls = me->getClass();
907 auto method = cls->getMethod<void()>("customExceptionThrower");
908
909 try {
910 method(self);
911 return env->NewStringUTF("method did not throw");
912 } catch (JniException& ex) {
913 auto replacement = JniException(std::move(ex));
914 return env->NewStringUTF(replacement.what());
915 }
916 }
917
TestMoveConstructorWithPopulatedWhat(JNIEnv * env,jobject self)918 jstring TestMoveConstructorWithPopulatedWhat(JNIEnv* env, jobject self) {
919 auto me = adopt_local(self);
920 auto cls = me->getClass();
921 auto method = cls->getMethod<void()>("customExceptionThrower");
922
923 try {
924 method(self);
925 return env->NewStringUTF("method did not throw");
926 } catch (JniException& ex) {
927 ex.what();
928 auto replacement = JniException(std::move(ex));
929 return env->NewStringUTF(replacement.what());
930 }
931 }
932
TestHandleCppRuntimeError(JNIEnv * env,jobject self,jstring message)933 void TestHandleCppRuntimeError(JNIEnv* env, jobject self, jstring message) {
934 throw std::runtime_error(ToString(env, message));
935 }
936
TestHandleCppIOBaseFailure(JNIEnv * env,jobject self)937 void TestHandleCppIOBaseFailure(JNIEnv* env, jobject self) {
938 throw std::ios_base::failure("A C++ IO base failure.");
939 }
940
TestHandleCppSystemError(JNIEnv * env,jobject self)941 void TestHandleCppSystemError(JNIEnv* env, jobject self) {
942 // Throw a sample std::system_error
943 throw std::system_error(EFAULT, std::system_category());
944 }
945
TestInterDsoExceptionHandlingA(JNIEnv * env,jobject self)946 void TestInterDsoExceptionHandlingA(JNIEnv* env, jobject self) {
947 inter_dso_exception_test_2a();
948 }
949
TestInterDsoExceptionHandlingB(JNIEnv * env,jobject self)950 jboolean TestInterDsoExceptionHandlingB(JNIEnv* env, jobject self) {
951 return inter_dso_exception_test_2b();
952 }
953
954 struct NonStdException /* has no base class */ {};
955
TestHandleNonStdException(JNIEnv * env,jobject self)956 void TestHandleNonStdException(JNIEnv* env, jobject self) {
957 throw NonStdException();
958 }
959
TestHandleCppIntThrow(JNIEnv * env,jobject self)960 void TestHandleCppIntThrow(JNIEnv* env, jobject self) {
961 throw 42;
962 }
963
TestHandleCppCharPointerThrow(JNIEnv * env,jobject self)964 void TestHandleCppCharPointerThrow(JNIEnv* env, jobject self) {
965 throw "Some random message";
966 }
967
TestThrowJavaExceptionByName(JNIEnv * env,jobject self)968 void TestThrowJavaExceptionByName(JNIEnv* env, jobject self) {
969 throwNewJavaException(
970 "java/lang/IllegalArgumentException", "bad news: %s", "it didn't work");
971 }
972
TestJThread(JNIEnv * env,jobject self)973 jint TestJThread(JNIEnv* env, jobject self) {
974 jint i = -1;
975 auto thread = JThread::create([&] {
976 i = 0;
977 std::this_thread::sleep_for(std::chrono::milliseconds(20));
978 i = 1;
979 });
980 thread->start();
981 thread->join();
982 return i;
983 }
984
985 // Global for simpleWorker tests. Relies on thread sync points (constructor,
986 // join) for "locking".
987 jint gWorkerValue;
988
simpleWorker(jobject grefSelf,jdouble input)989 void simpleWorker(jobject grefSelf, jdouble input) {
990 auto attachGuard = ThreadScope(); // This tests the move constructor.
991 auto self = adopt_global(grefSelf);
992 // Claw up from the object to avoid classloader issues.
993 auto barMethod = self->getClass()->getMethod<jint(jdouble)>("bar");
994 gWorkerValue = barMethod(self.get(), input);
995 }
996
nestedSimpleWorker(jobject grefSelf,jdouble input)997 void nestedSimpleWorker(jobject grefSelf, jdouble input) {
998 ThreadScope attachGuard; // More efficient version of guard; no move
999 // constructor required.
1000 simpleWorker(grefSelf, input);
1001 }
1002
TestThreadScopeGuard(JNIEnv * env,jobject self,jdouble input)1003 jint TestThreadScopeGuard(JNIEnv* env, jobject self, jdouble input) {
1004 // Turn self into a global reference before passing it to a working thread.
1005 auto grefSelf = make_global(adopt_local(self));
1006 auto childThread = std::thread(simpleWorker, grefSelf.release(), input);
1007 childThread.join();
1008 return gWorkerValue;
1009 }
1010
TestNestedThreadScopeGuard(JNIEnv * env,jobject self,jdouble input)1011 jint TestNestedThreadScopeGuard(JNIEnv* env, jobject self, jdouble input) {
1012 // Turn self into a global reference before passing it to a working thread.
1013 auto grefSelf = make_global(adopt_local(self));
1014 auto childThread = std::thread(nestedSimpleWorker, grefSelf.release(), input);
1015 childThread.join();
1016 return gWorkerValue;
1017 }
1018
classLoadWorker()1019 void classLoadWorker() {
1020 gWorkerValue = 0;
1021 try {
1022 // This should fail because we aren't attached.
1023 Callbacks::javaClassLocal();
1024 gWorkerValue = -1;
1025 return;
1026 } catch (std::exception& e) {
1027 // ignored
1028 }
1029 try {
1030 ThreadScope::WithClassLoader([&] {
1031 // This should now succeed.
1032 Callbacks::javaClassLocal();
1033 gWorkerValue = 1;
1034 });
1035 } catch (std::exception& e) {
1036 gWorkerValue = -2;
1037 // Catch this and log it so that we get a test failure instead of a crash.
1038 FBJNI_LOGE("%s", e.what());
1039 }
1040 }
1041
TestClassLoadInWorker(JNIEnv * env,jobject self)1042 jint TestClassLoadInWorker(JNIEnv* env, jobject self) {
1043 std::thread t(classLoadWorker);
1044 t.join();
1045 return gWorkerValue;
1046 }
1047
TestClassLoadWorkerFastPath(JNIEnv * env,jobject self)1048 jint TestClassLoadWorkerFastPath(JNIEnv* env, jobject self) {
1049 jint i = 0;
1050 ThreadScope::WithClassLoader([&] {
1051 // Execute on the fast path
1052 Callbacks::javaClassLocal();
1053 i += 1;
1054 });
1055
1056 std::thread t([&] {
1057 ThreadScope::WithClassLoader([&] {
1058 // Execute on the slow path
1059 Callbacks::javaClassLocal();
1060 i += 1;
1061 });
1062 });
1063 t.join();
1064
1065 std::thread t2([&] {
1066 ThreadScope scope;
1067 ThreadScope::WithClassLoader([&] {
1068 // Execute on the slow path even though thread is already attached.
1069 Callbacks::javaClassLocal();
1070 i += 1;
1071 });
1072 });
1073 t2.join();
1074
1075 return i;
1076 }
1077
testNewObject(JNIEnv *,jobject self)1078 void testNewObject(JNIEnv*, jobject self) {
1079 // This is a compilation only test, verifies that all the types work out.
1080 auto cls = findClassLocal("java/lang/String");
1081 auto ctr = cls->getConstructor<jstring()>();
1082 local_ref<jstring> obj = cls->newObject(ctr);
1083 auto str = obj->toStdString();
1084 Use(str);
1085 }
1086
1087 template <typename T>
copyAndVerify(T & orig)1088 static jboolean copyAndVerify(T& orig) {
1089 T copy{orig};
1090 EXPECT(orig == copy);
1091
1092 return JNI_TRUE;
1093 }
1094
1095 template <typename T>
assignAndVerify(T & orig)1096 static jboolean assignAndVerify(T& orig) {
1097 T copy{};
1098 copy = orig;
1099 EXPECT(orig == copy);
1100
1101 return JNI_TRUE;
1102 }
1103
testNullReferences(JNIEnv *,jobject)1104 jboolean testNullReferences(JNIEnv*, jobject) {
1105 jobject nullobject = nullptr;
1106
1107 auto local = local_ref<jobject>{};
1108 EXPECT(!local);
1109
1110 auto localWrap = adopt_local(nullobject);
1111 EXPECT(!localWrap);
1112
1113 auto localMake = make_local(local);
1114 EXPECT(!localMake);
1115 EXPECT_SAME(local, localWrap, localMake);
1116
1117 auto global = global_ref<jobject>{};
1118 EXPECT(!global);
1119
1120 auto globalWrap = adopt_global(nullobject);
1121 EXPECT(!globalWrap);
1122
1123 auto globalMake = make_global(global);
1124 EXPECT(!globalMake);
1125 EXPECT_SAME(global, globalWrap, globalMake);
1126
1127 weak_ref<jobject> weak_global = weak_ref<jobject>{};
1128 EXPECT(!weak_global.lockLocal());
1129
1130 weak_ref<jobject> weak_globalWrap = adopt_weak_global(nullobject);
1131 EXPECT(!weak_globalWrap.lockLocal());
1132 EXPECT(weak_global.lockLocal() == weak_globalWrap.lockGlobal());
1133 EXPECT(!make_local(adopt_local(nullobject)));
1134 EXPECT(!make_global(nullobject));
1135
1136 return JNI_TRUE;
1137 }
1138
testCreatingReferences(JNIEnv *,jobject self)1139 jboolean testCreatingReferences(JNIEnv*, jobject self) {
1140 auto a = wrap_alias(self);
1141 auto l = adopt_local(self);
1142 auto g = make_global(l);
1143 auto w = make_weak(l);
1144
1145 EXPECT(a == l && a == g && a == w.lockLocal());
1146
1147 auto lp = make_local(self);
1148 auto la = make_local(a);
1149 auto ll = make_local(l);
1150 auto lg = make_local(g);
1151
1152 EXPECT(a == lp && a == la && a == ll && a == lg);
1153
1154 auto gp = make_global(self);
1155 auto ga = make_global(a);
1156 auto gl = make_global(l);
1157 auto gg = make_global(g);
1158
1159 EXPECT(a == gp && a == ga && a == gl && a == gg);
1160
1161 return JNI_TRUE;
1162 }
1163
testAssignmentAndCopyConstructors(JNIEnv *,jobject self)1164 jboolean testAssignmentAndCopyConstructors(JNIEnv*, jobject self) {
1165 using facebook::jni::internal::g_reference_stats;
1166
1167 g_reference_stats.reset();
1168 {
1169 // Wrapping existing local that should be deleted (locals = 1)
1170 auto local = adopt_local(self);
1171 // Copy constructor (locals = 2)
1172 EXPECT(copyAndVerify(local));
1173
1174 // Assignment (locals = 3)
1175 EXPECT(assignAndVerify(local));
1176
1177 // Creating a new global (globals = 1)
1178 auto global = make_global(local);
1179 // Copy constructor (globals = 2)
1180 EXPECT(copyAndVerify(global));
1181
1182 // Assignment (globals = 3)
1183 EXPECT(assignAndVerify(global));
1184
1185 // Creating a new weak (weaks = 1)
1186 auto weak = make_weak(local);
1187 // Copy constructor (weaks = 2, globals = 5)
1188 weak_ref<jobject> weakCopy{weak};
1189 EXPECT(weak.lockGlobal() == weakCopy.lockGlobal());
1190
1191 // Assignment (weaks = 3, globals = 7)
1192 weakCopy = weak;
1193 EXPECT(weak.lockGlobal() == weakCopy.lockGlobal());
1194
1195 auto alias = alias_ref<jobject>{local};
1196 alias_ref<jobject> aliasCopy{alias};
1197 EXPECT(alias == aliasCopy);
1198
1199 aliasCopy = alias;
1200 EXPECT(alias == aliasCopy);
1201
1202 alias = self;
1203 alias = global;
1204 // alias = weak; // Should not compile
1205 }
1206
1207 FBJNI_LOGE("locals: %d", g_reference_stats.locals_deleted.load());
1208 FBJNI_LOGE("globals: %d", g_reference_stats.globals_deleted.load());
1209 FBJNI_LOGE("weaks: %d", g_reference_stats.weaks_deleted.load());
1210
1211 EXPECT(
1212 g_reference_stats.locals_deleted == 3 &&
1213 g_reference_stats.globals_deleted == 7 &&
1214 g_reference_stats.weaks_deleted == 3);
1215
1216 return JNI_TRUE;
1217 }
1218
1219 template <template <typename> class RefType, typename T>
copyAndVerifyCross(RefType<T> & orig)1220 static jboolean copyAndVerifyCross(RefType<T>& orig) {
1221 RefType<ReprType<T>> reprCopy{orig};
1222 RefType<JniType<T>> jniCopy{orig};
1223 EXPECT(orig == reprCopy);
1224 EXPECT(orig == jniCopy);
1225 return JNI_TRUE;
1226 }
1227
1228 template <template <typename> class RefType, typename T>
assignAndVerifyCross(RefType<T> & orig)1229 static jboolean assignAndVerifyCross(RefType<T>& orig) {
1230 RefType<ReprType<T>> reprCopy{};
1231 reprCopy = orig;
1232 RefType<JniType<T>> jniCopy{};
1233 jniCopy = orig;
1234 EXPECT(orig == reprCopy);
1235 EXPECT(orig == jniCopy);
1236 return JNI_TRUE;
1237 }
1238
1239 template <template <typename> class RefType, typename T>
verifyMakeCross(RefType<T> & orig)1240 static jboolean verifyMakeCross(RefType<T>& orig) {
1241 RefType<ReprType<T>> copy{orig};
1242 {
1243 local_ref<T> local = make_local(copy);
1244 global_ref<T> global = make_global(copy);
1245 weak_ref<T> weak = make_weak(copy);
1246 }
1247
1248 {
1249 local_ref<ReprType<T>> local = make_local(copy);
1250 global_ref<ReprType<T>> global = make_global(copy);
1251 weak_ref<ReprType<T>> weak = make_weak(copy);
1252 }
1253
1254 {
1255 local_ref<T> local = make_local(orig);
1256 global_ref<T> global = make_global(orig);
1257 weak_ref<T> weak = make_weak(orig);
1258 }
1259
1260 {
1261 local_ref<ReprType<T>> local = make_local(orig);
1262 global_ref<ReprType<T>> global = make_global(orig);
1263 weak_ref<ReprType<T>> weak = make_weak(orig);
1264 }
1265
1266 return JNI_TRUE;
1267 }
1268
testAssignmentAndCopyCrossTypes(JNIEnv *,jobject self)1269 jboolean testAssignmentAndCopyCrossTypes(JNIEnv*, jobject self) {
1270 using facebook::jni::internal::g_reference_stats;
1271
1272 size_t locals = 0, globals = 0, weaks = 0;
1273 g_reference_stats.reset();
1274 #define VERIFY_REFERENCE_STATS() \
1275 do { \
1276 bool referenceStatsMatch = g_reference_stats.locals_deleted == locals && \
1277 g_reference_stats.globals_deleted == globals && \
1278 g_reference_stats.weaks_deleted == weaks; \
1279 if (!referenceStatsMatch) { \
1280 FBJNI_LOGE( \
1281 "locals: %d, expected: %zd", \
1282 g_reference_stats.locals_deleted.load(), \
1283 locals); \
1284 FBJNI_LOGE( \
1285 "globals: %d, expected: %zd", \
1286 g_reference_stats.globals_deleted.load(), \
1287 globals); \
1288 FBJNI_LOGE( \
1289 "weaks: %d, expected: %zd", \
1290 g_reference_stats.weaks_deleted.load(), \
1291 weaks); \
1292 } \
1293 EXPECT(referenceStatsMatch); \
1294 } while (0)
1295
1296 {
1297 VERIFY_REFERENCE_STATS();
1298
1299 auto local = adopt_local(self);
1300 VERIFY_REFERENCE_STATS();
1301
1302 EXPECT(copyAndVerifyCross<local_ref>(local));
1303 locals += 2;
1304 VERIFY_REFERENCE_STATS();
1305
1306 EXPECT(assignAndVerifyCross<local_ref>(local));
1307 locals += 2;
1308 VERIFY_REFERENCE_STATS();
1309
1310 EXPECT(verifyMakeCross<local_ref>(local));
1311 locals += 1;
1312 locals += 4;
1313 globals += 4;
1314 weaks += 4;
1315 VERIFY_REFERENCE_STATS();
1316
1317 auto global = make_global(local);
1318 VERIFY_REFERENCE_STATS();
1319
1320 EXPECT(copyAndVerifyCross<global_ref>(global));
1321 globals += 2;
1322 VERIFY_REFERENCE_STATS();
1323
1324 EXPECT(assignAndVerifyCross<global_ref>(global));
1325 globals += 2;
1326 VERIFY_REFERENCE_STATS();
1327
1328 auto weak = make_weak(local);
1329 VERIFY_REFERENCE_STATS();
1330
1331 weak_ref<JObject> weakCopy{weak};
1332 VERIFY_REFERENCE_STATS();
1333
1334 EXPECT(weak.lockGlobal() == weakCopy.lockGlobal());
1335 globals += 2;
1336 VERIFY_REFERENCE_STATS();
1337
1338 weakCopy = weak;
1339 weaks += 1;
1340 EXPECT(weak.lockGlobal() == weakCopy.lockGlobal());
1341 globals += 2;
1342 VERIFY_REFERENCE_STATS();
1343
1344 auto alias = alias_ref<jobject>{local};
1345 alias_ref<JObject>{local};
1346
1347 alias_ref<JObject> aliasCopy{alias};
1348 EXPECT(alias == aliasCopy);
1349
1350 aliasCopy = alias;
1351 alias = aliasCopy;
1352 EXPECT(alias == aliasCopy);
1353
1354 alias = self;
1355 alias = global;
1356 // alias = weak; // Should not compile
1357
1358 weaks += 1; // `weakCopy` going out of scope
1359 weaks += 1; // `weak` going out of scope
1360 globals += 1; // `global` going out of scope
1361 locals += 1; // `local` going out of scope
1362 }
1363
1364 VERIFY_REFERENCE_STATS();
1365
1366 return JNI_TRUE;
1367 }
1368
testToString(JNIEnv * env,jobject self)1369 jboolean testToString(JNIEnv* env, jobject self) {
1370 auto dateClass = findClassLocal("java/util/Date");
1371 auto dateConstructor = dateClass->getConstructor<jobject()>();
1372 auto date = dateClass->newObject(dateConstructor);
1373
1374 auto objectClass = findClassLocal("java/lang/Object");
1375 auto objectConstructor = objectClass->getConstructor<jobject()>();
1376 auto object = objectClass->newObject(objectConstructor);
1377
1378 // First call the date implementation of toString
1379 auto dateString = date->toString();
1380 // And ensure that we don't use Date's toString method when calling
1381 // toString on the object. If this doesn't crash we are fine.
1382 auto objectString = object->toString();
1383
1384 return JNI_TRUE;
1385 }
1386
testCriticalNativeMethodBindsAndCanBeInvoked(jint a,jfloat b)1387 jboolean testCriticalNativeMethodBindsAndCanBeInvoked(jint a, jfloat b) {
1388 return JNI_TRUE;
1389 }
1390
1391 // These implicit nullptr tests aren't called, the test is that it
1392 // compiles.
returnNullAliasRef()1393 alias_ref<JObject> returnNullAliasRef() {
1394 return nullptr;
1395 }
1396
returnNullLocalRef()1397 local_ref<JObject> returnNullLocalRef() {
1398 return nullptr;
1399 }
1400
returnNullGlobalRef()1401 global_ref<JObject> returnNullGlobalRef() {
1402 return nullptr;
1403 }
1404
takesAliasRef(alias_ref<JObject>)1405 void takesAliasRef(alias_ref<JObject>) {}
takesLocalRef(local_ref<JObject>)1406 void takesLocalRef(local_ref<JObject>) {}
takesGlobalRef(global_ref<JObject>)1407 void takesGlobalRef(global_ref<JObject>) {}
1408
callWithNullRefs()1409 void callWithNullRefs() {
1410 takesAliasRef(nullptr);
1411 takesLocalRef(nullptr);
1412 takesGlobalRef(nullptr);
1413 }
1414
1415 struct SomeJavaFoo;
1416 struct OtherJavaFoo;
1417
1418 struct SomeJavaFoo : JavaClass<SomeJavaFoo> {
1419 // Ensure that smart references can be used in declarations using
1420 // forward-declared types.
1421 alias_ref<OtherJavaFoo> call(alias_ref<SomeJavaFoo>);
1422 static alias_ref<OtherJavaFoo> funcWithForwardDeclaredRefs(
1423 local_ref<OtherJavaFoo> foo);
1424 };
1425
1426 using sjf = SomeJavaFoo::javaobject;
1427
1428 static_assert(IsNonWeakReference<local_ref<jobject>>(), "");
1429 static_assert(IsNonWeakReference<local_ref<sjf>>(), "");
1430 static_assert(IsNonWeakReference<global_ref<jobject>>(), "");
1431 static_assert(IsNonWeakReference<jobject>(), "");
1432 static_assert(IsNonWeakReference<sjf>(), "");
1433 static_assert(IsNonWeakReference<jintArray>(), "");
1434 static_assert(IsNonWeakReference<jbooleanArray>(), "");
1435
1436 static_assert(!IsNonWeakReference<weak_ref<jobject>>(), "");
1437 static_assert(!IsNonWeakReference<weak_ref<sjf>>(), "");
1438 static_assert(!IsNonWeakReference<std::string>(), "");
1439 static_assert(!IsNonWeakReference<jint*>(), "");
1440 static_assert(!IsNonWeakReference<void>(), "");
1441 static_assert(!IsNonWeakReference<int>(), "");
1442
1443 static_assert(IsAnyReference<local_ref<jobject>>(), "");
1444 static_assert(IsAnyReference<local_ref<sjf>>(), "");
1445 static_assert(IsAnyReference<global_ref<jobject>>(), "");
1446 static_assert(IsAnyReference<jobject>(), "");
1447 static_assert(IsAnyReference<sjf>(), "");
1448 static_assert(IsAnyReference<jintArray>(), "");
1449 static_assert(IsAnyReference<jbooleanArray>(), "");
1450 static_assert(IsAnyReference<weak_ref<jobject>>(), "");
1451 static_assert(IsAnyReference<weak_ref<sjf>>(), "");
1452
1453 static_assert(!IsAnyReference<std::string>(), "");
1454 static_assert(!IsAnyReference<jint*>(), "");
1455 static_assert(!IsAnyReference<void>(), "");
1456 static_assert(!IsAnyReference<int>(), "");
1457
1458 static_assert(IsPlainJniReference<jobject>(), "");
1459 static_assert(IsPlainJniReference<sjf>(), "");
1460 static_assert(IsPlainJniReference<jintArray>(), "");
1461 static_assert(IsPlainJniReference<jbooleanArray>(), "");
1462
1463 static_assert(!IsPlainJniReference<local_ref<jobject>>(), "");
1464 static_assert(!IsPlainJniReference<local_ref<sjf>>(), "");
1465 static_assert(!IsPlainJniReference<global_ref<jobject>>(), "");
1466 static_assert(!IsPlainJniReference<weak_ref<jobject>>(), "");
1467 static_assert(!IsPlainJniReference<weak_ref<sjf>>(), "");
1468 static_assert(!IsPlainJniReference<std::string>(), "");
1469 static_assert(!IsPlainJniReference<jint*>(), "");
1470 static_assert(!IsPlainJniReference<void>(), "");
1471 static_assert(!IsPlainJniReference<int>(), "");
1472
1473 static_assert(IsJniPrimitive<int>(), "");
1474 static_assert(IsJniPrimitive<jint>(), "");
1475 static_assert(IsJniPrimitive<jboolean>(), "");
1476
1477 static_assert(!IsJniPrimitive<jobject>(), "");
1478 static_assert(!IsJniPrimitive<sjf>(), "");
1479 static_assert(!IsJniPrimitive<jintArray>(), "");
1480 static_assert(!IsJniPrimitive<jbooleanArray>(), "");
1481 static_assert(!IsJniPrimitive<local_ref<jobject>>(), "");
1482 static_assert(!IsJniPrimitive<local_ref<sjf>>(), "");
1483 static_assert(!IsJniPrimitive<global_ref<jobject>>(), "");
1484 static_assert(!IsJniPrimitive<weak_ref<jobject>>(), "");
1485 static_assert(!IsJniPrimitive<weak_ref<sjf>>(), "");
1486 static_assert(!IsJniPrimitive<std::string>(), "");
1487 static_assert(!IsJniPrimitive<jint*>(), "");
1488 static_assert(!IsJniPrimitive<void>(), "");
1489
1490 static_assert(IsJniPrimitiveArray<jintArray>(), "");
1491 static_assert(IsJniPrimitiveArray<jbooleanArray>(), "");
1492
1493 static_assert(!IsJniPrimitiveArray<int>(), "");
1494 static_assert(!IsJniPrimitiveArray<jint>(), "");
1495 static_assert(!IsJniPrimitiveArray<jboolean>(), "");
1496 static_assert(!IsJniPrimitiveArray<jobject>(), "");
1497 static_assert(!IsJniPrimitiveArray<sjf>(), "");
1498 static_assert(!IsJniPrimitiveArray<local_ref<jobject>>(), "");
1499 static_assert(!IsJniPrimitiveArray<local_ref<sjf>>(), "");
1500 static_assert(!IsJniPrimitiveArray<global_ref<jobject>>(), "");
1501 static_assert(!IsJniPrimitiveArray<weak_ref<jobject>>(), "");
1502 static_assert(!IsJniPrimitiveArray<weak_ref<sjf>>(), "");
1503 static_assert(!IsJniPrimitiveArray<std::string>(), "");
1504 static_assert(!IsJniPrimitiveArray<jint*>(), "");
1505 static_assert(!IsJniPrimitiveArray<void>(), "");
1506
1507 static_assert(IsJniScalar<jintArray>(), "");
1508 static_assert(IsJniScalar<jbooleanArray>(), "");
1509 static_assert(IsJniScalar<int>(), "");
1510 static_assert(IsJniScalar<jint>(), "");
1511 static_assert(IsJniScalar<jboolean>(), "");
1512 static_assert(IsJniScalar<jobject>(), "");
1513 static_assert(IsJniScalar<sjf>(), "");
1514
1515 static_assert(!IsJniScalar<local_ref<jobject>>(), "");
1516 static_assert(!IsJniScalar<local_ref<sjf>>(), "");
1517 static_assert(!IsJniScalar<global_ref<jobject>>(), "");
1518 static_assert(!IsJniScalar<weak_ref<jobject>>(), "");
1519 static_assert(!IsJniScalar<weak_ref<sjf>>(), "");
1520 static_assert(!IsJniScalar<std::string>(), "");
1521 static_assert(!IsJniScalar<jint*>(), "");
1522 static_assert(!IsJniScalar<void>(), "");
1523
1524 static_assert(IsJniType<jintArray>(), "");
1525 static_assert(IsJniType<jbooleanArray>(), "");
1526 static_assert(IsJniType<int>(), "");
1527 static_assert(IsJniType<jint>(), "");
1528 static_assert(IsJniType<jboolean>(), "");
1529 static_assert(IsJniType<jobject>(), "");
1530 static_assert(IsJniType<sjf>(), "");
1531 static_assert(IsJniType<void>(), "");
1532
1533 static_assert(!IsJniType<local_ref<jobject>>(), "");
1534 static_assert(!IsJniType<local_ref<sjf>>(), "");
1535 static_assert(!IsJniType<global_ref<jobject>>(), "");
1536 static_assert(!IsJniType<weak_ref<jobject>>(), "");
1537 static_assert(!IsJniType<weak_ref<sjf>>(), "");
1538 static_assert(!IsJniType<std::string>(), "");
1539 static_assert(!IsJniType<jint*>(), "");
1540
1541 constexpr const char* jaccess_class_name = "com/facebook/jni/FBJniTests";
1542
1543 struct _jfakeClass : _jobject {};
1544 using jFakeClass = _jfakeClass*;
1545
1546 // This gives a better error message than doing the static_assert inline
1547 // (because it will contain the two resolved types).
1548 template <typename T, typename F>
StaticAssertSame()1549 void StaticAssertSame() {
1550 static_assert(std::is_same<T, F>::value, "");
1551 };
1552
1553 } // namespace
1554
RegisterFbjniTests()1555 void RegisterFbjniTests() {
1556 StaticAssertSame<JniType<jFakeClass>, jFakeClass>();
1557
1558 StaticAssertSame<PrimitiveOrJniType<JObject>, jobject>();
1559 StaticAssertSame<PrimitiveOrJniType<JClass>, jclass>();
1560 StaticAssertSame<PrimitiveOrJniType<JArrayInt>, jintArray>();
1561 StaticAssertSame<PrimitiveOrJniType<jint>, jint>();
1562 StaticAssertSame<PrimitiveOrJniType<TestThing>, TestThing::javaobject>();
1563
1564 registerNatives(
1565 jaccess_class_name,
1566 {
1567 makeNativeMethod("nativeTestClassResolution", TestClassResolution),
1568 makeNativeMethod(
1569 "nativeTestLazyClassResolution", TestLazyClassResolution),
1570 makeNativeMethod("nativeCreateInstanceOf", TestCreateInstanceOf),
1571 makeNativeMethod(
1572 "nativeTestVirtualMethodResolution_I",
1573 TestVirtualMethodResolution_I),
1574 makeNativeMethod("nativeTestTypeDescriptors", TestTypeDescriptors),
1575 makeNativeMethod(
1576 "nativeTestVirtualMethodResolution_arrB",
1577 TestVirtualMethodResolution_arrB),
1578 makeNativeMethod(
1579 "nativeTestVirtualMethodResolution_S_arrS",
1580 TestVirtualMethodResolution_S_arrS),
1581 makeNativeMethod(
1582 "nativeTestVirtualMethodResolution_arrarrS",
1583 TestVirtualMethodResolution_arrarrS),
1584 makeNativeMethod(
1585 "nativeTestVirtualMethodResolution_arrarrI",
1586 TestVirtualMethodResolution_arrarrI),
1587 makeNativeMethod(
1588 "nativeTestLazyVirtualMethodResolution_I",
1589 TestLazyVirtualMethodResolution_I),
1590 makeNativeMethod(
1591 "nativeTestJMethodCallbacks",
1592 "(Lcom/facebook/jni/FBJniTests$Callbacks;)V",
1593 TestJMethodCallbacks),
1594 makeNativeMethod(
1595 "nativeTestJStaticMethodCallbacks", TestJStaticMethodCallbacks),
1596 makeNativeMethod("nativeTestIsAssignableFrom", TestIsAssignableFrom),
1597 makeNativeMethod("nativeTestIsInstanceOf", TestIsInstanceOf),
1598 makeNativeMethod("nativeTestIsSameObject", TestIsSameObject),
1599 makeNativeMethod("nativeTestGetSuperclass", TestGetSuperclass),
1600 makeNativeMethod("nativeTestWeakRefs", TestWeakRefs),
1601 makeNativeMethod("nativeTestAlias", TestAlias),
1602 makeNativeMethod(
1603 "nativeTestAutoAliasRefReturningVoid",
1604 TestAutoAliasRefReturningVoid),
1605 makeNativeMethod(
1606 "nativeTestAliasRefConversions", testAliasRefConversions),
1607 makeNativeMethod(
1608 "nativeTestCreatingReferences", testCreatingReferences),
1609 makeNativeMethod(
1610 "nativeTestAssignmentAndCopyConstructors",
1611 testAssignmentAndCopyConstructors),
1612 makeNativeMethod(
1613 "nativeTestAssignmentAndCopyCrossTypes",
1614 testAssignmentAndCopyCrossTypes),
1615 makeNativeMethod("nativeTestNullReferences", testNullReferences),
1616 makeNativeMethod("nativeTestFieldAccess", TestFieldAccess),
1617 makeNativeMethod(
1618 "nativeTestStringFieldAccess", TestStringFieldAccess),
1619 makeNativeMethod(
1620 "nativeTestReferenceFieldAccess", TestReferenceFieldAccess),
1621 makeNativeMethod(
1622 "nativeTestStaticFieldAccess", TestStaticFieldAccess),
1623 makeNativeMethod(
1624 "nativeTestStaticStringFieldAccess", TestStaticStringFieldAccess),
1625 makeNativeMethod(
1626 "nativeTestStaticReferenceFieldAccess",
1627 TestStaticReferenceFieldAccess),
1628 makeNativeMethod("nativeTestNonVirtualMethod", TestNonVirtualMethod),
1629 makeNativeMethod("nativeTestArrayCreation", TestArrayCreation),
1630 makeNativeMethod(
1631 "nativeTestMultidimensionalObjectArray",
1632 TestMultidimensionalObjectArray),
1633 makeNativeMethod(
1634 "nativeTestMultidimensionalPrimitiveArray",
1635 TestMultidimensionalPrimitiveArray),
1636 makeNativeMethod("nativeTestBuildStringArray", TestBuildStringArray),
1637 makeNativeMethod(
1638 "testHandleJavaCustomExceptionNative",
1639 TestHandleJavaCustomException),
1640 makeNativeMethod(
1641 "testHandleNullExceptionMessageNative",
1642 TestHandleNullExceptionMessage),
1643 makeNativeMethod(
1644 "nativeTestHandleNestedException", TestHandleNestedException),
1645 makeNativeMethod(
1646 "nativeTestHandleNoRttiException", TestHandleNoRttiException),
1647 makeNativeMethod("nativeTestCopyConstructor", TestCopyConstructor),
1648 makeNativeMethod(
1649 "nativeTestMoveConstructorWithEmptyWhat",
1650 TestMoveConstructorWithEmptyWhat),
1651 makeNativeMethod(
1652 "nativeTestMoveConstructorWithPopulatedWhat",
1653 TestMoveConstructorWithPopulatedWhat),
1654 makeNativeMethod(
1655 "nativeTestHandleCppRuntimeError", TestHandleCppRuntimeError),
1656 makeNativeMethod(
1657 "nativeTestHandleCppIOBaseFailure", TestHandleCppIOBaseFailure),
1658 makeNativeMethod(
1659 "nativeTestHandleCppSystemError", TestHandleCppSystemError),
1660 makeNativeMethod(
1661 "nativeTestInterDsoExceptionHandlingA",
1662 TestInterDsoExceptionHandlingA),
1663 makeNativeMethod(
1664 "nativeTestInterDsoExceptionHandlingB",
1665 TestInterDsoExceptionHandlingB),
1666 makeNativeMethod(
1667 "nativeTestHandleNonStdExceptionThrow",
1668 TestHandleNonStdException),
1669 makeNativeMethod(
1670 "nativeTestHandleCppIntThrow", TestHandleCppIntThrow),
1671 makeNativeMethod(
1672 "nativeTestHandleCppCharPointerThrow",
1673 TestHandleCppCharPointerThrow),
1674 makeNativeMethod(
1675 "nativeTestThrowJavaExceptionByName",
1676 TestThrowJavaExceptionByName),
1677 makeNativeMethod("nativeTestJThread", TestJThread),
1678 makeNativeMethod("nativeTestThreadScopeGuard", TestThreadScopeGuard),
1679 makeNativeMethod(
1680 "nativeTestNestedThreadScopeGuard", TestNestedThreadScopeGuard),
1681 makeNativeMethod(
1682 "nativeTestClassLoadInWorker", TestClassLoadInWorker),
1683 makeNativeMethod(
1684 "nativeTestClassLoadWorkerFastPath", TestClassLoadWorkerFastPath),
1685 makeNativeMethod(
1686 "nativeTestHandleCppCharPointerThrow",
1687 TestHandleCppCharPointerThrow),
1688 makeNativeMethod("nativeTestToString", testToString),
1689 makeNativeMethod(
1690 "nativeTestThrowJavaExceptionByName",
1691 TestThrowJavaExceptionByName),
1692 makeNativeMethod("nativeTestThreadScopeGuard", TestThreadScopeGuard),
1693 makeNativeMethod(
1694 "nativeTestNestedThreadScopeGuard", TestNestedThreadScopeGuard),
1695 makeNativeMethod("nativeTestNullJString", testNullJString),
1696 makeNativeMethod("nativeTestSwap", testSwap),
1697 makeNativeMethod("nativeTestEqualOperator", testEqualOperator),
1698 makeNativeMethod("nativeTestReleaseAlias", testReleaseAlias),
1699 makeNativeMethod(
1700 "nativeTestLockingWeakReferences", testLockingWeakReferences),
1701 makeNativeMethod(
1702 "nativeStaticCastAliasRefToString", StaticCastAliasRefToString),
1703 makeNativeMethod(
1704 "nativeDynamicCastAliasRefToThrowable",
1705 DynamicCastAliasRefToThrowable),
1706 makeNativeMethod(
1707 "nativeStaticCastLocalRefToString", StaticCastLocalRefToString),
1708 makeNativeMethod(
1709 "nativeDynamicCastLocalRefToString", DynamicCastLocalRefToString),
1710 makeNativeMethod(
1711 "nativeStaticCastGlobalRefToString", StaticCastGlobalRefToString),
1712 makeNativeMethod(
1713 "nativeDynamicCastGlobalRefToString",
1714 DynamicCastGlobalRefToString),
1715 makeNativeMethod(
1716 "testMethodResolutionWithCxxTypesNative",
1717 TestMethodResolutionWithCxxTypes),
1718 makeCriticalNativeMethod_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(
1719 "nativeCriticalNativeMethodBindsAndCanBeInvoked",
1720 testCriticalNativeMethodBindsAndCanBeInvoked),
1721 });
1722 }
1723