1 /** 2 * Copyright (c) 2021-2024 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 ark { 30 class ObjectHeader; 31 } // namespace ark 32 33 namespace ark::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 template <class T> 73 class VRegisterIface { 74 public: SetValue(int64_t v)75 ALWAYS_INLINE inline void SetValue(int64_t v) 76 { 77 static_cast<T *>(this)->SetValue(v); 78 } 79 GetValue() const80 ALWAYS_INLINE inline int64_t GetValue() const 81 { 82 return static_cast<const T *>(this)->GetValue(); 83 } 84 Set(int32_t value)85 ALWAYS_INLINE inline void Set(int32_t value) 86 { 87 SetValue(value); 88 } 89 Set(uint32_t value)90 ALWAYS_INLINE inline void Set(uint32_t value) 91 { 92 SetValue(value); 93 } 94 Set(int64_t value)95 ALWAYS_INLINE inline void Set(int64_t value) 96 { 97 SetValue(value); 98 } 99 Set(uint64_t value)100 ALWAYS_INLINE inline void Set(uint64_t value) 101 { 102 auto v = bit_cast<int64_t>(value); 103 SetValue(v); 104 } 105 Set(float value)106 ALWAYS_INLINE inline void Set(float value) 107 { 108 auto v = bit_cast<int32_t>(value); 109 SetValue(v); 110 } 111 Set(double value)112 ALWAYS_INLINE inline void Set(double value) 113 { 114 auto v = bit_cast<int64_t>(value); 115 SetValue(v); 116 } 117 Set(ObjectHeader *value)118 ALWAYS_INLINE inline void Set(ObjectHeader *value) 119 { 120 mem::ValidateObject(mem::RootType::ROOT_THREAD, value); 121 auto v = down_cast<helpers::TypeHelperT<OBJECT_POINTER_SIZE * BYTE_SIZE, true>>(value); 122 SetValue(v); 123 } 124 Get() const125 ALWAYS_INLINE inline int32_t Get() const 126 { 127 return GetAs<int32_t>(); 128 } 129 GetFloat() const130 ALWAYS_INLINE inline float GetFloat() const 131 { 132 return GetAs<float>(); 133 } 134 GetLong() const135 ALWAYS_INLINE inline int64_t GetLong() const 136 { 137 return GetValue(); 138 } 139 GetDouble() const140 ALWAYS_INLINE inline double GetDouble() const 141 { 142 return GetAs<double>(); 143 } 144 GetReference() const145 ALWAYS_INLINE inline ObjectHeader *GetReference() const 146 { 147 return GetAs<ObjectHeader *>(); 148 } 149 150 template <typename M, std::enable_if_t<std::is_same_v<int8_t, M> || std::is_same_v<uint8_t, M> || 151 std::is_same_v<int16_t, M> || std::is_same_v<uint16_t, M> || 152 std::is_same_v<std::int32_t, M> || std::is_same_v<uint32_t, M> || 153 std::is_same_v<std::int64_t, M> || std::is_same_v<uint64_t, M>> * = nullptr> GetAs() const154 ALWAYS_INLINE inline M GetAs() const 155 { 156 return static_cast<M>(GetValue()); 157 } 158 159 template <typename M, std::enable_if_t<std::is_same_v<float, M>> * = nullptr> GetAs() const160 ALWAYS_INLINE inline float GetAs() const 161 { 162 return bit_cast<float>(Get()); 163 } 164 165 template <typename M, std::enable_if_t<std::is_same_v<double, M>> * = nullptr> GetAs() const166 ALWAYS_INLINE inline double GetAs() const 167 { 168 return bit_cast<double>(GetValue()); 169 } 170 171 template <typename M, std::enable_if_t<std::is_same_v<ObjectHeader *, M>> * = nullptr> GetAs() const172 ALWAYS_INLINE inline ObjectHeader *GetAs() const 173 { 174 return reinterpret_cast<ObjectHeader *>(static_cast<ObjectPointerType>(GetValue())); 175 } 176 177 private: 178 static constexpr int8_t BYTE_SIZE = 8; 179 }; 180 181 // ========== Tagless VRegister ========== 182 // VRegister is an independent module which only contains a 64-bit value, and previous tag info is held by Frame 183 // StaticVRegisterRef contains payload and mirror vregister ptr, while DynamicVRegisterRef contains payload ptr only 184 // They can help you to access the tag info, like `HasObject`, `SetPrimitive` 185 // More details please refer to the comment in `Frame.h`. 186 187 class VRegister : public VRegisterIface<VRegister> { 188 public: 189 VRegister() = default; 190 VRegister(int64_t v)191 ALWAYS_INLINE inline explicit VRegister(int64_t v) 192 { 193 SetValue(v); 194 } 195 SetValue(int64_t v)196 ALWAYS_INLINE inline void SetValue(int64_t v) 197 { 198 v_ = v; 199 } 200 GetValue() const201 ALWAYS_INLINE inline int64_t GetValue() const 202 { 203 return v_; 204 } 205 206 ~VRegister() = default; 207 208 DEFAULT_COPY_SEMANTIC(VRegister); 209 DEFAULT_MOVE_SEMANTIC(VRegister); 210 GetValueOffset()211 ALWAYS_INLINE static inline constexpr uint32_t GetValueOffset() 212 { 213 return MEMBER_OFFSET(VRegister, v_); 214 } 215 216 private: 217 // Stores the bit representation of the register value, regardless of the real type. 218 // It can contain int/uint 8/16/32/64, float, double and ObjectHeader *. 219 int64_t v_ {0}; 220 }; 221 222 template <class T, class VRegT = VRegister> 223 class VRegisterRef { 224 public: VRegisterRef(VRegT *payload)225 ALWAYS_INLINE inline explicit VRegisterRef(VRegT *payload) : payload_(payload) {} 226 SetValue(int64_t v)227 ALWAYS_INLINE inline void SetValue(int64_t v) 228 { 229 payload_->SetValue(v); 230 } 231 GetValue() const232 ALWAYS_INLINE inline int64_t GetValue() const 233 { 234 return payload_->GetValue(); 235 } 236 HasObject() const237 ALWAYS_INLINE inline bool HasObject() const 238 { 239 return static_cast<const T *>(this)->HasObject(); 240 } 241 MovePrimitive(const T &other)242 ALWAYS_INLINE inline void MovePrimitive(const T &other) 243 { 244 ASSERT(!other.HasObject()); 245 static_cast<T *>(this)->MovePrimitive(other); 246 } 247 MoveReference(const T &other)248 ALWAYS_INLINE inline void MoveReference(const T &other) 249 { 250 ASSERT(other.HasObject()); 251 static_cast<T *>(this)->MoveReference(other); 252 } 253 Move(const T &other)254 ALWAYS_INLINE inline void Move(const T &other) 255 { 256 static_cast<T *>(this)->Move(other); 257 } 258 SetPrimitive(int32_t value)259 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 260 { 261 static_cast<T *>(this)->SetPrimitive(value); 262 } 263 SetPrimitive(int64_t value)264 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 265 { 266 static_cast<T *>(this)->SetPrimitive(value); 267 } 268 SetPrimitive(float value)269 ALWAYS_INLINE inline void SetPrimitive(float value) 270 { 271 static_cast<T *>(this)->SetPrimitive(value); 272 } 273 SetPrimitive(double value)274 ALWAYS_INLINE inline void SetPrimitive(double value) 275 { 276 static_cast<T *>(this)->SetPrimitive(value); 277 } 278 SetPrimitive(uint64_t value)279 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 280 { 281 static_cast<T *>(this)->SetPrimitive(value); 282 } 283 SetReference(ObjectHeader *obj)284 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 285 { 286 static_cast<T *>(this)->SetReference(obj); 287 } 288 Set(int32_t value)289 ALWAYS_INLINE inline void Set(int32_t value) 290 { 291 payload_->Set(value); 292 } 293 Set(uint32_t value)294 ALWAYS_INLINE inline void Set(uint32_t value) 295 { 296 payload_->Set(value); 297 } 298 Set(int64_t value)299 ALWAYS_INLINE inline void Set(int64_t value) 300 { 301 payload_->Set(value); 302 } 303 Set(uint64_t value)304 ALWAYS_INLINE inline void Set(uint64_t value) 305 { 306 payload_->Set(value); 307 } 308 Set(float value)309 ALWAYS_INLINE inline void Set(float value) 310 { 311 payload_->Set(value); 312 } 313 Set(double value)314 ALWAYS_INLINE inline void Set(double value) 315 { 316 payload_->Set(value); 317 } 318 Set(ObjectHeader *value)319 ALWAYS_INLINE inline void Set(ObjectHeader *value) 320 { 321 payload_->Set(value); 322 } 323 Get() const324 ALWAYS_INLINE inline int32_t Get() const 325 { 326 return payload_->Get(); 327 } 328 GetLong() const329 ALWAYS_INLINE inline int64_t GetLong() const 330 { 331 return payload_->GetLong(); 332 } 333 GetFloat() const334 ALWAYS_INLINE inline float GetFloat() const 335 { 336 return payload_->GetFloat(); 337 } 338 GetDouble() const339 ALWAYS_INLINE inline double GetDouble() const 340 { 341 return payload_->GetDouble(); 342 } 343 GetReference() const344 ALWAYS_INLINE inline ObjectHeader *GetReference() const 345 { 346 return payload_->GetReference(); 347 } 348 349 template <typename M> GetAs() const350 ALWAYS_INLINE inline M GetAs() const 351 { 352 return payload_->template GetAs<M>(); 353 } 354 355 #ifndef NDEBUG DumpVReg() const356 ALWAYS_INLINE inline PandaString DumpVReg() const 357 { 358 PandaStringStream values; 359 if (HasObject()) { 360 values << "obj = " << std::hex << GetValue(); 361 } else { 362 values << "pri = (i64) " << GetValue() << " | " 363 << "(f32) " << GetFloat() << " | " 364 << "(f64) " << GetDouble() << " | " 365 << "(hex) " << std::hex << GetValue(); 366 } 367 return values.str(); 368 } 369 #endif 370 371 ~VRegisterRef() = default; 372 373 DEFAULT_COPY_SEMANTIC(VRegisterRef); 374 DEFAULT_MOVE_SEMANTIC(VRegisterRef); 375 376 static constexpr int64_t GC_OBJECT_TYPE = 0x1; 377 static constexpr int64_t PRIMITIVE_TYPE = 0x0; 378 379 protected: 380 VRegT *payload_ {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 381 }; 382 383 class StaticVRegisterRef : public VRegisterRef<StaticVRegisterRef> { 384 public: StaticVRegisterRef(VRegister *payload, VRegister *mirror)385 ALWAYS_INLINE inline explicit StaticVRegisterRef(VRegister *payload, VRegister *mirror) 386 : VRegisterRef(payload), mirror_(mirror) 387 { 388 } 389 SetTag(int64_t value)390 ALWAYS_INLINE inline void SetTag(int64_t value) 391 { 392 mirror_->SetValue(value); 393 } 394 GetTag() const395 ALWAYS_INLINE inline int64_t GetTag() const 396 { 397 return mirror_->GetValue(); 398 } 399 Move(std::pair<int64_t, int64_t> value)400 ALWAYS_INLINE inline void Move(std::pair<int64_t, int64_t> value) 401 { 402 payload_->SetValue(value.first); 403 mirror_->SetValue(value.second); 404 } 405 406 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) operator =(const StaticVRegisterRef &other)407 ALWAYS_INLINE inline StaticVRegisterRef &operator=(const StaticVRegisterRef &other) 408 { 409 *payload_ = *other.payload_; 410 *mirror_ = *other.mirror_; 411 return *this; 412 } 413 414 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) operator =(StaticVRegisterRef &&other)415 ALWAYS_INLINE inline StaticVRegisterRef &operator=(StaticVRegisterRef &&other) 416 { 417 *payload_ = *other.payload_; 418 *mirror_ = *other.mirror_; 419 return *this; 420 } 421 HasObject() const422 ALWAYS_INLINE inline bool HasObject() const 423 { 424 return mirror_->GetValue() == GC_OBJECT_TYPE; 425 } 426 MovePrimitive(const StaticVRegisterRef &other)427 ALWAYS_INLINE inline void MovePrimitive(const StaticVRegisterRef &other) 428 { 429 payload_->SetValue(other.payload_->GetValue()); 430 mirror_->SetValue(PRIMITIVE_TYPE); 431 } 432 MoveReference(const StaticVRegisterRef &other)433 ALWAYS_INLINE inline void MoveReference(const StaticVRegisterRef &other) 434 { 435 payload_->SetValue(other.payload_->GetValue()); 436 mirror_->SetValue(GC_OBJECT_TYPE); 437 } 438 Move(const StaticVRegisterRef &other)439 ALWAYS_INLINE inline void Move(const StaticVRegisterRef &other) 440 { 441 payload_->SetValue(other.payload_->GetValue()); 442 mirror_->SetValue(other.mirror_->GetValue()); 443 } 444 SetPrimitive(int32_t value)445 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 446 { 447 payload_->Set(value); 448 mirror_->SetValue(PRIMITIVE_TYPE); 449 } 450 SetPrimitive(int64_t value)451 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 452 { 453 payload_->Set(value); 454 mirror_->SetValue(PRIMITIVE_TYPE); 455 } 456 SetPrimitive(float value)457 ALWAYS_INLINE inline void SetPrimitive(float value) 458 { 459 payload_->Set(value); 460 mirror_->SetValue(PRIMITIVE_TYPE); 461 } 462 SetPrimitive(double value)463 ALWAYS_INLINE inline void SetPrimitive(double value) 464 { 465 payload_->Set(value); 466 mirror_->SetValue(PRIMITIVE_TYPE); 467 } 468 SetPrimitive(uint64_t value)469 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 470 { 471 payload_->Set(value); 472 mirror_->SetValue(PRIMITIVE_TYPE); 473 } 474 SetReference(ObjectHeader *obj)475 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 476 { 477 payload_->Set(obj); 478 mirror_->SetValue(GC_OBJECT_TYPE); 479 } 480 481 ~StaticVRegisterRef() = default; 482 483 DEFAULT_COPY_CTOR(StaticVRegisterRef); 484 DEFAULT_MOVE_CTOR(StaticVRegisterRef); 485 486 private: 487 VRegister *mirror_ {nullptr}; 488 }; 489 490 class DynamicVRegisterRef : public VRegisterRef<DynamicVRegisterRef> { 491 public: DynamicVRegisterRef(VRegister *payload)492 ALWAYS_INLINE inline explicit DynamicVRegisterRef(VRegister *payload) : VRegisterRef(payload) {} 493 Move(std::pair<int64_t, int64_t> value)494 ALWAYS_INLINE inline void Move(std::pair<int64_t, int64_t> value) 495 { 496 payload_->SetValue(value.first); 497 } 498 499 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) operator =(const DynamicVRegisterRef &other)500 ALWAYS_INLINE inline DynamicVRegisterRef &operator=(const DynamicVRegisterRef &other) 501 { 502 *payload_ = *other.payload_; 503 return *this; 504 } 505 506 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) operator =(DynamicVRegisterRef &&other)507 ALWAYS_INLINE inline DynamicVRegisterRef &operator=(DynamicVRegisterRef &&other) 508 { 509 *payload_ = *other.payload_; 510 return *this; 511 } 512 HasObject() const513 ALWAYS_INLINE inline bool HasObject() const 514 { 515 coretypes::TaggedValue v(payload_->GetAs<uint64_t>()); 516 return v.IsHeapObject(); 517 } 518 MovePrimitive(const DynamicVRegisterRef &other)519 ALWAYS_INLINE inline void MovePrimitive(const DynamicVRegisterRef &other) 520 { 521 ASSERT(!other.HasObject()); 522 Move(other); 523 } 524 MoveReference(const DynamicVRegisterRef &other)525 ALWAYS_INLINE inline void MoveReference(const DynamicVRegisterRef &other) 526 { 527 ASSERT(other.HasObject()); 528 Move(other); 529 } 530 Move(const DynamicVRegisterRef &other)531 ALWAYS_INLINE inline void Move(const DynamicVRegisterRef &other) 532 { 533 payload_->SetValue(other.payload_->GetValue()); 534 } 535 SetPrimitive(int32_t value)536 ALWAYS_INLINE inline void SetPrimitive(int32_t value) 537 { 538 payload_->Set(value); 539 } 540 SetPrimitive(int64_t value)541 ALWAYS_INLINE inline void SetPrimitive(int64_t value) 542 { 543 payload_->Set(value); 544 } 545 SetPrimitive(float value)546 ALWAYS_INLINE inline void SetPrimitive(float value) 547 { 548 payload_->Set(value); 549 } 550 SetPrimitive(double value)551 ALWAYS_INLINE inline void SetPrimitive(double value) 552 { 553 payload_->Set(value); 554 } 555 SetPrimitive(uint64_t value)556 ALWAYS_INLINE inline void SetPrimitive(uint64_t value) 557 { 558 payload_->Set(value); 559 } 560 SetReference(ObjectHeader *obj)561 ALWAYS_INLINE inline void SetReference(ObjectHeader *obj) 562 { 563 coretypes::TaggedValue v(obj); 564 payload_->Set(v.GetRawData()); 565 } 566 567 ~DynamicVRegisterRef() = default; 568 569 DEFAULT_COPY_CTOR(DynamicVRegisterRef); 570 DEFAULT_MOVE_CTOR(DynamicVRegisterRef); 571 }; 572 573 } // namespace ark::interpreter 574 575 #endif // PANDA_INTERPRETER_VREGISTER_H_ 576