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