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