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