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