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