Home | History | Annotate | Download | only in nativehelper
      1 /*
      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", "(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.
    142  */
    143 
    144 #ifndef NATIVEHELPER_JNI_MACROS_H
    145 #define NATIVEHELPER_JNI_MACROS_H
    146 
    147 // The below basic macros do not perform automatic stringification,
    148 // invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn)
    149 
    150 // 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 //
    201 // Intended to construct a JNINativeMethod.
    202 //   (Assumes the C name is the ClassName_JavaMethodName).
    203 //
    204 // 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
    209 #endif
    210 
    211 #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 
    238 ////////////////////////////////////////////////////////
    239 //                IMPLEMENTATION ONLY.
    240 //                DO NOT USE DIRECTLY.
    241 ////////////////////////////////////////////////////////
    242 
    243 #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
    279 
    280 // C-style cast for C, C++-style cast for C++ to avoid warnings/errors.
    281 #if defined(__cplusplus)
    282 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
    283     which_cast<to>
    284 #else
    285 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \
    286     (to)
    287 #endif
    288 
    289 #endif  // NATIVEHELPER_JNI_MACROS_H
    290