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 #include "verification/type/type_system.h"
17
18 #include "runtime/include/thread_scopes.h"
19 #include "verification/jobs/job.h"
20 #include "verification/jobs/service.h"
21 #include "verification/public_internal.h"
22 #include "verification/plugins.h"
23 #include "verifier_messages.h"
24
25 namespace panda::verifier {
26
ClassNameToDescriptorString(char const * name)27 static PandaString ClassNameToDescriptorString(char const *name)
28 {
29 PandaString str = "L";
30 for (char const *s = name; *s != '\0'; s++) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
31 char c = (*s == '.') ? '/' : *s;
32 str += c;
33 }
34 str += ';';
35 return str;
36 }
37
TypeSystem(VerifierService * service,panda_file::SourceLang lang)38 TypeSystem::TypeSystem(VerifierService *service, panda_file::SourceLang lang)
39 : service_ {service},
40 plugin_ {plugin::GetLanguagePlugin(lang)},
41 langCtx_ {panda::plugins::GetLanguageContextBase(lang)},
42 linkerCtx_ {service->GetClassLinker()->GetExtension(LanguageContext {langCtx_})->GetBootContext()}
43 {
44 ScopedChangeThreadStatus st(ManagedThread::GetCurrent(), ThreadStatus::RUNNING);
__anon046b39260102(uint8_t const *descr) 45 auto compute = [&](uint8_t const *descr) -> Type {
46 if (descr != nullptr) {
47 Job::ErrorHandler handler;
48 auto *klass = service->GetClassLinker()->GetClass(descr, true, linkerCtx_, &handler);
49 if (klass == nullptr) {
50 return Type {};
51 }
52 return Type {klass};
53 }
54 return Type {};
55 };
56
57 class_ = compute(langCtx_.GetClassClassDescriptor());
58 object_ = compute(langCtx_.GetObjectClassDescriptor());
59 // Throwable is not given to us as descriptor for some reason. NOTE(gogabr): correct this.
60 auto throwableClassName = langCtx_.GetVerificationTypeThrowable();
61 if (throwableClassName != nullptr) {
62 auto throwableDescrStr = ClassNameToDescriptorString(throwableClassName);
63 throwable_ = compute(utf::CStringAsMutf8(throwableDescrStr.c_str()));
64 } else {
65 throwable_ = Type {};
66 }
67 plugin_->TypeSystemSetup(this);
68 }
69
DescriptorToClass(uint8_t const * descr)70 Class const *TypeSystem::DescriptorToClass(uint8_t const *descr)
71 {
72 Job::ErrorHandler handler;
73 return service_->GetClassLinker()->GetClass(descr, true, linkerCtx_, &handler);
74 }
75
DescriptorToType(uint8_t const * descr)76 Type TypeSystem::DescriptorToType(uint8_t const *descr)
77 {
78 auto cls = DescriptorToClass(descr);
79 if (cls == nullptr) {
80 return Type {};
81 }
82 return Type {cls};
83 }
84
ExtendBySupers(PandaUnorderedSet<Type> * set,Class const * klass)85 void TypeSystem::ExtendBySupers(PandaUnorderedSet<Type> *set, Class const *klass)
86 {
87 // NOTE(gogabr): do we need to cache intermediate results? Measure!
88 Type newTp = Type {klass};
89 if (set->count(newTp) > 0) {
90 return;
91 }
92 set->insert(newTp);
93
94 Class const *super = klass->GetBase();
95 if (super != nullptr) {
96 ExtendBySupers(set, super);
97 }
98
99 for (auto const *a : klass->GetInterfaces()) {
100 ExtendBySupers(set, a);
101 }
102 }
103
NormalizedTypeOf(Type type)104 Type TypeSystem::NormalizedTypeOf(Type type)
105 {
106 ASSERT(!type.IsNone());
107 if (type == Type::Bot() || type == Type::Top()) {
108 return type;
109 }
110 auto t = normalizedTypeOf_.find(type);
111 if (t != normalizedTypeOf_.cend()) {
112 return t->second;
113 }
114 Type result = plugin_->NormalizeType(type, this);
115 normalizedTypeOf_[type] = result;
116 return result;
117 }
118
GetMethodSignature(Method const * method)119 MethodSignature const *TypeSystem::GetMethodSignature(Method const *method)
120 {
121 ScopedChangeThreadStatus st(ManagedThread::GetCurrent(), ThreadStatus::RUNNING);
122 auto &&methodId = method->GetUniqId();
123 auto it = signatureOfMethod_.find(methodId);
124 if (it != signatureOfMethod_.end()) {
125 return &it->second;
126 }
127
128 methodOfId_[methodId] = method;
129
130 MethodSignature sig;
131 if (method->GetReturnType().IsReference()) {
132 sig.result = DescriptorToType(method->GetRefReturnType().data);
133 } else {
134 sig.result = Type::FromTypeId(method->GetReturnType().GetId());
135 }
136 size_t refIdx = 0;
137 for (size_t i = 0; i < method->GetNumArgs(); i++) {
138 Type argType;
139 if (method->GetArgType(i).IsReference()) {
140 argType = DescriptorToType(method->GetRefArgType(refIdx++).data);
141 } else {
142 argType = Type::FromTypeId(method->GetArgType(i).GetId());
143 }
144 sig.args.push_back(argType);
145 }
146 signatureOfMethod_[methodId] = sig;
147 return &signatureOfMethod_[methodId];
148 }
149
SupertypesOfClass(Class const * klass)150 PandaUnorderedSet<Type> const *TypeSystem::SupertypesOfClass(Class const *klass)
151 {
152 ASSERT(!klass->IsArrayClass());
153 if (supertypesCache_.count(klass) > 0) {
154 return &supertypesCache_[klass];
155 }
156
157 PandaUnorderedSet<Type> toCache;
158 ExtendBySupers(&toCache, klass);
159 supertypesCache_[klass] = std::move(toCache);
160 return &supertypesCache_[klass];
161 }
162
MentionClass(Class const * klass)163 void TypeSystem::MentionClass(Class const *klass)
164 {
165 knownClasses_.insert(klass);
166 }
167
DisplayTypeSystem(std::function<void (PandaString const &)> const & handler)168 void TypeSystem::DisplayTypeSystem(std::function<void(PandaString const &)> const &handler)
169 {
170 handler("Classes:");
171 DisplayClasses([&handler](auto const &name) { handler(name); });
172 handler("Methods:");
173 DisplayMethods([&handler](auto const &name, auto const &sig) { handler(name + " : " + sig); });
174 handler("Subtyping (type <; supertype)");
175 DisplaySubtyping([&handler](auto const &type, auto const &supertype) { handler(type + " <: " + supertype); });
176 }
177
DisplayClasses(std::function<void (PandaString const &)> const & handler) const178 void TypeSystem::DisplayClasses(std::function<void(PandaString const &)> const &handler) const
179 {
180 for (auto const *klass : knownClasses_) {
181 handler((Type {klass}).ToString(this));
182 }
183 }
184
DisplayMethods(std::function<void (PandaString const &,PandaString const &)> const & handler) const185 void TypeSystem::DisplayMethods(std::function<void(PandaString const &, PandaString const &)> const &handler) const
186 {
187 for (auto const &it : signatureOfMethod_) {
188 auto &id = it.first;
189 auto &sig = it.second;
190 auto const *method = methodOfId_.at(id);
191 handler(method->GetFullName(), sig.ToString(this));
192 }
193 }
194
DisplaySubtyping(std::function<void (PandaString const &,PandaString const &)> const & handler)195 void TypeSystem::DisplaySubtyping(std::function<void(PandaString const &, PandaString const &)> const &handler)
196 {
197 for (auto const *klass : knownClasses_) {
198 if (klass->IsArrayClass()) {
199 continue;
200 }
201 auto klassStr = (Type {klass}).ToString(this);
202 for (auto const &supertype : *SupertypesOfClass(klass)) {
203 handler(klassStr, supertype.ToString(this));
204 }
205 }
206 }
207
208 } // namespace panda::verifier
209