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