1 /*
2 * Copyright (c) 2021 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 panda {
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 ifm_num = 0;
28 for (size_t i = 0; i < itable.Size(); i++) {
29 auto &entry = itable[i];
30 auto methods = entry.GetMethods();
31 ifm_num += 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(ifm_num <= Class::IMTABLE_SIZE
40 ? ifm_num
41 : (ifm_num <= Class::IMTABLE_SIZE * OVERSIZE_MULTIPLE ? Class::IMTABLE_SIZE : 0));
42 }
43
Build(ITable itable,bool is_interface)44 void IMTableBuilder::Build(ITable itable, bool is_interface)
45 {
46 if (is_interface || itable.Size() == 0U) {
47 return;
48 }
49
50 size_t ifm_num = 0;
51 for (size_t i = 0; i < itable.Size(); i++) {
52 auto &entry = itable[i];
53 auto methods = entry.GetMethods();
54 ifm_num += methods.Size();
55 }
56
57 // set imtable size rules: the same as function above
58 SetIMTSize(ifm_num <= Class::IMTABLE_SIZE
59 ? ifm_num
60 : (ifm_num <= 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 imtable_size = klass->GetIMTSize();
70 if (imtable_size == 0U) {
71 return;
72 }
73
74 std::array<bool, Class::IMTABLE_SIZE> is_method_conflict = {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 itf_methods = entry.GetInterface()->GetVirtualMethods();
82 auto imp_methods = entry.GetMethods();
83
84 for (size_t j = 0; j < itf_methods.Size(); j++) {
85 auto imp_method = imp_methods[j];
86 auto itf_method_id = klass->GetIMTableIndex(itf_methods[j].GetFileId().GetOffset());
87 if (!is_method_conflict.at(itf_method_id)) {
88 auto ret = AddMethod(imtable, imtable_size, itf_method_id, imp_method);
89 is_method_conflict[itf_method_id] = !ret;
90 }
91 }
92 }
93
94 #ifndef NDEBUG
95 DumpIMTable(klass);
96 #endif // NDEBUG
97 }
98
AddMethod(panda::Span<panda::Method * > imtable,uint32_t imtable_size,uint32_t id,Method * method)99 bool IMTableBuilder::AddMethod(panda::Span<panda::Method *> imtable, [[maybe_unused]] uint32_t imtable_size,
100 uint32_t id, Method *method)
101 {
102 bool result = false;
103 ASSERT(id < imtable_size);
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 imtable_size = klass->GetIMTSize();
118 for (size_t i = 0; i < imtable_size; 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 panda
130