• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #ifndef PANDA_RUNTIME_INTERPRETER_VREGISTER_H_
17 #define PANDA_RUNTIME_INTERPRETER_VREGISTER_H_
18 
19 #include <cstddef>
20 #include <cstdint>
21 
22 #include "libpandabase/macros.h"
23 #include "libpandabase/utils/bit_helpers.h"
24 #include "libpandabase/utils/bit_utils.h"
25 #include "libpandabase/utils/logger.h"
26 #include "runtime/include/coretypes/tagged_value.h"
27 #include "runtime/include/mem/panda_string.h"
28 #include "runtime/include/object_header.h"
29 
30 namespace panda::interpreter {
31 // An uint64_t value is used for storing the tags of values. This kind of tags are compatible with Java and dynamic
32 // languages, and the tag is encoded as below.
33 // tag bits | [63-7] |     [6-4]     |      [3-1]      |      [0]        |
34 // usage    | unused |  object type  | primitive type  | IsObject flag   |
35 // details  | unused | @000: default | @011: INT       | @0: value is a  |
36 //          |        | @001: STRING  | @100: DOUBLE    | primitive value |
37 //          |        |               |                 | @1: value is a  |
38 //          |        |               |                 | object pointer  |
39 
40 //
41 // All the fields' bits occupancy should be adaptive. For example, if we extend the 'IsObject flag' field by 1 bit,
42 // the 'IsObject flag' field will take bits [1-0] and the 'primitive type' field should take bits [4-2].
43 //
44 // This kind of tags are compatible with Java and dynamic languages, and that means if the lowest bit is 1,
45 // the value is an object pointer, otherwise, the value is a primitive value for both Java and dynamic languages.
46 
47 // [0]
48 static constexpr uint8_t OBJECT_FLAG_SHIFT = 0;
49 static constexpr uint8_t OBJECT_FLAG_BITS = 1;
50 // [3-1]
51 static constexpr uint8_t PRIMITIVE_FIRST_SHIFT = OBJECT_FLAG_SHIFT + OBJECT_FLAG_BITS;
52 static constexpr uint8_t PRIMITIVE_TYPE_BITS = 3;
53 // [6-4]
54 static constexpr uint8_t OBJECT_FIRST_SHIFT = PRIMITIVE_FIRST_SHIFT + PRIMITIVE_TYPE_BITS;
55 static constexpr uint8_t OBJECT_TYPE_BITS = 3;
56 
57 // OBJECT_FLAG_MASK is compatible with Java and dynamic languages, and 0x1 means the value is 'reference type' in Java
58 // and 'HeapObject' type in dynamic language.
59 static constexpr coretypes::TaggedType OBJECT_FLAG_MASK = 0x1;
60 
61 // PrimitiveIndex's max capacity is (2 ^ PRIMITIVE_TYPE_BITS). If the number of values in PrimitiveIndex
62 // exceeds the capacity, PRIMITIVE_TYPE_BITS should be increased.
63 enum PrimitiveIndex : uint8_t { INT_IDX = 3, DOUBLE_IDX };
64 
65 // ObjectIndex's max capacity is (2 ^ OBJECT_TYPE_BITS). If the number of values in ObjectIndex
66 // exceeds the capacity, ObjectIndex should be increased.
67 enum ObjectIndex : uint8_t { STRING_IDX = 1 };
68 
69 enum TypeTag : uint64_t {
70     // Tags of primitive types
71     INT = (static_cast<uint64_t>(INT_IDX) << PRIMITIVE_FIRST_SHIFT),
72     DOUBLE = (static_cast<uint64_t>(DOUBLE_IDX) << PRIMITIVE_FIRST_SHIFT),
73     // Tags of object types
74     OBJECT = OBJECT_FLAG_MASK,
75     STRING = (static_cast<uint64_t>(STRING_IDX) << OBJECT_FIRST_SHIFT) | OBJECT_FLAG_MASK,
76 };
77 
78 template <class T>
79 class VRegisterIface {
80 public:
SetValue(int64_t v)81     ALWAYS_INLINE inline void SetValue(int64_t v)
82     {
83         static_cast<T *>(this)->SetValue(v);
84     }
85 
GetValue()86     ALWAYS_INLINE inline int64_t GetValue() const
87     {
88         return static_cast<const T *>(this)->GetValue();
89     }
90 
SetTag(uint64_t tag)91     ALWAYS_INLINE inline void SetTag(uint64_t tag)
92     {
93         static_cast<T *>(this)->SetTag(tag);
94     }
95 
GetTag()96     ALWAYS_INLINE inline uint64_t GetTag() const
97     {
98         return static_cast<const T *>(this)->GetTag();
99     }
100 
101     template <class M>
MoveFrom(const VRegisterIface<M> & other)102     ALWAYS_INLINE inline void MoveFrom(const VRegisterIface<M> &other)
103     {
104         ASSERT(!other.HasObject());
105         SetValue(other.GetValue());
106         MarkAsPrimitive();
107     }
108 
109     template <class M>
MoveFromObj(const VRegisterIface<M> & other)110     ALWAYS_INLINE inline void MoveFromObj(const VRegisterIface<M> &other)
111     {
112         ASSERT(other.HasObject());
113         SetValue(other.GetValue());
114         MarkAsObject();
115     }
116 
117     template <class M>
Move(const VRegisterIface<M> & other)118     ALWAYS_INLINE inline void Move(const VRegisterIface<M> &other)
119     {
120         SetValue(other.GetValue());
121         SetTag(other.GetTag());
122     }
123 
Set(int32_t value)124     ALWAYS_INLINE inline void Set(int32_t value)
125     {
126         ASSERT(!HasObject());
127         SetValue(value);
128     }
129 
Set(uint32_t value)130     ALWAYS_INLINE inline void Set(uint32_t value)
131     {
132         ASSERT(!HasObject());
133         SetValue(value);
134     }
135 
Set(int64_t value)136     ALWAYS_INLINE inline void Set(int64_t value)
137     {
138         ASSERT(!HasObject());
139         SetValue(value);
140     }
141 
Set(uint64_t value)142     ALWAYS_INLINE inline void Set(uint64_t value)
143     {
144         ASSERT(!HasObject());
145         auto v = bit_cast<int64_t>(value);
146         SetValue(v);
147     }
148 
Set(float value)149     ALWAYS_INLINE inline void Set(float value)
150     {
151         ASSERT(!HasObject());
152         auto v = bit_cast<int32_t>(value);
153         SetValue(v);
154     }
155 
Set(double value)156     ALWAYS_INLINE inline void Set(double value)
157     {
158         ASSERT(!HasObject());
159         auto v = bit_cast<int64_t>(value);
160         SetValue(v);
161     }
162 
Set(ObjectHeader * value)163     ALWAYS_INLINE inline void Set(ObjectHeader *value)
164     {
165         ASSERT(HasObject());
166         auto v = bit_cast<object_pointer_type>(value);
167         SetValue(v);
168     }
169 
SetPrimitive(int32_t value)170     ALWAYS_INLINE inline void SetPrimitive(int32_t value)
171     {
172         SetValue(value);
173         MarkAsPrimitive();
174     }
175 
SetPrimitive(int64_t value)176     ALWAYS_INLINE inline void SetPrimitive(int64_t value)
177     {
178         SetValue(value);
179         MarkAsPrimitive();
180     }
181 
SetPrimitive(float value)182     ALWAYS_INLINE inline void SetPrimitive(float value)
183     {
184         auto v = bit_cast<int32_t>(value);
185         SetValue(v);
186         MarkAsPrimitive();
187     }
188 
SetPrimitive(double value)189     ALWAYS_INLINE inline void SetPrimitive(double value)
190     {
191         auto v = bit_cast<int64_t>(value);
192         SetValue(v);
193         MarkAsPrimitive();
194     }
195 
Get()196     ALWAYS_INLINE inline int32_t Get() const
197     {
198         ASSERT(!HasObject());
199         return static_cast<int32_t>(GetValue());
200     }
201 
GetFloat()202     ALWAYS_INLINE inline float GetFloat() const
203     {
204         ASSERT(!HasObject());
205         return bit_cast<float>(Get());
206     }
207 
GetLong()208     ALWAYS_INLINE inline int64_t GetLong() const
209     {
210         ASSERT(!HasObject());
211         return GetValue();
212     }
213 
GetDouble()214     ALWAYS_INLINE inline double GetDouble() const
215     {
216         ASSERT(!HasObject());
217         return bit_cast<double>(GetValue());
218     }
219 
GetReference()220     ALWAYS_INLINE inline ObjectHeader *GetReference() const
221     {
222         ASSERT(HasObject());
223         return reinterpret_cast<ObjectHeader *>(static_cast<object_pointer_type>(GetValue()));
224     }
225 
SetReference(ObjectHeader * obj)226     ALWAYS_INLINE inline void SetReference(ObjectHeader *obj)
227     {
228         auto v = down_cast<helpers::TypeHelperT<OBJECT_POINTER_SIZE * BYTE_SIZE, true>>(obj);
229         SetValue(v);
230         MarkAsObject();
231     }
232 
HasObject()233     ALWAYS_INLINE inline bool HasObject() const
234     {
235         return (GetTag() & OBJECT_MASK) != 0;
236     }
237 
MarkAsObject()238     ALWAYS_INLINE inline void MarkAsObject()
239     {
240         SetTag(GetTag() | OBJECT_MASK);
241     }
242 
MarkAsPrimitive()243     ALWAYS_INLINE inline void MarkAsPrimitive()
244     {
245         SetTag(GetTag() & ~OBJECT_MASK);
246     }
247 
248     template <typename M>
GetAs()249     ALWAYS_INLINE inline M GetAs() const
250     {
251         return ValueAccessor<M>::Get(*this);
252     }
253 
254 #ifndef NDEBUG
DumpVReg()255     ALWAYS_INLINE inline PandaString DumpVReg()
256     {
257         PandaStringStream values;
258         if (HasObject() != 0) {
259             values << "obj = " << std::hex << GetValue();
260         } else {
261             values << "pri = (i64) " << GetValue() << " | "
262                    << "(f32) " << GetFloat() << " | "
263                    << "(f64) " << GetDouble() << " | "
264                    << "(hex) " << std::hex << GetValue();
265         }
266         values << " | tag = " << GetTag();
267         return values.str();
268     }
269 #endif
270 
271 private:
272     template <typename M, typename = void>
273     struct ValueAccessor {
274         static M Get(const VRegisterIface<T> &vreg);
275     };
276 
277     static constexpr uint64_t OBJECT_MASK = 0x1;
278 
279     static constexpr int8_t BYTE_SIZE = 8;
280 };
281 
282 }  // namespace panda::interpreter
283 
284 #endif  // PANDA_RUNTIME_INTERPRETER_VREGISTER_H_
285