blob: 12760385cc4495ebc85b5c1636ed804e7df3d2b4 [file] [log] [blame]
Igor Murashkin31927e42017-02-17 15:50:15 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
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
Igor Murashkina1969c42018-02-16 13:30:57 -080017/**
18 * Compile-time, zero-cost checking of JNI signatures against their C++ function type.
19 * This can trigger compile-time assertions if any of the input is invalid:
20 * (a) The signature specified does not conform to the JNI function descriptor syntax.
21 * (b) The C++ function is itself an invalid JNI function (e.g. missing JNIEnv*, etc).
22 * (c) The descriptor does not match the C++ function (e.g. "()V" will not match jint(jint)).
Igor Murashkin31927e42017-02-17 15:50:15 -080023 *
Igor Murashkina1969c42018-02-16 13:30:57 -080024 * The fundamental macros are as following:
25 * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD - Create a checked JNINativeMethod{name, sig, func}.
26 * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Same as above, but infer the JNI signature.
27 *
28 * Usage examples:
29 * // path/to/package/KlassName.java
30 * class KlassName {
31 * native jobject normal(int x);
32 * @FastNative native jobject fast(int x);
33 * @CriticalNative native int critical(long ptr);
34 * }
35 * // path_to_package_KlassName.cpp
36 * jobject KlassName_normal(JNIEnv*,jobject,jint) {...}
37 * jobject KlassName_fast(JNIEnv*,jobject,jint) {...}
38 * jint KlassName_critical(jlong) {...}
39 *
40 * // Manually specify each signature:
41 * JNINativeMethod[] gMethods = {
42 * MAKE_JNI_NATIVE_METHOD("normal", "(I)Ljava/lang/Object;", KlassName_normal),
43 * MAKE_JNI_FAST_NATIVE_METHOD("fast", "(I)Ljava/lang/Object;", KlassName_fast),
44 * MAKE_JNI_CRITICAL_NATIVE_METHOD("critical", "(Z)I", KlassName_critical),
45 * };
46 *
47 * // Automatically infer the signature:
48 * JNINativeMethod[] gMethodsAutomaticSignature = {
49 * MAKE_JNI_NATIVE_METHOD_AUTOSIG("normal", KlassName_normal),
50 * MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG("fast", KlassName_fast),
51 * MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG("critical", KlassName_critical),
52 * };
53 *
54 * // and then call JNIEnv::RegisterNatives with gMethods as usual.
55 *
56 * For convenience the following macros are defined:
57 * [FAST_|CRITICAL_]NATIVE_METHOD - Return JNINativeMethod for class, func name, and signature.
58 * OVERLOADED_[FAST_|CRITICAL_]NATIVE_METHOD - Same as above but allows a separate func identifier.
59 * [FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Return JNINativeMethod, sig inferred from function.
60 *
61 * The FAST_ prefix corresponds to functions annotated with @FastNative,
62 * and the CRITICAL_ prefix corresponds to functions annotated with @CriticalNative.
63 * See dalvik.annotation.optimization.CriticalNative for more details.
64 *
65 * =======================================
66 * Checking rules
67 * =======================================
68 *
69 * ---------------------------------------
70 * JNI descriptor syntax for functions
71 *
72 * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification
73 * under the subsection "Type Signatures" table entry "method type".
74 *
75 * JNI signatures not conforming to the above syntax are rejected.
76 * ---------------------------------------
77 * C++ function types
78 *
79 * A normal or @FastNative JNI function type must be of the form
80 *
81 * ReturnType (JNIEnv*, jclass|jobject, [ArgTypes...]) {}
82 *
83 * A @CriticalNative JNI function type:
84 *
85 * must be of the form... ReturnType ([ArgTypes...]){}
86 * and must not contain any Reference Types.
87 *
88 * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification
89 * under the subsection "Primitive Types" and "Reference Types" for the list
90 * of valid argument/return types.
91 *
92 * C++ function types not conforming to the above requirements are rejected.
93 * ---------------------------------------
94 * Matching of C++ function type against JNI function descriptor.
95 *
96 * Assuming all of the above conditions are met for signature and C++ type validity,
97 * then matching between the signature and the type validity can occur:
98 *
99 * Given a signature (Args...)Ret and the
100 * C++ function type of the form "CRet fn(JNIEnv*, jclass|jobject, CArgs...)",
101 * or for @CriticalNative of the form "CRet fn(CArgs...)"
102 *
103 * The number of Args... and the number of CArgs... must be equal.
104 *
105 * If so, attempt to match every component from the signature and function type
106 * against each other:
107 *
108 * ReturnType:
109 * V <-> void
110 * ArgumentType
111 *
112 * ArgumentType:
113 * PrimitiveType
114 * ReferenceType [except for @CriticalNative]
115 *
116 * PrimitiveType:
117 * Z <-> jboolean
118 * B <-> jbyte
119 * C <-> jchar
120 * S <-> jshort
121 * I <-> jint
122 * J <-> jlong
123 * F <-> jfloat
124 * D <-> jdouble
125 *
126 * ReferenceType:
127 * Ljava/lang/String; <-> jstring
128 * Ljava/lang/Class; <-> jclass
129 * L*; <- jobject
130 * Ljava/lang/Throwable; -> jthrowable
131 * L*; <- jthrowable
132 * [ PrimitiveType <-> ${CPrimitiveType}Array
133 * [ ReferenceType <-> jobjectArray
134 * [* <- jarray
135 *
136 * Wherein <-> represents a strong match (if the left or right pattern occurs,
137 * then left must match right, otherwise matching fails). <- and -> represent
138 * weak matches (that is, other match rules can be still attempted).
139 *
140 * Sidenote: Whilst a jobject could also represent a jclass, jstring, etc,
141 * the stricter approach is taken: the most exact C++ type must be used.
Igor Murashkin31927e42017-02-17 15:50:15 -0800142 */
143
144#ifndef NATIVEHELPER_JNI_MACROS_H
145#define NATIVEHELPER_JNI_MACROS_H
146
Igor Murashkina1969c42018-02-16 13:30:57 -0800147// The below basic macros do not perform automatic stringification,
148// invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn)
Igor Murashkin31927e42017-02-17 15:50:15 -0800149
Igor Murashkina1969c42018-02-16 13:30:57 -0800150// An expression that evaluates to JNINativeMethod { name, signature, function },
151// and applies the above compile-time checking for signature+function.
152// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
153#define MAKE_JNI_NATIVE_METHOD(name, signature, function) \
154 _NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function)
155
156// An expression that evaluates to JNINativeMethod { name, signature, function },
157// and applies the above compile-time checking for signature+function.
158// The equivalent Java Language code must be annotated with @FastNative.
159#define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \
160 _NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function)
161
162// An expression that evaluates to JNINativeMethod { name, signature, function },
163// and applies the above compile-time checking for signature+function.
164// The equivalent Java Language code must be annotated with @CriticalNative.
165#define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \
166 _NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function)
167
168// Automatically signature-inferencing macros are also available,
169// which also checks the C++ function types for validity:
170
171// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
172// by inferring the signature at compile-time. Only works when the C++ function type
173// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
174//
175// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
176#define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \
177 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function)
178
179// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
180// by inferring the signature at compile-time. Only works when the C++ function type
181// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
182//
183// The equivalent Java Language code must be annotated with @FastNative.
184#define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \
185 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function)
186
187// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
188// by inferring the signature at compile-time.
189//
190// The equivalent Java Language code must be annotated with @CriticalNative.
191#define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \
192 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function)
193
194// Convenience macros when the functions follow the naming convention:
195// .java file .cpp file
196// JavaLanguageName <-> ${ClassName}_${JavaLanguageName}
197//
198// Stringification is done automatically, invoked as:
199// NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature)
200//
Igor Murashkin31927e42017-02-17 15:50:15 -0800201// Intended to construct a JNINativeMethod.
202// (Assumes the C name is the ClassName_JavaMethodName).
Igor Murashkin31927e42017-02-17 15:50:15 -0800203//
Igor Murashkina1969c42018-02-16 13:30:57 -0800204// The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative)
205// for the (none,FAST_,CRITICAL_) variants of these macros.
206
207#ifdef NATIVE_METHOD // Remove definition from JniConstants.h
208#undef NATIVE_METHOD
Igor Murashkin31927e42017-02-17 15:50:15 -0800209#endif
210
Igor Murashkina1969c42018-02-16 13:30:57 -0800211#define NATIVE_METHOD(className, functionName, signature) \
212 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
213
214#define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \
215 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
216
217#define NATIVE_METHOD_AUTOSIG(className, functionName) \
218 MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
219
220#define FAST_NATIVE_METHOD(className, functionName, signature) \
221 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
222
223#define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \
224 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
225
226#define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \
227 MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
228
229#define CRITICAL_NATIVE_METHOD(className, functionName, signature) \
230 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
231
232#define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \
233 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
234
235#define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \
236 MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
237
Igor Murashkin31927e42017-02-17 15:50:15 -0800238////////////////////////////////////////////////////////
239// IMPLEMENTATION ONLY.
240// DO NOT USE DIRECTLY.
241////////////////////////////////////////////////////////
242
Igor Murashkina1969c42018-02-16 13:30:57 -0800243#if defined(__cplusplus) && __cplusplus >= 201402L
244#include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD
245#endif
246
247// Expands to an expression whose type is JNINativeMethod.
248// This is for older versions of C++ or C, so it has no compile-time checking.
249#define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \
250 ( \
251 (JNINativeMethod) { \
252 (name), \
253 (sig), \
254 _NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \
255 } \
256 )
257
258// C++14 or better, use compile-time checking.
259#if defined(__cplusplus) && __cplusplus >= 201402L
260// Expands to a compound expression whose type is JNINativeMethod.
261#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
262 MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn)
263
264// Expands to a compound expression whose type is JNINativeMethod.
265#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
266 MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function)
267
268#else
269// Older versions of C++ or C code get the regular macro that's unchecked.
270// Expands to a compound expression whose type is JNINativeMethod.
271#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
272 _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn)
273
274// Need C++14 or newer to use the AUTOSIG macros.
275#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
276 static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function);
277
278#endif // C++14 check
Igor Murashkin31927e42017-02-17 15:50:15 -0800279
280// C-style cast for C, C++-style cast for C++ to avoid warnings/errors.
281#if defined(__cplusplus)
Igor Murashkina1969c42018-02-16 13:30:57 -0800282#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
283 which_cast<to>
Igor Murashkin31927e42017-02-17 15:50:15 -0800284#else
Igor Murashkina1969c42018-02-16 13:30:57 -0800285#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
Igor Murashkin31927e42017-02-17 15:50:15 -0800286 (to)
287#endif
288
Igor Murashkina1969c42018-02-16 13:30:57 -0800289#endif // NATIVEHELPER_JNI_MACROS_H