• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 #ifndef PANDA_RUNTIME_VTABLE_BUILDER_BASE_H
16 #define PANDA_RUNTIME_VTABLE_BUILDER_BASE_H
17 
18 #include "libpandabase/macros.h"
19 #include "libpandabase/utils/hash.h"
20 #include "libpandabase/utils/utf.h"
21 #include "libpandafile/class_data_accessor-inl.h"
22 #include "libpandafile/file-inl.h"
23 #include "libpandafile/file_items.h"
24 #include "libpandafile/proto_data_accessor-inl.h"
25 #include "runtime/class_linker_context.h"
26 #include "runtime/include/class-inl.h"
27 #include "runtime/include/class_linker.h"
28 #include "runtime/include/mem/panda_containers.h"
29 #include "runtime/include/mem/panda_smart_pointers.h"
30 #include "runtime/include/vtable_builder_interface.h"
31 
32 namespace ark {
33 
34 class ClassLinker;
35 class ClassLinkerContext;
36 
37 class MethodInfo {
38 public:
MethodInfo(const panda_file::MethodDataAccessor & mda,size_t index,ClassLinkerContext * ctx)39     MethodInfo(const panda_file::MethodDataAccessor &mda, size_t index, ClassLinkerContext *ctx)
40         : pf_(&mda.GetPandaFile()),
41           name_(pf_->GetStringData(mda.GetNameId())),
42           protoId_(mda.GetProtoId()),
43           accessFlags_(mda.GetAccessFlags()),
44           classId_(mda.GetClassId()),
45           ctx_(ctx),
46           vmethodIndex_(index)
47     {
48     }
49 
50     explicit MethodInfo(Method *method, size_t index = 0, bool isBase = false)
51         : pf_(method->GetPandaFile()),
52           name_(method->GetName()),
53           protoId_(method->GetProtoId().GetEntityId()),
54           accessFlags_(method->GetAccessFlags()),
55           isBase_(isBase),
56           classId_(method->GetClass()->GetFileId()),
57           method_(method),
58           ctx_(method->GetClass()->GetLoadContext()),
59           vmethodIndex_(index)
60     {
61     }
62 
GetName()63     const panda_file::File::StringData &GetName() const
64     {
65         return name_;
66     }
67 
GetClassName()68     const uint8_t *GetClassName() const
69     {
70         return method_ != nullptr ? method_->GetClass()->GetDescriptor() : pf_->GetStringData(classId_).data;
71     }
72 
GetProtoId()73     Method::ProtoId GetProtoId() const
74     {
75         return Method::ProtoId(*pf_, protoId_);
76     }
77 
GetMethod()78     Method *GetMethod() const
79     {
80         return method_;
81     }
82 
GetVirtualMethodIndex()83     size_t GetVirtualMethodIndex() const
84     {
85         return vmethodIndex_;
86     }
87 
IsAbstract()88     bool IsAbstract() const
89     {
90         return (accessFlags_ & ACC_ABSTRACT) != 0;
91     }
92 
IsFinal()93     bool IsFinal() const
94     {
95         return (accessFlags_ & ACC_FINAL) != 0;
96     }
97 
IsPublic()98     bool IsPublic() const
99     {
100         return (accessFlags_ & ACC_PUBLIC) != 0;
101     }
102 
IsProtected()103     bool IsProtected() const
104     {
105         return (accessFlags_ & ACC_PROTECTED) != 0;
106     }
107 
IsPrivate()108     bool IsPrivate() const
109     {
110         return (accessFlags_ & ACC_PRIVATE) != 0;
111     }
112 
IsInterfaceMethod()113     bool IsInterfaceMethod() const
114     {
115         if (method_ != nullptr) {
116             return method_->GetClass()->IsInterface();
117         }
118 
119         panda_file::ClassDataAccessor cda(*pf_, classId_);
120         return cda.IsInterface();
121     }
122 
IsBase()123     bool IsBase() const
124     {
125         return isBase_;
126     }
127 
GetLoadContext()128     ClassLinkerContext *GetLoadContext() const
129     {
130         return ctx_;
131     }
132 
133     ~MethodInfo() = default;
134 
135     bool operator==(MethodInfo &other) = delete;
136 
137     DEFAULT_COPY_CTOR(MethodInfo);
138     NO_COPY_OPERATOR(MethodInfo);
139     NO_MOVE_SEMANTIC(MethodInfo);
140 
141 private:
142     const panda_file::File *pf_;
143     panda_file::File::StringData name_;
144     panda_file::File::EntityId protoId_;
145     uint32_t accessFlags_;
146     bool isBase_ {false};
147 
148     panda_file::File::EntityId classId_;
149     Method *method_ {nullptr};
150     ClassLinkerContext *ctx_ {nullptr};
151 
152     size_t vmethodIndex_ {0};
153 };
154 
155 class VTableInfo {
156 public:
VTableInfo(ArenaAllocator * allocator)157     explicit VTableInfo(ArenaAllocator *allocator)
158         : vmethods_(allocator->Adapter()), copiedMethods_(allocator->Adapter())
159     {
160     }
161 
162     struct MethodEntry {
MethodEntryMethodEntry163         explicit MethodEntry(size_t index) : index_(index) {}
164 
CandidateOrMethodEntry165         MethodInfo const *CandidateOr(MethodInfo const *orig) const
166         {
167             return candidate_ != nullptr ? candidate_ : orig;
168         }
169 
GetIndexMethodEntry170         size_t GetIndex() const
171         {
172             return index_;
173         }
174 
GetCandidateMethodEntry175         MethodInfo const *GetCandidate() const
176         {
177             return candidate_;
178         }
179 
SetCandidateMethodEntry180         void SetCandidate(MethodInfo const *candidate)
181         {
182             candidate_ = candidate;
183         }
184 
185     private:
186         size_t index_ {};
187         MethodInfo const *candidate_ {};
188     };
189 
190     struct CopiedMethodEntry {
CopiedMethodEntryCopiedMethodEntry191         explicit CopiedMethodEntry(size_t index) : index_(index) {}
192 
GetIndexCopiedMethodEntry193         size_t GetIndex() const
194         {
195             return index_;
196         }
197 
GetStatusCopiedMethodEntry198         CopiedMethod::Status GetStatus() const
199         {
200             return status_;
201         }
202 
SetStatusCopiedMethodEntry203         void SetStatus(CopiedMethod::Status status)
204         {
205             status_ = status;
206         }
207 
208     private:
209         size_t index_ {};
210         CopiedMethod::Status status_ {CopiedMethod::Status::ORDINARY};
211     };
212 
Methods()213     auto &Methods()
214     {
215         return vmethods_;
216     }
217 
Methods()218     auto &Methods() const
219     {
220         return vmethods_;
221     }
222 
CopiedMethods()223     auto &CopiedMethods()
224     {
225         return copiedMethods_;
226     }
227 
CopiedMethods()228     auto &CopiedMethods() const
229     {
230         return copiedMethods_;
231     }
232 
233     void AddEntry(const MethodInfo *info);
234 
235     CopiedMethodEntry &AddCopiedEntry(const MethodInfo *info);
236 
237     CopiedMethodEntry &UpdateCopiedEntry(const MethodInfo *orig, const MethodInfo *repl);
238 
GetVTableSize()239     size_t GetVTableSize() const
240     {
241         return vmethods_.size() + copiedMethods_.size();
242     }
243 
244     void UpdateClass(Class *klass) const;
245 
246     void DumpMappings();
247 
248     static void DumpVTable([[maybe_unused]] Class *klass);
249 
250 private:
251     struct MethodNameHash {
operatorMethodNameHash252         uint32_t operator()(const MethodInfo *methodInfo) const
253         {
254             return GetHash32String(methodInfo->GetName().data);
255         }
256     };
257 
258     ArenaUnorderedMap<MethodInfo const *, MethodEntry, MethodNameHash> vmethods_;
259     ArenaUnorderedMap<MethodInfo const *, CopiedMethodEntry, MethodNameHash> copiedMethods_;
260 };
261 
262 template <typename Pred, typename UMap>
263 class FilterBucketIterator {
264 public:
265     using LocalIter = typename UMap::local_iterator;
266 
FilterBucketIterator(Pred pred,UMap & umap,const typename UMap::key_type & key)267     FilterBucketIterator(Pred pred, UMap &umap, const typename UMap::key_type &key) : pred_(pred)
268     {
269         if (umap.bucket_count() == 0) {
270             return;
271         }
272         valid_ = true;
273         auto const bucket = umap.bucket(key);
274         iter_ = umap.begin(bucket);
275         endIter_ = umap.end(bucket);
276         Advance();
277     }
278 
IsEmpty()279     bool IsEmpty() const
280     {
281         return !valid_ || iter_ == endIter_;
282     }
283 
Value()284     typename UMap::reference Value()
285     {
286         ASSERT(!IsEmpty());
287         return *iter_;
288     }
289 
Next()290     void Next()
291     {
292         ASSERT(!IsEmpty());
293         ++iter_;
294         Advance();
295     }
296 
297 private:
Advance()298     void Advance()
299     {
300         while (!IsEmpty() && !pred_(iter_)) {
301             ++iter_;
302         }
303     }
304 
305     bool valid_ {};
306     LocalIter iter_ {};
307     LocalIter endIter_ {};
308     Pred pred_;
309 };
310 
311 template <typename UMap>
SameNameMethodInfoIterator(UMap & umap,MethodInfo const * info)312 auto SameNameMethodInfoIterator(UMap &umap, MethodInfo const *info)
313 {
314     auto pred = [info](auto other) { return other->first->GetName() == info->GetName(); };
315     return FilterBucketIterator(pred, umap, info);
316 }
317 
318 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
319 template <bool VISIT_SUPERITABLE>
320 class VTableBuilderBase : public VTableBuilder {
321 public:
322     bool Build(panda_file::ClassDataAccessor *cda, Class *baseClass, ITable itable, ClassLinkerContext *ctx) override;
323 
324     bool Build(Span<Method> methods, Class *baseClass, ITable itable, bool isInterface) override;
325 
326     void UpdateClass(Class *klass) const override;
327 
GetNumVirtualMethods()328     size_t GetNumVirtualMethods() const override
329     {
330         return numVmethods_;
331     }
332 
GetVTableSize()333     size_t GetVTableSize() const override
334     {
335         return vtable_.GetVTableSize();
336     }
337 
GetCopiedMethods()338     Span<const CopiedMethod> GetCopiedMethods() const override
339     {
340         return {orderedCopiedMethods_.data(), orderedCopiedMethods_.size()};
341     }
342 
343 protected:
VTableBuilderBase(ClassLinkerErrorHandler * errHandler)344     explicit VTableBuilderBase(ClassLinkerErrorHandler *errHandler) : errorHandler_(errHandler) {}
345 
346     [[nodiscard]] virtual bool ProcessClassMethod(const MethodInfo *info) = 0;
347     [[nodiscard]] virtual bool ProcessDefaultMethod(ITable itable, size_t itableIdx, MethodInfo *methodInfo) = 0;
348 
349     ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_INTERNAL};
350     VTableInfo vtable_ {&allocator_};
351     size_t numVmethods_ {0};
352     ArenaVector<CopiedMethod> orderedCopiedMethods_ {allocator_.Adapter()};
353     ClassLinkerErrorHandler *errorHandler_;
354 
355 private:
356     void BuildForInterface(panda_file::ClassDataAccessor *cda);
357 
358     void BuildForInterface(Span<Method> methods);
359 
360     void AddBaseMethods(Class *baseClass);
361 
362     [[nodiscard]] bool AddClassMethods(panda_file::ClassDataAccessor *cda, ClassLinkerContext *ctx);
363 
364     [[nodiscard]] bool AddClassMethods(Span<Method> methods);
365 
366     [[nodiscard]] bool AddDefaultInterfaceMethods(ITable itable, size_t superItableSize);
367 
368     bool hasDefaultMethods_ {false};
369 };
370 // NOLINTEND(misc-non-private-member-variables-in-classes)
371 
372 }  // namespace ark
373 
374 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_BASE_H
375