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