1 /*
2 * Copyright (c) 2021 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
16 #ifndef PANDA_RUNTIME_INCLUDE_VTABLE_BUILDER_INL_H_
17 #define PANDA_RUNTIME_INCLUDE_VTABLE_BUILDER_INL_H_
18
19 #include "runtime/include/vtable_builder.h"
20
21 namespace panda {
22
23 template <class SearchBySignature, class OverridePred>
BuildForInterface(panda_file::ClassDataAccessor * cda)24 void VTableBuilderImpl<SearchBySignature, OverridePred>::BuildForInterface(panda_file::ClassDataAccessor *cda)
25 {
26 ASSERT(cda->IsInterface());
27 cda->EnumerateMethods([this](panda_file::MethodDataAccessor &mda) {
28 if (mda.IsStatic()) {
29 return;
30 }
31
32 if (!mda.IsAbstract()) {
33 has_default_methods_ = true;
34 }
35
36 ++num_vmethods_;
37 });
38 }
39
40 template <class SearchBySignature, class OverridePred>
BuildForInterface(Span<Method> methods)41 void VTableBuilderImpl<SearchBySignature, OverridePred>::BuildForInterface(Span<Method> methods)
42 {
43 for (const auto &method : methods) {
44 if (method.IsStatic()) {
45 continue;
46 }
47
48 if (!method.IsAbstract()) {
49 has_default_methods_ = true;
50 }
51
52 ++num_vmethods_;
53 };
54 }
55
56 template <class SearchBySignature, class OverridePred>
AddBaseMethods(Class * base_class)57 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddBaseMethods(Class *base_class)
58 {
59 if (base_class != nullptr) {
60 auto base_class_vtable = base_class->GetVTable();
61
62 for (auto *method : base_class_vtable) {
63 vtable_.AddBaseMethod(MethodInfo(method, 0, true));
64 }
65 }
66 }
67
68 template <class SearchBySignature, class OverridePred>
AddClassMethods(panda_file::ClassDataAccessor * cda,ClassLinkerContext * ctx)69 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddClassMethods(panda_file::ClassDataAccessor *cda,
70 ClassLinkerContext *ctx)
71 {
72 cda->EnumerateMethods([this, ctx](panda_file::MethodDataAccessor &mda) {
73 if (mda.IsStatic()) {
74 return;
75 }
76
77 MethodInfo method_info(mda.GetPandaFile(), mda.GetMethodId(), num_vmethods_, ctx);
78 if (!vtable_.AddMethod(method_info)) {
79 vtable_.AddBaseMethod(method_info);
80 }
81
82 ++num_vmethods_;
83 });
84 }
85
86 template <class SearchBySignature, class OverridePred>
AddClassMethods(Span<Method> methods)87 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddClassMethods(Span<Method> methods)
88 {
89 for (auto &method : methods) {
90 if (method.IsStatic()) {
91 continue;
92 }
93
94 MethodInfo method_info(&method, num_vmethods_);
95 if (!vtable_.AddMethod(method_info)) {
96 vtable_.AddBaseMethod(method_info);
97 }
98
99 ++num_vmethods_;
100 }
101 }
102
103 template <class SearchBySignature, class OverridePred>
AddDefaultInterfaceMethods(ITable itable)104 void VTableBuilderImpl<SearchBySignature, OverridePred>::AddDefaultInterfaceMethods(ITable itable)
105 {
106 for (size_t i = itable.Size(); i > 0; i--) {
107 auto entry = itable[i - 1];
108 auto iface = entry.GetInterface();
109 if (!iface->HasDefaultMethods()) {
110 continue;
111 }
112
113 auto methods = iface->GetVirtualMethods();
114 for (auto &method : methods) {
115 if (method.IsAbstract()) {
116 continue;
117 }
118
119 if (vtable_.AddMethod(MethodInfo(&method, copied_methods_.size(), false, true))) {
120 copied_methods_.push_back(&method);
121 }
122 }
123 }
124 }
125
126 template <class SearchBySignature, class OverridePred>
Build(panda_file::ClassDataAccessor * cda,Class * base_class,ITable itable,ClassLinkerContext * ctx)127 void VTableBuilderImpl<SearchBySignature, OverridePred>::Build(panda_file::ClassDataAccessor *cda, Class *base_class,
128 ITable itable, ClassLinkerContext *ctx)
129 {
130 if (cda->IsInterface()) {
131 return BuildForInterface(cda);
132 }
133
134 AddBaseMethods(base_class);
135 AddClassMethods(cda, ctx);
136 AddDefaultInterfaceMethods(itable);
137 }
138
139 template <class SearchBySignature, class OverridePred>
Build(Span<Method> methods,Class * base_class,ITable itable,bool is_interface)140 void VTableBuilderImpl<SearchBySignature, OverridePred>::Build(Span<Method> methods, Class *base_class, ITable itable,
141 bool is_interface)
142 {
143 if (is_interface) {
144 return BuildForInterface(methods);
145 }
146
147 AddBaseMethods(base_class);
148 AddClassMethods(methods);
149 AddDefaultInterfaceMethods(itable);
150 }
151
152 template <class SearchBySignature, class OverridePred>
UpdateClass(Class * klass)153 void VTableBuilderImpl<SearchBySignature, OverridePred>::UpdateClass(Class *klass) const
154 {
155 if (klass->IsInterface()) {
156 if (has_default_methods_) {
157 klass->SetHasDefaultMethods();
158 }
159
160 size_t idx = 0;
161 for (auto &method : klass->GetVirtualMethods()) {
162 method.SetVTableIndex(idx++);
163 }
164 }
165
166 vtable_.UpdateClass(klass);
167 }
168
169 } // namespace panda
170
171 #endif // PANDA_RUNTIME_INCLUDE_VTABLE_BUILDER_INL_H_
172