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 #ifndef PANDA_INTERPRETER_VREGISTER_H_ 16 #define PANDA_INTERPRETER_VREGISTER_H_ 17 18 #include <cstddef> 19 #include <cstdint> 20 21 #include "libpandabase/macros.h" 22 #include "libpandabase/utils/bit_helpers.h" 23 #include "libpandabase/utils/bit_utils.h" 24 #include "libpandabase/utils/logger.h" 25 #include "runtime/include/coretypes/tagged_value.h" 26 #include "runtime/include/mem/panda_string.h" 27 #include "runtime/mem/object_helpers.h" 28 29 namespace panda { 30 class ObjectHeader; 31 } // namespace panda 32 33 namespace panda::interpreter { 34 // An uint64_t value is used for storing the tags of values. This kind of tags is compatible with static and dynamic 35 // languages, and the tag is encoded as below. 36 // tag bits | [63-7] | [6-4] | [3-1] | [0] | 37 // usage | unused | object type | primitive type | IsObject flag | 38 // details | unused | @000: default | @011: INT | @0: value is a | 39 // | | @001: STRING | @100: DOUBLE | primitive value | 40 // | | | | @1: value is a | 41 // | | | | object pointer | 42 43 // 44 // All the fields' bits occupancy should be adaptive. For example, if we extend the 'IsObject flag' field by 1 bit, 45 // the 'IsObject flag' field will take bits [1-0] and the 'primitive type' field should take bits [4-2]. 46 // 47 // This kind of tags is compatible with static and dynamic languages, and that means if the lowest bit is 1, 48 // the value is a object pointer, otherwise, the value is a primitive value for both static and dynamic languages. 49 50 // [0] 51 static constexpr uint8_t OBJECT_FLAG_SHIFT = 0; 52 static constexpr uint8_t OBJECT_FLAG_BITS = 1; 53 // [3-1] 54 static constexpr uint8_t PRIMITIVE_FIRST_SHIFT = OBJECT_FLAG_SHIFT + OBJECT_FLAG_BITS; 55 static constexpr uint8_t PRIMITIVE_TYPE_BITS = 3; 56 // [6-4] 57 static constexpr uint8_t OBJECT_FIRST_SHIFT = PRIMITIVE_FIRST_SHIFT + PRIMITIVE_TYPE_BITS; 58 static constexpr uint8_t OBJECT_TYPE_BITS = 3; 59 60 // OBJECT_FLAG_MASK is compatible with static and dynamic languages, and 0x1 means the value is 'reference type' in 61 // static and 'HeapObject' type in dynamic language. 62 static constexpr coretypes::TaggedType OBJECT_FLAG_MASK = 0x1; 63 64 // PrimitiveIndex's max capacity is (2 ^ PRIMITIVE_TYPE_BITS). If the number of values in PrimitiveIndex 65 // exceeds the capacity, PRIMITIVE_TYPE_BITS should be increased. 66 enum PrimitiveIndex : uint8_t { INT_IDX = 3, DOUBLE_IDX }; 67 68 // ObjectIndex's max capacity is (2 ^ OBJECT_TYPE_BITS). If the number of values in ObjectIndex 69 // exceeds the capacity, ObjectIndex should be increased. 70 enum ObjectIndex : uint8_t { STRING_IDX = 1 }; 71 72 enum TypeTag : uint64_t { 73 // Tags of primitive types 74 INT = (static_cast<uint64_t>(INT_IDX) << PRIMITIVE_FIRST_SHIFT), 75 DOUBLE = (static_cast<uint64_t>(DOUBLE_IDX) << PRIMITIVE_FIRST_SHIFT), 76 // Tags of object types 77 OBJECT = OBJECT_FLAG_MASK, 78 STRING = (static_cast<uint64_t>(STRING_IDX) << OBJECT_FIRST_SHIFT) | OBJECT_FLAG_MASK, 79 }; 80 81 template <class T> 82 class VRegisterIface { 83 public: SetValue(int64_t v)84 ALWAYS_INLINE inline void SetValue(int64_t v) 85 { 86 static_cast<T *>(this)->SetValue(v); 87 } 88 GetValue()89 ALWAYS_INLINE inline int64_t GetValue() const 90 { 91 return static_cast<const T *>(this)->GetValue(); 92 } 93 Set(int32_t value)94 ALWAYS_INLINE inline void Set(int32_t value) 95 { 96 SetValue(value); 97 } 98 Set(uint32_t value)99 ALWAYS_INLINE inline void Set(uint32_t value) 100 { 101 SetValue(value); 102 } 103 Set(int64_t value)104 ALWAYS_INLINE inline void Set(int64_t value) 105 { 106 SetValue(value); 107 } 108 Set(uint64_t value)109 ALWAYS_INLINE inline void Set(uint64_t value) 110 { 111 auto v = bit_cast<int64_t>(value); 112 SetValue(v); 113 } 114 Set(float value)115 ALWAYS_INLINE inline void Set(float value) 116 { 117 auto v = bit_cast<int32_t>(value); 118 SetValue(v); 119 } 120 Set(double value)121 ALWAYS_INLINE inline void Set(double value) 122 { 123 auto v = bit_cast<int64_t>(value); 124 SetValue(v); 125 } 126 Set(ObjectHeader * value)127 ALWAYS_INLINE inline void Set(ObjectHeader *value) 128 { 129 mem::ValidateObject(mem::RootType::ROOT_THREAD, value); 130 auto v = down_cast<helpers::TypeHelperT<OBJECT_POINTER_SIZE * BYTE_SIZE, true>>(value); 131 SetValue(v); 132 } 133 Get()134 ALWAYS_INLINE inline int32_t Get() const 135 { 136 return GetAs<int32_t>(); 137 } 138 GetFloat()139 ALWAYS_INLINE inline float GetFloat() const 140 { 141 return GetAs<float>(); 142 } 143 GetLong()144 ALWAYS_INLINE inline int64_t GetLong() const 145 { 146 return GetValue(); 147 } 148 GetDouble()149 ALWAYS_INLINE inline double GetDouble() const 150 { 151 return GetAs<double>(); 152 } 153 GetReference()154 ALWAYS_INLINE inline ObjectHeader *GetReference() const 155 { 156 return GetAs<ObjectHeader *>(); 157 } 158 159 template <typename M, std::enable_if_t<std::is_same_v<int8_t, M> || std::is_same_v<uint8_t, M> || 160 std::is_same_v<int16_t, M> || std::is_same_v<uint16_t, M> || 161 std::is_same_v<std::int32_t, M> || std::is_same_v<uint32_t, M> || 162 std::is_same_v<std::int64_t, M> || std::is_same_v<uint64_t, M>> * = nullptr> GetAs()163 ALWAYS_INLINE inline M GetAs() const 164 { 165 return static_cast<M>(GetValue()); 166 } 167 168 template <typename M, std::enable_if_t<std::is_same_v<float, M>> * = nullptr> GetAs()169 ALWAYS_INLINE inline float GetAs() const 170 { 171 return bit_cast<float>(Get()); 172 } 173 174 template <typename M, std::enable_if_t<std::is_same_v<double, M>> * = nullptr> GetAs()175 ALWAYS_INLINE inline double GetAs() const 176 { 177 return bit_cast<double>(GetValue()); 178 } 179 180 template <typename M, std::enable_if_t<std::is_same_v<ObjectHeader *, M>> * = nullptr> GetAs()181 ALWAYS_INLINE inline ObjectHeader *GetAs() const 182 { 183 return reinterpret_cast<ObjectHeader *>(static_cast<object_pointer_type>(GetValue())); 184 } 185 186 private: 187 static constexpr int8_t BYTE_SIZE = 8; 188 }; 189 190 // ========== Tagless VRegister ========== 191 // VRegister is an independent module which only contains a 64-bit value, and previous tag info is held by Frame 192 // StaticVRegisterRef contains payload and mirror vregister ptr, while DynamicVRegisterRef contains payload ptr only 193 // They can help you to access the tag info, like `HasObject`, `SetPrimitive` 194 // More details please refer to the comment in `Frame.h`. 195 196 class VRegister : public VRegisterIface<VRegister> { 197 public: 198 VRegister() = default; 199 VRegister(int64_t v)200 ALWAYS_INLINE inline explicit VRegister(int64_t v) 201 { 202 SetValue(v); 203 } 204 SetValue(int64_t v)205 ALWAYS_INLINE inline void SetValue(int64_t v) 206 { 207 v_ = v; 208 } 209 GetValue()210 ALWAYS_INLINE inline int64_t GetValue() const 211 { 212 return v_; 213 } 214 215 ~VRegister() = default; 216 217 DEFAULT_COPY_SEMANTIC(VRegister); 218 DEFAULT_MOVE_SEMANTIC(VRegister); 219 GetValueOffset()220 ALWAYS_INLINE static inline constexpr uint32_t GetValueOffset() 221 { 222 return MEMBER_OFFSET(VRegister, v_); 223 } 224 225 private: 226 // Stores the bit representation of the register value, regardless of the real type. 227 // It can contain int/uint 8/16/32/64, float, double and ObjectHeader *. 228 int64_t v_ {0}; 229 }; 230 231 template <class T, class VRegT = VRegister> 232 class VRegisterRef { 233 public: VRegisterRef(VRegT * payload)234 ALWAYS_INLINE inline explicit VRegisterRef(VRegT *payload) : payload_(payload) {} 235 SetValue(int64_t v)236 ALWAYS_INLINE inline void SetValue(int64_t v) 237 { 238 payload_->SetValue(v); 239 } 240 GetValue()241 ALWAYS_INLINE inline int64_t GetValue() const 242 { 243 return payload_->GetValue(); 244 } 245 HasObject()246 ALWAYS_INLINE inline bool HasObject() const 247 { 248 return static_cast<const T *>(this)->HasObject(); 249 } 250 MovePrimitive(const T & other)251 ALWAYS_INLINE inline void MovePrimitive(const T &other) 252 { 253 ASSERT(!other.HasObject()); 254 static_cast<T *>(this)->MovePrimitive(other); 255 } 256 MoveReference(const T & other)257 ALWAYS_INLINE inline void MoveReference(const T &other) 258 { 259 ASSERT(other.HasObject()); 260 static_cast<T *>(this)->MoveReference(other); 261 } 262 Move(const T & other)263 ALWAYS_INLINE inline void Move(const T &other) 264 { 265 static_cast<T *>(this)->Move(other); 266 } 267 SetPrimitive(int32_t value)268 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 269 { 270 static_cast<T *>(this)->SetPrimitive(value); 271 } 272 SetPrimitive(int64_t value)273 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 274 { 275 static_cast<T *>(this)->SetPrimitive(value); 276 } 277 SetPrimitive(float value)278 ALWAYS_INLINE inline void SetPrimitive(float value) 279 { 280 static_cast<T *>(this)->SetPrimitive(value); 281 } 282 SetPrimitive(double value)283 ALWAYS_INLINE inline void SetPrimitive(double value) 284 { 285 static_cast<T *>(this)->SetPrimitive(value); 286 } 287 SetPrimitive(uint64_t value)288 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 289 { 290 static_cast<T *>(this)->SetPrimitive(value); 291 } 292 SetReference(ObjectHeader * obj)293 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 294 { 295 static_cast<T *>(this)->SetReference(obj); 296 } 297 Set(int32_t value)298 ALWAYS_INLINE inline void Set(int32_t value) 299 { 300 payload_->Set(value); 301 } 302 Set(uint32_t value)303 ALWAYS_INLINE inline void Set(uint32_t value) 304 { 305 payload_->Set(value); 306 } 307 Set(int64_t value)308 ALWAYS_INLINE inline void Set(int64_t value) 309 { 310 payload_->Set(value); 311 } 312 Set(uint64_t value)313 ALWAYS_INLINE inline void Set(uint64_t value) 314 { 315 payload_->Set(value); 316 } 317 Set(float value)318 ALWAYS_INLINE inline void Set(float value) 319 { 320 payload_->Set(value); 321 } 322 Set(double value)323 ALWAYS_INLINE inline void Set(double value) 324 { 325 payload_->Set(value); 326 } 327 Set(ObjectHeader * value)328 ALWAYS_INLINE inline void Set(ObjectHeader *value) 329 { 330 payload_->Set(value); 331 } 332 Get()333 ALWAYS_INLINE inline int32_t Get() const 334 { 335 return payload_->Get(); 336 } 337 GetLong()338 ALWAYS_INLINE inline int64_t GetLong() const 339 { 340 return payload_->GetLong(); 341 } 342 GetFloat()343 ALWAYS_INLINE inline float GetFloat() const 344 { 345 return payload_->GetFloat(); 346 } 347 GetDouble()348 ALWAYS_INLINE inline double GetDouble() const 349 { 350 return payload_->GetDouble(); 351 } 352 GetReference()353 ALWAYS_INLINE inline ObjectHeader *GetReference() const 354 { 355 return payload_->GetReference(); 356 } 357 358 template <typename M> GetAs()359 ALWAYS_INLINE inline M GetAs() const 360 { 361 return payload_->template GetAs<M>(); 362 } 363 364 #ifndef NDEBUG DumpVReg()365 ALWAYS_INLINE inline PandaString DumpVReg() const 366 { 367 PandaStringStream values; 368 if (HasObject()) { 369 values << "obj = " << std::hex << GetValue(); 370 } else { 371 values << "pri = (i64) " << GetValue() << " | " 372 << "(f32) " << GetFloat() << " | " 373 << "(f64) " << GetDouble() << " | " 374 << "(hex) " << std::hex << GetValue(); 375 } 376 return values.str(); 377 } 378 #endif 379 380 ~VRegisterRef() = default; 381 382 DEFAULT_COPY_SEMANTIC(VRegisterRef); 383 DEFAULT_MOVE_SEMANTIC(VRegisterRef); 384 385 static constexpr int64_t GC_OBJECT_TYPE = 0x1; 386 static constexpr int64_t PRIMITIVE_TYPE = 0x0; 387 388 protected: 389 VRegT *payload_ {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 390 }; 391 392 class StaticVRegisterRef : public VRegisterRef<StaticVRegisterRef> { 393 public: StaticVRegisterRef(VRegister * payload,VRegister * mirror)394 ALWAYS_INLINE inline explicit StaticVRegisterRef(VRegister *payload, VRegister *mirror) 395 : VRegisterRef(payload), mirror_(mirror) 396 { 397 } 398 SetTag(int64_t value)399 ALWAYS_INLINE inline void SetTag(int64_t value) 400 { 401 mirror_->SetValue(value); 402 } 403 GetTag()404 ALWAYS_INLINE inline int64_t GetTag() const 405 { 406 return mirror_->GetValue(); 407 } 408 Move(std::pair<int64_t,int64_t> value)409 ALWAYS_INLINE inline void Move(std::pair<int64_t, int64_t> value) 410 { 411 payload_->SetValue(value.first); 412 mirror_->SetValue(value.second); 413 } 414 415 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) 416 ALWAYS_INLINE inline StaticVRegisterRef &operator=(const StaticVRegisterRef &other) 417 { 418 *payload_ = *other.payload_; 419 *mirror_ = *other.mirror_; 420 return *this; 421 } 422 423 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) 424 ALWAYS_INLINE inline StaticVRegisterRef &operator=(StaticVRegisterRef &&other) 425 { 426 *payload_ = *other.payload_; 427 *mirror_ = *other.mirror_; 428 return *this; 429 } 430 HasObject()431 ALWAYS_INLINE inline bool HasObject() const 432 { 433 return mirror_->GetValue() == GC_OBJECT_TYPE; 434 } 435 MovePrimitive(const StaticVRegisterRef & other)436 ALWAYS_INLINE inline void MovePrimitive(const StaticVRegisterRef &other) 437 { 438 payload_->SetValue(other.payload_->GetValue()); 439 mirror_->SetValue(PRIMITIVE_TYPE); 440 } 441 MoveReference(const StaticVRegisterRef & other)442 ALWAYS_INLINE inline void MoveReference(const StaticVRegisterRef &other) 443 { 444 payload_->SetValue(other.payload_->GetValue()); 445 mirror_->SetValue(GC_OBJECT_TYPE); 446 } 447 Move(const StaticVRegisterRef & other)448 ALWAYS_INLINE inline void Move(const StaticVRegisterRef &other) 449 { 450 payload_->SetValue(other.payload_->GetValue()); 451 mirror_->SetValue(other.mirror_->GetValue()); 452 } 453 SetPrimitive(int32_t value)454 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 455 { 456 payload_->Set(value); 457 mirror_->SetValue(PRIMITIVE_TYPE); 458 } 459 SetPrimitive(int64_t value)460 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 461 { 462 payload_->Set(value); 463 mirror_->SetValue(PRIMITIVE_TYPE); 464 } 465 SetPrimitive(float value)466 ALWAYS_INLINE inline void SetPrimitive(float value) 467 { 468 payload_->Set(value); 469 mirror_->SetValue(PRIMITIVE_TYPE); 470 } 471 SetPrimitive(double value)472 ALWAYS_INLINE inline void SetPrimitive(double value) 473 { 474 payload_->Set(value); 475 mirror_->SetValue(PRIMITIVE_TYPE); 476 } 477 SetPrimitive(uint64_t value)478 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 479 { 480 payload_->Set(value); 481 mirror_->SetValue(PRIMITIVE_TYPE); 482 } 483 SetReference(ObjectHeader * obj)484 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 485 { 486 payload_->Set(obj); 487 mirror_->SetValue(GC_OBJECT_TYPE); 488 } 489 490 ~StaticVRegisterRef() = default; 491 492 DEFAULT_COPY_CTOR(StaticVRegisterRef) DEFAULT_MOVE_CTOR(StaticVRegisterRef)493 DEFAULT_MOVE_CTOR(StaticVRegisterRef) 494 495 private: 496 VRegister *mirror_ {nullptr}; 497 }; 498 499 class DynamicVRegisterRef : public VRegisterRef<DynamicVRegisterRef> { 500 public: DynamicVRegisterRef(VRegister * payload)501 ALWAYS_INLINE inline explicit DynamicVRegisterRef(VRegister *payload) : VRegisterRef(payload) {} 502 Move(std::pair<int64_t,int64_t> value)503 ALWAYS_INLINE inline void Move(std::pair<int64_t, int64_t> value) 504 { 505 payload_->SetValue(value.first); 506 } 507 508 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) 509 ALWAYS_INLINE inline DynamicVRegisterRef &operator=(const DynamicVRegisterRef &other) 510 { 511 *payload_ = *other.payload_; 512 return *this; 513 } 514 515 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) 516 ALWAYS_INLINE inline DynamicVRegisterRef &operator=(DynamicVRegisterRef &&other) 517 { 518 *payload_ = *other.payload_; 519 return *this; 520 } 521 HasObject()522 ALWAYS_INLINE inline bool HasObject() const 523 { 524 coretypes::TaggedValue v(payload_->GetAs<uint64_t>()); 525 return v.IsHeapObject(); 526 } 527 MovePrimitive(const DynamicVRegisterRef & other)528 ALWAYS_INLINE inline void MovePrimitive(const DynamicVRegisterRef &other) 529 { 530 ASSERT(!other.HasObject()); 531 Move(other); 532 } 533 MoveReference(const DynamicVRegisterRef & other)534 ALWAYS_INLINE inline void MoveReference(const DynamicVRegisterRef &other) 535 { 536 ASSERT(other.HasObject()); 537 Move(other); 538 } 539 Move(const DynamicVRegisterRef & other)540 ALWAYS_INLINE inline void Move(const DynamicVRegisterRef &other) 541 { 542 payload_->SetValue(other.payload_->GetValue()); 543 } 544 SetPrimitive(int32_t value)545 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 546 { 547 payload_->Set(value); 548 } 549 SetPrimitive(int64_t value)550 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 551 { 552 payload_->Set(value); 553 } 554 SetPrimitive(float value)555 ALWAYS_INLINE inline void SetPrimitive(float value) 556 { 557 payload_->Set(value); 558 } 559 SetPrimitive(double value)560 ALWAYS_INLINE inline void SetPrimitive(double value) 561 { 562 payload_->Set(value); 563 } 564 SetPrimitive(uint64_t value)565 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 566 { 567 payload_->Set(value); 568 } 569 SetReference(ObjectHeader * obj)570 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 571 { 572 coretypes::TaggedValue v(obj); 573 payload_->Set(v.GetRawData()); 574 } 575 576 ~DynamicVRegisterRef() = default; 577 578 DEFAULT_COPY_CTOR(DynamicVRegisterRef) 579 DEFAULT_MOVE_CTOR(DynamicVRegisterRef) 580 }; 581 582 } // namespace panda::interpreter 583 584 #endif // PANDA_INTERPRETER_VREGISTER_H_ 585