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