• 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/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