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 #pragma once
18
19 #include <jni.h>
20
21 #include "Common.h"
22 #include "References.h"
23
24 namespace facebook {
25 namespace jni {
26
27 namespace detail {
28
29 // In order to avoid potentially filling the jni locals table,
30 // temporary objects (right now, this is just jstrings) need to be
31 // released. This is done by returning a holder which autoconverts to
32 // jstring.
33 template <typename T>
callToJni(T && t)34 inline T callToJni(T&& t) {
35 return t;
36 }
37
38 template <typename T>
callToJni(local_ref<T> && sref)39 inline JniType<T> callToJni(local_ref<T>&& sref) {
40 return sref.get();
41 }
42
43 template <typename T>
toPlainJniReference(T obj)44 enable_if_t<IsPlainJniReference<T>(), T> toPlainJniReference(T obj) {
45 return obj;
46 }
47
48 template <typename T>
toPlainJniReference(T repr)49 enable_if_t<IsJavaClassType<T>(), JniType<T>> toPlainJniReference(T repr) {
50 return ReprAccess<T>::get(repr);
51 }
52
53 // Normally, pass through types unmolested.
54 template <typename T, typename Enabled = void>
55 struct Convert {
56 typedef T jniType;
fromJniConvert57 static jniType fromJni(jniType t) {
58 return t;
59 }
toJniRetConvert60 static jniType toJniRet(jniType t) {
61 return t;
62 }
toCallConvert63 static jniType toCall(jniType t) {
64 return t;
65 }
66 };
67
68 // This is needed for return conversion
69 template <>
70 struct Convert<void> {
71 typedef void jniType;
72 };
73
74 // jboolean is an unsigned char, not a bool. Allow it to work either way.
75 template <>
76 struct Convert<bool> {
77 typedef jboolean jniType;
78 static bool fromJni(jniType t) {
79 return t;
80 }
81 static jniType toJniRet(bool t) {
82 return t;
83 }
84 static jniType toCall(bool t) {
85 return t;
86 }
87 };
88
89 // Sometimes (64-bit Android) jlong is "long long", but int64_t is "long".
90 // Allow int64_t to work as jlong.
91 template <typename T>
92 struct Convert<
93 T,
94 typename std::enable_if<
95 (std::is_same<T, long long>::value ||
96 std::is_same<T, int64_t>::value) &&
97 !std::is_same<T, jlong>::value>::type> {
98 typedef jlong jniType;
99 static T fromJni(jniType t) {
100 return t;
101 }
102 static jniType toJniRet(T t) {
103 return t;
104 }
105 static jniType toCall(T t) {
106 return t;
107 }
108 };
109
110 // convert to alias_ref<T> from T
111 template <typename T>
112 struct Convert<alias_ref<T>> {
113 typedef JniType<T> jniType;
114 static alias_ref<jniType> fromJni(jniType t) {
115 return wrap_alias(t);
116 }
117 static jniType toJniRet(alias_ref<jniType> t) {
118 return t.get();
119 }
120 static jniType toCall(const alias_ref<jniType>& t) {
121 return t.get();
122 }
123 };
124
125 // convert return from local_ref<T>
126 template <typename T>
127 struct Convert<local_ref<T>> {
128 typedef JniType<T> jniType;
129 // No automatic synthesis of local_ref
130 static jniType toJniRet(local_ref<jniType> t) {
131 return t.release();
132 }
133 static jniType toCall(const local_ref<jniType>& t) {
134 return t.get();
135 }
136 };
137
138 // convert return from global_ref<T>
139 template <typename T>
140 struct Convert<global_ref<T>> {
141 typedef JniType<T> jniType;
142 // No automatic synthesis of global_ref
143 static jniType toJniRet(global_ref<jniType>&& t) {
144 // If this gets called, ownership the global_ref was passed in here. (It's
145 // probably a copy of a persistent global_ref made when a function was
146 // declared to return a global_ref, but it could moved out or otherwise not
147 // referenced elsewhere. Doesn't matter.) Either way, the only safe way
148 // to return it is to make a local_ref, release it, and return the
149 // underlying local jobject.
150 auto ret = make_local(t);
151 return ret.release();
152 }
153 static jniType toJniRet(const global_ref<jniType>& t) {
154 // If this gets called, the function was declared to return const&. We
155 // have a ref to a global_ref whose lifetime will exceed this call, so we
156 // can just get the underlying jobject and return it to java without
157 // needing to make a local_ref.
158 return t.get();
159 }
160 static jniType toCall(const global_ref<jniType>& t) {
161 return t.get();
162 }
163 };
164
165 template <typename T>
166 struct jni_sig_from_cxx_t;
167 template <typename R, typename... Args>
168 struct jni_sig_from_cxx_t<R(Args...)> {
169 using JniRet = typename Convert<typename std::decay<R>::type>::jniType;
170 using JniSig =
171 JniRet(typename Convert<typename std::decay<Args>::type>::jniType...);
172 };
173
174 template <typename T>
175 using jni_sig_from_cxx = typename jni_sig_from_cxx_t<T>::JniSig;
176
177 } // namespace detail
178
179 template <typename R, typename... Args>
180 struct jmethod_traits_from_cxx<R(Args...)>
181 : jmethod_traits<detail::jni_sig_from_cxx<R(Args...)>> {};
182
183 } // namespace jni
184 } // namespace facebook
185