• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 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     ASSERT(baseMethods != nullptr);
88 
89     if (baseClass != nullptr) {
90         for (auto const &method : baseClass->GetVTable()) {
91             vtable_.AddEntry(&baseMethods->emplace_front(method, 0, true));
92         }
93     }
94 }
95 
96 template <bool VISIT_SUPERITABLE>
AddClassMethods(panda_file::ClassDataAccessor * cda,ClassLinkerContext * ctx)97 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddClassMethods(panda_file::ClassDataAccessor *cda, ClassLinkerContext *ctx)
98 {
99     ASSERT(cda != nullptr);
100     auto classMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
101     ASSERT(classMethods != nullptr);
102 
103     cda->EnumerateMethods([this, ctx, &classMethods](panda_file::MethodDataAccessor &mda) {
104         if (!mda.IsStatic()) {
105             classMethods->emplace_front(mda, numVmethods_++, ctx);
106         }
107     });
108 
109     for (auto &info : *classMethods) {
110         if (!ProcessClassMethod(&info)) {
111             return false;
112         }
113     }
114     return true;
115 }
116 
117 template <bool VISIT_SUPERITABLE>
AddClassMethods(Span<Method> methods)118 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddClassMethods(Span<Method> methods)
119 {
120     auto classMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
121     ASSERT(classMethods != nullptr);
122 
123     for (auto &method : methods) {
124         if (!method.IsStatic()) {
125             classMethods->emplace_front(&method, numVmethods_++);
126         }
127     }
128 
129     for (auto const &info : *classMethods) {
130         if (!ProcessClassMethod(&info)) {
131             return false;
132         }
133     }
134     return true;
135 }
136 
137 template <bool VISIT_SUPERITABLE>
AddDefaultInterfaceMethods(ITable itable,size_t superItableSize)138 bool VTableBuilderBase<VISIT_SUPERITABLE>::AddDefaultInterfaceMethods(ITable itable, size_t superItableSize)
139 {
140     auto defaultMethods = allocator_.New<ArenaForwardList<MethodInfo>>(allocator_.Adapter());
141     ASSERT(defaultMethods != nullptr);
142 
143     // NOTE(vpukhov): avoid traversing the whole itable and handle conflicting super vtable methods in a separate pass
144     size_t const traverseUpTo = VISIT_SUPERITABLE ? 0 : superItableSize;
145 
146     for (size_t i = itable.Size(); i != traverseUpTo;) {
147         i--;
148         auto iface = itable[i].GetInterface();
149         if (!iface->HasDefaultMethods()) {
150             continue;
151         }
152 
153         auto methods = iface->GetVirtualMethods();
154         for (auto &method : methods) {
155             if (method.IsAbstract()) {
156                 continue;
157             }
158             MethodInfo *info = &defaultMethods->emplace_front(&method);
159             if (!ProcessDefaultMethod(itable, i, info)) {
160                 return false;
161             }
162         }
163     }
164 
165     ASSERT(orderedCopiedMethods_.empty());
166     orderedCopiedMethods_.resize(vtable_.CopiedMethods().size());
167 
168     for (auto const &[info, entry] : vtable_.CopiedMethods()) {
169         CopiedMethod copied(info->GetMethod());
170         copied.SetStatus(entry.GetStatus());
171         orderedCopiedMethods_[entry.GetIndex()] = copied;
172     }
173     return true;
174 }
175 
176 template <bool VISIT_SUPERITABLE>
Build(panda_file::ClassDataAccessor * cda,Class * baseClass,ITable itable,ClassLinkerContext * ctx)177 bool VTableBuilderBase<VISIT_SUPERITABLE>::Build(panda_file::ClassDataAccessor *cda, Class *baseClass, ITable itable,
178                                                  ClassLinkerContext *ctx)
179 {
180     if (cda->IsInterface()) {
181         BuildForInterface(cda);
182         return true;
183     }
184 
185     AddBaseMethods(baseClass);
186     if (!AddClassMethods(cda, ctx)) {
187         return false;
188     }
189     if (!AddDefaultInterfaceMethods(itable, baseClass != nullptr ? baseClass->GetITable().Size() : 0)) {
190         return false;
191     }
192     return true;
193 }
194 
195 template <bool VISIT_SUPERITABLE>
Build(Span<Method> methods,Class * baseClass,ITable itable,bool isInterface)196 bool VTableBuilderBase<VISIT_SUPERITABLE>::Build(Span<Method> methods, Class *baseClass, ITable itable,
197                                                  bool isInterface)
198 {
199     if (isInterface) {
200         BuildForInterface(methods);
201         return true;
202     }
203 
204     AddBaseMethods(baseClass);
205     if (!AddClassMethods(methods)) {
206         return false;
207     }
208     if (!AddDefaultInterfaceMethods(itable, baseClass != nullptr ? baseClass->GetITable().Size() : 0)) {
209         return false;
210     }
211     return true;
212 }
213 
214 template <bool VISIT_SUPERITABLE>
UpdateClass(Class * klass)215 void VTableBuilderBase<VISIT_SUPERITABLE>::UpdateClass(Class *klass) const
216 {
217     if (klass->IsInterface()) {
218         if (hasDefaultMethods_) {
219             klass->SetHasDefaultMethods();
220         }
221 
222         size_t idx = 0;
223         for (auto &method : klass->GetVirtualMethods()) {
224             method.SetVTableIndex(idx++);
225         }
226     }
227 
228     vtable_.UpdateClass(klass);
229 }
230 
231 }  // namespace ark
232 
233 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_BASE_H
234