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