• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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