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