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