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