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