• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #ifndef PANDA_RUNTIME_CLASS_INL_H_
16 #define PANDA_RUNTIME_CLASS_INL_H_
17 
18 #include "runtime/include/class.h"
19 #include "runtime/include/class_helper.h"
20 #include "runtime/include/field.h"
21 #include "runtime/include/object_header.h"
22 #include "runtime/include/coretypes/tagged_value.h"
23 #include "runtime/include/object_accessor-inl.h"
24 
25 namespace ark {
26 
27 template <typename Item>
28 struct NameComp {
29     // NOLINTNEXTLINE(readability-identifier-naming)
equalNameComp30     bool equal(const Item &m, const panda_file::File::StringData &name) const
31     {
32         return m.GetName() == name;
33     }
operatorNameComp34     bool operator()(const Method &m, const panda_file::File::StringData &name) const
35     {
36         return m.GetName() < name;
37     }
38 };
39 
40 template <typename Item>
41 struct EntityIdComp {
42     // NOLINTNEXTLINE(readability-identifier-naming)
equalEntityIdComp43     bool equal(const Item &m, panda_file::File::EntityId id) const
44     {
45         return m.GetFileId().GetOffset() == id.GetOffset();
46     }
operatorEntityIdComp47     bool operator()(const Item &m, panda_file::File::EntityId id) const
48     {
49         return m.GetFileId().GetOffset() < id.GetOffset();
50     }
51 };
52 
53 using MethodNameComp = NameComp<Method>;
54 using MethodIdComp = EntityIdComp<Method>;
55 
56 template <typename Item>
PredComp(const Item & item)57 ALWAYS_INLINE inline bool PredComp([[maybe_unused]] const Item &item)
58 {
59     return true;
60 }
61 
62 template <typename Item, typename FirstPred, typename... Pred>
PredComp(const Item & item,const FirstPred & pred,const Pred &...preds)63 ALWAYS_INLINE inline bool PredComp(const Item &item, const FirstPred &pred, const Pred &...preds)
64 {
65     return pred(item) && PredComp(item, preds...);
66 }
67 
68 template <typename KeyComp, typename Key, typename Item, typename... Pred>
BinSearch(Span<Item> items,Key key,const Pred &...preds)69 ALWAYS_INLINE inline Item *BinSearch(Span<Item> items, Key key, const Pred &...preds)
70 {
71     auto it = std::lower_bound(items.begin(), items.end(), key, KeyComp());
72     while (it != items.end()) {
73         auto &item = *it;
74         if (!KeyComp().equal(item, key)) {
75             break;
76         }
77         if (PredComp(item, preds...)) {
78             return &item;
79         }
80         ++it;
81     }
82     return nullptr;
83 }
84 
85 // CC-OFFNXT(G.FUD.06) perf critical
GetTypeSize(panda_file::Type type)86 inline uint32_t Class::GetTypeSize(panda_file::Type type)
87 {
88     switch (type.GetId()) {
89         case panda_file::Type::TypeId::U1:
90         case panda_file::Type::TypeId::I8:
91         case panda_file::Type::TypeId::U8:
92             return sizeof(uint8_t);
93         case panda_file::Type::TypeId::I16:
94         case panda_file::Type::TypeId::U16:
95             return sizeof(uint16_t);
96         case panda_file::Type::TypeId::I32:
97         case panda_file::Type::TypeId::U32:
98         case panda_file::Type::TypeId::F32:
99             return sizeof(uint32_t);
100         case panda_file::Type::TypeId::I64:
101         case panda_file::Type::TypeId::U64:
102         case panda_file::Type::TypeId::F64:
103             return sizeof(uint64_t);
104         case panda_file::Type::TypeId::TAGGED:
105             return coretypes::TaggedValue::TaggedTypeSize();
106         case panda_file::Type::TypeId::REFERENCE:
107             return ClassHelper::OBJECT_POINTER_SIZE;
108         default:
109             UNREACHABLE();
110     }
111 }
112 
GetComponentSize()113 inline uint32_t Class::GetComponentSize() const
114 {
115     if (componentType_ == nullptr) {
116         return 0;
117     }
118 
119     return GetTypeSize(componentType_->GetType());
120 }
121 
IsClassClass()122 inline bool Class::IsClassClass() const
123 {
124     return GetManagedObject()->ClassAddr<Class>() == this;
125 }
126 
IsSubClassOf(const Class * klass)127 inline bool Class::IsSubClassOf(const Class *klass) const
128 {
129     const Class *current = this;
130 
131     do {
132         if (current == klass) {
133             return true;
134         }
135 
136         current = current->GetBase();
137     } while (current != nullptr);
138 
139     return false;
140 }
141 
142 // CC-OFFNXT(G.FUD.06) perf critical
IsAssignableFrom(const Class * klass)143 inline bool Class::IsAssignableFrom(const Class *klass) const
144 {
145     if (klass == this) {
146         return true;
147     }
148     if (IsObjectClass()) {
149         return !klass->IsPrimitive();
150     }
151     if (IsInterface()) {
152         return klass->Implements(this);
153     }
154     if (klass->IsArrayClass()) {
155         return IsArrayClass() && GetComponentType()->IsAssignableFrom(klass->GetComponentType());
156     }
157     return !klass->IsInterface() && klass->IsSubClassOf(this);
158 }
159 
Implements(const Class * klass)160 inline bool Class::Implements(const Class *klass) const
161 {
162     for (const auto &elem : itable_.Get()) {
163         if (elem.GetInterface() == klass) {
164             return true;
165         }
166     }
167 
168     return false;
169 }
170 
171 template <Class::FindFilter FILTER>
GetFields()172 inline Span<Field> Class::GetFields() const
173 {
174     switch (FILTER) {
175         case FindFilter::STATIC:
176             return GetStaticFields();
177         case FindFilter::INSTANCE:
178             return GetInstanceFields();
179         case FindFilter::ALL:
180             return GetFields();
181         default:
182             UNREACHABLE();
183     }
184 }
185 
186 template <Class::FindFilter FILTER, class Pred>
FindDeclaredField(Pred pred)187 inline Field *Class::FindDeclaredField(Pred pred) const
188 {
189     auto fields = GetFields<FILTER>();
190     auto it = std::find_if(fields.begin(), fields.end(), pred);
191     if (it != fields.end()) {
192         return &*it;
193     }
194     return nullptr;
195 }
196 
BinarySearchField(Span<Field> fields,panda_file::File::EntityId id)197 ALWAYS_INLINE inline Field *BinarySearchField(Span<Field> fields, panda_file::File::EntityId id)
198 {
199     auto comp = [](const Field &field, panda_file::File::EntityId fieldId) { return field.GetFileId() < fieldId; };
200     auto it = std::lower_bound(fields.begin(), fields.end(), id, comp);
201     if (it != fields.end() && (*it).GetFileId() == id) {
202         return &*it;
203     }
204     return nullptr;
205 }
206 
207 template <Class::FindFilter FILTER>
208 // CC-OFFNXT(G.FUD.06) solid logic
FindDeclaredField(panda_file::File::EntityId id)209 inline Field *Class::FindDeclaredField(panda_file::File::EntityId id) const
210 {
211     if (FILTER == FindFilter::ALL) {
212         auto staticFields = GetStaticFields();
213         auto *staticField = BinarySearchField(staticFields, id);
214         if (staticField != nullptr) {
215             return staticField;
216         }
217         auto instanceFields = GetInstanceFields();
218         auto *instanceField = BinarySearchField(instanceFields, id);
219         if (instanceField != nullptr) {
220             return instanceField;
221         }
222     } else {
223         auto fields = GetFields<FILTER>();
224         auto *field = BinarySearchField(fields, id);
225         if (field != nullptr) {
226             return field;
227         }
228     }
229 
230     return nullptr;
231 }
232 
233 template <Class::FindFilter FILTER, class Pred>
FindFieldInInterfaces(const Class * kls,Pred pred)234 inline Field *Class::FindFieldInInterfaces(const Class *kls, Pred pred) const
235 {
236     while (kls != nullptr) {
237         for (auto *iface : kls->GetInterfaces()) {
238             auto *field = iface->FindField<FILTER>(pred);
239             if (field != nullptr) {
240                 return field;
241             }
242         }
243 
244         kls = kls->GetBase();
245     }
246 
247     return nullptr;
248 }
249 
250 template <Class::FindFilter FILTER, class Pred>
251 // CC-OFFNXT(G.FUD.06) solid logic
FindField(Pred pred)252 inline Field *Class::FindField(Pred pred) const
253 {
254     auto *cls = this;
255     while (cls != nullptr) {
256         auto *field = cls->FindDeclaredField<FILTER>(pred);
257         if (field != nullptr) {
258             return field;
259         }
260 
261         cls = cls->GetBase();
262     }
263 
264     if (FILTER == FindFilter::STATIC || FILTER == FindFilter::ALL) {
265         return FindFieldInInterfaces<FILTER>(this, pred);
266     }
267 
268     return nullptr;
269 }
270 
271 template <Class::FindFilter FILTER>
272 // CC-OFFNXT(G.FUD.06) big swtich case
GetMethods()273 inline Span<Method> Class::GetMethods() const
274 {
275     switch (FILTER) {
276         case FindFilter::STATIC:
277             return GetStaticMethods();
278         case FindFilter::INSTANCE:
279             return GetVirtualMethods();
280         case FindFilter::ALL:
281             return GetMethods();
282         case FindFilter::COPIED:
283             return GetCopiedMethods();
284         default:
285             UNREACHABLE();
286     }
287 }
288 
289 template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
290 // CC-OFFNXT(G.FUD.06) solid logic
FindDirectMethod(Key key,const Pred &...preds)291 inline Method *Class::FindDirectMethod(Key key, const Pred &...preds) const
292 {
293     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
294     if constexpr (FILTER == FindFilter::ALL || FILTER == FindFilter::STATIC) {
295         auto methods = GetMethods<FindFilter::STATIC>();
296         auto *method = BinSearch<KeyComp>(methods, key, preds...);
297         if (method != nullptr) {
298             return method;
299         }
300     }
301 
302     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
303     if constexpr (FILTER == FindFilter::ALL || FILTER == FindFilter::INSTANCE) {
304         auto methods = GetMethods<FindFilter::INSTANCE>();
305         auto *method = BinSearch<KeyComp>(methods, key, preds...);
306         if (method != nullptr) {
307             return method;
308         }
309     }
310 
311     // Copied methods come from implemented interfaces default methods and unsorted,
312     // they can't be sorted by both id and name, so just visit method one by one now
313     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
314     if constexpr (FILTER == FindFilter::COPIED) {
315         auto methods = GetMethods<FindFilter::COPIED>();
316         for (auto &method : methods) {
317             if (KeyComp().equal(method, key) && PredComp(method, preds...)) {
318                 return &method;
319             }
320         }
321     }
322 
323     return nullptr;
324 }
325 
326 template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
327 // CC-OFFNXT(G.FUD.06) solid logic
FindClassMethod(Key key,const Pred &...preds)328 inline Method *Class::FindClassMethod(Key key, const Pred &...preds) const
329 {
330     auto *cls = this;
331     while (cls != nullptr) {
332         auto *method = cls->FindDirectMethod<FILTER, KeyComp>(key, preds...);
333         if (method != nullptr) {
334             return method;
335         }
336         cls = cls->GetBase();
337     }
338 
339     if (FILTER == FindFilter::ALL || FILTER == FindFilter::INSTANCE) {
340         return FindClassMethod<FindFilter::COPIED, KeyComp>(key, preds...);
341     }
342 
343     return nullptr;
344 }
345 
346 template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
347 // CC-OFFNXT(G.FUD.06) solid logic
FindInterfaceMethod(Key key,const Pred &...preds)348 inline Method *Class::FindInterfaceMethod(Key key, const Pred &...preds) const
349 {
350     static_assert(FILTER != FindFilter::COPIED, "interfaces don't have copied methods");
351 
352     if (LIKELY(IsInterface())) {
353         auto *method = FindDirectMethod<FILTER, KeyComp>(key, preds...);
354         if (method != nullptr) {
355             return method;
356         }
357     }
358 
359     if (FILTER == FindFilter::STATIC) {
360         return nullptr;
361     }
362 
363     for (const auto &entry : itable_.Get()) {
364         auto *iface = entry.GetInterface();
365         auto *method = iface->FindDirectMethod<FindFilter::INSTANCE, KeyComp>(key, preds...);
366         if (method != nullptr) {
367             return method;
368         }
369     }
370 
371     if (LIKELY(IsInterface())) {
372         return GetBase()->FindDirectMethod<FindFilter::INSTANCE, KeyComp>(
373             key, [&](const Method &method) { return method.IsPublic() && PredComp(method, preds...); });
374     }
375 
376     return nullptr;
377 }
378 
GetVirtualInterfaceMethod(panda_file::File::EntityId id)379 inline Method *Class::GetVirtualInterfaceMethod(panda_file::File::EntityId id) const
380 {
381     return FindInterfaceMethod<FindFilter::INSTANCE, MethodIdComp>(id);
382 }
383 
GetStaticInterfaceMethod(panda_file::File::EntityId id)384 inline Method *Class::GetStaticInterfaceMethod(panda_file::File::EntityId id) const
385 {
386     return FindInterfaceMethod<FindFilter::STATIC, MethodIdComp>(id);
387 }
388 
389 template <class Pred>
FindInstanceField(Pred pred)390 inline Field *Class::FindInstanceField(Pred pred) const
391 {
392     return FindField<FindFilter::INSTANCE>(pred);
393 }
394 
FindInstanceFieldById(panda_file::File::EntityId id)395 inline Field *Class::FindInstanceFieldById(panda_file::File::EntityId id) const
396 {
397     return FindField<FindFilter::INSTANCE>(id);
398 }
399 
400 template <class Pred>
FindStaticField(Pred pred)401 inline Field *Class::FindStaticField(Pred pred) const
402 {
403     return FindField<FindFilter::STATIC>(pred);
404 }
405 
FindStaticFieldById(panda_file::File::EntityId id)406 inline Field *Class::FindStaticFieldById(panda_file::File::EntityId id) const
407 {
408     return FindField<FindFilter::STATIC>(id);
409 }
410 
411 template <class Pred>
FindField(Pred pred)412 inline Field *Class::FindField(Pred pred) const
413 {
414     return FindField<FindFilter::ALL>(pred);
415 }
416 
417 template <class Pred>
FindDeclaredField(Pred pred)418 inline Field *Class::FindDeclaredField(Pred pred) const
419 {
420     return FindDeclaredField<FindFilter::ALL>(pred);
421 }
422 
GetInstanceFieldByName(const uint8_t * mutf8Name)423 inline Field *Class::GetInstanceFieldByName(const uint8_t *mutf8Name) const
424 {
425     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
426     return FindInstanceField([sd](const Field &field) { return field.GetName() == sd; });
427 }
428 
GetStaticFieldByName(const uint8_t * mutf8Name)429 inline Field *Class::GetStaticFieldByName(const uint8_t *mutf8Name) const
430 {
431     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
432     return FindStaticField([sd](const Field &field) { return field.GetName() == sd; });
433 }
434 
GetStaticFieldsOffset()435 inline size_t Class::GetStaticFieldsOffset() const
436 {
437     return ComputeClassSize(vtableSize_, imtSize_, 0, 0, 0, 0, 0, 0);
438 }
439 
GetDeclaredFieldByName(const uint8_t * mutf8Name)440 inline Field *Class::GetDeclaredFieldByName(const uint8_t *mutf8Name) const
441 {
442     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
443     return FindDeclaredField([sd](const Field &field) { return field.GetName() == sd; });
444 }
445 
GetVirtualClassMethod(panda_file::File::EntityId id)446 inline Method *Class::GetVirtualClassMethod(panda_file::File::EntityId id) const
447 {
448     return FindClassMethod<FindFilter::INSTANCE, MethodIdComp>(id);
449 }
450 
GetStaticClassMethod(panda_file::File::EntityId id)451 inline Method *Class::GetStaticClassMethod(panda_file::File::EntityId id) const
452 {
453     return FindClassMethod<FindFilter::STATIC, MethodIdComp>(id);
454 }
455 
GetDirectMethod(const uint8_t * mutf8Name,const Method::Proto & proto)456 inline Method *Class::GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
457 {
458     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
459     return FindDirectMethod<FindFilter::ALL, MethodNameComp>(
460         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
461 }
462 
GetClassMethod(const panda_file::File::StringData & sd,const Method::Proto & proto)463 inline Method *Class::GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const
464 {
465     return FindClassMethod<FindFilter::ALL, MethodNameComp>(
466         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
467 }
468 
GetStaticClassMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)469 inline Method *Class::GetStaticClassMethodByName(const panda_file::File::StringData &sd,
470                                                  const Method::Proto &proto) const
471 {
472     return FindClassMethod<FindFilter::STATIC, MethodNameComp>(
473         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
474 }
475 
GetVirtualClassMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)476 inline Method *Class::GetVirtualClassMethodByName(const panda_file::File::StringData &sd,
477                                                   const Method::Proto &proto) const
478 {
479     return FindClassMethod<FindFilter::INSTANCE, MethodNameComp>(
480         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
481 }
482 
GetInterfaceMethod(const panda_file::File::StringData & sd,const Method::Proto & proto)483 inline Method *Class::GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const
484 {
485     return FindInterfaceMethod<FindFilter::ALL, MethodNameComp>(
486         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
487 }
488 
GetStaticInterfaceMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)489 inline Method *Class::GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd,
490                                                      const Method::Proto &proto) const
491 {
492     return FindInterfaceMethod<FindFilter::STATIC, MethodNameComp>(
493         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
494 }
495 
GetVirtualInterfaceMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)496 inline Method *Class::GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd,
497                                                       const Method::Proto &proto) const
498 {
499     return FindInterfaceMethod<FindFilter::INSTANCE, MethodNameComp>(
500         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
501 }
502 
GetDirectMethod(const uint8_t * mutf8Name)503 inline Method *Class::GetDirectMethod(const uint8_t *mutf8Name) const
504 {
505     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
506     return FindDirectMethod<FindFilter::ALL, MethodNameComp>(sd);
507 }
508 
GetClassMethod(const uint8_t * mutf8Name)509 inline Method *Class::GetClassMethod(const uint8_t *mutf8Name) const
510 {
511     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
512     return FindClassMethod<FindFilter::ALL, MethodNameComp>(sd);
513 }
514 
GetStaticClassMethod(const uint8_t * mutf8Name)515 inline Method *Class::GetStaticClassMethod(const uint8_t *mutf8Name) const
516 {
517     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
518     return FindClassMethod<FindFilter::STATIC, MethodNameComp>(sd);
519 }
520 
GetVirtualClassMethod(const uint8_t * mutf8Name)521 inline Method *Class::GetVirtualClassMethod(const uint8_t *mutf8Name) const
522 {
523     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
524     return FindClassMethod<FindFilter::INSTANCE, MethodNameComp>(sd);
525 }
526 
GetClassMethod(const uint8_t * mutf8Name,const Method::Proto & proto)527 inline Method *Class::GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
528 {
529     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
530     return FindClassMethod<FindFilter::ALL, MethodNameComp>(
531         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
532 }
533 
GetStaticClassMethod(const uint8_t * mutf8Name,const Method::Proto & proto)534 inline Method *Class::GetStaticClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
535 {
536     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
537     return FindClassMethod<FindFilter::STATIC, MethodNameComp>(
538         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
539 }
540 
GetVirtualClassMethod(const uint8_t * mutf8Name,const Method::Proto & proto)541 inline Method *Class::GetVirtualClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
542 {
543     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
544     return FindClassMethod<FindFilter::INSTANCE, MethodNameComp>(
545         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
546 }
547 
GetInterfaceMethod(const uint8_t * mutf8Name)548 inline Method *Class::GetInterfaceMethod(const uint8_t *mutf8Name) const
549 {
550     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
551     return FindInterfaceMethod<FindFilter::ALL, MethodNameComp>(sd);
552 }
553 
GetStaticInterfaceMethod(const uint8_t * mutf8Name)554 inline Method *Class::GetStaticInterfaceMethod(const uint8_t *mutf8Name) const
555 {
556     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
557     return FindInterfaceMethod<FindFilter::STATIC, MethodNameComp>(sd);
558 }
559 
GetVirtualInterfaceMethod(const uint8_t * mutf8Name)560 inline Method *Class::GetVirtualInterfaceMethod(const uint8_t *mutf8Name) const
561 {
562     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
563     return FindInterfaceMethod<FindFilter::INSTANCE, MethodNameComp>(sd);
564 }
565 
GetInterfaceMethod(const uint8_t * mutf8Name,const Method::Proto & proto)566 inline Method *Class::GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
567 {
568     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
569     return FindInterfaceMethod<FindFilter::ALL, MethodNameComp>(
570         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
571 }
572 
GetStaticInterfaceMethod(const uint8_t * mutf8Name,const Method::Proto & proto)573 inline Method *Class::GetStaticInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
574 {
575     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
576     return FindInterfaceMethod<FindFilter::STATIC, MethodNameComp>(
577         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
578 }
579 
GetVirtualInterfaceMethod(const uint8_t * mutf8Name,const Method::Proto & proto)580 inline Method *Class::GetVirtualInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
581 {
582     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
583     return FindInterfaceMethod<FindFilter::INSTANCE, MethodNameComp>(
584         sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
585 }
586 
587 // CC-OFFNXT(G.FUD.06) perf critical
ResolveVirtualMethod(const Method * method)588 inline Method *Class::ResolveVirtualMethod(const Method *method) const
589 {
590     Method *resolved = nullptr;
591 
592     ASSERT(!IsInterface());
593 
594     if (method->GetClass()->IsInterface() && !method->IsDefaultInterfaceMethod()) {
595         // find method in imtable
596         auto imtableSize = GetIMTSize();
597         if (LIKELY(imtableSize != 0)) {
598             auto imtable = GetIMT();
599             auto methodId = GetIMTableIndex(method->GetFileId().GetOffset());
600             resolved = imtable[methodId];
601             if (resolved != nullptr) {
602                 return resolved;
603             }
604         }
605 
606         // find method in itable
607         auto *iface = method->GetClass();
608         auto itable = GetITable();
609         for (size_t i = 0; i < itable.Size(); i++) {
610             auto &entry = itable[i];
611             if (entry.GetInterface() != iface) {
612                 continue;
613             }
614 
615             resolved = entry.GetMethods()[method->GetVTableIndex()];
616         }
617     } else {
618         // find method in vtable
619         auto vtable = GetVTable();
620         ASSERT_PRINT(method->GetVTableIndex() < vtable.size(),
621                      "cls = " << this << ", managed object = " << GetManagedObject());
622         resolved = vtable[method->GetVTableIndex()];
623     }
624 
625     return resolved;
626 }
627 
ComputeClassSize(size_t vtableSize,size_t imtSize,size_t num8bitSfields,size_t num16bitSfields,size_t num32bitSfields,size_t num64bitSfields,size_t numRefSfields,size_t numTaggedSfields)628 constexpr size_t Class::ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields,
629                                          size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields,
630                                          size_t numRefSfields, size_t numTaggedSfields)
631 {
632     size_t size = sizeof(Class);
633     size = AlignUp(size, ClassHelper::OBJECT_POINTER_SIZE);
634     size += vtableSize * ClassHelper::POINTER_SIZE;
635     size += imtSize * ClassHelper::POINTER_SIZE;
636     size += numRefSfields * ClassHelper::OBJECT_POINTER_SIZE;
637 
638     constexpr size_t SIZE_64 = sizeof(uint64_t);
639     constexpr size_t SIZE_32 = sizeof(uint32_t);
640     constexpr size_t SIZE_16 = sizeof(uint16_t);
641     constexpr size_t SIZE_8 = sizeof(uint8_t);
642 
643     // Try to fill alignment gaps with fields that have smaller size from largest to smallests
644     static_assert(coretypes::TaggedValue::TaggedTypeSize() == SIZE_64,
645                   "Please fix alignment of the fields of type \"TaggedValue\"");
646     if (!IsAligned<SIZE_64>(size) && (num64bitSfields > 0 || numTaggedSfields > 0)) {
647         size_t padding = AlignUp(size, SIZE_64) - size;
648         size += padding;
649 
650         Pad(SIZE_32, &padding, &num32bitSfields);
651         Pad(SIZE_16, &padding, &num16bitSfields);
652         Pad(SIZE_8, &padding, &num8bitSfields);
653     }
654 
655     if (!IsAligned<SIZE_32>(size) && num32bitSfields > 0) {
656         size_t padding = AlignUp(size, SIZE_32) - size;
657         size += padding;
658 
659         Pad(SIZE_16, &padding, &num16bitSfields);
660         Pad(SIZE_8, &padding, &num8bitSfields);
661     }
662 
663     if (!IsAligned<SIZE_16>(size) && num16bitSfields > 0) {
664         size_t padding = AlignUp(size, SIZE_16) - size;
665         size += padding;
666 
667         Pad(SIZE_8, &padding, &num8bitSfields);
668     }
669 
670     size += num64bitSfields * SIZE_64 + num32bitSfields * SIZE_32 + num16bitSfields * SIZE_16 +
671             num8bitSfields * SIZE_8 + numTaggedSfields * coretypes::TaggedValue::TaggedTypeSize();
672 
673     return size;
674 }
675 
Pad(size_t size,size_t * padding,size_t * n)676 constexpr void Class::Pad(size_t size, size_t *padding, size_t *n)
677 {
678     while (*padding >= size && *n > 0) {
679         *padding -= size;
680         *n -= 1;
681     }
682 }
683 
GetVTableOffset()684 constexpr size_t Class::GetVTableOffset()
685 {
686     return ComputeClassSize(0, 0, 0, 0, 0, 0, 0, 0);
687 }
688 
GetVTable()689 inline Span<Method *> Class::GetVTable()
690 {
691     return GetClassSpan().SubSpan<Method *>(GetVTableOffset(), vtableSize_);
692 }
693 
GetVTable()694 inline Span<Method *const> Class::GetVTable() const
695 {
696     return GetClassSpan().SubSpan<Method *const>(GetVTableOffset(), vtableSize_);
697 }
698 
GetIMTOffset()699 inline size_t Class::GetIMTOffset() const
700 {
701     return GetVTableOffset() + vtableSize_ * sizeof(uintptr_t);
702 }
703 
704 // IS_VOLATILE = false
705 template <class T, bool IS_VOLATILE>
GetFieldPrimitive(size_t offset)706 inline T Class::GetFieldPrimitive(size_t offset) const
707 {
708     ASSERT_DO(IsInitializing() || IsInitialized(), LOG(ERROR, RUNTIME) << "class state: " << state_);
709     return ObjectAccessor::GetPrimitive<T, IS_VOLATILE>(this, offset);
710 }
711 
712 // IS_VOLATILE = false
713 template <class T, bool IS_VOLATILE>
SetFieldPrimitive(size_t offset,T value)714 inline void Class::SetFieldPrimitive(size_t offset, T value)
715 {
716     ObjectAccessor::SetPrimitive<T, IS_VOLATILE>(this, offset, value);
717 }
718 
719 // IS_VOLATILE = false , bool NEED_READ_BARRIER = true
720 template <bool IS_VOLATILE, bool NEED_READ_BARRIER>
GetFieldObject(size_t offset)721 inline ObjectHeader *Class::GetFieldObject(size_t offset) const
722 {
723     // NOTE(alovkov): GC can skip classes which are IsErroneous #6458
724     // GC can't easily check state & get fields because state can be changed concurrently and checking on every field
725     // is too expensive and it should be atomic {check state, get field}
726     ASSERT_DO(IsInitializing() || IsInitialized() || IsErroneous(), LOG(ERROR, RUNTIME) << "class state: " << state_);
727     return ObjectAccessor::GetObject<IS_VOLATILE, NEED_READ_BARRIER>(this, offset);
728 }
729 
730 // IS_VOLATILE = false , bool NEED_WRITE_BARRIER = true
731 template <bool IS_VOLATILE, bool NEED_WRITE_BARRIER>
SetFieldObject(size_t offset,ObjectHeader * value)732 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value)
733 {
734     auto object = GetManagedObject();
735     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
736     auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
737     ObjectAccessor::SetObject<IS_VOLATILE, NEED_WRITE_BARRIER>(object, newOffset, value);
738 }
739 
740 template <class T>
GetFieldPrimitive(const Field & field)741 inline T Class::GetFieldPrimitive(const Field &field) const
742 {
743     return ObjectAccessor::GetFieldPrimitive<T>(this, field);
744 }
745 
746 template <class T>
SetFieldPrimitive(const Field & field,T value)747 inline void Class::SetFieldPrimitive(const Field &field, T value)
748 {
749     ObjectAccessor::SetFieldPrimitive(this, field, value);
750 }
751 
752 // NEED_READ_BARRIER = true
753 template <bool NEED_READ_BARRIER>
GetFieldObject(const Field & field)754 inline ObjectHeader *Class::GetFieldObject(const Field &field) const
755 {
756     return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(this, field);
757 }
758 
759 // NEED_WRITE_BARRIER = true
760 template <bool NEED_WRITE_BARRIER>
SetFieldObject(const Field & field,ObjectHeader * value)761 inline void Class::SetFieldObject(const Field &field, ObjectHeader *value)
762 {
763     auto object = GetManagedObject();
764     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
765     auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
766     if (UNLIKELY(field.IsVolatile())) {
767         ObjectAccessor::SetObject<true, NEED_WRITE_BARRIER>(object, offset, value);
768     } else {
769         ObjectAccessor::SetObject<false, NEED_WRITE_BARRIER>(object, offset, value);
770     }
771 }
772 
773 // NEED_READ_BARRIER = true
774 template <bool NEED_READ_BARRIER>
GetFieldObject(ManagedThread * thread,const Field & field)775 inline ObjectHeader *Class::GetFieldObject(ManagedThread *thread, const Field &field) const
776 {
777     return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(thread, this, field);
778 }
779 
780 // NEED_WRITE_BARRIER = true
781 template <bool NEED_WRITE_BARRIER>
SetFieldObject(ManagedThread * thread,const Field & field,ObjectHeader * value)782 inline void Class::SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value)
783 {
784     auto object = GetManagedObject();
785     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
786     auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
787     if (UNLIKELY(field.IsVolatile())) {
788         ObjectAccessor::SetObject<true, NEED_WRITE_BARRIER>(thread, object, offset, value);
789     } else {
790         ObjectAccessor::SetObject<false, NEED_WRITE_BARRIER>(thread, object, offset, value);
791     }
792 }
793 
794 template <class T>
GetFieldPrimitive(size_t offset,std::memory_order memoryOrder)795 inline T Class::GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const
796 {
797     return ObjectAccessor::GetFieldPrimitive<T>(this, offset, memoryOrder);
798 }
799 
800 template <class T>
SetFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)801 inline void Class::SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
802 {
803     ObjectAccessor::SetFieldPrimitive(this, offset, value, memoryOrder);
804 }
805 
806 // NEED_READ_BARRIER = true
807 template <bool NEED_READ_BARRIER>
GetFieldObject(size_t offset,std::memory_order memoryOrder)808 inline ObjectHeader *Class::GetFieldObject(size_t offset, std::memory_order memoryOrder) const
809 {
810     return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(this, offset, memoryOrder);
811 }
812 
813 // NEED_WRITE_BARRIER = true
814 template <bool NEED_WRITE_BARRIER>
SetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)815 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
816 {
817     auto object = GetManagedObject();
818     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
819     auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
820     ObjectAccessor::SetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, value, memoryOrder);
821 }
822 
823 template <typename T>
CompareAndSetFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)824 inline bool Class::CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
825                                                bool strong)
826 {
827     return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, oldValue, newValue, memoryOrder, strong).first;
828 }
829 
830 // NEED_WRITE_BARRIER = true
831 template <bool NEED_WRITE_BARRIER>
CompareAndSetFieldObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)832 inline bool Class::CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
833                                             std::memory_order memoryOrder, bool strong)
834 {
835     auto object = GetManagedObject();
836     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
837     auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
838     return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, oldValue, newValue,
839                                                                         memoryOrder, strong)
840         .first;
841 }
842 
843 template <typename T>
CompareAndExchangeFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)844 inline T Class::CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
845                                                  bool strong)
846 {
847     return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, oldValue, newValue, memoryOrder, strong).second;
848 }
849 
850 // NEED_WRITE_BARRIER = true
851 template <bool NEED_WRITE_BARRIER>
CompareAndExchangeFieldObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)852 inline ObjectHeader *Class::CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
853                                                           std::memory_order memoryOrder, bool strong)
854 {
855     auto object = GetManagedObject();
856     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
857     auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
858     return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, oldValue, newValue,
859                                                                         memoryOrder, strong)
860         .second;
861 }
862 
863 template <typename T>
GetAndSetFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)864 inline T Class::GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
865 {
866     return ObjectAccessor::GetAndSetFieldPrimitive(this, offset, value, memoryOrder);
867 }
868 
869 // NEED_WRITE_BARRIER = true
870 template <bool NEED_WRITE_BARRIER>
GetAndSetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)871 inline ObjectHeader *Class::GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
872 {
873     auto object = GetManagedObject();
874     ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
875     auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
876     return ObjectAccessor::GetAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, value, memoryOrder);
877 }
878 
879 template <typename T>
GetAndAddFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)880 inline T Class::GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
881 {
882     return ObjectAccessor::GetAndAddFieldPrimitive(this, offset, value, memoryOrder);
883 }
884 
885 template <typename T>
GetAndBitwiseOrFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)886 inline T Class::GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
887 {
888     return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, offset, value, memoryOrder);
889 }
890 
891 template <typename T>
GetAndBitwiseAndFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)892 inline T Class::GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
893 {
894     return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, offset, value, memoryOrder);
895 }
896 
897 template <typename T>
GetAndBitwiseXorFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)898 inline T Class::GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
899 {
900     return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, offset, value, memoryOrder);
901 }
902 
903 }  // namespace ark
904 
905 #endif  // PANDA_RUNTIME_CLASS_INL_H_
906