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