xref: /aosp_15_r20/external/fbjni/test/jni/fbjni_tests.cpp (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
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