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 16 #ifndef PANDA_VERIFIER_TYPE_TYPE_HPP 17 #define PANDA_VERIFIER_TYPE_TYPE_HPP 18 19 #include "verification/util/mem.h" 20 21 #include "macros.h" 22 #include "runtime/include/class.h" 23 #include "runtime/include/method.h" 24 25 #include <variant> 26 27 namespace panda::verifier { 28 class TypeSystem; 29 30 class Type { 31 /* Invariant: 32 Intersections can only contain (builtins or classes). 33 Unions can only contain intersections or elementary types. 34 Top and Bot cannot be parts of intersections or unions. 35 */ 36 public: 37 enum Builtin : size_t { 38 TOP = 1, 39 U1, 40 I8, 41 U8, 42 I16, 43 U16, 44 I32, 45 U32, 46 F32, 47 F64, 48 I64, 49 U64, 50 INTEGRAL8, 51 INTEGRAL16, 52 INTEGRAL32, 53 INTEGRAL64, 54 FLOAT32, 55 FLOAT64, 56 BITS32, 57 BITS64, 58 PRIMITIVE, 59 REFERENCE, 60 NULL_REFERENCE, 61 OBJECT, 62 TYPE_CLASS, 63 ARRAY, 64 BOT, 65 66 LAST 67 }; 68 69 public: 70 Type() = default; 71 ~Type() = default; 72 DEFAULT_COPY_SEMANTIC(Type); 73 DEFAULT_MOVE_SEMANTIC(Type); 74 Type(Builtin builtin)75 explicit Type(Builtin builtin) : content_ {builtin} {} Type(Class const * klass)76 explicit Type(Class const *klass) : content_ {reinterpret_cast<uintptr_t>(klass)} 77 { 78 if (klass->IsPrimitive()) { 79 *this = FromTypeId(klass->GetType().GetId()); 80 } 81 } 82 83 PandaString ToString(TypeSystem const *tsys) const; 84 85 private: Type(uintptr_t content)86 explicit Type(uintptr_t content) : content_ {content} {} 87 88 static Type Intersection(Span<Type> span, TypeSystem *tsys); 89 static Type Union(Span<Type> span, TypeSystem *tsys); 90 91 private: 92 static int constexpr INTERSECTION_TAG = 1; 93 static int constexpr UNION_TAG = 2; 94 95 static size_t constexpr BITS_FOR_SPAN_SIZE = 8; 96 // NOLINTNEXTLINE(hicpp-signed-bitwise) 97 static size_t constexpr SPAN_MASK = (1 << BITS_FOR_SPAN_SIZE) - 1; 98 // NOLINTNEXTLINE(hicpp-signed-bitwise) 99 static size_t constexpr MAX_SPAN_SIZE = (1 << BITS_FOR_SPAN_SIZE) - 1; 100 SpanSize(uintptr_t v)101 static size_t SpanSize(uintptr_t v) 102 { 103 return v & SPAN_MASK; 104 } 105 SpanIndex(uintptr_t v)106 static size_t SpanIndex(uintptr_t v) 107 { 108 return v >> BITS_FOR_SPAN_SIZE; 109 } 110 ConstructPayload(size_t spanSize,size_t spanIndex)111 static uintptr_t ConstructPayload(size_t spanSize, size_t spanIndex) 112 { 113 ASSERT(spanSize > 0 && spanSize <= MAX_SPAN_SIZE); 114 return (spanIndex << BITS_FOR_SPAN_SIZE) | spanSize; 115 } 116 117 public: 118 static Type FromTypeId(panda_file::Type::TypeId tid); 119 Bot()120 static Type Bot() 121 { 122 return Type {Builtin::BOT}; 123 } Top()124 static Type Top() 125 { 126 return Type {Builtin::TOP}; 127 } 128 IsNone()129 ALWAYS_INLINE bool IsNone() const 130 { 131 return content_ == 0; 132 } IsValid()133 ALWAYS_INLINE bool IsValid() const 134 { 135 return content_ != 0; 136 } IsBuiltin()137 ALWAYS_INLINE bool IsBuiltin() const 138 { 139 return IsValid() && content_ < Builtin::LAST; 140 } IsClass()141 ALWAYS_INLINE bool IsClass() const 142 { 143 return IsValid() && !IsBuiltin() && IsPointer(content_); 144 } IsIntersection()145 ALWAYS_INLINE bool IsIntersection() const 146 { 147 return IsNotPointer(content_) && GetTag(content_) == INTERSECTION_TAG; 148 } IsUnion()149 ALWAYS_INLINE bool IsUnion() const 150 { 151 return IsNotPointer(content_) && GetTag(content_) == UNION_TAG; 152 } 153 GetBuiltin()154 ALWAYS_INLINE Builtin GetBuiltin() const 155 { 156 ASSERT(IsBuiltin()); 157 return static_cast<Builtin>(content_); 158 } GetClass()159 ALWAYS_INLINE Class const *GetClass() const 160 { 161 ASSERT(IsClass()); 162 return reinterpret_cast<Class const *>(content_); 163 } 164 165 bool IsConsistent() const; 166 167 panda_file::Type::TypeId ToTypeId() const; 168 169 size_t GetTypeWidth() const; 170 171 Type GetArrayElementType(TypeSystem *tsys) const; 172 173 // Careful: span is invalidated whenever a new intersection or union is created. 174 Span<Type const> GetIntersectionMembers(TypeSystem const *tsys) const; 175 Span<Type const> GetUnionMembers(TypeSystem const *tsys) const; 176 177 private: 178 uintptr_t content_ {0}; 179 180 static Type IntersectSpans(Span<Type const> lhs, Span<Type const> rhs, TypeSystem *tsys); 181 182 friend bool IsSubtypeImpl(Type lhs, Type rhs, TypeSystem *tsys); 183 friend Type TpIntersection(Type lhs, Type rhs, TypeSystem *tsys); 184 friend Type TpUnion(Type lhs, Type rhs, TypeSystem *tsys); 185 friend struct std::hash<Type>; 186 friend bool operator==(Type lhs, Type rhs); 187 }; 188 189 ALWAYS_INLINE inline bool operator==(Type lhs, Type rhs) 190 { 191 return lhs.content_ == rhs.content_; 192 } 193 194 ALWAYS_INLINE inline bool operator!=(Type lhs, Type rhs) 195 { 196 return !(lhs == rhs); 197 } 198 199 ALWAYS_INLINE inline bool IsSubtype(Type lhs, Type rhs, TypeSystem *tsys) 200 { 201 return lhs == rhs || IsSubtypeImpl(lhs, rhs, tsys); 202 } 203 204 struct MethodSignature { 205 // NOLINTBEGIN(misc-non-private-member-variables-in-classes) 206 PandaVector<Type> args; 207 Type result; 208 // NOLINTEND(misc-non-private-member-variables-in-classes) 209 210 PandaString ToString(TypeSystem const *tsys) const 211 { 212 std::stringstream ss; 213 ss << "("; 214 bool first = true; 215 for (auto const &arg : args) { 216 if (first) { 217 first = false; 218 } else { 219 ss << ", "; 220 } 221 ss << arg.ToString(tsys); 222 } 223 ss << ") -> "; 224 ss << result.ToString(tsys); 225 return PandaString(ss.str()); 226 } 227 }; 228 229 } // namespace panda::verifier 230 231 namespace std { 232 template <> 233 struct hash<panda::verifier::Type> { 234 size_t operator()(panda::verifier::Type tp) const 235 { 236 return hash<uintptr_t>()(tp.content_); 237 } 238 }; 239 } // namespace std 240 241 #endif // !PANDA_VERIFIER_TYPE_TYPE_HPP 242