• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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