• 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_INL_H
16 #define PANDA_RUNTIME_VTABLE_BUILDER_BASE_INL_H
17 
18 #include "runtime/include/vtable_builder_base.h"
19 
20 namespace ark {
21 
22 void OnVTableConflict(ClassLinkerErrorHandler *errHandler, ClassLinker::Error error, std::string_view msg,
23                       MethodInfo const *info1, MethodInfo const *info2);
24 
25 void OnVTableConflict(ClassLinkerErrorHandler *errHandler, ClassLinker::Error error, std::string_view msg,
26                       Method const *info1, Method const *info2);
27 
AddEntry(const MethodInfo * info)28 inline void VTableInfo::AddEntry(const MethodInfo *info)
29 {
30     [[maybe_unused]] auto res = vmethods_.insert({info, MethodEntry(vmethods_.size())});
31     ASSERT(res.second);
32 }
33 
AddCopiedEntry(const MethodInfo * info)34 inline VTableInfo::CopiedMethodEntry &VTableInfo::AddCopiedEntry(const MethodInfo *info)
35 {
36     auto res = copiedMethods_.insert({info, CopiedMethodEntry(copiedMethods_.size())});
37     ASSERT(res.second);
38     return res.first->second;
39 }
40 
UpdateCopiedEntry(const MethodInfo * orig,const MethodInfo * repl)41 inline VTableInfo::CopiedMethodEntry &VTableInfo::UpdateCopiedEntry(const MethodInfo *orig, const MethodInfo *repl)
42 {
43     auto it = copiedMethods_.find(orig);
44     ASSERT(it != copiedMethods_.end());
45     CopiedMethodEntry entry = it->second;
46     copiedMethods_.erase(it);
47     return copiedMethods_.emplace_hint(it, repl, entry)->second;
48 }
49 
50 template <bool VISIT_SUPERITABLE>
BuildForInterface(panda_file::ClassDataAccessor * cda)51 void VTableBuilderBase<VISIT_SUPERITABLE>::BuildForInterface(panda_file::ClassDataAccessor *cda)
52 {
53     ASSERT(cda->IsInterface());
54     cda->EnumerateMethods([this](panda_file::MethodDataAccessor &mda) {
55         if (mda.IsStatic()) {
56             return;
57         }
58 
59         if (!mda.IsAbstract()) {
60             hasDefaultMethods_ = true;
61         }
62 
63         ++numVmethods_;
64     });
65 }
66 
67 template <bool VISIT_SUPERITABLE>
BuildForInterface(Span<Method> methods)68 void VTableBuilderBase<VISIT_SUPERITABLE>::BuildForInterface(Span<Method> methods)
69 {
70     for (const auto &method : methods) {
71         if (method.IsStatic()) {
72             continue;
73         }
74 
75         if (!method.IsAbstract()) {
76             hasDefaultMethods_ = true;
77         }
78 
79         ++numVmethods_;
80     }
81 }
82 
83 template <bool VISIT_SUPERITABLE>
AddBaseMethods(Class * baseClass)84 void VTableBuilderBase<VISIT_SUPERITABLE>::AddBaseMethods(Class *baseClass)
85 {
86     auto baseMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
87 
88     if (baseClass != nullptr) {
89         for (auto const &method : baseClass->GetVTable()) {
90             vtable_.AddEntry(&baseMethods->emplace_front(method, 0, true));
91         }
92     }
93 }
94 
95 template <bool VISIT_SUPERITABLE>
AddClassMethods(panda_file::ClassDataAccessor * cda,ClassLinkerContext * ctx)96 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddClassMethods(panda_file::ClassDataAccessor *cda, ClassLinkerContext *ctx)
97 {
98     auto classMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
99 
100     cda->EnumerateMethods([this, ctx, &classMethods](panda_file::MethodDataAccessor &mda) {
101         if (!mda.IsStatic()) {
102             classMethods->emplace_front(mda, numVmethods_++, ctx);
103         }
104     });
105 
106     for (auto &info : *classMethods) {
107         if (!ProcessClassMethod(&info)) {
108             return false;
109         }
110     }
111     return true;
112 }
113 
114 template <bool VISIT_SUPERITABLE>
AddClassMethods(Span<Method> methods)115 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddClassMethods(Span<Method> methods)
116 {
117     auto classMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
118 
119     for (auto &method : methods) {
120         if (!method.IsStatic()) {
121             classMethods->emplace_front(&method, numVmethods_++);
122         }
123     }
124 
125     for (auto const &info : *classMethods) {
126         if (!ProcessClassMethod(&info)) {
127             return false;
128         }
129     }
130     return true;
131 }
132 
133 template <bool VISIT_SUPERITABLE>
AddDefaultInterfaceMethods(ITable itable,size_t superItableSize)134 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddDefaultInterfaceMethods(ITable itable, size_t superItableSize)
135 {
136     auto defaultMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
137 
138     // NOTE(vpukhov): avoid traversing the whole itable and handle conflicting super vtable methods in a separate pass
139     size_t const traverseUpTo = VISIT_SUPERITABLE ? 0 : superItableSize;
140 
141     for (size_t i = itable.Size(); i != traverseUpTo;) {
142         i--;
143         auto iface = itable[i].GetInterface();
144         if (!iface->HasDefaultMethods()) {
145             continue;
146         }
147 
148         auto methods = iface->GetVirtualMethods();
149         for (auto &method : methods) {
150             if (method.IsAbstract()) {
151                 continue;
152             }
153             MethodInfo *info = &defaultMethods->emplace_front(&method);
154             if (!ProcessDefaultMethod(itable, i, info)) {
155                 return false;
156             }
157         }
158     }
159 
160     ASSERT(orderedCopiedMethods_.empty());
161     orderedCopiedMethods_.resize(vtable_.CopiedMethods().size());
162 
163     for (auto const &[info, entry] : vtable_.CopiedMethods()) {
164         CopiedMethod copied(info->GetMethod());
165         copied.SetStatus(entry.GetStatus());
166         orderedCopiedMethods_[entry.GetIndex()] = copied;
167     }
168     return true;
169 }
170 
171 template <bool VISIT_SUPERITABLE>
Build(panda_file::ClassDataAccessor * cda,Class * baseClass,ITable itable,ClassLinkerContext * ctx)172 bool VTableBuilderBase<VISIT_SUPERITABLE>::Build(panda_file::ClassDataAccessor *cda, Class *baseClass, ITable itable,
173                                                  ClassLinkerContext *ctx)
174 {
175     if (cda->IsInterface()) {
176         BuildForInterface(cda);
177         return true;
178     }
179 
180     AddBaseMethods(baseClass);
181     if (!AddClassMethods(cda, ctx)) {
182         return false;
183     }
184     if (!AddDefaultInterfaceMethods(itable, baseClass != nullptr ? baseClass->GetITable().Size() : 0)) {
185         return false;
186     }
187     return true;
188 }
189 
190 template <bool VISIT_SUPERITABLE>
Build(Span<Method> methods,Class * baseClass,ITable itable,bool isInterface)191 bool VTableBuilderBase<VISIT_SUPERITABLE>::Build(Span<Method> methods, Class *baseClass, ITable itable,
192                                                  bool isInterface)
193 {
194     if (isInterface) {
195         BuildForInterface(methods);
196         return true;
197     }
198 
199     AddBaseMethods(baseClass);
200     if (!AddClassMethods(methods)) {
201         return false;
202     }
203     if (!AddDefaultInterfaceMethods(itable, baseClass != nullptr ? baseClass->GetITable().Size() : 0)) {
204         return false;
205     }
206     return true;
207 }
208 
209 template <bool VISIT_SUPERITABLE>
UpdateClass(Class * klass)210 void VTableBuilderBase<VISIT_SUPERITABLE>::UpdateClass(Class *klass) const
211 {
212     if (klass->IsInterface()) {
213         if (hasDefaultMethods_) {
214             klass->SetHasDefaultMethods();
215         }
216 
217         size_t idx = 0;
218         for (auto &method : klass->GetVirtualMethods()) {
219             method.SetVTableIndex(idx++);
220         }
221     }
222 
223     vtable_.UpdateClass(klass);
224 }
225 
226 }  // namespace ark
227 
228 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_BASE_H
229