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