• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
31 #ifndef PANDA_RUNTIME_INCLUDE_OBJECT_HEADER_H_
32 #define PANDA_RUNTIME_INCLUDE_OBJECT_HEADER_H_
33 
34 #include <atomic>
35 #include <ctime>
36 
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 static auto hash_seed = std::atomic<uint32_t>(LINEAR_SEED + std::time(nullptr));
49 
50 }  // namespace object_header_traits
51 
52 class BaseClass;
53 class Class;
54 class Field;
55 class ManagedThread;
56 
57 class 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 mark_word)65     inline void SetMark(volatile MarkWord mark_word)
66     {
67         markWord_ = mark_word.Value();
68     }
69 
AtomicGetMark()70     inline MarkWord AtomicGetMark() const
71     {
72         auto ptr = const_cast<MarkWord *>(reinterpret_cast<const MarkWord *>(&markWord_));
73         auto atomic_ptr = reinterpret_cast<std::atomic<MarkWord> *>(ptr);
74         return atomic_ptr->load();
75     }
76 
SetClass(BaseClass * klass)77     inline void SetClass(BaseClass *klass)
78     {
79         static_assert(sizeof(ClassHelper::classWordSize) == sizeof(object_pointer_type));
80         reinterpret_cast<std::atomic<ClassHelper::classWordSize> *>(&classWord_)
81             ->store(static_cast<ClassHelper::classWordSize>(ToObjPtrType(klass)), std::memory_order_release);
82         ASSERT(AtomicClassAddr<BaseClass>() == klass);
83     }
84 
85     template <typename T>
ClassAddr()86     inline T *ClassAddr() const
87     {
88         return AtomicClassAddr<T>();
89     }
90 
91     template <typename T>
AtomicClassAddr()92     inline T *AtomicClassAddr() const
93     {
94         auto ptr = const_cast<ClassHelper::classWordSize *>(&classWord_);
95         return reinterpret_cast<T *>(
96             reinterpret_cast<std::atomic<ClassHelper::classWordSize> *>(ptr)->load(std::memory_order_acquire));
97     }
98 
99     // Generate hash value for an object.
GenerateHashCode()100     static inline uint32_t GenerateHashCode()
101     {
102         uint32_t ex_val;
103         uint32_t n_val;
104         do {
105             ex_val = object_header_traits::hash_seed.load(std::memory_order_relaxed);
106             n_val = ex_val * object_header_traits::LINEAR_X + object_header_traits::LINEAR_Y;
107         } while (!object_header_traits::hash_seed.compare_exchange_weak(ex_val, n_val, std::memory_order_relaxed) ||
108                  (ex_val & MarkWord::HASH_MASK) == 0);
109         return ex_val & MarkWord::HASH_MASK;
110     }
111 
112     // Get Hash value for an object.
113     uint32_t GetHashCode();
114     uint32_t GetHashCodeFromMonitor(Monitor *monitor_p);
115 
116     // Size of object header
ObjectHeaderSize()117     static constexpr int ObjectHeaderSize()
118     {
119         return sizeof(ObjectHeader);
120     }
121 
GetClassOffset()122     static constexpr size_t GetClassOffset()
123     {
124         return MEMBER_OFFSET(ObjectHeader, classWord_);
125     }
126 
GetMarkWordOffset()127     static constexpr size_t GetMarkWordOffset()
128     {
129         return MEMBER_OFFSET(ObjectHeader, markWord_);
130     }
131 
132     // Garbage collection method
133     template <bool atomic_flag = true>
IsMarkedForGC()134     inline bool IsMarkedForGC() const
135     {
136         if constexpr (!atomic_flag) {  // NOLINTNEXTLINE(readability-braces-around-statements)
137             return GetMark().IsMarkedForGC();
138         }
139         return AtomicGetMark().IsMarkedForGC();
140     }
141     template <bool atomic_flag = true>
SetMarkedForGC()142     inline void SetMarkedForGC()
143     {
144         if constexpr (!atomic_flag) {  // NOLINTNEXTLINE(readability-braces-around-statements)
145             SetMark(GetMark().SetMarkedForGC());
146             return;
147         }
148         bool res;
149         do {
150             MarkWord word = AtomicGetMark();
151             res = AtomicSetMark(word, word.SetMarkedForGC());
152         } while (!res);
153     }
154     template <bool atomic_flag = true>
SetUnMarkedForGC()155     inline void SetUnMarkedForGC()
156     {
157         if constexpr (!atomic_flag) {  // NOLINTNEXTLINE(readability-braces-around-statements)
158             SetMark(GetMark().SetUnMarkedForGC());
159             return;
160         }
161         bool res;
162         do {
163             MarkWord word = AtomicGetMark();
164             res = AtomicSetMark(word, word.SetUnMarkedForGC());
165         } while (!res);
166     }
IsForwarded()167     inline bool IsForwarded() const
168     {
169         return AtomicGetMark().GetState() == MarkWord::ObjectState::STATE_GC;
170     }
171 
172     // Type test methods
173     inline bool IsInstance() const;
174 
175     // Get field address in Class
176     inline void *FieldAddr(int offset) const;
177 
178     bool AtomicSetMark(MarkWord old_mark_word, MarkWord new_mark_word);
179 
180     // Accessors to typical Class types
181     template <class T, bool is_volatile = false>
182     T GetFieldPrimitive(size_t offset) const;
183 
184     template <class T, bool is_volatile = false>
185     void SetFieldPrimitive(size_t offset, T value);
186 
187     template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false>
188     ObjectHeader *GetFieldObject(int offset) const;
189 
190     template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false>
191     void SetFieldObject(size_t offset, ObjectHeader *value);
192 
193     template <class T>
194     T GetFieldPrimitive(const Field &field) const;
195 
196     template <class T>
197     void SetFieldPrimitive(const Field &field, T value);
198 
199     template <bool need_read_barrier = true, bool is_dyn = false>
200     ObjectHeader *GetFieldObject(const Field &field) const;
201 
202     template <bool need_write_barrier = true, bool is_dyn = false>
203     void SetFieldObject(const Field &field, ObjectHeader *value);
204 
205     // Pass thread parameter to speed up interpreter
206     template <bool need_read_barrier = true, bool is_dyn = false>
207     ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field);
208 
209     template <bool need_write_barrier = true, bool is_dyn = false>
210     void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value);
211 
212     template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false>
213     void SetFieldObject(ManagedThread *thread, size_t offset, ObjectHeader *value);
214 
215     template <class T>
216     T GetFieldPrimitive(size_t offset, std::memory_order memory_order) const;
217 
218     template <class T>
219     void SetFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
220 
221     template <bool need_read_barrier = true, bool is_dyn = false>
222     ObjectHeader *GetFieldObject(size_t offset, std::memory_order memory_order) const;
223 
224     template <bool need_write_barrier = true, bool is_dyn = false>
225     void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
226 
227     template <typename T>
228     bool CompareAndSetFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
229                                      bool strong);
230 
231     template <bool need_write_barrier = true, bool is_dyn = false>
232     bool CompareAndSetFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
233                                   std::memory_order memory_order, bool strong);
234 
235     template <typename T>
236     T CompareAndExchangeFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
237                                        bool strong);
238 
239     template <bool need_write_barrier = true, bool is_dyn = false>
240     ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
241                                                 std::memory_order memory_order, bool strong);
242 
243     template <typename T>
244     T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
245 
246     template <bool need_write_barrier = true, bool is_dyn = false>
247     ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
248 
249     template <typename T>
250     T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
251 
252     template <typename T>
253     T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
254 
255     template <typename T>
256     T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
257 
258     template <typename T>
259     T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memory_order);
260 
261     /*
262      * Is the object is an instance of specified class.
263      * 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
264      * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements.
265      */
266     inline bool IsInstanceOf(Class *klass);
267 
268     // Verification methods
269     static void Verify(ObjectHeader *object_header);
270 
271     static ObjectHeader *Create(BaseClass *klass);
272 
273     static ObjectHeader *CreateNonMovable(BaseClass *klass);
274 
275     static ObjectHeader *Clone(ObjectHeader *src);
276 
277     static ObjectHeader *ShallowCopy(ObjectHeader *src);
278 
279     size_t ObjectSize() const;
280 
281 private:
282     MarkWord::markWordSize markWord_;
283     ClassHelper::classWordSize classWord_;
284 
285     /**
286      * Allocates memory for the Object. No ctor is called.
287      * @param klass - class of Object
288      * @param non_movable - if true, object will be allocated in non-movable space
289      * @return pointer to the created Object
290      */
291     static ObjectHeader *CreateObject(BaseClass *klass, bool non_movable);
292 };
293 
294 constexpr uint32_t OBJECT_HEADER_CLASS_OFFSET = 4U;
295 static_assert(OBJECT_HEADER_CLASS_OFFSET == panda::ObjectHeader::GetClassOffset());
296 
297 }  // namespace panda
298 
299 #endif  // PANDA_RUNTIME_INCLUDE_OBJECT_HEADER_H_
300