• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 
16 #include "ets_itable_builder.h"
17 
18 #include "runtime/include/class_linker.h"
19 #include "runtime/include/exceptions.h"
20 #include "runtime/include/mem/panda_containers.h"
21 
22 namespace panda::ets {
23 
FindMethodInVTable(Class * klass,Method * method)24 static Method *FindMethodInVTable(Class *klass, Method *method)
25 {
26     auto vtable = klass->GetVTable();
27     for (size_t i = vtable.size(); i > 0; i--) {
28         auto idx = i - 1;
29         if (vtable[idx]->GetName() == method->GetName() && vtable[idx]->GetProtoId() == method->GetProtoId()) {
30             return vtable[idx];
31         }
32     }
33 
34     return nullptr;
35 }
36 
37 // add interfaces
38 // interfaces of a superclass (they are located before others)
39 // self interfaces and interfaces of self interfaces
40 // add methods if it's not an interface (methods are located only for classes)
Build(ClassLinker * classLinker,Class * base,Span<Class * > classInterfaces,bool isInterface)41 void EtsITableBuilder::Build(ClassLinker *classLinker, Class *base, Span<Class *> classInterfaces, bool isInterface)
42 {
43     PandaUnorderedSet<Class *> interfaces;
44 
45     if (base != nullptr) {
46         auto superItable = base->GetITable().Get();
47         for (auto item : superItable) {
48             interfaces.insert(item.GetInterface());
49         }
50     }
51 
52     for (auto interface : classInterfaces) {
53         auto table = interface->GetITable().Get();
54         for (auto item : table) {
55             interfaces.insert(item.GetInterface());
56         }
57         interfaces.insert(interface);
58     }
59 
60     auto allocator = classLinker->GetAllocator();
61     ITable::Entry *array = nullptr;
62     if (!interfaces.empty()) {
63         array = allocator->AllocArray<ITable::Entry>(interfaces.size());
64     }
65 
66     Span<ITable::Entry> itable {array, interfaces.size()};
67 
68     for (auto &entry : itable) {
69         entry.SetMethods({nullptr, nullptr});
70     }
71 
72     if (base != nullptr) {
73         auto superItable = base->GetITable().Get();
74         for (size_t i = 0; i < superItable.size(); i++) {
75             itable[i] = superItable[i].Copy(allocator);
76             interfaces.erase(superItable[i].GetInterface());
77         }
78     }
79 
80     size_t superItableSize = 0;
81     if (base != nullptr) {
82         superItableSize = base->GetITable().Size();
83     }
84 
85     size_t shift = superItableSize;
86 
87     for (auto interface : classInterfaces) {
88         auto table = interface->GetITable().Get();
89         for (auto &item : table) {
90             auto iterator = interfaces.find(item.GetInterface());
91             if (iterator != interfaces.end()) {
92                 itable[shift] = item.Copy(allocator);
93                 interfaces.erase(item.GetInterface());
94                 shift += 1;
95             }
96         }
97         auto iterator = interfaces.find(interface);
98         if (iterator != interfaces.end()) {
99             itable[shift].SetInterface(interface);
100             interfaces.erase(interface);
101             shift += 1;
102         }
103     }
104 
105     ASSERT(interfaces.empty());
106 
107     if (!isInterface) {
108         for (size_t i = superItableSize; i < itable.Size(); i++) {
109             auto &entry = itable[i];
110             auto methods = entry.GetInterface()->GetVirtualMethods();
111             Method **methodsAlloc = nullptr;
112             if (!methods.Empty()) {
113                 methodsAlloc = allocator->AllocArray<Method *>(methods.size());
114             }
115             Span<Method *> methodsArray = {methodsAlloc, methods.size()};
116             entry.SetMethods(methodsArray);
117         }
118     }
119 
120     itable_ = ITable(itable);
121 }
122 
Resolve(Class * klass)123 void EtsITableBuilder::Resolve(Class *klass)
124 {
125     if (klass->IsInterface()) {
126         return;
127     }
128 
129     for (size_t i = itable_.Size(); i > 0; i--) {
130         auto entry = itable_[i - 1];
131         auto methods = entry.GetInterface()->GetVirtualMethods();
132         for (size_t j = 0; j < methods.size(); j++) {
133             auto *res = FindMethodInVTable(klass, &methods[j]);
134             if (res == nullptr) {
135                 res = &methods[j];
136             }
137 
138             entry.GetMethods()[j] = res;
139         }
140     }
141 }
142 
UpdateClass(Class * klass)143 void EtsITableBuilder::UpdateClass(Class *klass)
144 {
145     klass->SetITable(itable_);
146     DumpITable(klass);
147 }
148 
DumpITable(Class * klass)149 void EtsITableBuilder::DumpITable([[maybe_unused]] Class *klass)
150 {
151 #ifndef NDEBUG
152     LOG(DEBUG, CLASS_LINKER) << "itable of class " << klass->GetName() << ":";
153     auto itable = klass->GetITable();
154     size_t idxI = 0;
155     size_t idxM = 0;
156     for (size_t i = 0; i < itable.Size(); i++) {
157         auto entry = itable[i];
158         auto interface = entry.GetInterface();
159         LOG(DEBUG, CLASS_LINKER) << "[ interface - " << idxI++ << " ] " << interface->GetName() << ":";
160         auto methods = entry.GetMethods();
161         for (auto *method : methods) {
162             LOG(DEBUG, CLASS_LINKER) << "[ method - " << idxM++ << " ] " << method->GetFullName() << " - "
163                                      << method->GetFileId().GetOffset();
164         }
165     }
166 #endif  // NDEBUG
167 }
168 
169 }  // namespace panda::ets
170