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