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
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 uint8_t * mutf8Name,const Method::Proto & proto)463 inline Method *Class::GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
464 {
465 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
466 return GetClassMethod(sd, proto);
467 }
468
GetClassMethod(const panda_file::File::StringData & sd,const Method::Proto & proto)469 inline Method *Class::GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const
470 {
471 return FindClassMethod<FindFilter::ALL, MethodNameComp>(
472 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
473 }
474
GetStaticClassMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)475 inline Method *Class::GetStaticClassMethodByName(const panda_file::File::StringData &sd,
476 const Method::Proto &proto) const
477 {
478 return FindClassMethod<FindFilter::STATIC, MethodNameComp>(
479 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
480 }
481
GetVirtualClassMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)482 inline Method *Class::GetVirtualClassMethodByName(const panda_file::File::StringData &sd,
483 const Method::Proto &proto) const
484 {
485 return FindClassMethod<FindFilter::INSTANCE, MethodNameComp>(
486 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
487 }
488
GetInterfaceMethod(const uint8_t * mutf8Name,const Method::Proto & proto)489 inline Method *Class::GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const
490 {
491 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
492 return GetInterfaceMethod(sd, proto);
493 }
494
GetInterfaceMethod(const panda_file::File::StringData & sd,const Method::Proto & proto)495 inline Method *Class::GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const
496 {
497 return FindInterfaceMethod<FindFilter::ALL, MethodNameComp>(
498 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
499 }
500
GetStaticInterfaceMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)501 inline Method *Class::GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd,
502 const Method::Proto &proto) const
503 {
504 return FindInterfaceMethod<FindFilter::STATIC, MethodNameComp>(
505 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
506 }
507
GetVirtualInterfaceMethodByName(const panda_file::File::StringData & sd,const Method::Proto & proto)508 inline Method *Class::GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd,
509 const Method::Proto &proto) const
510 {
511 return FindInterfaceMethod<FindFilter::INSTANCE, MethodNameComp>(
512 sd, [&proto](const Method &method) { return method.GetProtoId() == proto; });
513 }
514
GetDirectMethod(const uint8_t * mutf8Name)515 inline Method *Class::GetDirectMethod(const uint8_t *mutf8Name) const
516 {
517 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
518 return FindDirectMethod<FindFilter::ALL, MethodNameComp>(sd);
519 }
520
GetClassMethod(const uint8_t * mutf8Name)521 inline Method *Class::GetClassMethod(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::ALL, MethodNameComp>(sd);
525 }
526
GetInterfaceMethod(const uint8_t * mutf8Name)527 inline Method *Class::GetInterfaceMethod(const uint8_t *mutf8Name) const
528 {
529 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(mutf8Name)), mutf8Name};
530 return FindInterfaceMethod<FindFilter::ALL, MethodNameComp>(sd);
531 }
532
533 // CC-OFFNXT(G.FUD.06) perf critical
ResolveVirtualMethod(const Method * method)534 inline Method *Class::ResolveVirtualMethod(const Method *method) const
535 {
536 Method *resolved = nullptr;
537
538 ASSERT(!IsInterface());
539
540 if (method->GetClass()->IsInterface() && !method->IsDefaultInterfaceMethod()) {
541 // find method in imtable
542 auto imtableSize = GetIMTSize();
543 if (LIKELY(imtableSize != 0)) {
544 auto imtable = GetIMT();
545 auto methodId = GetIMTableIndex(method->GetFileId().GetOffset());
546 resolved = imtable[methodId];
547 if (resolved != nullptr) {
548 return resolved;
549 }
550 }
551
552 // find method in itable
553 auto *iface = method->GetClass();
554 auto itable = GetITable();
555 for (size_t i = 0; i < itable.Size(); i++) {
556 auto &entry = itable[i];
557 if (entry.GetInterface() != iface) {
558 continue;
559 }
560
561 resolved = entry.GetMethods()[method->GetVTableIndex()];
562 }
563 } else {
564 // find method in vtable
565 auto vtable = GetVTable();
566 ASSERT_PRINT(method->GetVTableIndex() < vtable.size(),
567 "cls = " << this << ", managed object = " << GetManagedObject());
568 resolved = vtable[method->GetVTableIndex()];
569 }
570
571 return resolved;
572 }
573
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)574 constexpr size_t Class::ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields,
575 size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields,
576 size_t numRefSfields, size_t numTaggedSfields)
577 {
578 size_t size = sizeof(Class);
579 size = AlignUp(size, ClassHelper::OBJECT_POINTER_SIZE);
580 size += vtableSize * ClassHelper::POINTER_SIZE;
581 size += imtSize * ClassHelper::POINTER_SIZE;
582 size += numRefSfields * ClassHelper::OBJECT_POINTER_SIZE;
583
584 constexpr size_t SIZE_64 = sizeof(uint64_t);
585 constexpr size_t SIZE_32 = sizeof(uint32_t);
586 constexpr size_t SIZE_16 = sizeof(uint16_t);
587 constexpr size_t SIZE_8 = sizeof(uint8_t);
588
589 // Try to fill alignment gaps with fields that have smaller size from largest to smallests
590 static_assert(coretypes::TaggedValue::TaggedTypeSize() == SIZE_64,
591 "Please fix alignment of the fields of type \"TaggedValue\"");
592 if (!IsAligned<SIZE_64>(size) && (num64bitSfields > 0 || numTaggedSfields > 0)) {
593 size_t padding = AlignUp(size, SIZE_64) - size;
594 size += padding;
595
596 Pad(SIZE_32, &padding, &num32bitSfields);
597 Pad(SIZE_16, &padding, &num16bitSfields);
598 Pad(SIZE_8, &padding, &num8bitSfields);
599 }
600
601 if (!IsAligned<SIZE_32>(size) && num32bitSfields > 0) {
602 size_t padding = AlignUp(size, SIZE_32) - size;
603 size += padding;
604
605 Pad(SIZE_16, &padding, &num16bitSfields);
606 Pad(SIZE_8, &padding, &num8bitSfields);
607 }
608
609 if (!IsAligned<SIZE_16>(size) && num16bitSfields > 0) {
610 size_t padding = AlignUp(size, SIZE_16) - size;
611 size += padding;
612
613 Pad(SIZE_8, &padding, &num8bitSfields);
614 }
615
616 size += num64bitSfields * SIZE_64 + num32bitSfields * SIZE_32 + num16bitSfields * SIZE_16 +
617 num8bitSfields * SIZE_8 + numTaggedSfields * coretypes::TaggedValue::TaggedTypeSize();
618
619 return size;
620 }
621
Pad(size_t size,size_t * padding,size_t * n)622 constexpr void Class::Pad(size_t size, size_t *padding, size_t *n)
623 {
624 while (*padding >= size && *n > 0) {
625 *padding -= size;
626 *n -= 1;
627 }
628 }
629
GetVTableOffset()630 constexpr size_t Class::GetVTableOffset()
631 {
632 return ComputeClassSize(0, 0, 0, 0, 0, 0, 0, 0);
633 }
634
GetVTable()635 inline Span<Method *> Class::GetVTable()
636 {
637 return GetClassSpan().SubSpan<Method *>(GetVTableOffset(), vtableSize_);
638 }
639
GetVTable()640 inline Span<Method *const> Class::GetVTable() const
641 {
642 return GetClassSpan().SubSpan<Method *const>(GetVTableOffset(), vtableSize_);
643 }
644
GetIMTOffset()645 inline size_t Class::GetIMTOffset() const
646 {
647 return GetVTableOffset() + vtableSize_ * sizeof(uintptr_t);
648 }
649
650 // IS_VOLATILE = false
651 template <class T, bool IS_VOLATILE>
GetFieldPrimitive(size_t offset)652 inline T Class::GetFieldPrimitive(size_t offset) const
653 {
654 ASSERT_DO(IsInitializing() || IsInitialized(), LOG(ERROR, RUNTIME) << "class state: " << state_);
655 return ObjectAccessor::GetPrimitive<T, IS_VOLATILE>(this, offset);
656 }
657
658 // IS_VOLATILE = false
659 template <class T, bool IS_VOLATILE>
SetFieldPrimitive(size_t offset,T value)660 inline void Class::SetFieldPrimitive(size_t offset, T value)
661 {
662 ObjectAccessor::SetPrimitive<T, IS_VOLATILE>(this, offset, value);
663 }
664
665 // IS_VOLATILE = false , bool NEED_READ_BARRIER = true
666 template <bool IS_VOLATILE, bool NEED_READ_BARRIER>
GetFieldObject(size_t offset)667 inline ObjectHeader *Class::GetFieldObject(size_t offset) const
668 {
669 // NOTE(alovkov): GC can skip classes which are IsErroneous #6458
670 // GC can't easily check state & get fields because state can be changed concurrently and checking on every field
671 // is too expensive and it should be atomic {check state, get field}
672 ASSERT_DO(IsInitializing() || IsInitialized() || IsErroneous(), LOG(ERROR, RUNTIME) << "class state: " << state_);
673 return ObjectAccessor::GetObject<IS_VOLATILE, NEED_READ_BARRIER>(this, offset);
674 }
675
676 // IS_VOLATILE = false , bool NEED_WRITE_BARRIER = true
677 template <bool IS_VOLATILE, bool NEED_WRITE_BARRIER>
SetFieldObject(size_t offset,ObjectHeader * value)678 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value)
679 {
680 auto object = GetManagedObject();
681 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
682 auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
683 ObjectAccessor::SetObject<IS_VOLATILE, NEED_WRITE_BARRIER>(object, newOffset, value);
684 }
685
686 template <class T>
GetFieldPrimitive(const Field & field)687 inline T Class::GetFieldPrimitive(const Field &field) const
688 {
689 return ObjectAccessor::GetFieldPrimitive<T>(this, field);
690 }
691
692 template <class T>
SetFieldPrimitive(const Field & field,T value)693 inline void Class::SetFieldPrimitive(const Field &field, T value)
694 {
695 ObjectAccessor::SetFieldPrimitive(this, field, value);
696 }
697
698 // NEED_READ_BARRIER = true
699 template <bool NEED_READ_BARRIER>
GetFieldObject(const Field & field)700 inline ObjectHeader *Class::GetFieldObject(const Field &field) const
701 {
702 return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(this, field);
703 }
704
705 // NEED_WRITE_BARRIER = true
706 template <bool NEED_WRITE_BARRIER>
SetFieldObject(const Field & field,ObjectHeader * value)707 inline void Class::SetFieldObject(const Field &field, ObjectHeader *value)
708 {
709 auto object = GetManagedObject();
710 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
711 auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
712 if (UNLIKELY(field.IsVolatile())) {
713 ObjectAccessor::SetObject<true, NEED_WRITE_BARRIER>(object, offset, value);
714 } else {
715 ObjectAccessor::SetObject<false, NEED_WRITE_BARRIER>(object, offset, value);
716 }
717 }
718
719 // NEED_READ_BARRIER = true
720 template <bool NEED_READ_BARRIER>
GetFieldObject(ManagedThread * thread,const Field & field)721 inline ObjectHeader *Class::GetFieldObject(ManagedThread *thread, const Field &field) const
722 {
723 return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(thread, this, field);
724 }
725
726 // NEED_WRITE_BARRIER = true
727 template <bool NEED_WRITE_BARRIER>
SetFieldObject(ManagedThread * thread,const Field & field,ObjectHeader * value)728 inline void Class::SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value)
729 {
730 auto object = GetManagedObject();
731 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
732 auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
733 if (UNLIKELY(field.IsVolatile())) {
734 ObjectAccessor::SetObject<true, NEED_WRITE_BARRIER>(thread, object, offset, value);
735 } else {
736 ObjectAccessor::SetObject<false, NEED_WRITE_BARRIER>(thread, object, offset, value);
737 }
738 }
739
740 template <class T>
GetFieldPrimitive(size_t offset,std::memory_order memoryOrder)741 inline T Class::GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const
742 {
743 return ObjectAccessor::GetFieldPrimitive<T>(this, offset, memoryOrder);
744 }
745
746 template <class T>
SetFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)747 inline void Class::SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
748 {
749 ObjectAccessor::SetFieldPrimitive(this, offset, value, memoryOrder);
750 }
751
752 // NEED_READ_BARRIER = true
753 template <bool NEED_READ_BARRIER>
GetFieldObject(size_t offset,std::memory_order memoryOrder)754 inline ObjectHeader *Class::GetFieldObject(size_t offset, std::memory_order memoryOrder) const
755 {
756 return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER>(this, offset, memoryOrder);
757 }
758
759 // NEED_WRITE_BARRIER = true
760 template <bool NEED_WRITE_BARRIER>
SetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)761 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
762 {
763 auto object = GetManagedObject();
764 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
765 auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
766 ObjectAccessor::SetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, value, memoryOrder);
767 }
768
769 template <typename T>
CompareAndSetFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)770 inline bool Class::CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
771 bool strong)
772 {
773 return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, oldValue, newValue, memoryOrder, strong).first;
774 }
775
776 // NEED_WRITE_BARRIER = true
777 template <bool NEED_WRITE_BARRIER>
CompareAndSetFieldObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)778 inline bool Class::CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
779 std::memory_order memoryOrder, bool strong)
780 {
781 auto object = GetManagedObject();
782 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
783 auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
784 return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, oldValue, newValue,
785 memoryOrder, strong)
786 .first;
787 }
788
789 template <typename T>
CompareAndExchangeFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)790 inline T Class::CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
791 bool strong)
792 {
793 return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, oldValue, newValue, memoryOrder, strong).second;
794 }
795
796 // NEED_WRITE_BARRIER = true
797 template <bool NEED_WRITE_BARRIER>
CompareAndExchangeFieldObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)798 inline ObjectHeader *Class::CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
799 std::memory_order memoryOrder, bool strong)
800 {
801 auto object = GetManagedObject();
802 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
803 auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
804 return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, oldValue, newValue,
805 memoryOrder, strong)
806 .second;
807 }
808
809 template <typename T>
GetAndSetFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)810 inline T Class::GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
811 {
812 return ObjectAccessor::GetAndSetFieldPrimitive(this, offset, value, memoryOrder);
813 }
814
815 // NEED_WRITE_BARRIER = true
816 template <bool NEED_WRITE_BARRIER>
GetAndSetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)817 inline ObjectHeader *Class::GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
818 {
819 auto object = GetManagedObject();
820 ASSERT(ToUintPtr(object) < ToUintPtr(this) && ToUintPtr(this) < ToUintPtr(object) + object->ObjectSize());
821 auto newOffset = offset + (ToUintPtr(this) - ToUintPtr(object));
822 return ObjectAccessor::GetAndSetFieldObject<NEED_WRITE_BARRIER>(object, newOffset, value, memoryOrder);
823 }
824
825 template <typename T>
GetAndAddFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)826 inline T Class::GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
827 {
828 return ObjectAccessor::GetAndAddFieldPrimitive(this, offset, value, memoryOrder);
829 }
830
831 template <typename T>
GetAndBitwiseOrFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)832 inline T Class::GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
833 {
834 return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, offset, value, memoryOrder);
835 }
836
837 template <typename T>
GetAndBitwiseAndFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)838 inline T Class::GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
839 {
840 return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, offset, value, memoryOrder);
841 }
842
843 template <typename T>
GetAndBitwiseXorFieldPrimitive(size_t offset,T value,std::memory_order memoryOrder)844 inline T Class::GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder)
845 {
846 return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, offset, value, memoryOrder);
847 }
848
849 } // namespace ark
850
851 #endif // PANDA_RUNTIME_CLASS_INL_H_
852