• 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 // 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 monitor_in_place = (static_cast<markWordSize>(monitor) & MONITOR_POINTER_MASK)
205                                         << MONITOR_POINTER_SHIFT;
206         return MarkWord(temp | monitor_in_place | (STATUS_HEAVYWEIGHT_LOCK << STATUS_SHIFT));
207     }
208 
209     MarkWord DecodeFromHash(uint32_t hash);
210 
DecodeFromForwardingAddress(markWordSize forwarding_address)211     MarkWord DecodeFromForwardingAddress(markWordSize forwarding_address)
212     {
213         static_assert(sizeof(markWordSize) == OBJECT_POINTER_SIZE,
214                       "MarkWord has different size than OBJECT_POINTER_SIZE");
215         ASSERT((forwarding_address & FORWARDING_ADDRESS_MASK_IN_PLACE) == forwarding_address);
216         return DecodeFromForwardingAddressField(forwarding_address >> FORWARDING_ADDRESS_SHIFT);
217     }
218 
DecodeFromLightLock(os::thread::ThreadId thread_id,uint32_t count)219     MarkWord DecodeFromLightLock(os::thread::ThreadId thread_id, 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 lightlock_thread_in_place = (static_cast<markWordSize>(thread_id) & LIGHT_LOCK_THREADID_MASK)
226                                                  << LIGHT_LOCK_THREADID_SHIFT;
227         markWordSize lightlock_lock_count_in_place = (static_cast<markWordSize>(count) & LIGHT_LOCK_LOCK_COUNT_MASK)
228                                                      << LIGHT_LOCK_LOCK_COUNT_SHIFT;
229         return MarkWord(temp | lightlock_thread_in_place | lightlock_lock_count_in_place |
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                 LOG(DEBUG, RUNTIME) << "Undefined object state";
288                 return STATE_GC;
289         }
290     }
291 
GetThreadId()292     os::thread::ThreadId GetThreadId() const
293     {
294         LOG_IF(GetState() != STATE_LIGHT_LOCKED, DEBUG, RUNTIME) << "Wrong State";
295         return static_cast<os::thread::ThreadId>((Value() >> LIGHT_LOCK_THREADID_SHIFT) & LIGHT_LOCK_THREADID_MASK);
296     }
297 
GetLockCount()298     uint32_t GetLockCount() const
299     {
300         LOG_IF(GetState() != STATE_LIGHT_LOCKED, DEBUG, RUNTIME) << "Wrong State";
301         return static_cast<uint32_t>((Value() >> LIGHT_LOCK_LOCK_COUNT_SHIFT) & LIGHT_LOCK_LOCK_COUNT_MASK);
302     }
303 
304     uint32_t GetHash() const;
305 
GetForwardingAddress()306     markWordSize GetForwardingAddress() const
307     {
308         LOG_IF(GetState() != STATE_GC, DEBUG, RUNTIME) << "Wrong State";
309         return GetForwardingAddressField() << FORWARDING_ADDRESS_SHIFT;
310     }
311 
GetMonitorId()312     Monitor::MonitorId GetMonitorId() const
313     {
314         LOG_IF(GetState() != STATE_HEAVY_LOCKED, DEBUG, RUNTIME) << "Wrong State";
315         return static_cast<Monitor::MonitorId>((Value() >> MONITOR_POINTER_SHIFT) & MONITOR_POINTER_MASK);
316     }
317 
GetValue()318     markWordSize GetValue() const
319     {
320         return value_;
321     }
322 
323     ~MarkWord() = default;
324 
325     DEFAULT_COPY_SEMANTIC(MarkWord);
326     DEFAULT_MOVE_SEMANTIC(MarkWord);
327 
328     friend class MarkWordTest;
329     friend class ObjectHeader;
330 
331 private:
332     // The only field in MarkWord class.
333     markWordSize value_ {0};
334 
Value()335     markWordSize Value() volatile const
336     {
337         return value_;
338     }
339 
340     // Functions depend on memory model config
341     template <bool HashPolicy>
342     uint32_t GetHashConfigured() const;
343 
344     template <bool HashPolicy>
345     MarkWord DecodeFromHashConfigured(uint32_t hash);
346 
347     template <bool HashPolicy>
348     bool IsHashedConfigured() const;
349 
350     template <bool HashPolicy>
351     MarkWord SetHashedConfigured();
352 
MarkWord(markWordSize value)353     explicit MarkWord(markWordSize value) noexcept : value_(value) {}
354 
MarkWord()355     MarkWord() noexcept : value_(0) {}
356 
357     bool operator==(const MarkWord &other) const
358     {
359         return Value() == other.Value();
360     }
361 
362     /**
363      * @param forwarding_address - address shifted by FORWARDING_ADDRESS_SHIFT
364      * @return MarkWord with encoded forwarding_address and GC state
365      */
DecodeFromForwardingAddressField(markWordSize forwarding_address)366     MarkWord DecodeFromForwardingAddressField(markWordSize forwarding_address)
367     {
368         ASSERT(forwarding_address <= (std::numeric_limits<markWordSize>::max() >> FORWARDING_ADDRESS_SHIFT));
369         // Forwardind address consumes all bits except status. We don't need to save GC state
370         markWordSize forwarding_address_in_place = (forwarding_address & FORWARDING_ADDRESS_MASK)
371                                                    << FORWARDING_ADDRESS_SHIFT;
372         return MarkWord(forwarding_address_in_place | (STATUS_GC << STATUS_SHIFT));
373     }
374 
375     /**
376      * @return pointer shifted by FORWARDING_ADDRESS_SHIFT
377      */
GetForwardingAddressField()378     markWordSize GetForwardingAddressField() const
379     {
380         LOG_IF(GetState() != STATE_GC, DEBUG, RUNTIME) << "Wrong State";
381         return (Value() >> FORWARDING_ADDRESS_SHIFT) & FORWARDING_ADDRESS_MASK;
382     }
383 };
384 
385 }  // namespace panda
386 
387 #endif  // PANDA_RUNTIME_MARK_WORD_H_
388