1 /** 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 // All common ObjectHeader methods can be found here: 16 // - Get/Set Mark or Class word 17 // - Get size of the object header and an object itself 18 // - Get/Generate an object hash 19 // Methods, specific for Class word: 20 // - Get different object fields 21 // - Return object type 22 // - Verify object 23 // - Is it a subclass of not 24 // - Get field addr 25 // Methods, specific for Mark word: 26 // - Object locked/unlocked 27 // - Marked for GC or not 28 // - Monitor functions (get monitor, notify, notify all, wait) 29 // - Forwarded or not 30 #ifndef PANDA_RUNTIME_OBJECT_HEADER_H_ 31 #define PANDA_RUNTIME_OBJECT_HEADER_H_ 32 33 #include <atomic> 34 #include <ctime> 35 36 #include "runtime/mem/lock_config_helper.h" 37 #include "runtime/include/class_helper.h" 38 #include "runtime/mark_word.h" 39 40 namespace ark { 41 42 namespace object_header_traits { 43 44 constexpr const uint32_t LINEAR_X = 1103515245U; 45 constexpr const uint32_t LINEAR_Y = 12345U; 46 constexpr const uint32_t LINEAR_SEED = 987654321U; 47 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 48 extern std::atomic<uint32_t> g_hashSeed; 49 50 } // namespace object_header_traits 51 52 class BaseClass; 53 class Class; 54 class Field; 55 class ManagedThread; 56 57 class PANDA_PUBLIC_API ObjectHeader { 58 public: 59 // Simple getters and setters for Class and Mark words. 60 // Use it only in single thread GetMark()61 inline MarkWord GetMark() const 62 { 63 return *(const_cast<MarkWord *>(reinterpret_cast<const MarkWord *>(&markWord_))); 64 } SetMark(volatile MarkWord markWord)65 inline void SetMark(volatile MarkWord markWord) 66 { 67 markWord_ = markWord.Value(); 68 } 69 70 inline MarkWord AtomicGetMark(std::memory_order memoryOrder = std::memory_order_seq_cst) const 71 { 72 auto *ptr = const_cast<MarkWord *>(reinterpret_cast<const MarkWord *>(&markWord_)); 73 auto *atomicPtr = reinterpret_cast<std::atomic<MarkWord> *>(ptr); 74 // Atomic with parameterized order reason: memory order passed as argument 75 return atomicPtr->load(memoryOrder); 76 } 77 SetClass(BaseClass * klass)78 inline void SetClass(BaseClass *klass) 79 { 80 static_assert(sizeof(ClassHelper::ClassWordSize) == sizeof(ObjectPointerType)); 81 auto *classWordPtr = reinterpret_cast<std::atomic<ClassHelper::ClassWordSize> *>(&classWord_); 82 // NOTE(ipetrov): Set class with flags allocated by external CMC GC, will be removed when allocation in 32-bit 83 // space will be supported 84 #if defined(ARK_HYBRID) && defined(PANDA_TARGET_64) 85 // Atomic with acquire order reason: data race with classWord_ with dependecies on reads after the load which 86 // should become visible 87 auto flags = classWordPtr->load(std::memory_order_acquire) & ~GetClassMask(); 88 #else 89 constexpr ClassHelper::ClassWordSize flags = 0U; // NOLINT(readability-identifier-naming) 90 #endif 91 // Atomic with release order reason: data race with classWord_ with dependecies on writes before the store which 92 // should become visible acquire 93 classWordPtr->store(static_cast<ClassHelper::ClassWordSize>(ToObjPtrType(klass)) | flags, 94 std::memory_order_release); 95 ASSERT_PRINT(ClassAddr<BaseClass>() == klass, 96 "Stored class = " << ClassAddr<BaseClass>() << ", but passed is " << klass); 97 } 98 99 template <typename T> ClassAddr()100 inline T *ClassAddr() const 101 { 102 auto ptr = const_cast<ClassHelper::ClassWordSize *>(&classWord_); 103 // Atomic with acquire order reason: data race with classWord_ with dependecies on reads after the load which 104 // should become visible 105 return reinterpret_cast<T *>( 106 reinterpret_cast<std::atomic<ClassHelper::ClassWordSize> *>(ptr)->load(std::memory_order_acquire) & 107 GetClassMask()); 108 } 109 110 template <typename T> NotAtomicClassAddr()111 inline T *NotAtomicClassAddr() const 112 { 113 return reinterpret_cast<T *>(GetClassWord()); 114 } 115 116 // Generate hash value for an object. GenerateHashCode()117 static inline uint32_t GenerateHashCode() 118 { 119 uint32_t exVal; 120 uint32_t nVal; 121 do { 122 // Atomic with relaxed order reason: data race with hash_seed with no synchronization or ordering 123 // constraints imposed on other reads or writes 124 exVal = object_header_traits::g_hashSeed.load(std::memory_order_relaxed); 125 nVal = exVal * object_header_traits::LINEAR_X + object_header_traits::LINEAR_Y; 126 } while (!object_header_traits::g_hashSeed.compare_exchange_weak(exVal, nVal, std::memory_order_relaxed) || 127 (exVal & MarkWord::HASH_MASK) == 0); 128 return exVal & MarkWord::HASH_MASK; 129 } 130 131 // Get Hash value for an object. 132 template <MTModeT MT_MODE> 133 uint32_t GetHashCode(); 134 uint32_t GetHashCodeFromMonitor(Monitor *monitorP); 135 136 // Size of object header ObjectHeaderSize()137 static constexpr size_t ObjectHeaderSize() 138 { 139 return sizeof(ObjectHeader); 140 } 141 GetClassOffset()142 static constexpr size_t GetClassOffset() 143 { 144 return MEMBER_OFFSET(ObjectHeader, classWord_); 145 } 146 147 // Mask to get class word from register: 148 // * 64-bit system, 64-bit class word: 0xFFFFFFFFFFFFFFFF 149 // * 64-bit system, 48-bit class word: 0x0000FFFFFFFFFFFF (external CMC GC) 150 // * 64-bit system, 32-bit class word: 0x00000000FFFFFFFF 151 // * 32-bit system, 32-bit class word: 0xFFFFFFFF 152 // * 32-bit system, 16-bit class word: 0x0000FFFF GetClassMask()153 static constexpr size_t GetClassMask() 154 { 155 #if defined(ARK_HYBRID) && defined(PANDA_TARGET_64) 156 return static_cast<size_t>((1ULL << 48ULL) - 1ULL); 157 #else 158 return std::numeric_limits<size_t>::max() >> (ClassHelper::POINTER_SIZE - OBJECT_POINTER_SIZE) * BITS_PER_BYTE; 159 #endif 160 } 161 GetMarkWordOffset()162 static constexpr size_t GetMarkWordOffset() 163 { 164 return MEMBER_OFFSET(ObjectHeader, markWord_); 165 } 166 167 // Garbage collection method 168 template <bool ATOMIC_FLAG = true> IsMarkedForGC()169 inline bool IsMarkedForGC() const 170 { 171 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 172 return GetMark().IsMarkedForGC(); 173 } 174 return AtomicGetMark().IsMarkedForGC(); 175 } 176 template <bool ATOMIC_FLAG = true> SetMarkedForGC()177 inline void SetMarkedForGC() 178 { 179 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 180 SetMark(GetMark().SetMarkedForGC()); 181 return; 182 } 183 bool res; 184 MarkWord word = AtomicGetMark(); 185 do { 186 res = AtomicSetMark<false>(word, word.SetMarkedForGC()); 187 } while (!res); 188 } 189 template <bool ATOMIC_FLAG = true> SetUnMarkedForGC()190 inline void SetUnMarkedForGC() 191 { 192 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 193 SetMark(GetMark().SetUnMarkedForGC()); 194 return; 195 } 196 bool res; 197 MarkWord word = AtomicGetMark(); 198 do { 199 res = AtomicSetMark<false>(word, word.SetUnMarkedForGC()); 200 } while (!res); 201 } IsForwarded()202 inline bool IsForwarded() const 203 { 204 return AtomicGetMark().GetState() == MarkWord::ObjectState::STATE_GC; 205 } 206 207 // Type test methods 208 inline bool IsInstance() const; 209 210 // Get field address in Class 211 inline void *FieldAddr(int offset) const; 212 213 template <bool STRONG = true> 214 bool AtomicSetMark(MarkWord &oldMarkWord, MarkWord newMarkWord, 215 std::memory_order memoryOrder = std::memory_order_seq_cst) 216 { 217 // This is the way to operate with casting MarkWordSize <-> MarkWord and atomics 218 auto ptr = reinterpret_cast<MarkWord *>(&markWord_); 219 auto atomicPtr = reinterpret_cast<std::atomic<MarkWord> *>(ptr); 220 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) 221 if constexpr (STRONG) { // NOLINT(bugprone-suspicious-semicolon) 222 // Atomic with parameterized order reason: memory order passed as argument 223 return atomicPtr->compare_exchange_strong(oldMarkWord, newMarkWord, memoryOrder); 224 } 225 // CAS weak may return false results, but is more efficient, use it only in loops 226 // Atomic with parameterized order reason: memory order passed as argument 227 return atomicPtr->compare_exchange_weak(oldMarkWord, newMarkWord, memoryOrder); 228 } 229 230 // Accessors to typical Class types 231 232 template <class T, bool IS_VOLATILE = false> 233 T GetFieldPrimitive(size_t offset) const; 234 235 template <class T, bool IS_VOLATILE = false> 236 void SetFieldPrimitive(size_t offset, T value); 237 238 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 239 ObjectHeader *GetFieldObject(int offset) const; 240 241 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 242 void SetFieldObject(size_t offset, ObjectHeader *value); 243 244 template <class T> 245 T GetFieldPrimitive(const Field &field) const; 246 247 template <class T> 248 void SetFieldPrimitive(const Field &field, T value); 249 250 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 251 ObjectHeader *GetFieldObject(const Field &field) const; 252 253 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 254 void SetFieldObject(const Field &field, ObjectHeader *value); 255 256 // Pass thread parameter to speed up interpreter 257 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 258 ObjectHeader *GetFieldObject(const ManagedThread *thread, const Field &field); 259 260 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 261 void SetFieldObject(const ManagedThread *thread, const Field &field, ObjectHeader *value); 262 263 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 264 void SetFieldObject(const ManagedThread *thread, size_t offset, ObjectHeader *value); 265 266 template <class T> 267 T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const; 268 269 template <class T> 270 void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 271 272 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 273 ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const; 274 275 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 276 void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 277 278 template <typename T> 279 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 280 281 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 282 bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 283 std::memory_order memoryOrder, bool strong); 284 285 template <typename T> 286 T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, 287 bool strong); 288 289 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 290 ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 291 std::memory_order memoryOrder, bool strong); 292 293 template <typename T> 294 T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 295 296 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 297 ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 298 299 template <typename T> 300 T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 301 302 template <typename T> 303 T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 304 305 template <typename T> 306 T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 307 308 template <typename T> 309 T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 310 311 /* 312 * Is the object is an instance of specified class. 313 * Object of type O is instance of type T if O is the same as T or is subtype of T. For arrays T should be a root 314 * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements. 315 */ 316 inline bool IsInstanceOf(const Class *klass) const; 317 318 // Verification methods 319 static void Verify(ObjectHeader *objectHeader); 320 321 static ObjectHeader *Create(BaseClass *klass); 322 static ObjectHeader *Create(ManagedThread *thread, BaseClass *klass); 323 324 static ObjectHeader *CreateNonMovable(BaseClass *klass); 325 326 static ObjectHeader *Clone(ObjectHeader *src); 327 328 static ObjectHeader *ShallowCopy(ObjectHeader *src); 329 330 size_t ObjectSize() const; 331 332 template <LangTypeT LANG> ObjectSize(BaseClass * baseKlass)333 size_t ObjectSize(BaseClass *baseKlass) const 334 { 335 if constexpr (LANG == LangTypeT::LANG_TYPE_DYNAMIC) { 336 return ObjectSizeDyn(baseKlass); 337 } else { 338 static_assert(LANG == LangTypeT::LANG_TYPE_STATIC); 339 return ObjectSizeStatic(baseKlass); 340 } 341 } 342 343 private: 344 uint32_t GetHashCodeMTSingle(); 345 uint32_t GetHashCodeMTMulti(); 346 size_t ObjectSizeDyn(BaseClass *baseKlass) const; 347 size_t ObjectSizeStatic(BaseClass *baseKlass) const; 348 349 // NOTE(ipetrov): ClassWord mask usage is temporary solution, in the future all classes will be allocated in 32-bit 350 // address space GetClassWord()351 ALWAYS_INLINE ClassHelper::ClassWordSize GetClassWord() const 352 { 353 return classWord_ & GetClassMask(); 354 } 355 356 #if defined(ARK_HYBRID) && defined(PANDA_TARGET_32) 357 MarkWord::MarkWordSize markWord_; 358 ClassHelper::ClassWordSize classWord_; 359 #else 360 ClassHelper::ClassWordSize classWord_; 361 MarkWord::MarkWordSize markWord_; 362 #endif 363 /** 364 * Allocates memory for the Object. No ctor is called. 365 * @param klass - class of Object 366 * @param non_movable - if true, object will be allocated in non-movable space 367 * @return pointer to the created Object 368 */ 369 static ObjectHeader *CreateObject(BaseClass *klass, bool nonMovable); 370 static ObjectHeader *CreateObject(ManagedThread *thread, BaseClass *klass, bool nonMovable); 371 }; 372 373 constexpr uint32_t OBJECT_HEADER_CLASS_OFFSET = 0U; 374 static_assert(OBJECT_HEADER_CLASS_OFFSET == ark::ObjectHeader::GetClassOffset()); 375 376 // NOLINTBEGIN(readability-identifier-naming) 377 template <class T> 378 using is_object = std::bool_constant<std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>>; 379 380 template <class T> 381 constexpr bool is_object_v = is_object<T>::value; 382 // NOLINTEND(readability-identifier-naming) 383 384 } // namespace ark 385 386 #endif // PANDA_RUNTIME_OBJECT_HEADER_H_ 387