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