• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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