• 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_VARIANCE_INL_H
16 #define PANDA_RUNTIME_VTABLE_BUILDER_VARIANCE_INL_H
17 
18 #include "runtime/include/vtable_builder_variance.h"
19 #include "runtime/include/vtable_builder_base-inl.h"
20 
21 namespace ark {
22 
23 template <class ProtoCompatibility, class OverridePred>
IsOverriddenBy(Method::ProtoId const & base,Method::ProtoId const & derv)24 bool VarianceVTableBuilder<ProtoCompatibility, OverridePred>::IsOverriddenBy(Method::ProtoId const &base,
25                                                                              Method::ProtoId const &derv)
26 {
27     if (&base.GetPandaFile() == &derv.GetPandaFile() && base.GetEntityId() == derv.GetEntityId()) {
28         return true;
29     }
30     return ProtoCompatibility()(base, derv);
31 }
32 
33 template <class ProtoCompatibility, class OverridePred>
IsOverriddenOrOverrides(Method::ProtoId const & p1,Method::ProtoId const & p2)34 bool VarianceVTableBuilder<ProtoCompatibility, OverridePred>::IsOverriddenOrOverrides(Method::ProtoId const &p1,
35                                                                                       Method::ProtoId const &p2)
36 {
37     if (&p1.GetPandaFile() == &p2.GetPandaFile() && p1.GetEntityId() == p2.GetEntityId()) {
38         return true;
39     }
40     return ProtoCompatibility()(p1, p2) || ProtoCompatibility()(p2, p1);
41 }
42 
43 template <class ProtoCompatibility, class OverridePred>
ProcessClassMethod(const MethodInfo * info)44 bool VarianceVTableBuilder<ProtoCompatibility, OverridePred>::ProcessClassMethod(const MethodInfo *info)
45 {
46     bool compatibleFound = false;
47 
48     for (auto it = SameNameMethodInfoIterator(vtable_.Methods(), info); !it.IsEmpty(); it.Next()) {
49         auto &[itInfo, itEntry] = it.Value();
50 
51         if (!itInfo->IsBase()) {
52             continue;
53         }
54         if (IsOverriddenBy(itInfo->GetProtoId(), info->GetProtoId()) && OverridePred()(itInfo, info)) {
55             if (UNLIKELY(itInfo->IsFinal())) {
56                 OnVTableConflict(errorHandler_, ClassLinker::Error::OVERRIDES_FINAL, "Method overrides final method",
57                                  info, itInfo);
58                 return false;
59             }
60             if (UNLIKELY(itEntry.GetCandidate() != nullptr)) {
61                 OnVTableConflict(errorHandler_, ClassLinker::Error::MULTIPLE_OVERRIDE, "Multiple override", info,
62                                  itInfo);
63                 return false;
64             }
65             itEntry.SetCandidate(info);
66             compatibleFound = true;
67         }
68     }
69 
70     if (!compatibleFound) {
71         vtable_.AddEntry(info);
72     }
73     return true;
74 }
75 
76 template <class ProtoCompatibility, class OverridePred>
77 std::optional<MethodInfo const *>  // CC-OFF(G.FMT.07) project code style
ScanConflictingDefaultMethods(const MethodInfo * info)78 VarianceVTableBuilder<ProtoCompatibility, OverridePred>::ScanConflictingDefaultMethods(const MethodInfo *info)
79 {
80     // NOTE(vpukhov): test public flag
81     for (auto it = SameNameMethodInfoIterator(vtable_.Methods(), info); !it.IsEmpty(); it.Next()) {
82         MethodInfo const *itinfo = it.Value().second.CandidateOr(it.Value().first);
83         if (itinfo->IsInterfaceMethod()) {
84             continue;
85         }
86         if (IsOverriddenBy(info->GetProtoId(), itinfo->GetProtoId())) {
87             return std::nullopt;
88         }
89     }
90 
91     for (auto it = SameNameMethodInfoIterator(vtable_.Methods(), info); !it.IsEmpty(); it.Next()) {
92         MethodInfo const *itinfo = it.Value().second.CandidateOr(it.Value().first);
93         if (!itinfo->IsInterfaceMethod()) {
94             continue;
95         }
96         ASSERT(itinfo->GetMethod()->GetClass() != info->GetMethod()->GetClass());
97         if (IsOverriddenOrOverrides(info->GetProtoId(), itinfo->GetProtoId())) {
98             return itinfo;
99         }
100     }
101 
102     for (auto it = SameNameMethodInfoIterator(vtable_.CopiedMethods(), info); !it.IsEmpty(); it.Next()) {
103         MethodInfo const *itinfo = it.Value().first;
104         if (!itinfo->IsInterfaceMethod()) {
105             continue;
106         }
107         if (itinfo->GetMethod()->GetClass() == info->GetMethod()->GetClass()) {
108             continue;
109         }
110         if (IsOverriddenOrOverrides(info->GetProtoId(), itinfo->GetProtoId())) {
111             return itinfo;
112         }
113     }
114     return nullptr;
115 }
116 
117 template <class ProtoCompatibility, class OverridePred>
ProcessDefaultMethod(ITable itable,size_t itableIdx,MethodInfo * methodInfo)118 bool VarianceVTableBuilder<ProtoCompatibility, OverridePred>::ProcessDefaultMethod(ITable itable, size_t itableIdx,
119                                                                                    MethodInfo *methodInfo)
120 {
121     auto skipOrConflict = ScanConflictingDefaultMethods(methodInfo);
122     if (!skipOrConflict.has_value()) {
123         return true;
124     }
125     MethodInfo const *conflict = skipOrConflict.value();
126     [[maybe_unused]] Class *iface = itable[itableIdx].GetInterface();
127 
128     // if the default method is added for the first time, just add it.
129     if (LIKELY(conflict == nullptr)) {
130         vtable_.AddCopiedEntry(methodInfo);
131         return true;
132     }
133 
134     OnVTableConflict(errorHandler_, ClassLinker::Error::MULTIPLE_IMPLEMENT, "Conflicting default implementations",
135                      conflict, methodInfo);
136     return false;
137 }
138 
139 }  // namespace ark
140 
141 #endif  // PANDA_RUNTIME_VTABLE_BUILDER_VARIANCE_INL_H
142