1 /* 2 * Copyright (C) 2022 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 #ifndef ART_RUNTIME_JNI_LOCAL_REFERENCE_TABLE_H_ 18 #define ART_RUNTIME_JNI_LOCAL_REFERENCE_TABLE_H_ 19 20 #include <stdint.h> 21 22 #include <iosfwd> 23 #include <limits> 24 #include <string> 25 26 #include <android-base/logging.h> 27 28 #include "base/bit_field.h" 29 #include "base/bit_utils.h" 30 #include "base/casts.h" 31 #include "base/dchecked_vector.h" 32 #include "base/locks.h" 33 #include "base/macros.h" 34 #include "base/mem_map.h" 35 #include "base/mutex.h" 36 #include "gc_root.h" 37 #include "indirect_reference_table.h" 38 #include "mirror/object_reference.h" 39 #include "obj_ptr.h" 40 #include "offsets.h" 41 42 namespace art HIDDEN { 43 44 class RootInfo; 45 46 namespace mirror { 47 class Object; 48 } // namespace mirror 49 50 namespace jni { 51 52 // Maintain a table of local JNI references. 53 // 54 // The table contains object references that are part of the GC root set. When an object is 55 // added we return an `IndirectRef` that is not a valid pointer but can be used to find the 56 // original value in O(1) time. Conversions to and from local JNI references are performed 57 // on upcalls and downcalls as well as in JNI functions, so they need to be very fast. 58 // 59 // To be efficient for JNI local variable storage, we need to provide operations that allow us to 60 // operate on segments of the table, where segments are pushed and popped as if on a stack. For 61 // example, deletion of an entry should only succeed if it appears in the current segment, and we 62 // want to be able to strip off the current segment quickly when a method returns. Additions to the 63 // table must be made in the current segment even if space is available in an earlier area. 64 // 65 // A new segment is created when we call into native code from managed code, or when we handle 66 // the JNI PushLocalFrame function. 67 // 68 // The GC must be able to scan the entire table quickly. 69 // 70 // In summary, these must be very fast: 71 // - adding or removing a segment 72 // - adding references (always adding to the current segment) 73 // - converting a local reference back to an Object 74 // These can be a little slower, but must still be pretty quick: 75 // - removing individual references 76 // - scanning the entire table straight through 77 // 78 // If there's more than one segment, we don't guarantee that the table will fill completely before 79 // we fail due to lack of space. We do ensure that the current segment will pack tightly, which 80 // should satisfy JNI requirements (e.g. EnsureLocalCapacity). 81 82 // To get the desired behavior for JNI locals, we need to know the bottom and top of the current 83 // "segment". When we call a native method or push a local frame, the current top index gets pushed 84 // on, and serves as the new bottom. When we pop a frame off, the value from the stack becomes the 85 // new top index, and the value stored in the previous frame becomes the new bottom. 86 // 87 // If we delete entries from the middle of the list, we will be left with "holes" which we track 88 // with a singly-linked list, so that they can be reused quickly. After a segment has been removed, 89 // we need to prune removed free entries from the front of this singly-linked list before we can 90 // reuse a free entry from the current segment. This is linear in the number of entries removed 91 // and may appear as a slow reference addition but this slow down is attributable to the previous 92 // removals with a constant time per removal. 93 // 94 // Without CheckJNI, we aim for the fastest possible implementation, so there is no error checking 95 // (in release build) and stale references can be erroneously used, especially after the same slot 96 // has been reused for another reference which we cannot easily detect (even in debug build). 97 // 98 // With CheckJNI, we rotate the slots that we use based on a "serial number". 99 // This increases the memory use but it allows for decent error detection. 100 // 101 // We allow switching between CheckJNI enabled and disabled but entries created with CheckJNI 102 // disabled shall have weaker checking even after enabling CheckJNI and the switch can also 103 // prevent reusing a hole that held a reference created with a different CheckJNI setting. 104 105 // The state of the current segment contains the top index. 106 struct LRTSegmentState { 107 uint32_t top_index; 108 }; 109 110 // Use as initial value for "cookie", and when table has only one segment. 111 static constexpr LRTSegmentState kLRTFirstSegment = { 0 }; 112 113 // Each entry in the `LocalReferenceTable` can contain a null (initially or after a `Trim()`) 114 // or reference, or it can be marked as free and hold the index of the next free entry. 115 // If CheckJNI is (or was) enabled, some entries can contain serial numbers instead and 116 // only one other entry in a CheckJNI chunk starting with a serial number is active. 117 // 118 // Valid bit patterns: 119 // 33222222222211111111110000000000 120 // 10987654321098765432109876543210 121 // null: 00000000000000000000000000000000 // Only above the top index. 122 // reference: <----- reference value ----->000 // See also `kObjectAlignment`. 123 // free: <-------- next free --------->01 124 // serial number: <------ serial number ------->10 // CheckJNI entry. 125 // Note that serial number entries can appear only as the first entry of a 16-byte aligned 126 // chunk of four entries and the serial number in the range [1, 3] specifies which of the 127 // other three entries in the chunk is currently used. 128 class LrtEntry { 129 public: 130 void SetReference(ObjPtr<mirror::Object> ref) REQUIRES_SHARED(Locks::mutator_lock_); 131 132 ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_); 133 IsNull()134 bool IsNull() const { 135 return root_.IsNull(); 136 } 137 138 void SetNextFree(uint32_t next_free) REQUIRES_SHARED(Locks::mutator_lock_); 139 GetNextFree()140 uint32_t GetNextFree() { 141 DCHECK(IsFree()); 142 DCHECK(!IsSerialNumber()); 143 return NextFreeField::Decode(GetRawValue()); 144 } 145 IsFree()146 bool IsFree() { 147 return (GetRawValue() & (1u << kFlagFree)) != 0u; 148 } 149 150 void SetSerialNumber(uint32_t serial_number) REQUIRES_SHARED(Locks::mutator_lock_); 151 GetSerialNumber()152 uint32_t GetSerialNumber() { 153 DCHECK(IsSerialNumber()); 154 DCHECK(!IsFree()); 155 return GetSerialNumberUnchecked(); 156 } 157 GetSerialNumberUnchecked()158 uint32_t GetSerialNumberUnchecked() { 159 return SerialNumberField::Decode(GetRawValue()); 160 } 161 IsSerialNumber()162 bool IsSerialNumber() { 163 return (GetRawValue() & (1u << kFlagSerialNumber)) != 0u; 164 } 165 GetRootAddress()166 GcRoot<mirror::Object>* GetRootAddress() { 167 return &root_; 168 } 169 FreeListEnd()170 static constexpr uint32_t FreeListEnd() { 171 return MaxInt<uint32_t>(kFieldNextFreeBits); 172 } 173 174 private: 175 // Definitions of bit fields and flags. 176 static constexpr size_t kFlagFree = 0u; 177 static constexpr size_t kFlagSerialNumber = kFlagFree + 1u; 178 static constexpr size_t kFieldNextFree = kFlagSerialNumber + 1u; 179 static constexpr size_t kFieldNextFreeBits = BitSizeOf<uint32_t>() - kFieldNextFree; 180 181 using NextFreeField = BitField<uint32_t, kFieldNextFree, kFieldNextFreeBits>; 182 using SerialNumberField = NextFreeField; 183 184 static_assert(kObjectAlignment > (1u << kFlagFree)); 185 static_assert(kObjectAlignment > (1u << kFlagSerialNumber)); 186 187 void SetVRegValue(uint32_t value) REQUIRES_SHARED(Locks::mutator_lock_); 188 GetRawValue()189 uint32_t GetRawValue() { 190 return root_.AddressWithoutBarrier()->AsVRegValue(); 191 } 192 193 // We record the contents as a `GcRoot<>` but it is an actual `GcRoot<>` only if it's below 194 // the current segment's top index, it's not a "serial number" or inactive entry in a CheckJNI 195 // chunk, and it's not marked as "free". Such entries are never null. 196 GcRoot<mirror::Object> root_; 197 }; 198 static_assert(sizeof(LrtEntry) == sizeof(mirror::CompressedReference<mirror::Object>)); 199 // Assert that the low bits of an `LrtEntry*` are sufficient for encoding the reference kind. 200 static_assert(enum_cast<uint32_t>(IndirectRefKind::kLastKind) < alignof(LrtEntry)); 201 202 203 // We initially allocate local reference tables with a small number of entries, packing 204 // multiple tables into a single page. If we need to expand, we double the capacity, 205 // first allocating another chunk with the same number of entries as the first chunk 206 // and then allocating twice as big chunk on each subsequent expansion. 207 static constexpr size_t kInitialLrtBytes = 512; // Number of bytes in an initial local table. 208 static constexpr size_t kSmallLrtEntries = kInitialLrtBytes / sizeof(LrtEntry); 209 static_assert(IsPowerOfTwo(kInitialLrtBytes)); 210 211 static_assert(kMinPageSize % kInitialLrtBytes == 0); 212 static_assert(kInitialLrtBytes % sizeof(LrtEntry) == 0); 213 214 // A minimal stopgap allocator for initial small local LRT tables. 215 class SmallLrtAllocator { 216 public: 217 SmallLrtAllocator(); 218 219 // Allocate a small block of `LrtEntries` for the `LocalReferenceTable` table. The `size` 220 // must be a power of 2, at least `kSmallLrtEntries`, and requiring less than a page of memory. 221 LrtEntry* Allocate(size_t size, std::string* error_msg) REQUIRES(!lock_); 222 223 void Deallocate(LrtEntry* unneeded, size_t size) REQUIRES(!lock_); 224 225 private: 226 // Number of free lists in the allocator. 227 #ifdef ART_PAGE_SIZE_AGNOSTIC 228 const size_t num_lrt_slots_ = (WhichPowerOf2(gPageSize / kInitialLrtBytes)); 229 #else 230 static constexpr size_t num_lrt_slots_ = (WhichPowerOf2(gPageSize / kInitialLrtBytes)); 231 #endif 232 233 size_t GetIndex(size_t size); 234 235 // Free lists of small chunks linked through the first word. 236 dchecked_vector<void*> free_lists_; 237 238 // Repository of MemMaps used for small LRT tables. 239 dchecked_vector<MemMap> shared_lrt_maps_; 240 241 Mutex lock_; // Level kGenericBottomLock; acquired before mem_map_lock_, which is a C++ mutex. 242 }; 243 244 class LocalReferenceTable { 245 public: 246 explicit LocalReferenceTable(bool check_jni); 247 ~LocalReferenceTable(); 248 249 // Set the CheckJNI enabled status. 250 // Called only from the Zygote post-fork callback while the process is single-threaded. 251 // Enabling CheckJNI reduces the number of entries that can be stored, thus invalidating 252 // guarantees provided by a previous call to `EnsureFreeCapacity()`. 253 void SetCheckJniEnabled(bool enabled); 254 255 // Returns whether the CheckJNI is enabled for this `LocalReferenceTable`. IsCheckJniEnabled()256 bool IsCheckJniEnabled() const { 257 return (free_entries_list_ & (1u << kFlagCheckJni)) != 0u; 258 } 259 260 // Initialize the `LocalReferenceTable`. 261 // 262 // Max_count is the requested minimum initial capacity (resizable). The actual initial 263 // capacity can be higher to utilize all allocated memory. 264 // 265 // Returns true on success. 266 // On failure, returns false and reports error in `*error_msg`. 267 bool Initialize(size_t max_count, std::string* error_msg); 268 269 // Add a new entry. The `obj` must be a valid non-null object reference. This function 270 // will return null if an error happened (with an appropriate error message set). 271 EXPORT IndirectRef Add(ObjPtr<mirror::Object> obj, std::string* error_msg) 272 REQUIRES_SHARED(Locks::mutator_lock_); 273 274 // Given an `IndirectRef` in the table, return the `Object` it refers to. 275 // 276 // This function may abort under error conditions in debug build. 277 // In release builds, error conditions are unchecked and the function can 278 // return old or invalid references from popped segments and deleted entries. 279 ObjPtr<mirror::Object> Get(IndirectRef iref) const 280 REQUIRES_SHARED(Locks::mutator_lock_) ALWAYS_INLINE; 281 282 // Updates an existing indirect reference to point to a new object. 283 // Used exclusively for updating `String` references after calling a `String` constructor. 284 void Update(IndirectRef iref, ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); 285 286 // Remove an existing entry. 287 // 288 // If the entry is not between the current top index and the bottom index 289 // specified by the cookie, we don't remove anything. This is the behavior 290 // required by JNI's DeleteLocalRef function. 291 // 292 // Returns "false" if nothing was removed. 293 bool Remove(IndirectRef iref) 294 REQUIRES_SHARED(Locks::mutator_lock_); 295 296 void AssertEmpty(); 297 298 void Dump(std::ostream& os) const 299 REQUIRES_SHARED(Locks::mutator_lock_) 300 REQUIRES(!Locks::alloc_tracker_lock_); 301 GetKind()302 IndirectRefKind GetKind() const { 303 return kLocal; 304 } 305 306 // Return the number of entries in the entire table. This includes holes, 307 // and so may be larger than the actual number of "live" entries. 308 // The value corresponds to the number of entries for the current CheckJNI setting 309 // and may be wrong if there are entries created with a different CheckJNI setting. Capacity()310 size_t Capacity() const { 311 if (IsCheckJniEnabled()) { 312 DCHECK_ALIGNED(segment_state_.top_index, kCheckJniEntriesPerReference); 313 return segment_state_.top_index / kCheckJniEntriesPerReference; 314 } else { 315 return segment_state_.top_index; 316 } 317 } 318 319 // Ensure that at least free_capacity elements are available, or return false. 320 // Caller ensures free_capacity > 0. 321 bool EnsureFreeCapacity(size_t free_capacity, std::string* error_msg) 322 REQUIRES_SHARED(Locks::mutator_lock_); 323 // See implementation of EnsureFreeCapacity. We'll only state here how much is trivially free, 324 // without recovering holes. Thus this is a conservative estimate. 325 size_t FreeCapacity() const; 326 327 EXPORT void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) 328 REQUIRES_SHARED(Locks::mutator_lock_); 329 PushFrame()330 LRTSegmentState PushFrame() { 331 if (kDebugLRT) { 332 LOG(INFO) << "+++ Push frame: previous state " << previous_state_.top_index << " -> " 333 << segment_state_.top_index; 334 } 335 LRTSegmentState result = previous_state_; 336 previous_state_ = segment_state_; 337 return result; 338 } 339 PopFrame(LRTSegmentState previous_state)340 void PopFrame(LRTSegmentState previous_state) { 341 if (kDebugLRT) { 342 LOG(INFO) << "+++ Pop frame: current state " << segment_state_.top_index << " -> " 343 << previous_state_.top_index << ", previous state -> " << previous_state.top_index; 344 } 345 segment_state_ = previous_state_; 346 previous_state_ = previous_state; 347 } 348 PreviousStateOffset()349 static MemberOffset PreviousStateOffset() { 350 // Note: The `previous_state_` must be before any pointer-size-dependent members, so that 351 // `MEMBER_OFFSET()` gives the correct value even for cross-compilation. 352 return MemberOffset(OFFSETOF_MEMBER(LocalReferenceTable, previous_state_)); 353 } 354 SegmentStateOffset()355 static MemberOffset SegmentStateOffset() { 356 // Note: The `segment_state_` must be before any pointer-size-dependent members, so that 357 // `MEMBER_OFFSET()` gives the correct value even for cross-compilation. 358 return MemberOffset(OFFSETOF_MEMBER(LocalReferenceTable, segment_state_)); 359 } 360 361 // Release pages past the end of the table that may have previously held references. 362 void Trim() REQUIRES_SHARED(Locks::mutator_lock_); 363 364 /* Reference validation for CheckJNI and debug build. */ 365 bool IsValidReference(IndirectRef, /*out*/std::string* error_msg) const 366 REQUIRES_SHARED(Locks::mutator_lock_); 367 368 private: 369 static constexpr bool kDebugLRT = false; 370 371 // Flags and fields in the `free_entries_list_`. 372 static constexpr size_t kFlagCheckJni = 0u; 373 // Skip a bit to have the same value range for the "first free" as the "next free" in `LrtEntry`. 374 static constexpr size_t kFlagPadding = kFlagCheckJni + 1u; 375 static constexpr size_t kFieldFirstFree = kFlagPadding + 1u; 376 static constexpr size_t kFieldFirstFreeSize = BitSizeOf<uint32_t>() - kFieldFirstFree; 377 378 using FirstFreeField = BitField<uint32_t, kFieldFirstFree, kFieldFirstFreeSize>; 379 380 // The value of `FirstFreeField` in `free_entries_list_` indicating the end of the free list. 381 static constexpr uint32_t kFreeListEnd = LrtEntry::FreeListEnd(); 382 static_assert(kFreeListEnd == MaxInt<uint32_t>(kFieldFirstFreeSize)); 383 384 // The value of `free_entries_list_` indicating empty free list and disabled CheckJNI. 385 static constexpr uint32_t kEmptyFreeListAndCheckJniDisabled = 386 FirstFreeField::Update(kFreeListEnd, 0u); // kFlagCheckJni not set. 387 388 // The number of entries per reference to detect obsolete reference uses with CheckJNI enabled. 389 // The first entry serves as a serial number, one of the remaining entries can hold the actual 390 // reference or the next free index. 391 static constexpr size_t kCheckJniEntriesPerReference = 4u; 392 static_assert(IsPowerOfTwo(kCheckJniEntriesPerReference)); 393 394 // The maximum total table size we allow. 395 static constexpr size_t kMaxTableSizeInBytes = 128 * MB; 396 static_assert(IsPowerOfTwo(kMaxTableSizeInBytes)); 397 static_assert(IsPowerOfTwo(sizeof(LrtEntry))); 398 static constexpr size_t kMaxTableSize = kMaxTableSizeInBytes / sizeof(LrtEntry); 399 ToIndirectRef(LrtEntry * entry)400 static IndirectRef ToIndirectRef(LrtEntry* entry) { 401 // The `IndirectRef` can be used to directly access the underlying `GcRoot<>`. 402 DCHECK_EQ(reinterpret_cast<GcRoot<mirror::Object>*>(entry), entry->GetRootAddress()); 403 return reinterpret_cast<IndirectRef>( 404 reinterpret_cast<uintptr_t>(entry) | static_cast<uintptr_t>(kLocal)); 405 } 406 ToLrtEntry(IndirectRef iref)407 static LrtEntry* ToLrtEntry(IndirectRef iref) { 408 DCHECK_EQ(IndirectReferenceTable::GetIndirectRefKind(iref), kLocal); 409 return IndirectReferenceTable::ClearIndirectRefKind<LrtEntry*>(iref); 410 } 411 GetTableSize(size_t table_index)412 static constexpr size_t GetTableSize(size_t table_index) { 413 // First two tables have size `kSmallLrtEntries`, then it doubles for subsequent tables. 414 return kSmallLrtEntries << (table_index != 0u ? table_index - 1u : 0u); 415 } 416 NumTablesForSize(size_t size)417 static constexpr size_t NumTablesForSize(size_t size) { 418 DCHECK_GE(size, kSmallLrtEntries); 419 DCHECK(IsPowerOfTwo(size)); 420 return 1u + WhichPowerOf2(size / kSmallLrtEntries); 421 } 422 MaxSmallTables()423 static size_t MaxSmallTables() { 424 return NumTablesForSize(gPageSize / sizeof(LrtEntry)); 425 } 426 GetEntry(size_t entry_index)427 LrtEntry* GetEntry(size_t entry_index) const { 428 DCHECK_LT(entry_index, max_entries_); 429 if (LIKELY(small_table_ != nullptr)) { 430 DCHECK_LT(entry_index, kSmallLrtEntries); 431 DCHECK_EQ(max_entries_, kSmallLrtEntries); 432 return &small_table_[entry_index]; 433 } 434 size_t table_start_index = 435 (entry_index < kSmallLrtEntries) ? 0u : TruncToPowerOfTwo(entry_index); 436 size_t table_index = 437 (entry_index < kSmallLrtEntries) ? 0u : NumTablesForSize(table_start_index); 438 LrtEntry* table = tables_[table_index]; 439 return &table[entry_index - table_start_index]; 440 } 441 442 // Get the entry index for a local reference. Note that this may be higher than 443 // the current segment state. Returns maximum uint32 value if the reference does not 444 // point to one of the internal tables. 445 uint32_t GetReferenceEntryIndex(IndirectRef iref) const; 446 GetCheckJniSerialNumberEntry(LrtEntry * entry)447 static LrtEntry* GetCheckJniSerialNumberEntry(LrtEntry* entry) { 448 return AlignDown(entry, kCheckJniEntriesPerReference * sizeof(LrtEntry)); 449 } 450 451 static uint32_t IncrementSerialNumber(LrtEntry* serial_number_entry) 452 REQUIRES_SHARED(Locks::mutator_lock_); 453 IsValidSerialNumber(uint32_t serial_number)454 static bool IsValidSerialNumber(uint32_t serial_number) { 455 return serial_number != 0u && serial_number < kCheckJniEntriesPerReference; 456 } 457 458 // Debug mode check that the reference is valid. 459 void DCheckValidReference(IndirectRef iref) const REQUIRES_SHARED(Locks::mutator_lock_); 460 461 // Resize the backing table to be at least `new_size` elements long. The `new_size` 462 // must be larger than the current size. After return max_entries_ >= new_size. 463 bool Resize(size_t new_size, std::string* error_msg); 464 465 // Extract the first free index from `free_entries_list_`. GetFirstFreeIndex()466 uint32_t GetFirstFreeIndex() const { 467 return FirstFreeField::Decode(free_entries_list_); 468 } 469 470 // Remove popped free entries from the list. 471 // Called only if `free_entries_list_` points to a popped entry. 472 template <typename EntryGetter> 473 void PrunePoppedFreeEntries(EntryGetter&& get_entry); 474 475 // Helper template function for visiting roots. 476 template <typename Visitor> 477 void VisitRootsInternal(Visitor&& visitor) const REQUIRES_SHARED(Locks::mutator_lock_); 478 479 /// semi-public - read/write by jni down calls. 480 // These two members need to be before any pointer-size-dependent members, so that 481 // `MEMBER_OFFSET()` gives the correct value even for cross-compilation. 482 LRTSegmentState previous_state_; 483 LRTSegmentState segment_state_; 484 485 // The maximum number of entries (modulo resizing). 486 uint32_t max_entries_; 487 488 // The singly-linked list of free nodes. 489 // We use entry indexes instead of pointers and `kFreeListEnd` instead of null indicates 490 // the end of the list. See `LocalReferenceTable::GetEntry()` and `LrtEntry::GetNextFree(). 491 // 492 // We use the lowest bit to record whether CheckJNI is enabled. This helps us 493 // check that the list is empty and CheckJNI is disabled in a single comparison. 494 uint32_t free_entries_list_; 495 496 // Individual tables. 497 // As long as we have only one small table, we use `small_table_` to avoid an extra load 498 // from another heap allocated location, otherwise we set it to null and use `tables_`. 499 LrtEntry* small_table_; // For optimizing the fast-path. 500 dchecked_vector<LrtEntry*> tables_; 501 502 // Mem maps where we store tables allocated directly with `MemMap` 503 // rather than the `SmallLrtAllocator`. 504 dchecked_vector<MemMap> table_mem_maps_; 505 }; 506 507 } // namespace jni 508 } // namespace art 509 510 #endif // ART_RUNTIME_JNI_LOCAL_REFERENCE_TABLE_H_ 511