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