1 /*
2  Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License, version 2.0,
6  as published by the Free Software Foundation.
7 
8  This program is also distributed with certain software (including
9  but not limited to OpenSSL) that is licensed under separate terms,
10  as designated in a particular file or component or in included license
11  documentation.  The authors of MySQL hereby grant you an additional
12  permission to link the program and your derivative works with the
13  separately licensed software that they have included with MySQL.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License, version 2.0, for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 /*
25  * jtie_tconv_ptrbyval_impl.hpp
26  */
27 
28 #ifndef jtie_tconv_ptrbyval_impl_hpp
29 #define jtie_tconv_ptrbyval_impl_hpp
30 
31 #include <assert.h> // not using namespaces yet
32 #include <jni.h>
33 
34 #include "jtie_tconv_ptrbyval.hpp"
35 #include "jtie_tconv_impl.hpp"
36 #include "jtie_tconv_array_impl.hpp"
37 #include "jtie_tconv_utils_impl.hpp"
38 #include "helpers.hpp"
39 
40 // ---------------------------------------------------------------------------
41 // ArrayPtrParam, ArrayPtrResult
42 // ---------------------------------------------------------------------------
43 
44 // Returns zero if an array has a min size; otherwise, an exception is pending.
45 template< jlong N >
46 inline cstatus
ensureMinArraySize(jarray ja,JNIEnv * env)47 ensureMinArraySize(jarray ja, JNIEnv * env) {
48     assert(ja != NULL);
49 
50     // init return value to error
51     cstatus s = -1;
52 
53     // check the array's length
54     jsize n = env->GetArrayLength(ja);
55     if (env->ExceptionCheck() != JNI_OK) {
56         // exception pending
57         assert(false); // coding error: argument not valid
58     } else {
59         if (n < N) {
60             const char * c = "java/lang/IllegalArgumentException";
61             const char * m = ("JTie: the Java array's length is too small for"
62                               "  the mapped parameter (file: " __FILE__ ")");
63             registerException(env, c, m);
64         } else {
65             // ok
66             s = 0;
67         }
68     }
69     return s;
70 }
71 
72 // Implements the mapping of arrays to pointer parameters.
73 template< typename J, typename C >
74 struct ArrayPtrParam {
75     static C *
convertArrayPtrParam76     convert(cstatus & s, typename J::JA_t * j, JNIEnv * env) {
77         TRACE("C * ArrayPtrParam.convert(cstatus &, typename J::JA_t *, JNIEnv *)");
78         // init return value and status to error
79         s = -1;
80         C * c = NULL;
81 
82         if (j == NULL) {
83             // ok
84             s = 0;
85         } else {
86             if (ensureMinArraySize< J::length >(j, env) != 0) {
87                 // exception pending
88             } else {
89                 assert(env->GetArrayLength(j) >= J::length);
90 
91                 // get a C array, to be released by releaseArrayElements()
92                 // ignore whether C array is pinned or a copy of Java array
93                 c = (ArrayConv< typename J::JA_t *, C * >
94                      ::getArrayElements(env, j, NULL));
95                 if (c == NULL) {
96                     // exception pending
97                 } else {
98                     // ok
99                     s = 0;
100                 }
101             }
102         }
103         return c;
104     }
105 
106     static void
releaseArrayPtrParam107     release(C * c, typename J::JA_t * j, JNIEnv * env) {
108         TRACE("void ArrayPtrParam.release(C *, typename J::JA_t *, JNIEnv *)");
109 
110         // compile-time flag whether to copy back any possible changes to the
111         // Java array; tradeoff between
112         // - minor performance gains for non-mutable types (const C *)
113         // - observable data differences for C functions that modify an array
114         //   argument by casting away its constness
115         //
116         // the settings below reflect this semantics: for
117         // - mutable types (C *):
118         //   ==> all changes to the C array are reflected in the Java array
119         // - non-mutable types (const C *) and
120         //   - C functions that modify the array despite its constness and
121         //     - a JVM that returns a pointer to the pinned, original array
122         //       ==> all changes are reflected in the Java array
123         //     - a JVM that choses to return a copy of the original array
124         //       ==> any change to the C array is lost
125         const jint copyBackMode
126             = (TypeInfo< C >::isMutable()
127                ? 0		// copy back content if needed and free buffer
128                : JNI_ABORT);	// free the buffer without copying back
129 
130         if (c == NULL) {
131             assert(j == NULL); // corresponding convert() succeeded (!)
132             // ok
133         } else {
134             assert(j != NULL);
135             // release the C array allocated by getArrayElements()
136             (ArrayConv< typename J::JA_t *, C * >
137              ::releaseArrayElements(env, j, c, copyBackMode));
138         }
139     }
140 };
141 
142 // Implements the mapping of arrays to pointer results.
143 template< typename J, typename C >
144 struct ArrayPtrResult {
145     static J *
convertArrayPtrResult146     convert(C * c, JNIEnv * env) {
147         TRACE("J * ArrayPtrResult.convert(C *, JNIEnv *)");
148 
149         // init return value to error
150         J * j = NULL;
151 
152         if (c == NULL) {
153             // ok
154         } else {
155             jarray jja = (ArrayConv< typename J::JA_t *, C * >
156                           ::newArray(env, J::length, c));
157             J * ja = static_cast< J * >(jja);
158             if (ja == NULL) {
159                 // exception pending
160             } else {
161                 assert(env->GetArrayLength(ja) == J::length);
162                 // ok
163                 j = ja;
164             }
165         }
166         return j;
167     }
168 };
169 
170 // ---------------------------------------------------------------------------
171 // Specializations for pointer type conversions
172 // ---------------------------------------------------------------------------
173 
174 // Avoid mapping types by broad, generic rules, which easily results in
175 // template instantiation ambiguities for non-primitive types.  Therefore,
176 // we enumerate all specicializations for primitive type pointers.
177 
178 // extend array param specializations to const pointers
179 template< typename C >
180 struct Param< _jbooleanArray *, C * const >
181     : Param< _jbooleanArray *, C * > {};
182 template< typename C >
183 struct Param< _jbyteArray *, C * const >
184     : Param< _jbyteArray *, C * > {};
185 template< typename C >
186 struct Param< _jshortArray *, C * const >
187     : Param< _jshortArray *, C * > {};
188 template< typename C >
189 struct Param< _jintArray *, C * const >
190     : Param< _jintArray *, C * > {};
191 template< typename C >
192 struct Param< _jlongArray *, C * const >
193     : Param< _jlongArray *, C * > {};
194 template< typename C >
195 struct Param< _jfloatArray *, C * const >
196     : Param< _jfloatArray *, C * > {};
197 template< typename C >
198 struct Param< _jdoubleArray *, C * const >
199     : Param< _jdoubleArray *, C * > {};
200 
201 // extend result array specializations to const pointers
202 template< typename C >
203 struct Result< _jbooleanArray *, C * const >
204     : Result< _jbooleanArray *, C * > {};
205 template< typename C >
206 struct Result< _jbyteArray *, C * const >
207     : Result< _jbyteArray *, C * > {};
208 template< typename C >
209 struct Result< _jshortArray *, C * const >
210     : Result< _jshortArray *, C * > {};
211 template< typename C >
212 struct Result< _jintArray *, C * const >
213     : Result< _jintArray *, C * > {};
214 template< typename C >
215 struct Result< _jlongArray *, C * const >
216     : Result< _jlongArray *, C * > {};
217 template< typename C >
218 struct Result< _jfloatArray *, C * const >
219     : Result< _jfloatArray *, C * > {};
220 template< typename C >
221 struct Result< _jdoubleArray *, C * const >
222     : Result< _jdoubleArray *, C * > {};
223 
224 // extend BoundedArrays specializations to const pointers
225 template< typename J, typename C >
226 struct Param< _jtie_j_ArrayMapper< J > *, C * const >
227     :  Param< _jtie_j_ArrayMapper< J > *, C * > {};
228 template< typename J, typename C >
229 struct Result< _jtie_j_ArrayMapper< J > *, C * const >
230     : Result< _jtie_j_ArrayMapper< J > *, C * > {};
231 
232 // specialize BoundedArrays mapped to pointers/arrays:
233 // - params: require a minimum array length given by the BoundedArray's
234 //   static data member
235 // - results: allocate array with a length given by the BoundedArray's
236 //   static data member
237 template< typename J, typename C >
238 struct Param< _jtie_j_ArrayMapper< J > *, C * >
239     : ArrayPtrParam< _jtie_j_ArrayMapper< J >, C > {};
240 template< typename J, typename C >
241 struct Result< _jtie_j_ArrayMapper< J > *, C * >
242     : ArrayPtrResult< _jtie_j_ArrayMapper< J >, C > {};
243 
244 // specialize arrays mapped to pointers/arrays:
245 // - params: do not require a minimum buffer capacity, for size may be zero
246 //   when just passing an address
247 // - results: allocate buffer with a capacity of zero, since the size is
248 //    unknown (i.e., just returning an address)
249 #define JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING( J, C )                      \
250     template<>                                                          \
251     struct Param< J *, C * >                                            \
252         : ArrayPtrParam< _jtie_j_BoundedArray< J, 0 >, C > {};          \
253     template<>                                                          \
254     struct Param< J *, const C * >                                      \
255         : ArrayPtrParam< _jtie_j_BoundedArray< J, 0 >, const C > {};    \
256     template<>                                                          \
257     struct Result< J *, C * >                                           \
258         : ArrayPtrResult< _jtie_j_BoundedArray< J, 0 >, C > {};         \
259     template<>                                                          \
260     struct Result< J *, const C * >                                     \
261         : ArrayPtrResult< _jtie_j_BoundedArray< J, 0 >, const C > {};
262 
263 // ---------------------------------------------------------------------------
264 // Specializations for pointer to exact-width primitive type conversions
265 // ---------------------------------------------------------------------------
266 
267 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jbooleanArray, bool)
268 
269 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jbyteArray, char)
270 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jbyteArray, signed char)
271 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jbyteArray, unsigned char)
272 
273 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jfloatArray, float)
274 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jdoubleArray, double)
275 
276 // ---------------------------------------------------------------------------
277 // Specializations for pointer to variable-width primitive type conversions
278 // ---------------------------------------------------------------------------
279 
280 // jshort in LP32, ILP32, LP64, ILP64, LLP64
281 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jshortArray, signed short)
282 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jshortArray, unsigned short)
283 
284 // jshort in LP32
285 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jshortArray, signed int)
286 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jshortArray, unsigned int)
287 
288 // jint in ILP32, LP64, LLP64
289 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jintArray, signed int)
290 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jintArray, unsigned int)
291 
292 // jint in LP32, ILP32, LLP64
293 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jintArray, signed long)
294 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jintArray, unsigned long)
295 
296 // jlong in ILP64
297 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, signed int)
298 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, unsigned int)
299 
300 // jlong in LP64, ILP64
301 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, signed long)
302 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, unsigned long)
303 
304 // jlong in LLP64
305 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, signed long long)
306 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jlongArray, unsigned long long)
307 
308 // jdouble
309 JTIE_SPECIALIZE_ARRAY_TYPE_MAPPING(_jdoubleArray, long double)
310 
311 // ---------------------------------------------------------------------------
312 
313 #endif // jtie_tconv_ptrbyval_impl_hpp
314