| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * Compile-time, zero-cost checking of JNI signatures against their C++ function type. |
| * This can trigger compile-time assertions if any of the input is invalid: |
| * (a) The signature specified does not conform to the JNI function descriptor syntax. |
| * (b) The C++ function is itself an invalid JNI function (e.g. missing JNIEnv*, etc). |
| * (c) The descriptor does not match the C++ function (e.g. "()V" will not match jint(jint)). |
| * |
| * The fundamental macros are as following: |
| * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD - Create a checked JNINativeMethod{name, sig, func}. |
| * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Same as above, but infer the JNI signature. |
| * |
| * Usage examples: |
| * // path/to/package/KlassName.java |
| * class KlassName { |
| * native jobject normal(int x); |
| * @FastNative native jobject fast(int x); |
| * @CriticalNative native int critical(long ptr); |
| * } |
| * // path_to_package_KlassName.cpp |
| * jobject KlassName_normal(JNIEnv*,jobject,jint) {...} |
| * jobject KlassName_fast(JNIEnv*,jobject,jint) {...} |
| * jint KlassName_critical(jlong) {...} |
| * |
| * // Manually specify each signature: |
| * JNINativeMethod[] gMethods = { |
| * MAKE_JNI_NATIVE_METHOD("normal", "(I)Ljava/lang/Object;", KlassName_normal), |
| * MAKE_JNI_FAST_NATIVE_METHOD("fast", "(I)Ljava/lang/Object;", KlassName_fast), |
| * MAKE_JNI_CRITICAL_NATIVE_METHOD("critical", "(J)I", KlassName_critical), |
| * }; |
| * |
| * // Automatically infer the signature: |
| * JNINativeMethod[] gMethodsAutomaticSignature = { |
| * MAKE_JNI_NATIVE_METHOD_AUTOSIG("normal", KlassName_normal), |
| * MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG("fast", KlassName_fast), |
| * MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG("critical", KlassName_critical), |
| * }; |
| * |
| * // and then call JNIEnv::RegisterNatives with gMethods as usual. |
| * |
| * For convenience the following macros are defined: |
| * [FAST_|CRITICAL_]NATIVE_METHOD - Return JNINativeMethod for class, func name, and signature. |
| * OVERLOADED_[FAST_|CRITICAL_]NATIVE_METHOD - Same as above but allows a separate func identifier. |
| * [FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Return JNINativeMethod, sig inferred from function. |
| * |
| * The FAST_ prefix corresponds to functions annotated with @FastNative, |
| * and the CRITICAL_ prefix corresponds to functions annotated with @CriticalNative. |
| * See dalvik.annotation.optimization.CriticalNative for more details. |
| * |
| * ======================================= |
| * Checking rules |
| * ======================================= |
| * |
| * --------------------------------------- |
| * JNI descriptor syntax for functions |
| * |
| * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification |
| * under the subsection "Type Signatures" table entry "method type". |
| * |
| * JNI signatures not conforming to the above syntax are rejected. |
| * --------------------------------------- |
| * C++ function types |
| * |
| * A normal or @FastNative JNI function type must be of the form |
| * |
| * ReturnType (JNIEnv*, jclass|jobject, [ArgTypes...]) {} |
| * |
| * A @CriticalNative JNI function type: |
| * |
| * must be of the form... ReturnType ([ArgTypes...]){} |
| * and must not contain any Reference Types. |
| * |
| * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification |
| * under the subsection "Primitive Types" and "Reference Types" for the list |
| * of valid argument/return types. |
| * |
| * C++ function types not conforming to the above requirements are rejected. |
| * --------------------------------------- |
| * Matching of C++ function type against JNI function descriptor. |
| * |
| * Assuming all of the above conditions are met for signature and C++ type validity, |
| * then matching between the signature and the type validity can occur: |
| * |
| * Given a signature (Args...)Ret and the |
| * C++ function type of the form "CRet fn(JNIEnv*, jclass|jobject, CArgs...)", |
| * or for @CriticalNative of the form "CRet fn(CArgs...)" |
| * |
| * The number of Args... and the number of CArgs... must be equal. |
| * |
| * If so, attempt to match every component from the signature and function type |
| * against each other: |
| * |
| * ReturnType: |
| * V <-> void |
| * ArgumentType |
| * |
| * ArgumentType: |
| * PrimitiveType |
| * ReferenceType [except for @CriticalNative] |
| * |
| * PrimitiveType: |
| * Z <-> jboolean |
| * B <-> jbyte |
| * C <-> jchar |
| * S <-> jshort |
| * I <-> jint |
| * J <-> jlong |
| * F <-> jfloat |
| * D <-> jdouble |
| * |
| * ReferenceType: |
| * Ljava/lang/String; <-> jstring |
| * Ljava/lang/Class; <-> jclass |
| * L*; <- jobject |
| * Ljava/lang/Throwable; -> jthrowable |
| * L*; <- jthrowable |
| * [ PrimitiveType <-> ${CPrimitiveType}Array |
| * [ ReferenceType <-> jobjectArray |
| * [* <- jarray |
| * |
| * Wherein <-> represents a strong match (if the left or right pattern occurs, |
| * then left must match right, otherwise matching fails). <- and -> represent |
| * weak matches (that is, other match rules can be still attempted). |
| * |
| * Sidenote: Whilst a jobject could also represent a jclass, jstring, etc, |
| * the stricter approach is taken: the most exact C++ type must be used. |
| */ |
| |
| #pragma once |
| |
| // The below basic macros do not perform automatic stringification, |
| // invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn) |
| |
| // An expression that evaluates to JNINativeMethod { name, signature, function }, |
| // and applies the above compile-time checking for signature+function. |
| // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. |
| #define MAKE_JNI_NATIVE_METHOD(name, signature, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function) |
| |
| // An expression that evaluates to JNINativeMethod { name, signature, function }, |
| // and applies the above compile-time checking for signature+function. |
| // The equivalent Java Language code must be annotated with @FastNative. |
| #define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function) |
| |
| // An expression that evaluates to JNINativeMethod { name, signature, function }, |
| // and applies the above compile-time checking for signature+function. |
| // The equivalent Java Language code must be annotated with @CriticalNative. |
| #define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function) |
| |
| // Automatically signature-inferencing macros are also available, |
| // which also checks the C++ function types for validity: |
| |
| // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } |
| // by inferring the signature at compile-time. Only works when the C++ function type |
| // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). |
| // |
| // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. |
| #define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function) |
| |
| // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } |
| // by inferring the signature at compile-time. Only works when the C++ function type |
| // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). |
| // |
| // The equivalent Java Language code must be annotated with @FastNative. |
| #define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function) |
| |
| // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } |
| // by inferring the signature at compile-time. |
| // |
| // The equivalent Java Language code must be annotated with @CriticalNative. |
| #define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function) |
| |
| // Convenience macros when the functions follow the naming convention: |
| // .java file .cpp file |
| // JavaLanguageName <-> ${ClassName}_${JavaLanguageName} |
| // |
| // Stringification is done automatically, invoked as: |
| // NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature) |
| // |
| // Intended to construct a JNINativeMethod. |
| // (Assumes the C name is the ClassName_JavaMethodName). |
| // |
| // The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative) |
| // for the (none,FAST_,CRITICAL_) variants of these macros. |
| |
| #define NATIVE_METHOD(className, functionName, signature) \ |
| MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) |
| |
| #define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \ |
| MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) |
| |
| #define NATIVE_METHOD_AUTOSIG(className, functionName) \ |
| MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) |
| |
| #define FAST_NATIVE_METHOD(className, functionName, signature) \ |
| MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) |
| |
| #define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \ |
| MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) |
| |
| #define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \ |
| MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) |
| |
| #define CRITICAL_NATIVE_METHOD(className, functionName, signature) \ |
| MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) |
| |
| #define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \ |
| MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) |
| |
| #define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \ |
| MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) |
| |
| //////////////////////////////////////////////////////// |
| // IMPLEMENTATION ONLY. |
| // DO NOT USE DIRECTLY. |
| //////////////////////////////////////////////////////// |
| |
| #if defined(__cplusplus) && __cplusplus >= 201402L |
| #include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD |
| #endif |
| |
| // Expands to an expression whose type is JNINativeMethod. |
| // This is for older versions of C++ or C, so it has no compile-time checking. |
| #define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \ |
| ( \ |
| (JNINativeMethod) { \ |
| (name), \ |
| (sig), \ |
| _NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \ |
| } \ |
| ) |
| |
| // C++14 or better, use compile-time checking. |
| #if defined(__cplusplus) && __cplusplus >= 201402L |
| // Expands to a compound expression whose type is JNINativeMethod. |
| #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ |
| MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn) |
| |
| // Expands to a compound expression whose type is JNINativeMethod. |
| #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ |
| MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function) |
| |
| #else |
| // Older versions of C++ or C code get the regular macro that's unchecked. |
| // Expands to a compound expression whose type is JNINativeMethod. |
| #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ |
| _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) |
| |
| // Need C++14 or newer to use the AUTOSIG macros. |
| #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ |
| static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function); |
| |
| #endif // C++14 check |
| |
| // C-style cast for C, C++-style cast for C++ to avoid warnings/errors. |
| #if defined(__cplusplus) |
| #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ |
| which_cast<to> |
| #else |
| #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ |
| (to) |
| #endif |
| |