Home | History | Annotate | Download | only in detail
      1 /*
      2  * Copyright (C) 2018 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 /*
     19  * WARNING: Do not include and use these directly. Use jni_macros.h instead!
     20  * The "detail" namespace should be a strong hint not to depend on the internals,
     21  * which could change at any time.
     22  *
     23  * This implements the underlying mechanism for compile-time JNI signature/ctype checking
     24  * and inference.
     25  *
     26  * This file provides the constexpr basic blocks such as strings, arrays, vectors
     27  * as well as the JNI-specific parsing functionality.
     28  *
     29  * Everything is implemented via generic-style (templates without metaprogramming)
     30  * wherever possible. Traditional template metaprogramming is used sparingly.
     31  *
     32  * Everything in this file except ostream<< is constexpr.
     33  */
     34 
     35 #pragma once
     36 
     37 #include <iostream>     // std::ostream
     38 #include <jni.h>        // jni typedefs, JniNativeMethod.
     39 #include <type_traits>  // std::common_type, std::remove_cv
     40 
     41 namespace nativehelper {
     42 namespace detail {
     43 
     44 // If CHECK evaluates to false then X_ASSERT will halt compilation.
     45 //
     46 // Asserts meant to be used only within constexpr context.
     47 #if defined(JNI_SIGNATURE_CHECKER_DISABLE_ASSERTS)
     48 # define X_ASSERT(CHECK) do { if ((false)) { (CHECK) ? void(0) : void(0); } } while (false)
     49 #else
     50 # define X_ASSERT(CHECK) \
     51     ( (CHECK) ? void(0) : jni_assertion_failure(#CHECK) )
     52 #endif
     53 
     54 // The runtime 'jni_assert' will never get called from a constexpr context;
     55 // instead compilation will abort with a stack trace.
     56 //
     57 // Inspect the frame above this one to see the exact nature of the failure.
     58 inline void jni_assertion_failure(const char* /*msg*/) __attribute__((noreturn));
     59 inline void jni_assertion_failure(const char* /*msg*/) {
     60   std::terminate();
     61 }
     62 
     63 // An immutable constexpr string view, similar to std::string_view but for C++14.
     64 // For a mutable string see instead ConstexprVector<char>.
     65 //
     66 // As it is a read-only view into a string, it is not guaranteed to be zero-terminated.
     67 struct ConstexprStringView {
     68   // Implicit conversion from string literal:
     69   //     ConstexprStringView str = "hello_world";
     70   template<size_t N>
     71   constexpr ConstexprStringView(const char (& lit)[N])  // NOLINT: explicit.
     72       : _array(lit), _size(N - 1) {
     73     // Using an array of characters is not allowed because the inferred size would be wrong.
     74     // Use the other constructor instead for that.
     75     X_ASSERT(lit[N - 1] == '\0');
     76   }
     77 
     78   constexpr ConstexprStringView(const char* ptr, size_t size)
     79       : _array(ptr), _size(size) {
     80     // See the below constructor instead.
     81     X_ASSERT(ptr != nullptr);
     82   }
     83 
     84   // Implicit conversion from nullptr, creates empty view.
     85   //   ConstexprStringView str = nullptr;
     86   explicit constexpr ConstexprStringView(const decltype(nullptr)&)
     87       : _array(""), _size(0u) {
     88   }
     89 
     90   // No-arg constructor: Create empty view.
     91   constexpr ConstexprStringView() : _array(""), _size(0u) {}
     92 
     93   constexpr size_t size() const {
     94     return _size;
     95   }
     96 
     97   constexpr bool empty() const {
     98     return size() == 0u;
     99   }
    100 
    101   constexpr char operator[](size_t i) const {
    102     X_ASSERT(i <= size());
    103     return _array[i];
    104   }
    105 
    106   // Create substring from this[start..start+len).
    107   constexpr ConstexprStringView substr(size_t start, size_t len) const {
    108     X_ASSERT(start <= size());
    109     X_ASSERT(start + len <= size());
    110 
    111     return ConstexprStringView(&_array[start], len);
    112   }
    113 
    114   // Create maximum length substring that begins at 'start'.
    115   constexpr ConstexprStringView substr(size_t start) const {
    116     X_ASSERT(start <= size());
    117     return substr(start, size() - start);
    118   }
    119 
    120   using const_iterator = const char*;
    121 
    122   constexpr const_iterator begin() const {
    123     return &_array[0];
    124   }
    125 
    126   constexpr const_iterator end() const {
    127     return &_array[size()];
    128   }
    129 
    130  private:
    131   const char* _array;  // Never-null for simplicity.
    132   size_t _size;
    133 };
    134 
    135 constexpr bool
    136 operator==(const ConstexprStringView& lhs, const ConstexprStringView& rhs) {
    137   if (lhs.size() != rhs.size()) {
    138     return false;
    139   }
    140   for (size_t i = 0; i < lhs.size(); ++i) {
    141     if (lhs[i] != rhs[i]) {
    142       return false;
    143     }
    144   }
    145   return true;
    146 }
    147 
    148 constexpr bool
    149 operator!=(const ConstexprStringView& lhs, const ConstexprStringView& rhs) {
    150   return !(lhs == rhs);
    151 }
    152 
    153 inline std::ostream& operator<<(std::ostream& os, const ConstexprStringView& str) {
    154   for (char c : str) {
    155     os << c;
    156   }
    157   return os;
    158 }
    159 
    160 constexpr bool IsValidJniDescriptorShorty(char shorty) {
    161   constexpr char kValidJniTypes[] =
    162       {'V', 'Z', 'B', 'C', 'S', 'I', 'J', 'F', 'D', 'L', '[', '(', ')'};
    163 
    164   for (char c : kValidJniTypes) {
    165     if (c == shorty) {
    166       return true;
    167     }
    168   }
    169 
    170   return false;
    171 }
    172 
    173 // A constexpr "vector" that supports storing a variable amount of Ts
    174 // in an array-like interface.
    175 //
    176 // An up-front kMaxSize must be given since constexpr does not support
    177 // dynamic allocations.
    178 template<typename T, size_t kMaxSize>
    179 struct ConstexprVector {
    180  public:
    181   constexpr explicit ConstexprVector() : _size(0u), _array{} {
    182   }
    183 
    184  private:
    185   // Custom iterator to support ptr-one-past-end into the union array without
    186   // undefined behavior.
    187   template<typename Elem>
    188   struct VectorIterator {
    189     Elem* ptr;
    190 
    191     constexpr VectorIterator& operator++() {
    192       ++ptr;
    193       return *this;
    194     }
    195 
    196     constexpr VectorIterator operator++(int) const {
    197       VectorIterator tmp(*this);
    198       ++tmp;
    199       return tmp;
    200     }
    201 
    202     constexpr auto& operator*() {
    203       // Use 'auto' here since using 'T' is incorrect with const_iterator.
    204       return ptr->_value;
    205     }
    206 
    207     constexpr const T& operator*() const {
    208       return ptr->_value;
    209     }
    210 
    211     constexpr bool operator==(const VectorIterator& other) const {
    212       return ptr == other.ptr;
    213     }
    214 
    215     constexpr bool operator!=(const VectorIterator& other) const {
    216       return !(*this == other);
    217     }
    218   };
    219 
    220   // Do not require that T is default-constructible by using a union.
    221   struct MaybeElement {
    222     union {
    223       T _value;
    224     };
    225   };
    226 
    227  public:
    228   using iterator = VectorIterator<MaybeElement>;
    229   using const_iterator = VectorIterator<const MaybeElement>;
    230 
    231   constexpr iterator begin() {
    232     return {&_array[0]};
    233   }
    234 
    235   constexpr iterator end() {
    236     return {&_array[size()]};
    237   }
    238 
    239   constexpr const_iterator begin() const {
    240     return {&_array[0]};
    241   }
    242 
    243   constexpr const_iterator end() const {
    244     return {&_array[size()]};
    245   }
    246 
    247   constexpr void push_back(const T& value) {
    248     X_ASSERT(_size + 1 <= kMaxSize);
    249 
    250     _array[_size]._value = value;
    251     _size++;
    252   }
    253 
    254   // A pop operation could also be added since constexpr T's
    255   // have default destructors, it would just be _size--.
    256   // We do not need a pop() here though.
    257 
    258   constexpr const T& operator[](size_t i) const {
    259     return _array[i]._value;
    260   }
    261 
    262   constexpr T& operator[](size_t i) {
    263     return _array[i]._value;
    264   }
    265 
    266   constexpr size_t size() const {
    267     return _size;
    268   }
    269  private:
    270 
    271   size_t _size;
    272   MaybeElement _array[kMaxSize];
    273 };
    274 
    275 // Parsed and validated "long" form of a single JNI descriptor.
    276 // e.g. one of "J", "Ljava/lang/Object;" etc.
    277 struct JniDescriptorNode {
    278   ConstexprStringView longy;
    279 
    280   constexpr JniDescriptorNode(ConstexprStringView longy)
    281       : longy(longy) {  // NOLINT: explicit.
    282     X_ASSERT(!longy.empty());
    283   }
    284   constexpr JniDescriptorNode() : longy() {}
    285 
    286   constexpr char shorty() {
    287     // Must be initialized with the non-default constructor.
    288     X_ASSERT(!longy.empty());
    289     return longy[0];
    290   }
    291 };
    292 
    293 inline std::ostream& operator<<(std::ostream& os, const JniDescriptorNode& node) {
    294   os << node.longy;
    295   return os;
    296 }
    297 
    298 // Equivalent of C++17 std::optional.
    299 //
    300 // An optional is essentially a type safe
    301 //    union {
    302 //      void Nothing,
    303 //      T    Some;
    304 //    };
    305 //
    306 template<typename T>
    307 struct ConstexprOptional {
    308   // Create a default optional with no value.
    309   constexpr ConstexprOptional() : _has_value(false), _nothing() {
    310   }
    311 
    312   // Create an optional with a value.
    313   constexpr ConstexprOptional(const T& value)
    314       : _has_value(true), _value(value) {
    315   }
    316 
    317   constexpr explicit operator bool() const {
    318     return _has_value;
    319   }
    320 
    321   constexpr bool has_value() const {
    322     return _has_value;
    323   }
    324 
    325   constexpr const T& value() const {
    326     X_ASSERT(has_value());
    327     return _value;
    328   }
    329 
    330   constexpr const T* operator->() const {
    331     return &(value());
    332   }
    333 
    334  private:
    335   bool _has_value;
    336   // The "Nothing" is likely unnecessary but improves readability.
    337   struct Nothing {};
    338   union {
    339     Nothing _nothing;
    340     T _value;
    341   };
    342 };
    343 
    344 template<typename T>
    345 constexpr bool
    346 operator==(const ConstexprOptional<T>& lhs, const ConstexprOptional<T>& rhs) {
    347   if (lhs && rhs) {
    348     return lhs.value() == rhs.value();
    349   }
    350   return lhs.has_value() == rhs.has_value();
    351 }
    352 
    353 template<typename T>
    354 constexpr bool
    355 operator!=(const ConstexprOptional<T>& lhs, const ConstexprOptional<T>& rhs) {
    356   return !(lhs == rhs);
    357 }
    358 
    359 template<typename T>
    360 inline std::ostream& operator<<(std::ostream& os, const ConstexprOptional<T>& val) {
    361   if (val) {
    362     os << val.value();
    363   }
    364   return os;
    365 }
    366 
    367 // Equivalent of std::nullopt
    368 // Allows implicit conversion to any empty ConstexprOptional<T>.
    369 // Mostly useful for macros that need to return an empty constexpr optional.
    370 struct NullConstexprOptional {
    371   template<typename T>
    372   constexpr operator ConstexprOptional<T>() const {
    373     return ConstexprOptional<T>();
    374   }
    375 };
    376 
    377 inline std::ostream& operator<<(std::ostream& os, NullConstexprOptional) {
    378   return os;
    379 }
    380 
    381 #if !defined(PARSE_FAILURES_NONFATAL)
    382 // Unfortunately we cannot have custom messages here, as it just prints a stack trace with the macros expanded.
    383 // This is at least more flexible than static_assert which requires a string literal.
    384 // NOTE: The message string literal must be on same line as the macro to be seen during a compilation error.
    385 #define PARSE_FAILURE(msg) X_ASSERT(! #msg)
    386 #define PARSE_ASSERT_MSG(cond, msg) X_ASSERT(#msg && (cond))
    387 #define PARSE_ASSERT(cond) X_ASSERT(cond)
    388 #else
    389 #define PARSE_FAILURE(msg) return NullConstexprOptional{};
    390 #define PARSE_ASSERT_MSG(cond, msg) if (!(cond)) { PARSE_FAILURE(msg); }
    391 #define PARSE_ASSERT(cond) if (!(cond)) { PARSE_FAILURE(""); }
    392 #endif
    393 
    394 // This is a placeholder function and should not be called directly.
    395 constexpr void ParseFailure(const char* msg) {
    396   (void) msg;  // intentionally no-op.
    397 }
    398 
    399 // Temporary parse data when parsing a function descriptor.
    400 struct ParseTypeDescriptorResult {
    401   // A single argument descriptor, e.g. "V" or "Ljava/lang/Object;"
    402   ConstexprStringView token;
    403   // The remainder of the function descriptor yet to be parsed.
    404   ConstexprStringView remainder;
    405 
    406   constexpr bool has_token() const {
    407     return token.size() > 0u;
    408   }
    409 
    410   constexpr bool has_remainder() const {
    411     return remainder.size() > 0u;
    412   }
    413 
    414   constexpr JniDescriptorNode as_node() const {
    415     X_ASSERT(has_token());
    416     return {token};
    417   }
    418 };
    419 
    420 // Parse a single type descriptor out of a function type descriptor substring,
    421 // and return the token and the remainder string.
    422 //
    423 // If parsing fails (i.e. illegal syntax), then:
    424 //    parses are fatal -> assertion is triggered (default behavior),
    425 //    parses are nonfatal -> returns nullopt (test behavior).
    426 constexpr ConstexprOptional<ParseTypeDescriptorResult>
    427 ParseSingleTypeDescriptor(ConstexprStringView single_type,
    428                           bool allow_void = false) {
    429   constexpr NullConstexprOptional kUnreachable = {};
    430 
    431   // Nothing else left.
    432   if (single_type.size() == 0) {
    433     return ParseTypeDescriptorResult{};
    434   }
    435 
    436   ConstexprStringView token;
    437   ConstexprStringView remainder = single_type.substr(/*start*/1u);
    438 
    439   char c = single_type[0];
    440   PARSE_ASSERT(IsValidJniDescriptorShorty(c));
    441 
    442   enum State {
    443     kSingleCharacter,
    444     kArray,
    445     kObject
    446   };
    447 
    448   State state = kSingleCharacter;
    449 
    450   // Parse the first character to figure out if we should parse the rest.
    451   switch (c) {
    452     case '!': {
    453       constexpr bool fast_jni_is_deprecated = false;
    454       PARSE_ASSERT(fast_jni_is_deprecated);
    455       break;
    456     }
    457     case 'V':
    458       if (!allow_void) {
    459         constexpr bool void_type_descriptor_only_allowed_in_return_type = false;
    460         PARSE_ASSERT(void_type_descriptor_only_allowed_in_return_type);
    461       }
    462       [[clang::fallthrough]];
    463     case 'Z':
    464     case 'B':
    465     case 'C':
    466     case 'S':
    467     case 'I':
    468     case 'J':
    469     case 'F':
    470     case 'D':
    471       token = single_type.substr(/*start*/0u, /*len*/1u);
    472       break;
    473     case 'L':
    474       state = kObject;
    475       break;
    476     case '[':
    477       state = kArray;
    478       break;
    479     default: {
    480       // See JNI Chapter 3: Type Signatures.
    481       PARSE_FAILURE("Expected a valid type descriptor character.");
    482       return kUnreachable;
    483     }
    484   }
    485 
    486   // Possibly parse an arbitary-long remainder substring.
    487   switch (state) {
    488     case kSingleCharacter:
    489       return {{token, remainder}};
    490     case kArray: {
    491       // Recursively parse the array component, as it's just any non-void type descriptor.
    492       ConstexprOptional<ParseTypeDescriptorResult>
    493           maybe_res = ParseSingleTypeDescriptor(remainder, /*allow_void*/false);
    494       PARSE_ASSERT(maybe_res);  // Downstream parsing has asserted, bail out.
    495 
    496       ParseTypeDescriptorResult res = maybe_res.value();
    497 
    498       // Reject illegal array type descriptors such as "]".
    499       PARSE_ASSERT_MSG(res.has_token(),
    500                        "All array types must follow by their component type (e.g. ']I', ']]Z', etc. ");
    501 
    502       token = single_type.substr(/*start*/0u, res.token.size() + 1u);
    503 
    504       return {{token, res.remainder}};
    505     }
    506     case kObject: {
    507       // Parse the fully qualified class, e.g. Lfoo/bar/baz;
    508       // Note checking that each part of the class name is a valid class identifier
    509       // is too complicated (JLS 3.8).
    510       // This simple check simply scans until the next ';'.
    511       bool found_semicolon = false;
    512       size_t semicolon_len = 0;
    513       for (size_t i = 0; i < single_type.size(); ++i) {
    514         if (single_type[i] == ';') {
    515           semicolon_len = i + 1;
    516           found_semicolon = true;
    517           break;
    518         }
    519       }
    520 
    521       PARSE_ASSERT(found_semicolon);
    522 
    523       token = single_type.substr(/*start*/0u, semicolon_len);
    524       remainder = single_type.substr(/*start*/semicolon_len);
    525 
    526       bool class_name_is_empty = token.size() <= 2u;  // e.g. "L;"
    527       PARSE_ASSERT(!class_name_is_empty);
    528 
    529       return {{token, remainder}};
    530     }
    531     default:
    532       X_ASSERT(false);
    533   }
    534 
    535   X_ASSERT(false);
    536   return kUnreachable;
    537 }
    538 
    539 // Abstract data type to represent container for Ret(Args,...).
    540 template<typename T, size_t kMaxSize>
    541 struct FunctionSignatureDescriptor {
    542   ConstexprVector<T, kMaxSize> args;
    543   T ret;
    544 
    545   static constexpr size_t max_size = kMaxSize;
    546 };
    547 
    548 
    549 template<typename T, size_t kMaxSize>
    550 inline std::ostream& operator<<(std::ostream& os,
    551                                 const FunctionSignatureDescriptor<T,
    552                                                                   kMaxSize>& signature) {
    553   size_t count = 0;
    554   os << "args={";
    555   for (auto& arg : signature.args) {
    556     os << arg;
    557 
    558     if (count != signature.args.size() - 1) {
    559       os << ",";
    560     }
    561 
    562     ++count;
    563   }
    564   os << "}, ret=";
    565   os << signature.ret;
    566   return os;
    567 }
    568 
    569 // Ret(Args...) of JniDescriptorNode.
    570 template<size_t kMaxSize>
    571 using JniSignatureDescriptor = FunctionSignatureDescriptor<JniDescriptorNode,
    572                                                            kMaxSize>;
    573 
    574 // Parse a JNI function signature descriptor into a JniSignatureDescriptor.
    575 //
    576 // If parsing fails (i.e. illegal syntax), then:
    577 //    parses are fatal -> assertion is triggered (default behavior),
    578 //    parses are nonfatal -> returns nullopt (test behavior).
    579 template<size_t kMaxSize>
    580 constexpr ConstexprOptional<JniSignatureDescriptor<kMaxSize>>
    581 ParseSignatureAsList(ConstexprStringView signature) {
    582   // The list of JNI descritors cannot possibly exceed the number of characters
    583   // in the JNI string literal. We leverage this to give an upper bound of the strlen.
    584   // This is a bit wasteful but in constexpr there *must* be a fixed upper size for data structures.
    585   ConstexprVector<JniDescriptorNode, kMaxSize> jni_desc_node_list;
    586   JniDescriptorNode return_jni_desc;
    587 
    588   enum State {
    589     kInitial = 0,
    590     kParsingParameters = 1,
    591     kParsingReturnType = 2,
    592     kCompleted = 3,
    593   };
    594 
    595   State state = kInitial;
    596 
    597   while (!signature.empty()) {
    598     switch (state) {
    599       case kInitial: {
    600         char c = signature[0];
    601         PARSE_ASSERT_MSG(c == '(',
    602                          "First character of a JNI signature must be a '('");
    603         state = kParsingParameters;
    604         signature = signature.substr(/*start*/1u);
    605         break;
    606       }
    607       case kParsingParameters: {
    608         char c = signature[0];
    609         if (c == ')') {
    610           state = kParsingReturnType;
    611           signature = signature.substr(/*start*/1u);
    612           break;
    613         }
    614 
    615         ConstexprOptional<ParseTypeDescriptorResult>
    616             res = ParseSingleTypeDescriptor(signature, /*allow_void*/false);
    617         PARSE_ASSERT(res);
    618 
    619         jni_desc_node_list.push_back(res->as_node());
    620 
    621         signature = res->remainder;
    622         break;
    623       }
    624       case kParsingReturnType: {
    625         ConstexprOptional<ParseTypeDescriptorResult>
    626             res = ParseSingleTypeDescriptor(signature, /*allow_void*/true);
    627         PARSE_ASSERT(res);
    628 
    629         return_jni_desc = res->as_node();
    630         signature = res->remainder;
    631         state = kCompleted;
    632         break;
    633       }
    634       default: {
    635         // e.g. "()VI" is illegal because the V terminates the signature.
    636         PARSE_FAILURE("Signature had left over tokens after parsing return type");
    637         break;
    638       }
    639     }
    640   }
    641 
    642   switch (state) {
    643     case kCompleted:
    644       // Everything is ok.
    645       break;
    646     case kParsingParameters:
    647       PARSE_FAILURE("Signature was missing ')'");
    648       break;
    649     case kParsingReturnType:
    650       PARSE_FAILURE("Missing return type");
    651     case kInitial:
    652       PARSE_FAILURE("Cannot have an empty signature");
    653     default:
    654       X_ASSERT(false);
    655   }
    656 
    657   return {{jni_desc_node_list, return_jni_desc}};
    658 }
    659 
    660 // What kind of JNI does this type belong to?
    661 enum NativeKind {
    662   kNotJni,        // Illegal parameter used inside of a function type.
    663   kNormalJniCallingConventionParameter,
    664   kNormalNative,
    665   kFastNative,      // Also valid in normal.
    666   kCriticalNative,  // Also valid in fast/normal.
    667 };
    668 
    669 // Is this type final, i.e. it cannot be subtyped?
    670 enum TypeFinal {
    671   kNotFinal,
    672   kFinal         // e.g. any primitive or any "final" class such as String.
    673 };
    674 
    675 // What position is the JNI type allowed to be in?
    676 // Ignored when in a CriticalNative context.
    677 enum NativePositionAllowed {
    678   kNotAnyPosition,
    679   kReturnPosition,
    680   kZerothPosition,
    681   kFirstOrLaterPosition,
    682   kSecondOrLaterPosition,
    683 };
    684 
    685 constexpr NativePositionAllowed ConvertPositionToAllowed(size_t position) {
    686   switch (position) {
    687     case 0:
    688       return kZerothPosition;
    689     case 1:
    690       return kFirstOrLaterPosition;
    691     default:
    692       return kSecondOrLaterPosition;
    693   }
    694 }
    695 
    696 // Type traits for a JNI parameter type. See below for specializations.
    697 template<typename T>
    698 struct jni_type_trait {
    699   static constexpr NativeKind native_kind = kNotJni;
    700   static constexpr const char type_descriptor[] = "(illegal)";
    701   static constexpr NativePositionAllowed position_allowed = kNotAnyPosition;
    702   static constexpr TypeFinal type_finality = kNotFinal;
    703   static constexpr const char type_name[] = "(illegal)";
    704 };
    705 
    706 // Access the jni_type_trait<T> from a non-templated constexpr function.
    707 // Identical non-static fields to jni_type_trait, see Reify().
    708 struct ReifiedJniTypeTrait {
    709   NativeKind native_kind;
    710   ConstexprStringView type_descriptor;
    711   NativePositionAllowed position_allowed;
    712   TypeFinal type_finality;
    713   ConstexprStringView type_name;
    714 
    715   template<typename T>
    716   static constexpr ReifiedJniTypeTrait Reify() {
    717     // This should perhaps be called 'Type Erasure' except we don't use virtuals,
    718     // so it's not quite the same idiom.
    719     using TR = jni_type_trait<T>;
    720     return {TR::native_kind,
    721             TR::type_descriptor,
    722             TR::position_allowed,
    723             TR::type_finality,
    724             TR::type_name};
    725   }
    726 
    727   // Find the most similar ReifiedJniTypeTrait corresponding to the type descriptor.
    728   //
    729   // Any type can be found by using the exact canonical type descriptor as listed
    730   // in the jni type traits definitions.
    731   //
    732   // Non-final JNI types have limited support for inexact similarity:
    733   //   [[* | [L* -> jobjectArray
    734   //   L* -> jobject
    735   //
    736   // Otherwise return a nullopt.
    737   static constexpr ConstexprOptional<ReifiedJniTypeTrait>
    738   MostSimilarTypeDescriptor(ConstexprStringView type_descriptor);
    739 };
    740 
    741 constexpr bool
    742 operator==(const ReifiedJniTypeTrait& lhs, const ReifiedJniTypeTrait& rhs) {
    743   return lhs.native_kind == rhs.native_kind
    744       && rhs.type_descriptor == lhs.type_descriptor &&
    745       lhs.position_allowed == rhs.position_allowed
    746       && rhs.type_finality == lhs.type_finality &&
    747       lhs.type_name == rhs.type_name;
    748 }
    749 
    750 inline std::ostream& operator<<(std::ostream& os, const ReifiedJniTypeTrait& rjft) {
    751   // os << "ReifiedJniTypeTrait<" << rjft.type_name << ">";
    752   os << rjft.type_name;
    753   return os;
    754 }
    755 
    756 // Template specialization for any JNI typedefs.
    757 #define JNI_TYPE_TRAIT(jtype, the_type_descriptor, the_native_kind, the_type_finality, the_position) \
    758 template <>                                                                    \
    759 struct jni_type_trait< jtype > {                                               \
    760   static constexpr NativeKind native_kind = the_native_kind;                   \
    761   static constexpr const char type_descriptor[] = the_type_descriptor;         \
    762   static constexpr NativePositionAllowed position_allowed = the_position;      \
    763   static constexpr TypeFinal type_finality = the_type_finality;                \
    764   static constexpr const char type_name[] = #jtype;                            \
    765 };
    766 
    767 #define DEFINE_JNI_TYPE_TRAIT(TYPE_TRAIT_FN)                                                                  \
    768 TYPE_TRAIT_FN(jboolean,          "Z",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    769 TYPE_TRAIT_FN(jbyte,             "B",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    770 TYPE_TRAIT_FN(jchar,             "C",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    771 TYPE_TRAIT_FN(jshort,            "S",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    772 TYPE_TRAIT_FN(jint,              "I",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    773 TYPE_TRAIT_FN(jlong,             "J",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    774 TYPE_TRAIT_FN(jfloat,            "F",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    775 TYPE_TRAIT_FN(jdouble,           "D",                      kCriticalNative,   kFinal, kSecondOrLaterPosition) \
    776 TYPE_TRAIT_FN(jobject,           "Ljava/lang/Object;",     kFastNative,    kNotFinal, kFirstOrLaterPosition)  \
    777 TYPE_TRAIT_FN(jclass,            "Ljava/lang/Class;",      kFastNative,       kFinal, kFirstOrLaterPosition)  \
    778 TYPE_TRAIT_FN(jstring,           "Ljava/lang/String;",     kFastNative,       kFinal, kSecondOrLaterPosition) \
    779 TYPE_TRAIT_FN(jarray,            "Ljava/lang/Object;",     kFastNative,    kNotFinal, kSecondOrLaterPosition) \
    780 TYPE_TRAIT_FN(jobjectArray,      "[Ljava/lang/Object;",    kFastNative,    kNotFinal, kSecondOrLaterPosition) \
    781 TYPE_TRAIT_FN(jbooleanArray,     "[Z",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    782 TYPE_TRAIT_FN(jbyteArray,        "[B",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    783 TYPE_TRAIT_FN(jcharArray,        "[C",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    784 TYPE_TRAIT_FN(jshortArray,       "[S",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    785 TYPE_TRAIT_FN(jintArray,         "[I",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    786 TYPE_TRAIT_FN(jlongArray,        "[J",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    787 TYPE_TRAIT_FN(jfloatArray,       "[F",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    788 TYPE_TRAIT_FN(jdoubleArray,      "[D",                     kFastNative,       kFinal, kSecondOrLaterPosition) \
    789 TYPE_TRAIT_FN(jthrowable,        "Ljava/lang/Throwable;",  kFastNative,    kNotFinal, kSecondOrLaterPosition) \
    790 TYPE_TRAIT_FN(JNIEnv*,           "",                       kNormalJniCallingConventionParameter, kFinal, kZerothPosition) \
    791 TYPE_TRAIT_FN(void,              "V",                      kCriticalNative,   kFinal, kReturnPosition)        \
    792 
    793 DEFINE_JNI_TYPE_TRAIT(JNI_TYPE_TRAIT)
    794 
    795 // See ReifiedJniTypeTrait for documentation.
    796 constexpr ConstexprOptional<ReifiedJniTypeTrait>
    797 ReifiedJniTypeTrait::MostSimilarTypeDescriptor(ConstexprStringView type_descriptor) {
    798 #define MATCH_EXACT_TYPE_DESCRIPTOR_FN(type, type_desc, native_kind, ...) \
    799     if (type_descriptor == type_desc && native_kind >= kNormalNative) {                        \
    800       return { Reify<type>() };                                \
    801     }
    802 
    803   // Attempt to look up by the precise type match first.
    804   DEFINE_JNI_TYPE_TRAIT(MATCH_EXACT_TYPE_DESCRIPTOR_FN);
    805 
    806   // Otherwise, we need to do an imprecise match:
    807   char shorty = type_descriptor.size() >= 1 ? type_descriptor[0] : '\0';
    808   if (shorty == 'L') {
    809     // Something more specific like Ljava/lang/Throwable, string, etc
    810     // is already matched by the macro-expanded conditions above.
    811     return {Reify<jobject>()};
    812   } else if (type_descriptor.size() >= 2) {
    813     auto shorty_shorty = type_descriptor.substr(/*start*/0, /*size*/2u);
    814     if (shorty_shorty == "[[" || shorty_shorty == "[L") {
    815       // JNI arrays are covariant, so any type T[] (T!=primitive) is castable to Object[].
    816       return {Reify<jobjectArray>()};
    817     }
    818   }
    819 
    820   // To handle completely invalid values.
    821   return NullConstexprOptional{};
    822 }
    823 
    824 // Check if a jni parameter type is valid given its position and native_kind.
    825 template <typename T>
    826 constexpr bool IsValidJniParameter(NativeKind native_kind, NativePositionAllowed position) {
    827   // const,volatile does not affect JNI compatibility since it does not change ABI.
    828   using expected_trait = jni_type_trait<typename std::remove_cv<T>::type>;
    829   NativeKind expected_native_kind = expected_trait::native_kind;
    830 
    831   // Most types 'T' are not valid for JNI.
    832   if (expected_native_kind == NativeKind::kNotJni) {
    833     return false;
    834   }
    835 
    836   // The rest of the types might be valid, but it depends on the context (native_kind)
    837   // and also on their position within the parameters.
    838 
    839   // Position-check first. CriticalNatives ignore positions since the first 2 special parameters are stripped.
    840   while (native_kind != kCriticalNative) {
    841     NativePositionAllowed expected_position = expected_trait::position_allowed;
    842     X_ASSERT(expected_position != kNotAnyPosition);
    843 
    844     // Is this a return-only position?
    845     if (expected_position == kReturnPosition) {
    846       if (position != kReturnPosition) {
    847         // void can only be in the return position.
    848         return false;
    849       }
    850       // Don't do the other non-return position checks for a return-only position.
    851       break;
    852     }
    853 
    854     // JNIEnv* can only be in the first spot.
    855     if (position == kZerothPosition && expected_position != kZerothPosition) {
    856       return false;
    857       // jobject, jclass can be 1st or anywhere afterwards.
    858     } else if (position == kFirstOrLaterPosition
    859         && expected_position != kFirstOrLaterPosition) {
    860       return false;
    861       // All other parameters must be in 2nd+ spot, or in the return type.
    862     } else if (position == kSecondOrLaterPosition
    863         || position == kReturnPosition) {
    864       if (expected_position != kFirstOrLaterPosition
    865           && expected_position != kSecondOrLaterPosition) {
    866         return false;
    867       }
    868     }
    869 
    870     break;
    871   }
    872 
    873   // Ensure the type appropriate is for the native kind.
    874   if (expected_native_kind == kNormalJniCallingConventionParameter) {
    875     // It's always wrong to use a JNIEnv* anywhere but the 0th spot.
    876     if (native_kind == kCriticalNative) {
    877       // CriticalNative does not allow using a JNIEnv*.
    878       return false;
    879     }
    880 
    881     return true;  // OK: JniEnv* used in 0th position.
    882   } else if (expected_native_kind == kCriticalNative) {
    883     // CriticalNative arguments are always valid JNI types anywhere used.
    884     return true;
    885   } else if (native_kind == kCriticalNative) {
    886     // The expected_native_kind was non-critical but we are in a critical context.
    887     // Illegal type.
    888     return false;
    889   }
    890 
    891   // Everything else is fine, e.g. fast/normal native + fast/normal native parameters.
    892   return true;
    893 }
    894 
    895 // Is there sufficient number of parameters given the kind of JNI that it is?
    896 constexpr bool IsJniParameterCountValid(NativeKind native_kind, size_t count) {
    897   if (native_kind == kNormalNative || native_kind == kFastNative) {
    898     return count >= 2u;
    899   } else if (native_kind == kCriticalNative) {
    900     return true;
    901   }
    902 
    903   constexpr bool invalid_parameter = false;
    904   X_ASSERT(invalid_parameter);
    905   return false;
    906 }
    907 
    908 // Basic template interface. See below for partial specializations.
    909 //
    910 // Each instantiation will have a 'value' field that determines whether or not
    911 // all of the Args are valid JNI arguments given their native_kind.
    912 template<NativeKind native_kind, size_t position, typename ... Args>
    913 struct is_valid_jni_argument_type {
    914   // static constexpr bool value = ?;
    915 };
    916 
    917 template<NativeKind native_kind, size_t position>
    918 struct is_valid_jni_argument_type<native_kind, position> {
    919   static constexpr bool value = true;
    920 };
    921 
    922 template<NativeKind native_kind, size_t position, typename T>
    923 struct is_valid_jni_argument_type<native_kind, position, T> {
    924   static constexpr bool value =
    925       IsValidJniParameter<T>(native_kind, ConvertPositionToAllowed(position));
    926 };
    927 
    928 template<NativeKind native_kind, size_t position, typename T, typename ... Args>
    929 struct is_valid_jni_argument_type<native_kind, position, T, Args...> {
    930   static constexpr bool value =
    931       IsValidJniParameter<T>(native_kind, ConvertPositionToAllowed(position))
    932           && is_valid_jni_argument_type<native_kind,
    933                                         position + 1,
    934                                         Args...>::value;
    935 };
    936 
    937 // This helper is required to decompose the function type into a list of arg types.
    938 template<NativeKind native_kind, typename T, T fn>
    939 struct is_valid_jni_function_type_helper;
    940 
    941 template<NativeKind native_kind, typename R, typename ... Args, R fn(Args...)>
    942 struct is_valid_jni_function_type_helper<native_kind, R(Args...), fn> {
    943   static constexpr bool value =
    944       IsJniParameterCountValid(native_kind, sizeof...(Args))
    945           && IsValidJniParameter<R>(native_kind, kReturnPosition)
    946           && is_valid_jni_argument_type<native_kind, /*position*/
    947                                         0,
    948                                         Args...>::value;
    949 };
    950 
    951 // Is this function type 'T' a valid C++ function type given the native_kind?
    952 template<NativeKind native_kind, typename T, T fn>
    953 constexpr bool IsValidJniFunctionType() {
    954   return is_valid_jni_function_type_helper<native_kind, T, fn>::value;
    955   // TODO: we could replace template metaprogramming with constexpr by
    956   // using FunctionTypeMetafunction.
    957 }
    958 
    959 // Many parts of std::array is not constexpr until C++17.
    960 template<typename T, size_t N>
    961 struct ConstexprArray {
    962   // Intentionally public to conform to std::array.
    963   // This means all constructors are implicit.
    964   // *NOT* meant to be used directly, use the below functions instead.
    965   //
    966   // The reason std::array has it is to support direct-list-initialization,
    967   // e.g. "ConstexprArray<T, sz>{T{...}, T{...}, T{...}, ...};"
    968   //
    969   // Note that otherwise this would need a very complicated variadic
    970   // argument constructor to only support list of Ts.
    971   T _array[N];
    972 
    973   constexpr size_t size() const {
    974     return N;
    975   }
    976 
    977   using iterator = T*;
    978   using const_iterator = const T*;
    979 
    980   constexpr iterator begin() {
    981     return &_array[0];
    982   }
    983 
    984   constexpr iterator end() {
    985     return &_array[N];
    986   }
    987 
    988   constexpr const_iterator begin() const {
    989     return &_array[0];
    990   }
    991 
    992   constexpr const_iterator end() const {
    993     return &_array[N];
    994   }
    995 
    996   constexpr T& operator[](size_t i) {
    997     return _array[i];
    998   }
    999 
   1000   constexpr const T& operator[](size_t i) const {
   1001     return _array[i];
   1002   }
   1003 };
   1004 
   1005 // Why do we need this?
   1006 // auto x = {1,2,3} creates an initializer_list,
   1007 //   but they can't be returned because it contains pointers to temporaries.
   1008 // auto x[] = {1,2,3} doesn't even work because auto for arrays is not supported.
   1009 //
   1010 // an alternative would be to pull up std::common_t directly into the call site
   1011 //   std::common_type_t<Args...> array[] = {1,2,3}
   1012 // but that's even more cludgier.
   1013 //
   1014 // As the other "stdlib-wannabe" functions, it's weaker than the library
   1015 // fundamentals std::make_array but good enough for our use.
   1016 template<typename... Args>
   1017 constexpr auto MakeArray(Args&& ... args) {
   1018   return ConstexprArray<typename std::common_type<Args...>::type,
   1019                         sizeof...(Args)>{args...};
   1020 }
   1021 
   1022 // See below.
   1023 template<typename T, T fn>
   1024 struct FunctionTypeMetafunction {
   1025 };
   1026 
   1027 // Enables the "map" operation over the function component types.
   1028 template<typename R, typename ... Args, R fn(Args...)>
   1029 struct FunctionTypeMetafunction<R(Args...), fn> {
   1030   // Count how many arguments there are, and add 1 for the return type.
   1031   static constexpr size_t
   1032       count = sizeof...(Args) + 1u;  // args and return type.
   1033 
   1034   // Return an array where the metafunction 'Func' has been applied
   1035   // to every argument type. The metafunction must be returning a common type.
   1036   template<template<typename Arg> class Func>
   1037   static constexpr auto map_args() {
   1038     return map_args_impl<Func>(holder < Args > {}...);
   1039   }
   1040 
   1041   // Apply the metafunction 'Func' over the return type.
   1042   template<template<typename Ret> class Func>
   1043   static constexpr auto map_return() {
   1044     return Func<R>{}();
   1045   }
   1046 
   1047  private:
   1048   template<typename T>
   1049   struct holder {
   1050   };
   1051 
   1052   template<template<typename Arg> class Func, typename Arg0, typename... ArgsRest>
   1053   static constexpr auto map_args_impl(holder<Arg0>, holder<ArgsRest>...) {
   1054     // One does not simply call MakeArray with 0 template arguments...
   1055     auto array = MakeArray(
   1056         Func<Args>{}()...
   1057     );
   1058 
   1059     return array;
   1060   }
   1061 
   1062   template<template<typename Arg> class Func>
   1063   static constexpr auto map_args_impl() {
   1064     // This overload provides support for MakeArray() with 0 arguments.
   1065     using ComponentType = decltype(Func<void>{}());
   1066 
   1067     return ConstexprArray<ComponentType, /*size*/0u>{};
   1068   }
   1069 };
   1070 
   1071 // Apply ReifiedJniTypeTrait::Reify<T> for every function component type.
   1072 template<typename T>
   1073 struct ReifyJniTypeMetafunction {
   1074   constexpr ReifiedJniTypeTrait operator()() const {
   1075     auto res = ReifiedJniTypeTrait::Reify<T>();
   1076     X_ASSERT(res.native_kind != kNotJni);
   1077     return res;
   1078   }
   1079 };
   1080 
   1081 // Ret(Args...) where every component is a ReifiedJniTypeTrait.
   1082 template<size_t kMaxSize>
   1083 using ReifiedJniSignature = FunctionSignatureDescriptor<ReifiedJniTypeTrait,
   1084                                                         kMaxSize>;
   1085 
   1086 // Attempts to convert the function type T into a list of ReifiedJniTypeTraits
   1087 // that correspond to the function components.
   1088 //
   1089 // If conversion fails (i.e. non-jni compatible types), then:
   1090 //    parses are fatal -> assertion is triggered (default behavior),
   1091 //    parses are nonfatal -> returns nullopt (test behavior).
   1092 template <NativeKind native_kind,
   1093           typename T,
   1094           T fn,
   1095           size_t kMaxSize = FunctionTypeMetafunction<T, fn>::count>
   1096 constexpr ConstexprOptional<ReifiedJniSignature<kMaxSize>>
   1097 MaybeMakeReifiedJniSignature() {
   1098   if (!IsValidJniFunctionType<native_kind, T, fn>()) {
   1099     PARSE_FAILURE("The function signature has one or more types incompatible with JNI.");
   1100   }
   1101 
   1102   ReifiedJniTypeTrait return_jni_trait =
   1103       FunctionTypeMetafunction<T,
   1104                          fn>::template map_return<ReifyJniTypeMetafunction>();
   1105 
   1106   constexpr size_t
   1107       kSkipArgumentPrefix = (native_kind != kCriticalNative) ? 2u : 0u;
   1108   ConstexprVector<ReifiedJniTypeTrait, kMaxSize> args;
   1109   auto args_list =
   1110       FunctionTypeMetafunction<T, fn>::template map_args<ReifyJniTypeMetafunction>();
   1111   size_t args_index = 0;
   1112   for (auto& arg : args_list) {
   1113     // Ignore the 'JNIEnv*, jobject' / 'JNIEnv*, jclass' prefix,
   1114     // as its not part of the function descriptor string.
   1115     if (args_index >= kSkipArgumentPrefix) {
   1116       args.push_back(arg);
   1117     }
   1118 
   1119     ++args_index;
   1120   }
   1121 
   1122   return {{args, return_jni_trait}};
   1123 }
   1124 
   1125 #define COMPARE_DESCRIPTOR_CHECK(expr) if (!(expr)) return false
   1126 #define COMPARE_DESCRIPTOR_FAILURE_MSG(msg) if ((true)) return false
   1127 
   1128 // Compares a user-defined JNI descriptor (of a single argument or return value)
   1129 // to a reified jni type trait that was derived from the C++ function type.
   1130 //
   1131 // If comparison fails (i.e. non-jni compatible types), then:
   1132 //    parses are fatal -> assertion is triggered (default behavior),
   1133 //    parses are nonfatal -> returns false (test behavior).
   1134 constexpr bool
   1135 CompareJniDescriptorNodeErased(JniDescriptorNode user_defined_descriptor,
   1136                                ReifiedJniTypeTrait derived) {
   1137 
   1138   ConstexprOptional<ReifiedJniTypeTrait> user_reified_opt =
   1139       ReifiedJniTypeTrait::MostSimilarTypeDescriptor(user_defined_descriptor.longy);
   1140 
   1141   if (!user_reified_opt.has_value()) {
   1142     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1143         "Could not find any JNI C++ type corresponding to the type descriptor");
   1144   }
   1145 
   1146   char user_shorty = user_defined_descriptor.longy.size() > 0 ?
   1147                      user_defined_descriptor.longy[0] :
   1148                      '\0';
   1149 
   1150   ReifiedJniTypeTrait user = user_reified_opt.value();
   1151   if (user == derived) {
   1152     // If we had a similar match, immediately return success.
   1153     return true;
   1154   } else if (derived.type_name == "jthrowable") {
   1155     if (user_shorty == 'L') {
   1156       // Weakly allow any objects to correspond to a jthrowable.
   1157       // We do not know the managed type system so we have to be permissive here.
   1158       return true;
   1159     } else {
   1160       COMPARE_DESCRIPTOR_FAILURE_MSG(
   1161           "jthrowable must correspond to an object type descriptor");
   1162     }
   1163   } else if (derived.type_name == "jarray") {
   1164     if (user_shorty == '[') {
   1165       // a jarray is the base type for all other array types. Allow.
   1166       return true;
   1167     } else {
   1168       // Ljava/lang/Object; is the root for all array types.
   1169       // Already handled above in 'if user == derived'.
   1170       COMPARE_DESCRIPTOR_FAILURE_MSG(
   1171           "jarray must correspond to array type descriptor");
   1172     }
   1173   }
   1174   // Otherwise, the comparison has failed and the rest of this is only to
   1175   // pick the most appropriate error message.
   1176   //
   1177   // Note: A weaker form of comparison would allow matching 'Ljava/lang/String;'
   1178   // against 'jobject', etc. However the policy choice here is to enforce the strictest
   1179   // comparison that we can to utilize the type system to its fullest.
   1180 
   1181   if (derived.type_finality == kFinal || user.type_finality == kFinal) {
   1182     // Final types, e.g. "I", "Ljava/lang/String;" etc must match exactly
   1183     // the C++ jni descriptor string ('I' -> jint, 'Ljava/lang/String;' -> jstring).
   1184     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1185         "The JNI descriptor string must be the exact type equivalent of the "
   1186             "C++ function signature.");
   1187   } else if (user_shorty == '[') {
   1188     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1189         "The array JNI descriptor must correspond to j${type}Array or jarray");
   1190   } else if (user_shorty == 'L') {
   1191     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1192         "The object JNI descriptor must correspond to jobject.");
   1193   } else {
   1194     X_ASSERT(false);  // We should never get here, but either way this means the types did not match
   1195     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1196         "The JNI type descriptor string does not correspond to the C++ JNI type.");
   1197   }
   1198 }
   1199 
   1200 // Matches a user-defined JNI function descriptor against the C++ function type.
   1201 //
   1202 // If matches fails, then:
   1203 //    parses are fatal -> assertion is triggered (default behavior),
   1204 //    parses are nonfatal -> returns false (test behavior).
   1205 template<NativeKind native_kind, typename T, T fn, size_t kMaxSize>
   1206 constexpr bool
   1207 MatchJniDescriptorWithFunctionType(ConstexprStringView user_function_descriptor) {
   1208   constexpr size_t kReifiedMaxSize = FunctionTypeMetafunction<T, fn>::count;
   1209 
   1210   ConstexprOptional<ReifiedJniSignature<kReifiedMaxSize>>
   1211       reified_signature_opt =
   1212       MaybeMakeReifiedJniSignature<native_kind, T, fn>();
   1213   if (!reified_signature_opt) {
   1214     // Assertion handling done by MaybeMakeReifiedJniSignature.
   1215     return false;
   1216   }
   1217 
   1218   ConstexprOptional<JniSignatureDescriptor<kMaxSize>> user_jni_sig_desc_opt =
   1219       ParseSignatureAsList<kMaxSize>(user_function_descriptor);
   1220 
   1221   if (!user_jni_sig_desc_opt) {
   1222     // Assertion handling done by ParseSignatureAsList.
   1223     return false;
   1224   }
   1225 
   1226   ReifiedJniSignature<kReifiedMaxSize>
   1227       reified_signature = reified_signature_opt.value();
   1228   JniSignatureDescriptor<kMaxSize>
   1229       user_jni_sig_desc = user_jni_sig_desc_opt.value();
   1230 
   1231   if (reified_signature.args.size() != user_jni_sig_desc.args.size()) {
   1232     COMPARE_DESCRIPTOR_FAILURE_MSG(
   1233         "Number of parameters in JNI descriptor string"
   1234             "did not match number of parameters in C++ function type");
   1235   } else if (!CompareJniDescriptorNodeErased(user_jni_sig_desc.ret,
   1236                                              reified_signature.ret)) {
   1237     // Assertion handling done by CompareJniDescriptorNodeErased.
   1238     return false;
   1239   } else {
   1240     for (size_t i = 0; i < user_jni_sig_desc.args.size(); ++i) {
   1241       if (!CompareJniDescriptorNodeErased(user_jni_sig_desc.args[i],
   1242                                           reified_signature.args[i])) {
   1243         // Assertion handling done by CompareJniDescriptorNodeErased.
   1244         return false;
   1245       }
   1246     }
   1247   }
   1248 
   1249   return true;
   1250 }
   1251 
   1252 // Supports inferring the JNI function descriptor string from the C++
   1253 // function type when all type components are final.
   1254 template<NativeKind native_kind, typename T, T fn>
   1255 struct InferJniDescriptor {
   1256   static constexpr size_t kMaxSize = FunctionTypeMetafunction<T, fn>::count;
   1257 
   1258   // Convert the C++ function type into a JniSignatureDescriptor which holds
   1259   // the canonical (according to jni_traits) descriptors for each component.
   1260   // The C++ type -> JNI mapping must be nonambiguous (see jni_macros.h for exact rules).
   1261   //
   1262   // If conversion fails (i.e. C++ signatures is illegal for JNI, or the types are ambiguous):
   1263   //    if parsing is fatal -> assertion failure (default behavior)
   1264   //    if parsing is nonfatal -> returns nullopt (test behavior).
   1265   static constexpr ConstexprOptional<JniSignatureDescriptor<kMaxSize>> FromFunctionType() {
   1266     constexpr size_t kReifiedMaxSize = kMaxSize;
   1267     ConstexprOptional<ReifiedJniSignature<kReifiedMaxSize>>
   1268         reified_signature_opt =
   1269         MaybeMakeReifiedJniSignature<native_kind, T, fn>();
   1270     if (!reified_signature_opt) {
   1271       // Assertion handling done by MaybeMakeReifiedJniSignature.
   1272       return NullConstexprOptional{};
   1273     }
   1274 
   1275     ReifiedJniSignature<kReifiedMaxSize>
   1276         reified_signature = reified_signature_opt.value();
   1277 
   1278     JniSignatureDescriptor<kReifiedMaxSize> signature_descriptor;
   1279 
   1280     if (reified_signature.ret.type_finality != kFinal) {
   1281       // e.g. jint, jfloatArray, jstring, jclass are ok. jobject, jthrowable, jarray are not.
   1282       PARSE_FAILURE("Bad return type. Only unambigous (final) types can be used to infer a signature.");  // NOLINT
   1283     }
   1284     signature_descriptor.ret =
   1285         JniDescriptorNode{reified_signature.ret.type_descriptor};
   1286 
   1287     for (size_t i = 0; i < reified_signature.args.size(); ++i) {
   1288       const ReifiedJniTypeTrait& arg_trait = reified_signature.args[i];
   1289       if (arg_trait.type_finality != kFinal) {
   1290         PARSE_FAILURE("Bad parameter type. Only unambigous (final) types can be used to infer a signature.");  // NOLINT
   1291       }
   1292       signature_descriptor.args.push_back(JniDescriptorNode{
   1293           arg_trait.type_descriptor});
   1294     }
   1295 
   1296     return {signature_descriptor};
   1297   }
   1298 
   1299   // Calculate the exact string size that the JNI descriptor will be
   1300   // at runtime.
   1301   //
   1302   // Without this we cannot allocate enough space within static storage
   1303   // to fit the compile-time evaluated string.
   1304   static constexpr size_t CalculateStringSize() {
   1305     ConstexprOptional<JniSignatureDescriptor<kMaxSize>>
   1306         signature_descriptor_opt =
   1307         FromFunctionType();
   1308     if (!signature_descriptor_opt) {
   1309       // Assertion handling done by FromFunctionType.
   1310       return 0u;
   1311     }
   1312 
   1313     JniSignatureDescriptor<kMaxSize> signature_descriptor =
   1314         signature_descriptor_opt.value();
   1315 
   1316     size_t acc_size = 1u;  // All sigs start with '('.
   1317 
   1318     // Now add every parameter.
   1319     for (size_t j = 0; j < signature_descriptor.args.size(); ++j) {
   1320       const JniDescriptorNode& arg_descriptor = signature_descriptor.args[j];
   1321       // for (const JniDescriptorNode& arg_descriptor : signature_descriptor.args) {
   1322       acc_size += arg_descriptor.longy.size();
   1323     }
   1324 
   1325     acc_size += 1u;   // Add space for ')'.
   1326 
   1327     // Add space for the return value.
   1328     acc_size += signature_descriptor.ret.longy.size();
   1329 
   1330     return acc_size;
   1331   }
   1332 
   1333   static constexpr size_t kMaxStringSize = CalculateStringSize();
   1334   using ConstexprStringDescriptorType = ConstexprArray<char,
   1335                                                        kMaxStringSize + 1>;
   1336 
   1337   static constexpr bool kAllowPartialStrings = false;
   1338 
   1339   // Convert the JniSignatureDescriptor we get in FromFunctionType()
   1340   // into a flat constexpr char array.
   1341   //
   1342   // This is done by repeated string concatenation at compile-time.
   1343   static constexpr ConstexprStringDescriptorType GetString() {
   1344     ConstexprStringDescriptorType c_str{};
   1345 
   1346     ConstexprOptional<JniSignatureDescriptor<kMaxSize>>
   1347         signature_descriptor_opt =
   1348         FromFunctionType();
   1349     if (!signature_descriptor_opt.has_value()) {
   1350       // Assertion handling done by FromFunctionType.
   1351       c_str[0] = '\0';
   1352       return c_str;
   1353     }
   1354 
   1355     JniSignatureDescriptor<kMaxSize> signature_descriptor =
   1356         signature_descriptor_opt.value();
   1357 
   1358     size_t pos = 0u;
   1359     c_str[pos++] = '(';
   1360 
   1361     // Copy all parameter descriptors.
   1362     for (size_t j = 0; j < signature_descriptor.args.size(); ++j) {
   1363       const JniDescriptorNode& arg_descriptor = signature_descriptor.args[j];
   1364       ConstexprStringView longy = arg_descriptor.longy;
   1365       for (size_t i = 0; i < longy.size(); ++i) {
   1366         if (kAllowPartialStrings && pos >= kMaxStringSize) {
   1367           break;
   1368         }
   1369         c_str[pos++] = longy[i];
   1370       }
   1371     }
   1372 
   1373     if (!kAllowPartialStrings || pos < kMaxStringSize) {
   1374       c_str[pos++] = ')';
   1375     }
   1376 
   1377     // Copy return descriptor.
   1378     ConstexprStringView longy = signature_descriptor.ret.longy;
   1379     for (size_t i = 0; i < longy.size(); ++i) {
   1380       if (kAllowPartialStrings && pos >= kMaxStringSize) {
   1381         break;
   1382       }
   1383       c_str[pos++] = longy[i];
   1384     }
   1385 
   1386     if (!kAllowPartialStrings) {
   1387       X_ASSERT(pos == kMaxStringSize);
   1388     }
   1389 
   1390     c_str[pos] = '\0';
   1391 
   1392     return c_str;
   1393   }
   1394 
   1395   // Turn a pure constexpr string into one that can be accessed at non-constexpr
   1396   // time. Note that the 'static constexpr' storage must be in the scope of a
   1397   // function (prior to C++17) to avoid linking errors.
   1398   static const char* GetStringAtRuntime() {
   1399     static constexpr ConstexprStringDescriptorType str = GetString();
   1400     return &str[0];
   1401   }
   1402 };
   1403 
   1404 // Expression to return JNINativeMethod, performs checking on signature+fn.
   1405 #define MAKE_CHECKED_JNI_NATIVE_METHOD(native_kind, name_, signature_, fn) \
   1406   ([]() {                                                                \
   1407     using namespace nativehelper::detail;                                \
   1408     static_assert(                                                       \
   1409         MatchJniDescriptorWithFunctionType<native_kind,                  \
   1410                                            decltype(fn),                 \
   1411                                            fn,                           \
   1412                                            sizeof(signature_)>(signature_),\
   1413         "JNI signature doesn't match C++ function type.");               \
   1414     /* Suppress implicit cast warnings by explicitly casting. */         \
   1415     return JNINativeMethod {                                             \
   1416         const_cast<decltype(JNINativeMethod::name)>(name_),              \
   1417         const_cast<decltype(JNINativeMethod::signature)>(signature_),    \
   1418         reinterpret_cast<void*>(&fn)};                                   \
   1419   })()
   1420 
   1421 // Expression to return JNINativeMethod, infers signature from fn.
   1422 #define MAKE_INFERRED_JNI_NATIVE_METHOD(native_kind, name_, fn)          \
   1423   ([]() {                                                                \
   1424     using namespace nativehelper::detail;                                \
   1425     /* Suppress implicit cast warnings by explicitly casting. */         \
   1426     return JNINativeMethod {                                             \
   1427         const_cast<decltype(JNINativeMethod::name)>(name_),              \
   1428         const_cast<decltype(JNINativeMethod::signature)>(                \
   1429             InferJniDescriptor<native_kind,                              \
   1430                                decltype(fn),                             \
   1431                                fn>::GetStringAtRuntime()),               \
   1432         reinterpret_cast<void*>(&fn)};                                   \
   1433   })()
   1434 
   1435 }  // namespace detail
   1436 }  // namespace nativehelper
   1437 
   1438