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