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/include/class_helper.h" 37 #include "runtime/mark_word.h" 38 39 namespace panda { 40 41 namespace object_header_traits { 42 43 constexpr const uint32_t LINEAR_X = 1103515245U; 44 constexpr const uint32_t LINEAR_Y = 12345U; 45 constexpr const uint32_t LINEAR_SEED = 987654321U; 46 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 47 static auto hash_seed = std::atomic<uint32_t>(LINEAR_SEED + std::time(nullptr)); 48 49 } // namespace object_header_traits 50 51 class BaseClass; 52 class Class; 53 class Field; 54 class ManagedThread; 55 56 class ObjectHeader { 57 public: 58 // Simple getters and setters for Class and Mark words. 59 // Use it only in single thread GetMark()60 inline MarkWord GetMark() const 61 { 62 return *(const_cast<MarkWord *>(reinterpret_cast<const MarkWord *>(&markWord_))); 63 } SetMark(volatile MarkWord mark_word)64 inline void SetMark(volatile MarkWord mark_word) 65 { 66 markWord_ = mark_word.Value(); 67 } 68 AtomicGetMark()69 inline MarkWord AtomicGetMark() const 70 { 71 auto ptr = const_cast<MarkWord *>(reinterpret_cast<const MarkWord *>(&markWord_)); 72 auto atomic_ptr = reinterpret_cast<std::atomic<MarkWord> *>(ptr); 73 // Atomic with seq_cst order reason: data race with markWord_ with requirement for sequentially consistent order 74 // where threads observe all modifications in the same order 75 return atomic_ptr->load(std::memory_order_seq_cst); 76 } 77 SetClass(BaseClass * klass)78 inline void SetClass(BaseClass *klass) 79 { 80 static_assert(sizeof(ClassHelper::classWordSize) == sizeof(object_pointer_type)); 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(AtomicClassAddr<BaseClass>() == klass); 86 } 87 88 template <typename T> ClassAddr()89 inline T *ClassAddr() const 90 { 91 return AtomicClassAddr<T>(); 92 } 93 94 template <typename T> AtomicClassAddr()95 inline T *AtomicClassAddr() const 96 { 97 auto ptr = const_cast<ClassHelper::classWordSize *>(&classWord_); 98 // Atomic with acquire order reason: data race with classWord_ with dependecies on reads after the load which 99 // should become visible 100 return reinterpret_cast<T *>( 101 reinterpret_cast<std::atomic<ClassHelper::classWordSize> *>(ptr)->load(std::memory_order_acquire)); 102 } 103 104 // Generate hash value for an object. GenerateHashCode()105 static inline uint32_t GenerateHashCode() 106 { 107 uint32_t ex_val; 108 uint32_t n_val; 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 ex_val = object_header_traits::hash_seed.load(std::memory_order_relaxed); 113 n_val = ex_val * object_header_traits::LINEAR_X + object_header_traits::LINEAR_Y; 114 } while (!object_header_traits::hash_seed.compare_exchange_weak(ex_val, n_val, std::memory_order_relaxed) || 115 (ex_val & MarkWord::HASH_MASK) == 0); 116 return ex_val & MarkWord::HASH_MASK; 117 } 118 119 // Get Hash value for an object. 120 template <MTModeT MTMode> 121 uint32_t GetHashCode(); 122 uint32_t GetHashCodeFromMonitor(Monitor *monitor_p); 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 do { 158 MarkWord word = AtomicGetMark(); 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 do { 171 MarkWord word = AtomicGetMark(); 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> AtomicSetMark(MarkWord old_mark_word,MarkWord new_mark_word)187 bool AtomicSetMark(MarkWord old_mark_word, MarkWord new_mark_word) 188 { 189 // This is the way to operate with casting MarkWordSize <-> MarkWord and atomics 190 auto ptr = reinterpret_cast<MarkWord *>(&markWord_); 191 auto atomic_ptr = reinterpret_cast<std::atomic<MarkWord> *>(ptr); 192 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) 193 if constexpr (strong) { // NOLINT(bugprone-suspicious-semicolon) 194 return atomic_ptr->compare_exchange_strong(old_mark_word, new_mark_word); 195 } 196 // CAS weak may return false results, but is more efficient, use it only in loops 197 return atomic_ptr->compare_exchange_weak(old_mark_word, new_mark_word); 198 } 199 200 // Accessors to typical Class types 201 202 template <class T, bool is_volatile = false> 203 T GetFieldPrimitive(size_t offset) const; 204 205 template <class T, bool is_volatile = false> 206 void SetFieldPrimitive(size_t offset, T value); 207 208 template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false> 209 ObjectHeader *GetFieldObject(int offset) const; 210 211 template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false> 212 void SetFieldObject(size_t offset, ObjectHeader *value); 213 214 template <class T> 215 T GetFieldPrimitive(const Field &field) const; 216 217 template <class T> 218 void SetFieldPrimitive(const Field &field, T value); 219 220 template <bool need_read_barrier = true, bool is_dyn = false> 221 ObjectHeader *GetFieldObject(const Field &field) const; 222 223 template <bool need_write_barrier = true, bool is_dyn = false> 224 void SetFieldObject(const Field &field, ObjectHeader *value); 225 226 // Pass thread parameter to speed up interpreter 227 template <bool need_read_barrier = true, bool is_dyn = false> 228 ObjectHeader *GetFieldObject(const ManagedThread *thread, const Field &field); 229 230 template <bool need_write_barrier = true, bool is_dyn = false> 231 void SetFieldObject(const ManagedThread *thread, const Field &field, ObjectHeader *value); 232 233 template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false> 234 void SetFieldObject(const ManagedThread *thread, size_t offset, ObjectHeader *value); 235 236 template <class T> 237 T GetFieldPrimitive(size_t offset, std::memory_order memory_order) const; 238 239 template <class T> 240 void SetFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 241 242 template <bool need_read_barrier = true, bool is_dyn = false> 243 ObjectHeader *GetFieldObject(size_t offset, std::memory_order memory_order) const; 244 245 template <bool need_write_barrier = true, bool is_dyn = false> 246 void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 247 248 template <typename T> 249 bool CompareAndSetFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, 250 bool strong); 251 252 template <bool need_write_barrier = true, bool is_dyn = false> 253 bool CompareAndSetFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 254 std::memory_order memory_order, bool strong); 255 256 template <typename T> 257 T CompareAndExchangeFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, 258 bool strong); 259 260 template <bool need_write_barrier = true, bool is_dyn = false> 261 ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 262 std::memory_order memory_order, bool strong); 263 264 template <typename T> 265 T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 266 267 template <bool need_write_barrier = true, bool is_dyn = false> 268 ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 269 270 template <typename T> 271 T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 272 273 template <typename T> 274 T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 275 276 template <typename T> 277 T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 278 279 template <typename T> 280 T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memory_order); 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 *object_header); 291 292 static ObjectHeader *Create(BaseClass *klass); 293 294 static ObjectHeader *CreateNonMovable(BaseClass *klass); 295 296 static ObjectHeader *Clone(ObjectHeader *src); 297 298 static ObjectHeader *ShallowCopy(ObjectHeader *src); 299 300 size_t ObjectSize() const; 301 302 private: 303 uint32_t GetHashCodeMTSingle(); 304 uint32_t GetHashCodeMTMulti(); 305 306 MarkWord::markWordSize markWord_; 307 ClassHelper::classWordSize classWord_; 308 309 /** 310 * Allocates memory for the Object. No ctor is called. 311 * @param klass - class of Object 312 * @param non_movable - if true, object will be allocated in non-movable space 313 * @return pointer to the created Object 314 */ 315 static ObjectHeader *CreateObject(BaseClass *klass, bool non_movable); 316 }; 317 318 constexpr uint32_t OBJECT_HEADER_CLASS_OFFSET = 4U; 319 static_assert(OBJECT_HEADER_CLASS_OFFSET == panda::ObjectHeader::GetClassOffset()); 320 321 } // namespace panda 322 323 #endif // PANDA_RUNTIME_OBJECT_HEADER_H_ 324