1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_jni_Types_h__
8 #define mozilla_jni_Types_h__
9 
10 #include <jni.h>
11 
12 #include "mozilla/jni/Refs.h"
13 #include "mozilla/jni/TypeAdapter.h"
14 
15 namespace mozilla {
16 namespace jni {
17 namespace detail {
18 
19 // TypeAdapter specializations are the interfaces between native/C++ types such
20 // as int32_t and JNI types such as jint. The template parameter T is the native
21 // type, and each TypeAdapter specialization can have the following members:
22 //
23 //  * Call: JNIEnv member pointer for making a method call that returns T.
24 //  * StaticCall: JNIEnv member pointer for making a static call that returns T.
25 //  * Get: JNIEnv member pointer for getting a field of type T.
26 //  * StaticGet: JNIEnv member pointer for getting a static field of type T.
27 //  * Set: JNIEnv member pointer for setting a field of type T.
28 //  * StaticGet: JNIEnv member pointer for setting a static field of type T.
29 //  * ToNative: static function that converts the JNI type to the native type.
30 //  * FromNative: static function that converts the native type to the JNI type.
31 
32 // TypeAdapter<LocalRef<Cls>> applies when jobject is a return value.
33 template <class Cls>
34 struct TypeAdapter<LocalRef<Cls>> {
35   using JNIType = typename Cls::Ref::JNIType;
36 
37   static constexpr auto Call = &JNIEnv::CallObjectMethodA;
38   static constexpr auto StaticCall = &JNIEnv::CallStaticObjectMethodA;
39   static constexpr auto Get = &JNIEnv::GetObjectField;
40   static constexpr auto StaticGet = &JNIEnv::GetStaticObjectField;
41 
42   // Declare instance as jobject because JNI methods return
43   // jobject even if the return value is really jstring, etc.
44   static LocalRef<Cls> ToNative(JNIEnv* env, jobject instance) {
45     return LocalRef<Cls>::Adopt(env, JNIType(instance));
46   }
47 
48   static JNIType FromNative(JNIEnv*, LocalRef<Cls>&& instance) {
49     return instance.Forget();
50   }
51 };
52 
53 // clang is picky about function types, including attributes that modify the
54 // calling convention, lining up.  GCC appears to be somewhat less so.
55 #ifdef __clang__
56 #  define MOZ_JNICALL_ABI JNICALL
57 #else
58 #  define MOZ_JNICALL_ABI
59 #endif
60 
61 // NDK r18 made jvalue* method parameters const. We detect the change directly
62 // instead of using ndk-version.h in order to remain compatible with r15 for
63 // now, which doesn't include those headers.
64 class CallArgs {
65   static const jvalue* test(void (JNIEnv::*)(jobject, jmethodID,
66                                              const jvalue*));
67   static jvalue* test(void (JNIEnv::*)(jobject, jmethodID, jvalue*));
68 
69  public:
70   using JValueType = decltype(test(&JNIEnv::CallVoidMethodA));
71 };
72 
73 template <class Cls>
74 constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Call)(
75     jobject, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;
76 template <class Cls>
77 constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticCall)(
78     jclass, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;
79 template <class Cls>
80 constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Get)(jobject, jfieldID);
81 template <class Cls>
82 constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticGet)(jclass,
83                                                                    jfieldID);
84 
85 // TypeAdapter<Ref<Cls>> applies when jobject is a parameter value.
86 template <class Cls, typename T>
87 struct TypeAdapter<Ref<Cls, T>> {
88   using JNIType = typename Ref<Cls, T>::JNIType;
89 
90   static constexpr auto Set = &JNIEnv::SetObjectField;
91   static constexpr auto StaticSet = &JNIEnv::SetStaticObjectField;
92 
93   static DependentRef<Cls> ToNative(JNIEnv* env, JNIType instance) {
94     return DependentRef<Cls>(instance);
95   }
96 
97   static JNIType FromNative(JNIEnv*, const Ref<Cls, T>& instance) {
98     return instance.Get();
99   }
100 };
101 
102 template <class Cls, typename T>
103 constexpr void (JNIEnv::*TypeAdapter<Ref<Cls, T>>::Set)(jobject, jfieldID,
104                                                         jobject);
105 template <class Cls, typename T>
106 constexpr void (JNIEnv::*TypeAdapter<Ref<Cls, T>>::StaticSet)(jclass, jfieldID,
107                                                               jobject);
108 
109 // jstring has its own Param type.
110 template <>
111 struct TypeAdapter<StringParam> : public TypeAdapter<String::Ref> {};
112 
113 template <class Cls>
114 struct TypeAdapter<const Cls&> : public TypeAdapter<Cls> {};
115 
116 }  // namespace detail
117 
118 using namespace detail;
119 
120 }  // namespace jni
121 }  // namespace mozilla
122 
123 #endif  // mozilla_jni_Types_h__
124