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