1 /* 2 * Copyright (C) 2009 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_INDIRECT_REFERENCE_TABLE_H_ 18 #define ART_RUNTIME_INDIRECT_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_utils.h" 29 #include "base/locks.h" 30 #include "base/macros.h" 31 #include "base/mem_map.h" 32 #include "base/mutex.h" 33 #include "gc_root.h" 34 #include "obj_ptr.h" 35 #include "offsets.h" 36 #include "read_barrier_option.h" 37 38 namespace art { 39 40 class IsMarkedVisitor; 41 class RootInfo; 42 43 namespace mirror { 44 class Object; 45 } // namespace mirror 46 47 // Indirect reference definition. This must be interchangeable with JNI's jobject, and it's 48 // convenient to let null be null, so we use void*. 49 // 50 // We need a 2-bit reference kind (global, local, weak global) and the rest of the `IndirectRef` 51 // is used to locate the actual reference storage. 52 // 53 // For global and weak global references, we need a (potentially) large table index and we also 54 // reserve some bits to be used to detect stale indirect references: we put a serial number in 55 // the extra bits, and keep a copy of the serial number in the table. This requires more memory 56 // and additional memory accesses on add/get, but is moving-GC safe. It will catch additional 57 // problems, e.g.: create iref1 for obj, delete iref1, create iref2 for same obj, lookup iref1. 58 // A pattern based on object bits will miss this. 59 // 60 // Local references use the same bits for the reference kind but the rest of their `IndirectRef` 61 // encoding is different, see `LocalReferenceTable` for details. 62 using IndirectRef = void*; 63 64 // Indirect reference kind, used as the two low bits of IndirectRef. 65 // 66 // For convenience these match up with enum jobjectRefType from jni.h, except that 67 // we use value 0 for JNI transitions instead of marking invalid reference type. 68 enum IndirectRefKind { 69 kJniTransition = 0, // <<JNI transition frame reference>> 70 kLocal = 1, // <<local reference>> 71 kGlobal = 2, // <<global reference>> 72 kWeakGlobal = 3, // <<weak global reference>> 73 kLastKind = kWeakGlobal 74 }; 75 std::ostream& operator<<(std::ostream& os, IndirectRefKind rhs); 76 const char* GetIndirectRefKindString(IndirectRefKind kind); 77 78 // Maintain a table of indirect references. Used for global and weak global JNI references. 79 // 80 // The table contains object references, where the strong global references are part of the 81 // GC root set (but not the weak global references). When an object is added we return an 82 // `IndirectRef` that is not a valid pointer but can be used to find the original value in O(1) 83 // time. Conversions to and from indirect references are performed in JNI functions and when 84 // returning from native methods to managed code, so they need to be very fast. 85 // 86 // The GC must be able to scan the entire table quickly. 87 // 88 // In summary, these must be very fast: 89 // - adding references 90 // - removing references 91 // - converting an indirect reference back to an Object 92 // These can be a little slower, but must still be pretty quick: 93 // - scanning the entire table straight through 94 95 // Table definition. 96 // 97 // For the global reference tables, the expected common operations are adding a new entry and 98 // removing a recently-added entry (usually the most-recently-added entry). 99 // 100 // If we delete entries from the middle of the list, we will be left with "holes". We track the 101 // number of holes so that, when adding new elements, we can quickly decide to do a trivial append 102 // or go slot-hunting. 103 // 104 // When the top-most entry is removed, any holes immediately below it are also removed. Thus, 105 // deletion of an entry may reduce "top_index" by more than one. 106 // 107 // Common alternative implementation: make IndirectRef a pointer to the actual reference slot. 108 // Instead of getting a table and doing a lookup, the lookup can be done instantly. Operations like 109 // determining the type and deleting the reference are more expensive because the table must be 110 // hunted for (i.e. you have to do a pointer comparison to see which table it's in), you can't move 111 // the table when expanding it (so realloc() is out), and tricks like serial number checking to 112 // detect stale references aren't possible (though we may be able to get similar benefits with other 113 // approaches). 114 // 115 // TODO: consider a "lastDeleteIndex" for quick hole-filling when an add immediately follows a 116 // delete. 117 118 // We associate a few bits of serial number with each reference, for error checking. 119 static constexpr unsigned int kIRTSerialBits = 3; 120 static constexpr uint32_t kIRTMaxSerial = ((1 << kIRTSerialBits) - 1); 121 122 class IrtEntry { 123 public: 124 void Add(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); 125 GetReference()126 GcRoot<mirror::Object>* GetReference() { 127 DCHECK_LE(serial_, kIRTMaxSerial); 128 return &reference_; 129 } 130 GetReference()131 const GcRoot<mirror::Object>* GetReference() const { 132 DCHECK_LE(serial_, kIRTMaxSerial); 133 return &reference_; 134 } 135 GetSerial()136 uint32_t GetSerial() const { 137 return serial_; 138 } 139 140 void SetReference(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); 141 142 private: 143 uint32_t serial_; // Incremented for each reuse; checked against reference. 144 GcRoot<mirror::Object> reference_; 145 }; 146 static_assert(sizeof(IrtEntry) == 2 * sizeof(uint32_t), "Unexpected sizeof(IrtEntry)"); 147 static_assert(IsPowerOfTwo(sizeof(IrtEntry)), "Unexpected sizeof(IrtEntry)"); 148 149 class IndirectReferenceTable { 150 public: 151 // Constructs an uninitialized indirect reference table. Use `Initialize()` to initialize it. 152 explicit IndirectReferenceTable(IndirectRefKind kind); 153 154 // Initialize the indirect reference table. 155 // 156 // Max_count is the requested total capacity (not resizable). The actual total capacity 157 // can be higher to utilize all allocated memory (rounding up to whole pages). 158 bool Initialize(size_t max_count, std::string* error_msg); 159 160 ~IndirectReferenceTable(); 161 162 // Add a new entry. "obj" must be a valid non-null object reference. This function will 163 // return null if an error happened (with an appropriate error message set). 164 IndirectRef Add(ObjPtr<mirror::Object> obj, std::string* error_msg) 165 REQUIRES_SHARED(Locks::mutator_lock_); 166 167 // Given an IndirectRef in the table, return the Object it refers to. 168 // 169 // This function may abort under error conditions. 170 template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> 171 ObjPtr<mirror::Object> Get(IndirectRef iref) const REQUIRES_SHARED(Locks::mutator_lock_) 172 ALWAYS_INLINE; 173 174 // Updates an existing indirect reference to point to a new object. 175 void Update(IndirectRef iref, ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); 176 177 // Remove an existing entry. 178 // 179 // If the entry is not between the current top index and the bottom index 180 // specified by the cookie, we don't remove anything. This is the behavior 181 // required by JNI's DeleteLocalRef function. 182 // 183 // Returns "false" if nothing was removed. 184 bool Remove(IndirectRef iref); 185 186 void Dump(std::ostream& os) const 187 REQUIRES_SHARED(Locks::mutator_lock_) 188 REQUIRES(!Locks::alloc_tracker_lock_); 189 GetKind()190 IndirectRefKind GetKind() const { 191 return kind_; 192 } 193 194 // Return the #of entries in the entire table. This includes holes, and 195 // so may be larger than the actual number of "live" entries. Capacity()196 size_t Capacity() const { 197 return top_index_; 198 } 199 200 // Return the number of non-null entries in the table. Only reliable for a 201 // single segment table. NEntriesForGlobal()202 int32_t NEntriesForGlobal() { 203 return top_index_ - current_num_holes_; 204 } 205 206 // We'll only state here how much is trivially free, without recovering holes. 207 // Thus this is a conservative estimate. 208 size_t FreeCapacity() const; 209 210 void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) 211 REQUIRES_SHARED(Locks::mutator_lock_); 212 213 // Release pages past the end of the table that may have previously held references. 214 void Trim() REQUIRES_SHARED(Locks::mutator_lock_); 215 216 // Determine what kind of indirect reference this is. Opposite of EncodeIndirectRefKind. GetIndirectRefKind(IndirectRef iref)217 ALWAYS_INLINE static inline IndirectRefKind GetIndirectRefKind(IndirectRef iref) { 218 return DecodeIndirectRefKind(reinterpret_cast<uintptr_t>(iref)); 219 } 220 GetGlobalOrWeakGlobalMask()221 static constexpr uintptr_t GetGlobalOrWeakGlobalMask() { 222 constexpr uintptr_t mask = enum_cast<uintptr_t>(kGlobal); 223 static_assert(IsPowerOfTwo(mask)); 224 static_assert((mask & kJniTransition) == 0u); 225 static_assert((mask & kLocal) == 0u); 226 static_assert((mask & kGlobal) != 0u); 227 static_assert((mask & kWeakGlobal) != 0u); 228 return mask; 229 } 230 IsGlobalOrWeakGlobalReference(IndirectRef iref)231 static bool IsGlobalOrWeakGlobalReference(IndirectRef iref) { 232 return (reinterpret_cast<uintptr_t>(iref) & GetGlobalOrWeakGlobalMask()) != 0u; 233 } 234 IsJniTransitionOrLocalReference(IndirectRef iref)235 static bool IsJniTransitionOrLocalReference(IndirectRef iref) { 236 return !IsGlobalOrWeakGlobalReference(iref); 237 } 238 239 template <typename T> ClearIndirectRefKind(IndirectRef iref)240 static T ClearIndirectRefKind(IndirectRef iref) { 241 static_assert(std::is_pointer_v<T>); 242 return reinterpret_cast<T>( 243 reinterpret_cast<uintptr_t>(iref) & ~static_cast<uintptr_t>(kKindMask)); 244 } 245 GetIndirectRefKindMask()246 static constexpr uintptr_t GetIndirectRefKindMask() { 247 return kKindMask; 248 } 249 250 /* Reference validation for CheckJNI. */ 251 bool IsValidReference(IndirectRef, /*out*/std::string* error_msg) const 252 REQUIRES_SHARED(Locks::mutator_lock_); 253 254 void SweepJniWeakGlobals(IsMarkedVisitor* visitor) 255 REQUIRES_SHARED(Locks::mutator_lock_) 256 REQUIRES(!Locks::jni_weak_globals_lock_); 257 258 private: 259 static constexpr uint32_t kShiftedSerialMask = (1u << kIRTSerialBits) - 1; 260 261 static constexpr size_t kKindBits = MinimumBitsToStore( 262 static_cast<uint32_t>(IndirectRefKind::kLastKind)); 263 static constexpr uint32_t kKindMask = (1u << kKindBits) - 1; 264 EncodeIndex(uint32_t table_index)265 static constexpr uintptr_t EncodeIndex(uint32_t table_index) { 266 static_assert(sizeof(IndirectRef) == sizeof(uintptr_t), "Unexpected IndirectRef size"); 267 DCHECK_LE(MinimumBitsToStore(table_index), BitSizeOf<uintptr_t>() - kIRTSerialBits - kKindBits); 268 return (static_cast<uintptr_t>(table_index) << kKindBits << kIRTSerialBits); 269 } DecodeIndex(uintptr_t uref)270 static constexpr uint32_t DecodeIndex(uintptr_t uref) { 271 return static_cast<uint32_t>((uref >> kKindBits) >> kIRTSerialBits); 272 } 273 EncodeIndirectRefKind(IndirectRefKind kind)274 static constexpr uintptr_t EncodeIndirectRefKind(IndirectRefKind kind) { 275 return static_cast<uintptr_t>(kind); 276 } DecodeIndirectRefKind(uintptr_t uref)277 static constexpr IndirectRefKind DecodeIndirectRefKind(uintptr_t uref) { 278 return static_cast<IndirectRefKind>(uref & kKindMask); 279 } 280 EncodeSerial(uint32_t serial)281 static constexpr uintptr_t EncodeSerial(uint32_t serial) { 282 DCHECK_LE(MinimumBitsToStore(serial), kIRTSerialBits); 283 return serial << kKindBits; 284 } DecodeSerial(uintptr_t uref)285 static constexpr uint32_t DecodeSerial(uintptr_t uref) { 286 return static_cast<uint32_t>(uref >> kKindBits) & kShiftedSerialMask; 287 } 288 EncodeIndirectRef(uint32_t table_index,uint32_t serial)289 constexpr uintptr_t EncodeIndirectRef(uint32_t table_index, uint32_t serial) const { 290 DCHECK_LT(table_index, max_entries_); 291 return EncodeIndex(table_index) | EncodeSerial(serial) | EncodeIndirectRefKind(kind_); 292 } 293 294 static void ConstexprChecks(); 295 296 // Extract the table index from an indirect reference. ExtractIndex(IndirectRef iref)297 ALWAYS_INLINE static uint32_t ExtractIndex(IndirectRef iref) { 298 return DecodeIndex(reinterpret_cast<uintptr_t>(iref)); 299 } 300 ToIndirectRef(uint32_t table_index)301 IndirectRef ToIndirectRef(uint32_t table_index) const { 302 DCHECK_LT(table_index, max_entries_); 303 uint32_t serial = table_[table_index].GetSerial(); 304 return reinterpret_cast<IndirectRef>(EncodeIndirectRef(table_index, serial)); 305 } 306 307 // Abort if check_jni is not enabled. Otherwise, just log as an error. 308 static void AbortIfNoCheckJNI(const std::string& msg); 309 310 /* extra debugging checks */ 311 bool CheckEntry(const char*, IndirectRef, uint32_t) const; 312 313 // Mem map where we store the indirect refs. 314 MemMap table_mem_map_; 315 // Bottom of the stack. Do not directly access the object references 316 // in this as they are roots. Use Get() that has a read barrier. 317 IrtEntry* table_; 318 // Bit mask, ORed into all irefs. 319 const IndirectRefKind kind_; 320 321 // The "top of stack" index where new references are added. 322 size_t top_index_; 323 324 // Maximum number of entries allowed. 325 size_t max_entries_; 326 327 // Some values to retain old behavior with holes. 328 // Description of the algorithm is in the .cc file. 329 // TODO: Consider other data structures for compact tables, e.g., free lists. 330 size_t current_num_holes_; // Number of holes in the current / top segment. 331 }; 332 333 } // namespace art 334 335 #endif // ART_RUNTIME_INDIRECT_REFERENCE_TABLE_H_ 336