• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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_STANDARD_INL_H
16 #define PANDA_RUNTIME_VTABLE_BUILDER_STANDARD_INL_H
17 
18 #include "runtime/include/vtable_builder_standard.h"
19 #include "runtime/include/vtable_builder_base-inl.h"
20 
21 namespace ark {
22 
23 template <class OverridePred>
IsOverriddenBy(Method::ProtoId const & base,Method::ProtoId const & derv)24 bool StandardVTableBuilder<OverridePred>::IsOverriddenBy(Method::ProtoId const &base, Method::ProtoId const &derv)
25 {
26     if (&base.GetPandaFile() == &derv.GetPandaFile() && base.GetEntityId() == derv.GetEntityId()) {
27         return true;
28     }
29     return VTableProtoIdentical()(base, derv);
30 }
31 
32 template <class OverridePred>
ProcessClassMethod(const MethodInfo * info)33 bool StandardVTableBuilder<OverridePred>::ProcessClassMethod(const MethodInfo *info)
34 {
35     bool compatibleFound = false;
36 
37     for (auto it = SameNameMethodInfoIterator(vtable_.Methods(), info); !it.IsEmpty(); it.Next()) {
38         auto &[itInfo, itEntry] = it.Value();
39 
40         if (!itInfo->IsBase()) {
41             continue;
42         }
43         if (IsOverriddenBy(itInfo->GetProtoId(), info->GetProtoId()) && OverridePred()(itInfo, info)) {
44             if (UNLIKELY(itInfo->IsFinal())) {
45                 OnVTableConflict(errorHandler_, ClassLinker::Error::OVERRIDES_FINAL, "Method overrides final method",
46                                  info, itInfo);
47                 return false;
48             }
49             itEntry.SetCandidate(info);
50             compatibleFound = true;
51         }
52     }
53 
54     if (!compatibleFound) {
55         vtable_.AddEntry(info);
56     }
57     return true;
58 }
59 
60 template <class OverridePred>
ScanConflictingDefaultMethods(const MethodInfo * info)61 std::optional<MethodInfo const *> StandardVTableBuilder<OverridePred>::ScanConflictingDefaultMethods(
62     const MethodInfo *info)
63 {
64     // NOTE(vpukhov): test public flag
65     for (auto it = SameNameMethodInfoIterator(vtable_.Methods(), info); !it.IsEmpty(); it.Next()) {
66         MethodInfo const *itinfo = it.Value().second.CandidateOr(it.Value().first);
67         VTableInfo::MethodEntry *itentry = &it.Value().second;
68 
69         if (!IsOverriddenBy(info->GetProtoId(), itinfo->GetProtoId())) {
70             continue;
71         }
72         if (!itinfo->IsInterfaceMethod()) {
73             // there is at least one implementing method, so skip default method
74             return std::nullopt;
75         }
76         if (!itinfo->IsBase()) {
77             break;
78         }
79         // NOTE(vpukhov): that method is possibly a conflict, but we traverse the whole itable to handle such cases
80         itentry->SetCandidate(info);
81     }
82 
83     for (auto it = SameNameMethodInfoIterator(vtable_.CopiedMethods(), info); !it.IsEmpty(); it.Next()) {
84         MethodInfo const *itinfo = it.Value().first;
85         if (!IsOverriddenBy(info->GetProtoId(), itinfo->GetProtoId())) {
86             continue;
87         }
88         if (itinfo->GetMethod()->GetClass()->Implements(info->GetMethod()->GetClass())) {
89             // more specific compatible method is defined, so skip default method
90             return std::nullopt;
91         }
92         return itinfo;
93     }
94 
95     return nullptr;
96 }
97 
98 // we have to guarantee that while we are iterating itable, the child interface has to be accessed before father
99 // interface. interface without inheritance has no limit.
100 template <class OverridePred>
IsMaxSpecificInterfaceMethod(const Class * iface,const Method & method,size_t startindex,const ITable & itable)101 bool StandardVTableBuilder<OverridePred>::IsMaxSpecificInterfaceMethod(const Class *iface, const Method &method,
102                                                                        size_t startindex, const ITable &itable)
103 {
104     for (size_t j = startindex; j < itable.Size(); j++) {
105         auto currentIface = itable[j].GetInterface();
106         if (!currentIface->Implements(iface)) {
107             continue;
108         }
109         for (auto &curmethod : currentIface->GetVirtualMethods()) {
110             if (method.GetName() != curmethod.GetName()) {
111                 continue;
112             }
113             if (IsOverriddenBy(method.GetProtoId(), curmethod.GetProtoId())) {
114                 return false;
115             }
116         }
117     }
118     return true;
119 }
120 
121 template <class OverridePred>
ProcessDefaultMethod(ITable itable,size_t itableIdx,MethodInfo * methodInfo)122 bool StandardVTableBuilder<OverridePred>::ProcessDefaultMethod(ITable itable, size_t itableIdx, MethodInfo *methodInfo)
123 {
124     auto skipOrConflict = ScanConflictingDefaultMethods(methodInfo);
125     if (!skipOrConflict.has_value()) {
126         return true;
127     }
128     MethodInfo const *conflict = skipOrConflict.value();
129     Class *iface = itable[itableIdx].GetInterface();
130     Method *method = methodInfo->GetMethod();
131 
132     // if the default method is added for the first time, just add it.
133     if (LIKELY(conflict == nullptr)) {
134         VTableInfo::CopiedMethodEntry *entry = &vtable_.AddCopiedEntry(methodInfo);
135         if (!IsMaxSpecificInterfaceMethod(iface, *method, itableIdx + 1, itable)) {
136             entry->SetStatus(CopiedMethod::Status::ABSTRACT);
137         }
138         return true;
139     }
140 
141     VTableInfo::CopiedMethodEntry *entry = &vtable_.CopiedMethods().find(conflict)->second;
142 
143     // Use the following algorithm to judge whether we have to replace existing DEFAULT METHOD.
144     // 1. if existing default method is ICCE, just skip.
145     // 2. if new method is not max-specific method, just skip.
146     //    existing default method can be AME or not, has no effect on final result. its okay.
147     // 3. if new method is max-specific method, check whether existing default method is AME
148     //   3.1  if no, set ICCE flag for existing method
149     //   3.2  if yes, replace existing method with new method(new method becomes a candidate)
150     if (entry->GetStatus() == CopiedMethod::Status::CONFLICT) {
151         return true;
152     }
153     if (!IsMaxSpecificInterfaceMethod(iface, *method, itableIdx + 1, itable)) {
154         return true;
155     }
156     if (entry->GetStatus() != CopiedMethod::Status::ABSTRACT) {
157         entry->SetStatus(CopiedMethod::Status::CONFLICT);
158         return true;
159     }
160     entry->SetStatus(CopiedMethod::Status::ORDINARY);
161     vtable_.UpdateCopiedEntry(conflict, methodInfo);
162     return true;
163 }
164 
165 }  // namespace ark
166 
167 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_STANDARD_INL_H
168