• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #ifndef PANDA_VERIFICATION_TYPE_TYPE_TYPE_H
17 #define PANDA_VERIFICATION_TYPE_TYPE_TYPE_H
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 ark::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     PandaString IntersectionToString(TypeSystem const *&tsys) const;
91     PandaString UnionToString(TypeSystem const *&tsys) const;
92 
93 private:
94     static int constexpr INTERSECTION_TAG = 1;
95     static int constexpr UNION_TAG = 2;
96 
97     static size_t constexpr BITS_FOR_SPAN_SIZE = 8;
98     // NOLINTNEXTLINE(hicpp-signed-bitwise)
99     static size_t constexpr SPAN_MASK = (1 << BITS_FOR_SPAN_SIZE) - 1;
100     // NOLINTNEXTLINE(hicpp-signed-bitwise)
101     static size_t constexpr MAX_SPAN_SIZE = (1 << BITS_FOR_SPAN_SIZE) - 1;
102 
SpanSize(uintptr_t v)103     static size_t SpanSize(uintptr_t v)
104     {
105         return v & SPAN_MASK;
106     }
107 
SpanIndex(uintptr_t v)108     static size_t SpanIndex(uintptr_t v)
109     {
110         return v >> BITS_FOR_SPAN_SIZE;
111     }
112 
ConstructPayload(size_t spanSize,size_t spanIndex)113     static uintptr_t ConstructPayload(size_t spanSize, size_t spanIndex)
114     {
115         ASSERT(spanSize > 0);
116         ASSERT(spanSize <= MAX_SPAN_SIZE);
117         return (spanIndex << BITS_FOR_SPAN_SIZE) | spanSize;
118     }
119 
120 public:
121     static Type FromTypeId(panda_file::Type::TypeId tid);
122 
Bot()123     static Type Bot()
124     {
125         return Type {Builtin::BOT};
126     }
Top()127     static Type Top()
128     {
129         return Type {Builtin::TOP};
130     }
131 
IsNone()132     ALWAYS_INLINE bool IsNone() const
133     {
134         return content_ == 0;
135     }
IsValid()136     ALWAYS_INLINE bool IsValid() const
137     {
138         return content_ != 0;
139     }
IsBuiltin()140     ALWAYS_INLINE bool IsBuiltin() const
141     {
142         return IsValid() && content_ < Builtin::LAST;
143     }
IsClass()144     ALWAYS_INLINE bool IsClass() const
145     {
146         return IsValid() && !IsBuiltin() && IsPointer(content_);
147     }
IsIntersection()148     ALWAYS_INLINE bool IsIntersection() const
149     {
150         return IsNotPointer(content_) && GetTag(content_) == INTERSECTION_TAG;
151     }
IsUnion()152     ALWAYS_INLINE bool IsUnion() const
153     {
154         return IsNotPointer(content_) && GetTag(content_) == UNION_TAG;
155     }
156 
GetBuiltin()157     ALWAYS_INLINE Builtin GetBuiltin() const
158     {
159         ASSERT(IsBuiltin());
160         return static_cast<Builtin>(content_);
161     }
GetClass()162     ALWAYS_INLINE Class const *GetClass() const
163     {
164         ASSERT(IsClass());
165         return reinterpret_cast<Class const *>(content_);
166     }
167 
168     bool IsConsistent() const;
169 
170     panda_file::Type::TypeId ToTypeId() const;
171 
172     size_t GetTypeWidth() const;
173 
174     Type GetArrayElementType(TypeSystem *tsys) const;
175 
176     // Careful: span is invalidated whenever a new intersection or union is created.
177     Span<Type const> GetIntersectionMembers(TypeSystem const *tsys) const;
178     Span<Type const> GetUnionMembers(TypeSystem const *tsys) const;
179 
180 private:
181     uintptr_t content_ {0};
182 
183     static Type IntersectSpans(Span<Type const> lhs, Span<Type const> rhs, TypeSystem *tsys);
184 
185     friend bool IsSubtypeImpl(Type lhs, Type rhs, TypeSystem *tsys);
186     friend Type TpIntersection(Type lhs, Type rhs, TypeSystem *tsys);
187     friend Type TpUnion(Type lhs, Type rhs, TypeSystem *tsys);
188     friend struct std::hash<Type>;
189     friend bool operator==(Type lhs, Type rhs);
190 };
191 
192 ALWAYS_INLINE inline bool operator==(Type lhs, Type rhs)
193 {
194     return lhs.content_ == rhs.content_;
195 }
196 
197 ALWAYS_INLINE inline bool operator!=(Type lhs, Type rhs)
198 {
199     return !(lhs == rhs);
200 }
201 
202 ALWAYS_INLINE inline bool IsSubtype(Type lhs, Type rhs, TypeSystem *tsys)
203 {
204     return lhs == rhs || IsSubtypeImpl(lhs, rhs, tsys);
205 }
206 
207 struct MethodSignature {
208     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
209     PandaVector<Type> args;
210     Type result;
211     // NOLINTEND(misc-non-private-member-variables-in-classes)
212 
213     PandaString ToString(TypeSystem const *tsys) const
214     {
215         std::stringstream ss;
216         ss << "(";
217         bool first = true;
218         for (auto const &arg : args) {
219             if (first) {
220                 first = false;
221             } else {
222                 ss << ", ";
223             }
224             ss << arg.ToString(tsys);
225         }
226         ss << ") -> ";
227         ss << result.ToString(tsys);
228         return PandaString(ss.str());
229     }
230 };
231 
232 }  // namespace ark::verifier
233 
234 namespace std {
235 template <>
236 struct hash<ark::verifier::Type> {
237     size_t operator()(ark::verifier::Type tp) const
238     {
239         return hash<uintptr_t>()(tp.content_);
240     }
241 };
242 }  // namespace std
243 
244 #endif  // PANDA_VERIFICATION_TYPE_TYPE_TYPE_H
245