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