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_INL_H_
16 #define PANDA_RUNTIME_VTABLE_BUILDER_INL_H_
17
18 #include "runtime/include/vtable_builder.h"
19
20 namespace panda {
21
22 template <class SearchBySignature, class OverridePred>
BuildForInterface(panda_file::ClassDataAccessor * cda)23 void VTableBuilderImpl<SearchBySignature, OverridePred>::BuildForInterface(panda_file::ClassDataAccessor *cda)
24 {
25 ASSERT(cda->IsInterface());
26 cda->EnumerateMethods([this](panda_file::MethodDataAccessor &mda) {
27 if (mda.IsStatic()) {
28 return;
29 }
30
31 if (!mda.IsAbstract()) {
32 has_default_methods_ = true;
33 }
34
35 ++num_vmethods_;
36 });
37 }
38
39 template <class SearchBySignature, class OverridePred>
BuildForInterface(Span<Method> methods)40 void VTableBuilderImpl<SearchBySignature, OverridePred>::BuildForInterface(Span<Method> methods)
41 {
42 for (const auto &method : methods) {
43 if (method.IsStatic()) {
44 continue;
45 }
46
47 if (!method.IsAbstract()) {
48 has_default_methods_ = true;
49 }
50
51 ++num_vmethods_;
52 }
53 }
54
55 template <class SearchBySignature, class OverridePred>
AddBaseMethods(Class * base_class)56 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddBaseMethods(Class *base_class)
57 {
58 if (base_class != nullptr) {
59 auto base_class_vtable = base_class->GetVTable();
60
61 for (auto *method : base_class_vtable) {
62 vtable_.AddBaseMethod(MethodInfo(method, 0, true));
63 }
64 }
65 }
66
67 template <class SearchBySignature, class OverridePred>
AddClassMethods(panda_file::ClassDataAccessor * cda,ClassLinkerContext * ctx)68 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddClassMethods(panda_file::ClassDataAccessor *cda,
69 ClassLinkerContext *ctx)
70 {
71 cda->EnumerateMethods([this, ctx](panda_file::MethodDataAccessor &mda) {
72 if (mda.IsStatic()) {
73 return;
74 }
75
76 MethodInfo method_info(mda, num_vmethods_, ctx);
77 if (!vtable_.AddMethod(method_info).first) {
78 vtable_.AddBaseMethod(method_info);
79 }
80
81 ++num_vmethods_;
82 });
83 }
84
85 template <class SearchBySignature, class OverridePred>
AddClassMethods(Span<Method> methods)86 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddClassMethods(Span<Method> methods)
87 {
88 for (auto &method : methods) {
89 if (method.IsStatic()) {
90 continue;
91 }
92
93 MethodInfo method_info(&method, num_vmethods_);
94 if (!vtable_.AddMethod(method_info).first) {
95 vtable_.AddBaseMethod(method_info);
96 }
97
98 ++num_vmethods_;
99 }
100 }
101
102 template <class SearchBySignature, class OverridePred>
AddDefaultInterfaceMethods(ITable itable)103 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddDefaultInterfaceMethods(ITable itable)
104 {
105 for (size_t i = itable.Size(); i > 0; i--) {
106 auto entry = itable[i - 1];
107 auto iface = entry.GetInterface();
108 if (!iface->HasDefaultMethods()) {
109 continue;
110 }
111
112 auto methods = iface->GetVirtualMethods();
113 for (auto &method : methods) {
114 if (method.IsAbstract()) {
115 continue;
116 }
117
118 auto [flag, idx] = vtable_.AddMethod(MethodInfo(&method, copied_methods_.size(), false, true));
119 if (!flag) {
120 continue;
121 }
122 // if the default method is added for the first time, just add it.
123 if (idx == MethodInfo::INVALID_METHOD_IDX) {
124 CopiedMethod cmethod(&method, false, false);
125 if (!IsMaxSpecificMethod(iface, method, i, itable)) {
126 cmethod.default_abstract_ = true;
127 }
128 copied_methods_.push_back(cmethod);
129 continue;
130 }
131 // use the following algorithm to judge whether we have to replace existing DEFAULT METHOD.
132 // 1. if existing default method is ICCE, just skip.
133 // 2. if this new method is not max-specific method, just skip.
134 // existing default method can be AME or not, has no effect on final result. its okay.
135 // 3. if this new method is max-specific method, check whether existing default method is AME
136 // 3.1 if no, set ICCE flag for exist method
137 // 3.2 if yes, replace exist method with new method(new method becomes a candidate)
138 if (copied_methods_[idx].default_conflict_) {
139 continue;
140 }
141 if (!IsMaxSpecificMethod(iface, method, i, itable)) {
142 continue;
143 }
144
145 if (!copied_methods_[idx].default_abstract_) {
146 copied_methods_[idx].default_conflict_ = true;
147 continue;
148 }
149 CopiedMethod cmethod(&method, false, false);
150 copied_methods_[idx] = cmethod;
151 }
152 }
153 }
154
155 template <class SearchBySignature, class OverridePred>
Build(panda_file::ClassDataAccessor * cda,Class * base_class,ITable itable,ClassLinkerContext * ctx)156 void VTableBuilderImpl<SearchBySignature, OverridePred>::Build(panda_file::ClassDataAccessor *cda, Class *base_class,
157 ITable itable, ClassLinkerContext *ctx)
158 {
159 if (cda->IsInterface()) {
160 return BuildForInterface(cda);
161 }
162
163 AddBaseMethods(base_class);
164 AddClassMethods(cda, ctx);
165 AddDefaultInterfaceMethods(itable);
166 }
167
168 template <class SearchBySignature, class OverridePred>
Build(Span<Method> methods,Class * base_class,ITable itable,bool is_interface)169 void VTableBuilderImpl<SearchBySignature, OverridePred>::Build(Span<Method> methods, Class *base_class, ITable itable,
170 bool is_interface)
171 {
172 if (is_interface) {
173 return BuildForInterface(methods);
174 }
175
176 AddBaseMethods(base_class);
177 AddClassMethods(methods);
178 AddDefaultInterfaceMethods(itable);
179 }
180
181 template <class SearchBySignature, class OverridePred>
UpdateClass(Class * klass)182 void VTableBuilderImpl<SearchBySignature, OverridePred>::UpdateClass(Class *klass) const
183 {
184 if (klass->IsInterface()) {
185 if (has_default_methods_) {
186 klass->SetHasDefaultMethods();
187 }
188
189 size_t idx = 0;
190 for (auto &method : klass->GetVirtualMethods()) {
191 method.SetVTableIndex(idx++);
192 }
193 }
194
195 vtable_.UpdateClass(klass);
196 }
197
198 } // namespace panda
199
200 #endif // PANDA_RUNTIME_VTABLE_BUILDER_H_
201