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