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