• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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