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