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