1 /** 2 * Copyright (c) 2021-2024 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 // Atomic with release order reason: data race with classWord_ with dependecies on writes before the store which 82 // should become visible acquire 83 reinterpret_cast<std::atomic<ClassHelper::ClassWordSize> *>(&classWord_) 84 ->store(static_cast<ClassHelper::ClassWordSize>(ToObjPtrType(klass)), std::memory_order_release); 85 ASSERT(ClassAddr<BaseClass>() == klass); 86 } 87 88 template <typename T> ClassAddr()89 inline T *ClassAddr() const 90 { 91 auto ptr = const_cast<ClassHelper::ClassWordSize *>(&classWord_); 92 // Atomic with acquire order reason: data race with classWord_ with dependecies on reads after the load which 93 // should become visible 94 return reinterpret_cast<T *>( 95 reinterpret_cast<std::atomic<ClassHelper::ClassWordSize> *>(ptr)->load(std::memory_order_acquire)); 96 } 97 98 template <typename T> NotAtomicClassAddr()99 inline T *NotAtomicClassAddr() const 100 { 101 return reinterpret_cast<T *>(*const_cast<ClassHelper::ClassWordSize *>(&classWord_)); 102 } 103 104 // Generate hash value for an object. GenerateHashCode()105 static inline uint32_t GenerateHashCode() 106 { 107 uint32_t exVal; 108 uint32_t nVal; 109 do { 110 // Atomic with relaxed order reason: data race with hash_seed with no synchronization or ordering 111 // constraints imposed on other reads or writes 112 exVal = object_header_traits::g_hashSeed.load(std::memory_order_relaxed); 113 nVal = exVal * object_header_traits::LINEAR_X + object_header_traits::LINEAR_Y; 114 } while (!object_header_traits::g_hashSeed.compare_exchange_weak(exVal, nVal, std::memory_order_relaxed) || 115 (exVal & MarkWord::HASH_MASK) == 0); 116 return exVal & MarkWord::HASH_MASK; 117 } 118 119 // Get Hash value for an object. 120 template <MTModeT MT_MODE> 121 uint32_t GetHashCode(); 122 uint32_t GetHashCodeFromMonitor(Monitor *monitorP); 123 124 // Size of object header ObjectHeaderSize()125 static constexpr size_t ObjectHeaderSize() 126 { 127 return sizeof(ObjectHeader); 128 } 129 GetClassOffset()130 static constexpr size_t GetClassOffset() 131 { 132 return MEMBER_OFFSET(ObjectHeader, classWord_); 133 } 134 GetMarkWordOffset()135 static constexpr size_t GetMarkWordOffset() 136 { 137 return MEMBER_OFFSET(ObjectHeader, markWord_); 138 } 139 140 // Garbage collection method 141 template <bool ATOMIC_FLAG = true> IsMarkedForGC()142 inline bool IsMarkedForGC() const 143 { 144 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 145 return GetMark().IsMarkedForGC(); 146 } 147 return AtomicGetMark().IsMarkedForGC(); 148 } 149 template <bool ATOMIC_FLAG = true> SetMarkedForGC()150 inline void SetMarkedForGC() 151 { 152 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 153 SetMark(GetMark().SetMarkedForGC()); 154 return; 155 } 156 bool res; 157 MarkWord word = AtomicGetMark(); 158 do { 159 res = AtomicSetMark<false>(word, word.SetMarkedForGC()); 160 } while (!res); 161 } 162 template <bool ATOMIC_FLAG = true> SetUnMarkedForGC()163 inline void SetUnMarkedForGC() 164 { 165 if constexpr (!ATOMIC_FLAG) { // NOLINTNEXTLINE(readability-braces-around-statements) 166 SetMark(GetMark().SetUnMarkedForGC()); 167 return; 168 } 169 bool res; 170 MarkWord word = AtomicGetMark(); 171 do { 172 res = AtomicSetMark<false>(word, word.SetUnMarkedForGC()); 173 } while (!res); 174 } IsForwarded()175 inline bool IsForwarded() const 176 { 177 return AtomicGetMark().GetState() == MarkWord::ObjectState::STATE_GC; 178 } 179 180 // Type test methods 181 inline bool IsInstance() const; 182 183 // Get field address in Class 184 inline void *FieldAddr(int offset) const; 185 186 template <bool STRONG = true> 187 bool AtomicSetMark(MarkWord &oldMarkWord, MarkWord newMarkWord, 188 std::memory_order memoryOrder = std::memory_order_seq_cst) 189 { 190 // This is the way to operate with casting MarkWordSize <-> MarkWord and atomics 191 auto ptr = reinterpret_cast<MarkWord *>(&markWord_); 192 auto atomicPtr = reinterpret_cast<std::atomic<MarkWord> *>(ptr); 193 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) 194 if constexpr (STRONG) { // NOLINT(bugprone-suspicious-semicolon) 195 // Atomic with parameterized order reason: memory order passed as argument 196 return atomicPtr->compare_exchange_strong(oldMarkWord, newMarkWord, memoryOrder); 197 } 198 // CAS weak may return false results, but is more efficient, use it only in loops 199 // Atomic with parameterized order reason: memory order passed as argument 200 return atomicPtr->compare_exchange_weak(oldMarkWord, newMarkWord, memoryOrder); 201 } 202 203 // Accessors to typical Class types 204 205 template <class T, bool IS_VOLATILE = false> 206 T GetFieldPrimitive(size_t offset) const; 207 208 template <class T, bool IS_VOLATILE = false> 209 void SetFieldPrimitive(size_t offset, T value); 210 211 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 212 ObjectHeader *GetFieldObject(int offset) const; 213 214 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 215 void SetFieldObject(size_t offset, ObjectHeader *value); 216 217 template <class T> 218 T GetFieldPrimitive(const Field &field) const; 219 220 template <class T> 221 void SetFieldPrimitive(const Field &field, T value); 222 223 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 224 ObjectHeader *GetFieldObject(const Field &field) const; 225 226 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 227 void SetFieldObject(const Field &field, ObjectHeader *value); 228 229 // Pass thread parameter to speed up interpreter 230 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 231 ObjectHeader *GetFieldObject(const ManagedThread *thread, const Field &field); 232 233 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 234 void SetFieldObject(const ManagedThread *thread, const Field &field, ObjectHeader *value); 235 236 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 237 void SetFieldObject(const ManagedThread *thread, size_t offset, ObjectHeader *value); 238 239 template <class T> 240 T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const; 241 242 template <class T> 243 void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 244 245 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 246 ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const; 247 248 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 249 void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 250 251 template <typename T> 252 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 253 254 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 255 bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 256 std::memory_order memoryOrder, bool strong); 257 258 template <typename T> 259 T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, 260 bool strong); 261 262 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 263 ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 264 std::memory_order memoryOrder, bool strong); 265 266 template <typename T> 267 T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 268 269 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 270 ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 271 272 template <typename T> 273 T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 274 275 template <typename T> 276 T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 277 278 template <typename T> 279 T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 280 281 template <typename T> 282 T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 283 284 /* 285 * Is the object is an instance of specified class. 286 * 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 287 * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements. 288 */ 289 inline bool IsInstanceOf(const Class *klass) const; 290 291 // Verification methods 292 static void Verify(ObjectHeader *objectHeader); 293 294 static ObjectHeader *Create(BaseClass *klass); 295 static ObjectHeader *Create(ManagedThread *thread, BaseClass *klass); 296 297 static ObjectHeader *CreateNonMovable(BaseClass *klass); 298 299 static ObjectHeader *Clone(ObjectHeader *src); 300 301 static ObjectHeader *ShallowCopy(ObjectHeader *src); 302 303 size_t ObjectSize() const; 304 305 template <LangTypeT LANG> ObjectSize(BaseClass * baseKlass)306 size_t ObjectSize(BaseClass *baseKlass) const 307 { 308 if constexpr (LANG == LangTypeT::LANG_TYPE_DYNAMIC) { 309 return ObjectSizeDyn(baseKlass); 310 } else { 311 static_assert(LANG == LangTypeT::LANG_TYPE_STATIC); 312 return ObjectSizeStatic(baseKlass); 313 } 314 } 315 316 private: 317 uint32_t GetHashCodeMTSingle(); 318 uint32_t GetHashCodeMTMulti(); 319 size_t ObjectSizeDyn(BaseClass *baseKlass) const; 320 size_t ObjectSizeStatic(BaseClass *baseKlass) const; 321 MarkWord::MarkWordSize markWord_; 322 ClassHelper::ClassWordSize classWord_; 323 324 /** 325 * Allocates memory for the Object. No ctor is called. 326 * @param klass - class of Object 327 * @param non_movable - if true, object will be allocated in non-movable space 328 * @return pointer to the created Object 329 */ 330 static ObjectHeader *CreateObject(BaseClass *klass, bool nonMovable); 331 static ObjectHeader *CreateObject(ManagedThread *thread, BaseClass *klass, bool nonMovable); 332 }; 333 334 constexpr uint32_t OBJECT_HEADER_CLASS_OFFSET = 4U; 335 static_assert(OBJECT_HEADER_CLASS_OFFSET == ark::ObjectHeader::GetClassOffset()); 336 337 } // namespace ark 338 339 #endif // PANDA_RUNTIME_OBJECT_HEADER_H_ 340