• 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 #ifndef PANDA_RUNTIME_VTABLE_BUILDER_H_
16 #define PANDA_RUNTIME_VTABLE_BUILDER_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/include/class-inl.h"
26 #include "runtime/include/mem/panda_containers.h"
27 #include "runtime/include/mem/panda_smart_pointers.h"
28 #include "runtime/include/method.h"
29 
30 namespace panda {
31 
32 bool IsMaxSpecificMethod(const Class *iface, const Method &method, size_t startindex, const ITable &itable);
33 
34 class ClassLinker;
35 class ClassLinkerContext;
36 
37 class MethodInfo {
38 public:
39     static constexpr size_t INVALID_METHOD_IDX = std::numeric_limits<size_t>::max();
MethodInfo(const panda_file::MethodDataAccessor & mda,size_t index,ClassLinkerContext * ctx)40     MethodInfo(const panda_file::MethodDataAccessor &mda, size_t index, ClassLinkerContext *ctx)
41         : pf_(&mda.GetPandaFile()),
42           class_id_(mda.GetClassId()),
43           access_flags_(mda.GetAccessFlags()),
44           name_(pf_->GetStringData(mda.GetNameId())),
45           proto_(*pf_, mda.GetProtoId()),
46           ctx_(ctx),
47           index_(index)
48     {
49     }
50 
51     explicit MethodInfo(Method *method, size_t index = 0, bool is_base = false, bool needs_copy = false)
method_(method)52         : method_(method),
53           pf_(method->GetPandaFile()),
54           class_id_(method->GetClass()->GetFileId()),
55           access_flags_(method->GetAccessFlags()),
56           name_(method->GetName()),
57           proto_(method->GetProtoId()),
58           ctx_(method->GetClass()->GetLoadContext()),
59           index_(index),
60           needs_copy_(needs_copy),
61           is_base_(is_base)
62     {
63     }
64 
IsEqualByNameAndSignature(const MethodInfo & other)65     bool IsEqualByNameAndSignature(const MethodInfo &other) const
66     {
67         return GetName() == other.GetName() && GetProtoId() == other.GetProtoId();
68     }
69 
GetName()70     const panda_file::File::StringData &GetName() const
71     {
72         return name_;
73     }
74 
GetClassName()75     const uint8_t *GetClassName() const
76     {
77         return method_ != nullptr ? method_->GetClass()->GetDescriptor() : pf_->GetStringData(class_id_).data;
78     }
79 
GetProtoId()80     const Method::ProtoId &GetProtoId() const
81     {
82         return proto_;
83     }
84 
GetMethod()85     Method *GetMethod() const
86     {
87         return method_;
88     }
89 
GetIndex()90     size_t GetIndex() const
91     {
92         return index_;
93     }
94 
IsAbstract()95     bool IsAbstract() const
96     {
97         return (access_flags_ & ACC_ABSTRACT) != 0;
98     }
99 
IsPublic()100     bool IsPublic() const
101     {
102         return (access_flags_ & ACC_PUBLIC) != 0;
103     }
104 
IsProtected()105     bool IsProtected() const
106     {
107         return (access_flags_ & ACC_PROTECTED) != 0;
108     }
109 
IsPrivate()110     bool IsPrivate() const
111     {
112         return (access_flags_ & ACC_PRIVATE) != 0;
113     }
114 
IsInterfaceMethod()115     bool IsInterfaceMethod() const
116     {
117         if (method_ != nullptr) {
118             return method_->GetClass()->IsInterface();
119         }
120 
121         panda_file::ClassDataAccessor cda(*pf_, class_id_);
122         return cda.IsInterface();
123     }
124 
NeedsCopy()125     bool NeedsCopy() const
126     {
127         return needs_copy_;
128     }
129 
IsBase()130     bool IsBase() const
131     {
132         return is_base_;
133     }
134 
GetLoadContext()135     ClassLinkerContext *GetLoadContext() const
136     {
137         return ctx_;
138     }
139 
IsCopied()140     bool IsCopied() const
141     {
142         if (method_ == nullptr) {
143             return false;
144         }
145 
146         return method_->IsDefaultInterfaceMethod();
147     }
148 
149     ~MethodInfo() = default;
150 
151     DEFAULT_COPY_CTOR(MethodInfo)
152     NO_COPY_OPERATOR(MethodInfo);
153     NO_MOVE_SEMANTIC(MethodInfo);
154 
155 private:
156     Method *method_ {nullptr};
157     const panda_file::File *pf_;
158     panda_file::File::EntityId class_id_;
159     uint32_t access_flags_;
160     panda_file::File::StringData name_;
161     Method::ProtoId proto_;
162     ClassLinkerContext *ctx_ {nullptr};
163     size_t index_ {0};
164     bool needs_copy_ {false};
165     bool is_base_ {false};
166 };
167 
168 template <class SearchPred, class OverridePred>
169 class VTable {
170 public:
AddBaseMethod(const MethodInfo & info)171     void AddBaseMethod(const MethodInfo &info)
172     {
173         methods_.insert({info, methods_.size()});
174     }
175 
AddMethod(const MethodInfo & info)176     std::pair<bool, size_t> AddMethod(const MethodInfo &info)
177     {
178         auto [beg_it, end_it] = methods_.equal_range(info);
179         if (beg_it == methods_.cend()) {
180             methods_.insert({info, methods_.size()});
181             return std::pair<bool, size_t>(true, MethodInfo::INVALID_METHOD_IDX);
182         }
183 
184         for (auto it = beg_it; it != end_it; ++it) {
185             std::pair<bool, size_t> res = OverridePred()(it->first, info);
186             if (res.first) {
187                 if (res.second == MethodInfo::INVALID_METHOD_IDX) {
188                     size_t idx = it->second;
189                     methods_.erase(it);
190                     methods_.insert({info, idx});
191                 }
192                 return res;
193             }
194         }
195 
196         return std::pair<bool, size_t>(false, MethodInfo::INVALID_METHOD_IDX);
197     }
198 
UpdateClass(Class * klass)199     void UpdateClass(Class *klass) const
200     {
201         auto vtable = klass->GetVTable();
202 
203         for (const auto &[method_info, idx] : methods_) {
204             Method *method = method_info.GetMethod();
205             if (method == nullptr) {
206                 method = &klass->GetVirtualMethods()[method_info.GetIndex()];
207                 method->SetVTableIndex(idx);
208             } else if (method_info.NeedsCopy()) {
209                 method = &klass->GetCopiedMethods()[method_info.GetIndex()];
210                 method->SetVTableIndex(idx);
211             } else if (!method_info.IsBase()) {
212                 method->SetVTableIndex(idx);
213             }
214 
215             vtable[idx] = method;
216         }
217 
218         DumpVTable(klass);
219     }
220 
DumpVTable(Class * klass)221     static void DumpVTable([[maybe_unused]] Class *klass)
222     {
223 #ifndef NDEBUG
224         LOG(DEBUG, CLASS_LINKER) << "vtable of class " << klass->GetName() << ":";
225         auto vtable = klass->GetVTable();
226         size_t idx = 0;
227         for (auto *method : vtable) {
228             LOG(DEBUG, CLASS_LINKER) << "[" << idx++ << "] " << method->GetFullName();
229         }
230 #endif  // NDEBUG
231     }
232 
Size()233     size_t Size() const
234     {
235         return methods_.size();
236     }
237 
238 private:
239     struct HashByName {
operatorHashByName240         uint32_t operator()(const MethodInfo &method_info) const
241         {
242             return GetHash32String(method_info.GetName().data);
243         }
244     };
245 
246     PandaUnorderedMultiMap<MethodInfo, size_t, HashByName, SearchPred> methods_;
247 };
248 
249 struct CopiedMethod {
CopiedMethodCopiedMethod250     CopiedMethod(Method *method, bool default_conflict, bool default_abstract)
251         : method_(method), default_conflict_(default_conflict), default_abstract_(default_abstract)
252     {
253     }
254     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
255     Method *method_;
256     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
257     bool default_conflict_;  // flag indicates whether current methed is judged icce
258     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
259     bool default_abstract_;  // flag indicates whether current methed is judged ame
260 };
261 
262 class VTableBuilder {
263 public:
264     VTableBuilder() = default;
265 
266     virtual void Build(panda_file::ClassDataAccessor *cda, Class *base_class, ITable itable,
267                        ClassLinkerContext *ctx) = 0;
268 
269     virtual void Build(Span<Method> methods, Class *base_class, ITable itable, bool is_interface) = 0;
270 
271     virtual void UpdateClass(Class *klass) const = 0;
272 
273     virtual size_t GetNumVirtualMethods() const = 0;
274 
275     virtual size_t GetVTableSize() const = 0;
276 
277     virtual const PandaVector<CopiedMethod> &GetCopiedMethods() const = 0;
278 
279     virtual ~VTableBuilder() = default;
280 
281     NO_COPY_SEMANTIC(VTableBuilder);
282     NO_MOVE_SEMANTIC(VTableBuilder);
283 };
284 
285 template <class SearchBySignature, class OverridePred>
286 class VTableBuilderImpl : public VTableBuilder {
287     void Build(panda_file::ClassDataAccessor *cda, Class *base_class, ITable itable, ClassLinkerContext *ctx) override;
288 
289     void Build(Span<Method> methods, Class *base_class, ITable itable, bool is_interface) override;
290 
291     void UpdateClass(Class *klass) const override;
292 
GetNumVirtualMethods()293     size_t GetNumVirtualMethods() const override
294     {
295         return num_vmethods_;
296     }
297 
GetVTableSize()298     size_t GetVTableSize() const override
299     {
300         return vtable_.Size();
301     }
302 
GetCopiedMethods()303     const PandaVector<CopiedMethod> &GetCopiedMethods() const override
304     {
305         return copied_methods_;
306     }
307 
308 private:
309     void BuildForInterface(panda_file::ClassDataAccessor *cda);
310 
311     void BuildForInterface(Span<Method> methods);
312 
313     void AddBaseMethods(Class *base_class);
314 
315     void AddClassMethods(panda_file::ClassDataAccessor *cda, ClassLinkerContext *ctx);
316 
317     void AddClassMethods(Span<Method> methods);
318 
319     void AddDefaultInterfaceMethods(ITable itable);
320 
321     VTable<SearchBySignature, OverridePred> vtable_;
322     size_t num_vmethods_ {0};
323     bool has_default_methods_ {false};
324     PandaVector<CopiedMethod> copied_methods_;
325 };
326 
327 }  // namespace panda
328 
329 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_H_
330