• 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 // Our main goal is to have similar interface for two different platforms - high-end and low-end.
16 //
17 // 64 bits object header for high-end devices: (64 bits pointer)
18 // |--------------------------------------------------------------------------------------|--------------------|
19 // |                                   Object Header (128 bits)                           |        State       |
20 // |-----------------------------------------------------|--------------------------------|--------------------|
21 // |                 Mark Word (64 bits)                 |      Class Word (64 bits)      |                    |
22 // |-----------------------------------------------------|--------------------------------|--------------------|
23 // | state:00 | RB:1 | GC:1 |        nothing:60          |     OOP to metadata object     |       Unlock       |
24 // |----------|------------------------------------------|--------------------------------|--------------------|
25 // | state:00 | RB:1 | GC:1 |  tId:29   |   Lcount:31    |     OOP to metadata object     |  Lightweight Lock  |
26 // |----------|------------------------------------------|--------------------------------|--------------------|
27 // | state:01 | RB:1 | GC:1 |        Monitor:60          |     OOP to metadata object     |  Heavyweight Lock  |
28 // |----------|------------------------------------------|--------------------------------|--------------------|
29 // | state:10 | RB:1 | GC:1 |          Hash:60           |     OOP to metadata object     |       Hashed       |
30 // |----------|------------------------------------------|--------------------------------|--------------------|
31 // | state:11 |           Forwarding address:62          |     OOP to metadata object     |         GC         |
32 // |-----------------------------------------------------|--------------------------------|--------------------|
33 //
34 // 64 bits object header for high-end devices: (32 bits pointer)
35 // |--------------------------------------------------------------------------------------|--------------------|
36 // |                                   Object Header (64 bits)                            |        State       |
37 // |-----------------------------------------------------|--------------------------------|--------------------|
38 // |                 Mark Word (32 bits)                 |      Class Word (32 bits)      |                    |
39 // |-----------------------------------------------------|--------------------------------|--------------------|
40 // | state:00 | RB:1 | GC:1 |        nothing:28          |     OOP to metadata object     |       Unlock       |
41 // |----------|------------------------------------------|--------------------------------|--------------------|
42 // | state:00 | RB:1 | GC:1 |  tId:13   |   Lcount:15    |     OOP to metadata object     |  Lightweight Lock  |
43 // |----------|------------------------------------------|--------------------------------|--------------------|
44 // | state:01 | RB:1 | GC:1 |        Monitor:28          |     OOP to metadata object     |  Heavyweight Lock  |
45 // |----------|------------------------------------------|--------------------------------|--------------------|
46 // | state:10 | RB:1 | GC:1 |          Hash:28           |     OOP to metadata object     |       Hashed       |
47 // |----------|------------------------------------------|--------------------------------|--------------------|
48 // | state:11 |           Forwarding address:30          |     OOP to metadata object     |         GC         |
49 // |-----------------------------------------------------|--------------------------------|--------------------|
50 //
51 // 32 bits object header for low-end devices:
52 // |--------------------------------------------------------------------------------------|--------------------|
53 // |                                   Object Header (32 bits)                            |        State       |
54 // |-----------------------------------------------------|--------------------------------|--------------------|
55 // |                 Mark Word (16 bits)                 |      Class Word (16 bits)      |                    |
56 // |-----------------------------------------------------|--------------------------------|--------------------|
57 // | state:00 | RB:1 | GC:1 |        nothing:12          |     OOP to metadata object     |       Unlock       |
58 // |----------|------------------------------------------|--------------------------------|--------------------|
59 // | state:00 | RB:1 | GC:1 |  tId:7    |   Lcount:4     |     OOP to metadata object     |  Lightweight Lock  |
60 // |----------|------------------------------------------|-------------------------------|---------------------|
61 // | state:01 | RB:1 | GC:1 |        Monitor:12          |     OOP to metadata object     |  Heavyweight Lock  |
62 // |----------|------------------------------------------|--------------------------------|--------------------|
63 // | state:10 | RB:1 | GC:1 |          Hash:12           |     OOP to metadata object     |       Hashed       |
64 // |-----------------------------------------------------|--------------------------------|--------------------|
65 // | state:11 |         Forwarding address:14            |     OOP to metadata object     |         GC         |
66 // |-----------------------------------------------------|--------------------------------|--------------------|
67 #ifndef PANDA_RUNTIME_MARK_WORD_H_
68 #define PANDA_RUNTIME_MARK_WORD_H_
69 
70 #include <cstdint>
71 
72 #include "libpandabase/os/thread.h"
73 #include "libpandabase/utils/logger.h"
74 #include "runtime/monitor.h"
75 #include "runtime/object_header_config.h"
76 
77 namespace ark {
78 
79 // Small helper
80 template <class Config>
81 class MarkWordConfig {
82 public:
83     using MarkWordSize = typename Config::Size;
84     static constexpr MarkWordSize CONFIG_MARK_WORD_BIT_SIZE = Config::BITS;
85     static constexpr MarkWordSize CONFIG_LOCK_THREADID_SIZE = Config::LOCK_THREADID_SIZE;
86     static constexpr bool CONFIG_IS_HASH_IN_OBJ_HEADER = Config::IS_HASH_IN_OBJ_HEADER;
87     static constexpr MarkWordSize CONFIG_HASH_STATUS_SIZE = Config::IS_HASH_IN_OBJ_HEADER ? 0 : 1;
88 };
89 
90 // One of our main purpose is to create an common interface for both IoT and High-level Mark Word.
91 // That's why we should always operate with uint32_t and convert it into MarkWordSize if necessary.
92 
93 class MarkWord : private MarkWordConfig<MemoryModelConfig> {
94 public:
95     using MarkWordSize = typename MarkWordConfig::MarkWordSize;  // To be visible outside
96 
97     // Big enum with all useful masks and shifts
98     enum MarkWordRepresentation : MarkWordSize {
99         STATUS_SIZE = 2UL,
100         GC_STATUS_SIZE = 1UL,
101         RB_STATUS_SIZE = 1UL,
102         HASH_STATUS_SIZE = CONFIG_HASH_STATUS_SIZE,  // This parameter is used only in special memory model config
103         MONITOR_POINTER_SIZE =
104             CONFIG_MARK_WORD_BIT_SIZE - STATUS_SIZE - GC_STATUS_SIZE - RB_STATUS_SIZE - HASH_STATUS_SIZE,
105         // If we don't have Hash inside an object header, thisThread constant shouldn't be used
106         HASH_SIZE = (CONFIG_HASH_STATUS_SIZE != 0UL)
107                         ? 0UL
108                         : (CONFIG_MARK_WORD_BIT_SIZE - STATUS_SIZE - GC_STATUS_SIZE - RB_STATUS_SIZE),
109         FORWARDING_ADDRESS_SIZE = CONFIG_MARK_WORD_BIT_SIZE - STATUS_SIZE - HASH_STATUS_SIZE,
110 
111         // Unlocked state masks and shifts
112         UNLOCKED_STATE_SHIFT = 0U,
113         UNLOCKED_STATE_MASK = (1UL << MONITOR_POINTER_SIZE) - 1UL,
114         UNLOCKED_STATE_MASK_IN_PLACE = UNLOCKED_STATE_MASK << UNLOCKED_STATE_SHIFT,
115 
116         // Lightweight Lock state masks and shifts
117         LIGHT_LOCK_THREADID_SIZE = CONFIG_LOCK_THREADID_SIZE,
118         LIGHT_LOCK_LOCK_COUNT_SIZE = MONITOR_POINTER_SIZE - LIGHT_LOCK_THREADID_SIZE,
119 
120         LIGHT_LOCK_LOCK_COUNT_SHIFT = 0U,
121         LIGHT_LOCK_LOCK_COUNT_MASK = (1UL << LIGHT_LOCK_LOCK_COUNT_SIZE) - 1UL,
122         LIGHT_LOCK_LOCK_COUNT_MASK_IN_PLACE = LIGHT_LOCK_LOCK_COUNT_MASK << LIGHT_LOCK_LOCK_COUNT_SHIFT,
123         LIGHT_LOCK_LOCK_MAX_COUNT = LIGHT_LOCK_LOCK_COUNT_MASK,
124 
125         LIGHT_LOCK_THREADID_SHIFT = LIGHT_LOCK_LOCK_COUNT_SIZE,
126         LIGHT_LOCK_THREADID_MASK = (1UL << LIGHT_LOCK_THREADID_SIZE) - 1UL,
127         LIGHT_LOCK_THREADID_MASK_IN_PLACE = LIGHT_LOCK_THREADID_MASK << LIGHT_LOCK_THREADID_SHIFT,
128         LIGHT_LOCK_THREADID_MAX_COUNT = LIGHT_LOCK_THREADID_MASK,
129 
130         // Heavyweight Lock state masks and shifts
131         MONITOR_POINTER_SHIFT = 0U,
132         MONITOR_POINTER_MASK = (1UL << MONITOR_POINTER_SIZE) - 1UL,
133         MONITOR_POINTER_MASK_IN_PLACE = MONITOR_POINTER_MASK << MONITOR_POINTER_SHIFT,
134         MONITOR_POINTER_MAX_COUNT = MONITOR_POINTER_MASK,
135 
136         // Hash state masks and shifts
137         HASH_SHIFT = 0U,
138         HASH_MASK = (1UL << HASH_SIZE) - 1UL,
139         HASH_MASK_IN_PLACE = HASH_MASK << HASH_SHIFT,
140 
141         // Forwarding state masks and shifts
142         FORWARDING_ADDRESS_SHIFT = 0U,
143         FORWARDING_ADDRESS_MASK = (1UL << FORWARDING_ADDRESS_SIZE) - 1UL,
144         FORWARDING_ADDRESS_MASK_IN_PLACE = FORWARDING_ADDRESS_MASK << FORWARDING_ADDRESS_SHIFT,
145 
146         // Status bits masks and shifts
147         STATUS_SHIFT = CONFIG_MARK_WORD_BIT_SIZE - STATUS_SIZE,
148         STATUS_MASK = (1UL << STATUS_SIZE) - 1UL,
149         STATUS_MASK_IN_PLACE = STATUS_MASK << STATUS_SHIFT,
150 
151         // An object status variants
152         STATUS_UNLOCKED = 0UL,
153         STATUS_LIGHTWEIGHT_LOCK = 0UL,
154         STATUS_HEAVYWEIGHT_LOCK = 1UL,
155         STATUS_HASHED = 2UL,
156         STATUS_GC = 3UL,  // Or Forwarding state
157 
158         // Marked for GC bit masks and shifts
159         GC_STATUS_SHIFT = MONITOR_POINTER_SIZE,
160         GC_STATUS_MASK = (1UL << GC_STATUS_SIZE) - 1UL,
161         GC_STATUS_MASK_IN_PLACE = GC_STATUS_MASK << GC_STATUS_SHIFT,
162 
163         // Read barrier bit masks and shifts
164         RB_STATUS_SHIFT = GC_STATUS_SHIFT + GC_STATUS_SIZE,
165         RB_STATUS_MASK = (1UL << RB_STATUS_SIZE) - 1UL,
166         RB_STATUS_MASK_IN_PLACE = RB_STATUS_MASK << RB_STATUS_SHIFT,
167     };
168 
169     enum ObjectState {
170         STATE_UNLOCKED,
171         STATE_LIGHT_LOCKED,
172         STATE_HEAVY_LOCKED,
173         STATE_HASHED,
174         STATE_GC,
175     };
176 
177     /* Create MarkWord from different objects:
178      * (We can't change GC bit)
179      */
DecodeFromMonitor(Monitor::MonitorId monitor)180     MarkWord DecodeFromMonitor(Monitor::MonitorId monitor)
181     {
182         // Clear monitor and status bits
183         MarkWordSize temp = Value() & (~(MONITOR_POINTER_MASK_IN_PLACE | STATUS_MASK_IN_PLACE));
184         MarkWordSize monitorInPlace = (static_cast<MarkWordSize>(monitor) & MONITOR_POINTER_MASK)
185                                       << MONITOR_POINTER_SHIFT;
186         return MarkWord(temp | monitorInPlace | (STATUS_HEAVYWEIGHT_LOCK << STATUS_SHIFT));
187     }
188 
DecodeFromHash(uint32_t hash)189     PANDA_PUBLIC_API MarkWord DecodeFromHash(uint32_t hash)
190     {
191         return DecodeFromHashWide(static_cast<MarkWordSize>(hash));
192     }
193 
DecodeFromForwardingAddress(MarkWordSize forwardingAddress)194     MarkWord DecodeFromForwardingAddress(MarkWordSize forwardingAddress)
195     {
196         static_assert(sizeof(MarkWordSize) == OBJECT_POINTER_SIZE,
197                       "MarkWord has different size than OBJECT_POINTER_SIZE");
198 
199         // High bits of markword ar occupied by state, so address should be shitfted
200         // before it is stored into mark word
201         forwardingAddress = forwardingAddress >> STATUS_SIZE;
202 
203         ASSERT((forwardingAddress & FORWARDING_ADDRESS_MASK_IN_PLACE) == forwardingAddress);
204         return DecodeFromForwardingAddressField(forwardingAddress >> FORWARDING_ADDRESS_SHIFT);
205     }
206 
DecodeFromLightLock(os::thread::ThreadId threadId,uint32_t count)207     MarkWord DecodeFromLightLock(os::thread::ThreadId threadId, uint32_t count)
208     {
209         // Clear monitor and status bits
210         MarkWordSize temp =
211             Value() &
212             (~(LIGHT_LOCK_THREADID_MASK_IN_PLACE | LIGHT_LOCK_LOCK_COUNT_MASK_IN_PLACE | STATUS_MASK_IN_PLACE));
213         MarkWordSize lightlockThreadInPlace = (static_cast<MarkWordSize>(threadId) & LIGHT_LOCK_THREADID_MASK)
214                                               << LIGHT_LOCK_THREADID_SHIFT;
215         MarkWordSize lightlockLockCountInPlace = (static_cast<MarkWordSize>(count) & LIGHT_LOCK_LOCK_COUNT_MASK)
216                                                  << LIGHT_LOCK_LOCK_COUNT_SHIFT;
217         return MarkWord(temp | lightlockThreadInPlace | lightlockLockCountInPlace |
218                         (STATUS_LIGHTWEIGHT_LOCK << STATUS_SHIFT));
219     }
220 
DecodeFromUnlocked()221     MarkWord DecodeFromUnlocked()
222     {
223         // Clear monitor and status bits
224         MarkWordSize unlocked = Value() & (~(UNLOCKED_STATE_MASK_IN_PLACE | STATUS_MASK_IN_PLACE));
225         return MarkWord(unlocked | (STATUS_UNLOCKED << STATUS_SHIFT));
226     }
227 
IsMarkedForGC()228     bool IsMarkedForGC() const
229     {
230         return (Value() & GC_STATUS_MASK_IN_PLACE) != 0U;
231     }
232 
IsReadBarrierSet()233     bool IsReadBarrierSet() const
234     {
235         return (Value() & RB_STATUS_MASK_IN_PLACE) != 0U;
236     }
237 
238     bool IsHashed() const;
239 
SetMarkedForGC()240     MarkWord SetMarkedForGC()
241     {
242         return MarkWord((Value() & (~GC_STATUS_MASK_IN_PLACE)) | GC_STATUS_MASK_IN_PLACE);
243     }
244 
SetUnMarkedForGC()245     MarkWord SetUnMarkedForGC()
246     {
247         return MarkWord(Value() & (~GC_STATUS_MASK_IN_PLACE));
248     }
249 
SetReadBarrier()250     MarkWord SetReadBarrier()
251     {
252         return MarkWord((Value() & (~RB_STATUS_MASK_IN_PLACE)) | RB_STATUS_MASK_IN_PLACE);
253     }
254 
ClearReadBarrier()255     MarkWord ClearReadBarrier()
256     {
257         return MarkWord(Value() & (~RB_STATUS_MASK_IN_PLACE));
258     }
259 
GetState()260     ObjectState GetState() const
261     {
262         switch ((Value() >> STATUS_SHIFT) & STATUS_MASK) {
263             case STATUS_HEAVYWEIGHT_LOCK:
264                 return STATE_HEAVY_LOCKED;
265             case STATUS_HASHED:
266                 return STATE_HASHED;
267             case STATUS_GC:
268                 return STATE_GC;
269             case STATUS_UNLOCKED:
270                 // We should distinguish between Unlocked and Lightweight Lock states:
271                 return ((Value() & UNLOCKED_STATE_MASK_IN_PLACE) == 0U) ? STATE_UNLOCKED : STATE_LIGHT_LOCKED;
272             default:
273                 // NOTE(aemelenko): Make it more user-friendly
274                 LOG(DEBUG, RUNTIME) << "Undefined object state";
275                 return STATE_GC;
276         }
277     }
278 
GetThreadId()279     os::thread::ThreadId GetThreadId() const
280     {
281         LOG_IF(GetState() != STATE_LIGHT_LOCKED, DEBUG, RUNTIME) << "Wrong State";
282         return static_cast<os::thread::ThreadId>((Value() >> LIGHT_LOCK_THREADID_SHIFT) & LIGHT_LOCK_THREADID_MASK);
283     }
284 
GetLockCount()285     uint32_t GetLockCount() const
286     {
287         LOG_IF(GetState() != STATE_LIGHT_LOCKED, DEBUG, RUNTIME) << "Wrong State";
288         return static_cast<uint32_t>((Value() >> LIGHT_LOCK_LOCK_COUNT_SHIFT) & LIGHT_LOCK_LOCK_COUNT_MASK);
289     }
290 
291     PANDA_PUBLIC_API uint32_t GetHash() const;
292 
GetForwardingAddress()293     MarkWordSize GetForwardingAddress() const
294     {
295         LOG_IF(GetState() != STATE_GC, DEBUG, RUNTIME) << "Wrong State";
296 
297         // High bits of markword ar occupied by state, so address should be shitfted
298         // before it is loaded from mark word
299         return GetForwardingAddressField() << FORWARDING_ADDRESS_SHIFT << STATUS_SIZE;
300     }
301 
IsForwarded()302     bool IsForwarded() const
303     {
304         return GetState() == MarkWord::ObjectState::STATE_GC;
305     }
306 
GetMonitorId()307     Monitor::MonitorId GetMonitorId() const
308     {
309         LOG_IF(GetState() != STATE_HEAVY_LOCKED, DEBUG, RUNTIME) << "Wrong State";
310         return static_cast<Monitor::MonitorId>((Value() >> MONITOR_POINTER_SHIFT) & MONITOR_POINTER_MASK);
311     }
312 
GetValue()313     MarkWordSize GetValue() const
314     {
315         return value_;
316     }
317 
318     ~MarkWord() = default;
319 
320     DEFAULT_COPY_SEMANTIC(MarkWord);
321     DEFAULT_MOVE_SEMANTIC(MarkWord);
322 
323     friend class MarkWordTest;
324     friend class ObjectHeader;
325 
326 protected:
DecodeFromHashWide(MarkWordSize hash)327     MarkWord DecodeFromHashWide(MarkWordSize hash)
328     {
329         // Clear hash and status bits
330         MarkWordSize temp = Value() & (~(HASH_MASK_IN_PLACE | STATUS_MASK_IN_PLACE));
331         MarkWordSize hashInPlace = (hash & HASH_MASK) << HASH_SHIFT;
332         return MarkWord(temp | hashInPlace | (STATUS_HASHED << STATUS_SHIFT));
333     }
334 
335 private:
336     // The only field in MarkWord class.
337     MarkWordSize value_ {0};
338 
Value()339     MarkWordSize Value() volatile const
340     {
341         return value_;
342     }
343 
MarkWord(MarkWordSize value)344     explicit MarkWord(MarkWordSize value) noexcept : value_(value) {}
345 
346     MarkWord() noexcept = default;
347 
348     bool operator==(const MarkWord &other) const
349     {
350         return Value() == other.Value();
351     }
352 
353     /**
354      * @param forwarding_address - address shifted by FORWARDING_ADDRESS_SHIFT
355      * @return MarkWord with encoded forwarding_address and GC state
356      */
DecodeFromForwardingAddressField(MarkWordSize forwardingAddress)357     MarkWord DecodeFromForwardingAddressField(MarkWordSize forwardingAddress)
358     {
359         ASSERT(forwardingAddress <= ((std::numeric_limits<MarkWordSize>::max()) >> FORWARDING_ADDRESS_SHIFT));
360         // Forwardind address consumes all bits except status. We don't need to save GC state
361         MarkWordSize forwardingAddressInPlace = (forwardingAddress & FORWARDING_ADDRESS_MASK)
362                                                 << FORWARDING_ADDRESS_SHIFT;
363         return MarkWord(forwardingAddressInPlace | (STATUS_GC << STATUS_SHIFT));
364     }
365 
366     /// @return pointer shifted by FORWARDING_ADDRESS_SHIFT
GetForwardingAddressField()367     MarkWordSize GetForwardingAddressField() const
368     {
369         LOG_IF(GetState() != STATE_GC, DEBUG, RUNTIME) << "Wrong State";
370         return (Value() >> FORWARDING_ADDRESS_SHIFT) & FORWARDING_ADDRESS_MASK;
371     }
372 };
373 
374 }  // namespace ark
375 
376 #endif  // PANDA_RUNTIME_MARK_WORD_H_
377