blob: ca03288f39d57bd6c341cdafe4dc81fc09108a23 [file] [log] [blame]
Fairphone ODM25c12f52023-12-15 17:24:06 +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
17/**
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)).
23 *
24 * 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", "(J)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.
142 */
143
144#pragma once
145
146// The below basic macros do not perform automatic stringification,
147// invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn)
148
149// An expression that evaluates to JNINativeMethod { name, signature, function },
150// and applies the above compile-time checking for signature+function.
151// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
152#define MAKE_JNI_NATIVE_METHOD(name, signature, function) \
153 _NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function)
154
155// An expression that evaluates to JNINativeMethod { name, signature, function },
156// and applies the above compile-time checking for signature+function.
157// The equivalent Java Language code must be annotated with @FastNative.
158#define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \
159 _NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function)
160
161// An expression that evaluates to JNINativeMethod { name, signature, function },
162// and applies the above compile-time checking for signature+function.
163// The equivalent Java Language code must be annotated with @CriticalNative.
164#define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \
165 _NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function)
166
167// Automatically signature-inferencing macros are also available,
168// which also checks the C++ function types for validity:
169
170// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
171// by inferring the signature at compile-time. Only works when the C++ function type
172// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
173//
174// The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative.
175#define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \
176 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function)
177
178// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
179// by inferring the signature at compile-time. Only works when the C++ function type
180// corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???).
181//
182// The equivalent Java Language code must be annotated with @FastNative.
183#define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \
184 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function)
185
186// An expression that evalutes to JNINativeMethod { name, infersig(function), function) }
187// by inferring the signature at compile-time.
188//
189// The equivalent Java Language code must be annotated with @CriticalNative.
190#define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \
191 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function)
192
193// Convenience macros when the functions follow the naming convention:
194// .java file .cpp file
195// JavaLanguageName <-> ${ClassName}_${JavaLanguageName}
196//
197// Stringification is done automatically, invoked as:
198// NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature)
199//
200// Intended to construct a JNINativeMethod.
201// (Assumes the C name is the ClassName_JavaMethodName).
202//
203// The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative)
204// for the (none,FAST_,CRITICAL_) variants of these macros.
205
206#define NATIVE_METHOD(className, functionName, signature) \
207 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
208
209#define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \
210 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
211
212#define NATIVE_METHOD_AUTOSIG(className, functionName) \
213 MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
214
215#define FAST_NATIVE_METHOD(className, functionName, signature) \
216 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
217
218#define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \
219 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
220
221#define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \
222 MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
223
224#define CRITICAL_NATIVE_METHOD(className, functionName, signature) \
225 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName)
226
227#define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \
228 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier)
229
230#define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \
231 MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName)
232
233////////////////////////////////////////////////////////
234// IMPLEMENTATION ONLY.
235// DO NOT USE DIRECTLY.
236////////////////////////////////////////////////////////
237
238#if defined(__cplusplus) && __cplusplus >= 201402L
239#include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD
240#endif
241
242// Expands to an expression whose type is JNINativeMethod.
243// This is for older versions of C++ or C, so it has no compile-time checking.
244#define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \
245 ( \
246 (JNINativeMethod) { \
247 (name), \
248 (sig), \
249 _NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \
250 } \
251 )
252
253// C++14 or better, use compile-time checking.
254#if defined(__cplusplus) && __cplusplus >= 201402L
255// Expands to a compound expression whose type is JNINativeMethod.
256#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
257 MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn)
258
259// Expands to a compound expression whose type is JNINativeMethod.
260#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
261 MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function)
262
263#else
264// Older versions of C++ or C code get the regular macro that's unchecked.
265// Expands to a compound expression whose type is JNINativeMethod.
266#define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \
267 _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn)
268
269// Need C++14 or newer to use the AUTOSIG macros.
270#define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \
271 static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function);
272
273#endif // C++14 check
274
275// C-style cast for C, C++-style cast for C++ to avoid warnings/errors.
276#if defined(__cplusplus)
277#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
278 which_cast<to>
279#else
280#define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
281 (to)
282#endif
283