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