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