1 /**
2 * Copyright (c) 2021-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
16 #include "libpandabase/macros.h"
17 #include "runtime/include/imtable_builder.h"
18 #include "runtime/include/class_linker.h"
19
20 namespace ark {
Build(const panda_file::ClassDataAccessor * cda,ITable itable)21 void IMTableBuilder::Build(const panda_file::ClassDataAccessor *cda, ITable itable)
22 {
23 if (cda->IsInterface() || itable.Size() == 0U) {
24 return;
25 }
26
27 size_t ifmNum = 0;
28 for (size_t i = 0; i < itable.Size(); i++) {
29 auto &entry = itable[i];
30 auto methods = entry.GetMethods();
31 ifmNum += methods.Size();
32 }
33
34 // set imtable size rules
35 // (1) as interface methods number when it's smaller than fixed IMTABLE_SIZE
36 // (2) as IMTABLE_SIZE when it's in [IMTABLE_SIZE, IMTABLE_SIZE * OVERSIZE_MULTIPLE], eg. [32,64]
37 // (3) as 0 when it's much more bigger than fixed IMTABLE_SIZE, since conflict probability is high and IMTable will
38 // be almost empty
39 SetIMTSize((ifmNum <= Class::IMTABLE_SIZE)
40 ? ifmNum
41 : ((ifmNum <= Class::IMTABLE_SIZE * OVERSIZE_MULTIPLE) ? Class::IMTABLE_SIZE : 0));
42 }
43
Build(ITable itable,bool isInterface)44 void IMTableBuilder::Build(ITable itable, bool isInterface)
45 {
46 if (isInterface || itable.Size() == 0U) {
47 return;
48 }
49
50 size_t ifmNum = 0;
51 for (size_t i = 0; i < itable.Size(); i++) {
52 auto &entry = itable[i];
53 auto methods = entry.GetMethods();
54 ifmNum += methods.Size();
55 }
56
57 // set imtable size rules: the same as function above
58 SetIMTSize((ifmNum <= Class::IMTABLE_SIZE)
59 ? ifmNum
60 : ((ifmNum <= Class::IMTABLE_SIZE * OVERSIZE_MULTIPLE) ? Class::IMTABLE_SIZE : 0));
61 }
62
UpdateClass(Class * klass)63 void IMTableBuilder::UpdateClass(Class *klass)
64 {
65 if (klass->IsInterface() || klass->IsAbstract()) {
66 return;
67 }
68
69 auto imtableSize = klass->GetIMTSize();
70 if (imtableSize == 0U) {
71 return;
72 }
73
74 std::array<bool, Class::IMTABLE_SIZE> isMethodConflict = {false};
75
76 auto itable = klass->GetITable();
77 auto imtable = klass->GetIMT();
78
79 for (size_t i = 0; i < itable.Size(); i++) {
80 auto &entry = itable[i];
81 auto itfMethods = entry.GetInterface()->GetVirtualMethods();
82 auto impMethods = entry.GetMethods();
83
84 for (size_t j = 0; j < itfMethods.Size(); j++) {
85 auto impMethod = impMethods[j];
86 auto itfMethodId = klass->GetIMTableIndex(itfMethods[j].GetFileId().GetOffset());
87 if (!isMethodConflict.at(itfMethodId)) {
88 auto ret = AddMethod(imtable, imtableSize, itfMethodId, impMethod);
89 isMethodConflict[itfMethodId] = !ret;
90 }
91 }
92 }
93
94 #ifndef NDEBUG
95 DumpIMTable(klass);
96 #endif // NDEBUG
97 }
98
AddMethod(ark::Span<ark::Method * > imtable,uint32_t imtableSize,uint32_t id,Method * method)99 bool IMTableBuilder::AddMethod(ark::Span<ark::Method *> imtable, [[maybe_unused]] uint32_t imtableSize, uint32_t id,
100 Method *method)
101 {
102 bool result = false;
103 ASSERT(id < imtableSize);
104 if (imtable[id] == nullptr) {
105 imtable[id] = method;
106 result = true;
107 } else {
108 imtable[id] = nullptr;
109 }
110 return result;
111 }
112
DumpIMTable(Class * klass)113 void IMTableBuilder::DumpIMTable(Class *klass)
114 {
115 LOG(DEBUG, CLASS_LINKER) << "imtable of class " << klass->GetName() << ":";
116 auto imtable = klass->GetIMT();
117 auto imtableSize = klass->GetIMTSize();
118 for (size_t i = 0; i < imtableSize; i++) {
119 auto method = imtable[i];
120 if (method != nullptr) {
121 LOG(DEBUG, CLASS_LINKER) << "[ " << i << " ] " << method->GetFullName();
122 } else {
123 LOG(DEBUG, CLASS_LINKER) << "[ " << i << " ] "
124 << "FREE SLOT";
125 }
126 }
127 }
128
129 } // namespace ark
130