1 /*
2 * Copyright (c) 2021 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
16 #ifndef PANDA_RUNTIME_INCLUDE_CLASS_INL_H_
17 #define PANDA_RUNTIME_INCLUDE_CLASS_INL_H_
18
19 #include "runtime/include/class.h"
20 #include "runtime/include/coretypes/tagged_value.h"
21 #include "runtime/include/object_accessor-inl.h"
22
23 namespace panda {
24
GetTypeSize(panda_file::Type type)25 inline uint32_t Class::GetTypeSize(panda_file::Type type)
26 {
27 switch (type.GetId()) {
28 case panda_file::Type::TypeId::U1:
29 case panda_file::Type::TypeId::I8:
30 case panda_file::Type::TypeId::U8:
31 return sizeof(uint8_t);
32 case panda_file::Type::TypeId::I16:
33 case panda_file::Type::TypeId::U16:
34 return sizeof(uint16_t);
35 case panda_file::Type::TypeId::I32:
36 case panda_file::Type::TypeId::U32:
37 case panda_file::Type::TypeId::F32:
38 return sizeof(uint32_t);
39 case panda_file::Type::TypeId::I64:
40 case panda_file::Type::TypeId::U64:
41 case panda_file::Type::TypeId::F64:
42 return sizeof(uint64_t);
43 case panda_file::Type::TypeId::TAGGED:
44 return coretypes::TaggedValue::TaggedTypeSize();
45 case panda_file::Type::TypeId::REFERENCE:
46 return ClassHelper::OBJECT_POINTER_SIZE;
47 default:
48 UNREACHABLE();
49 }
50 }
51
GetComponentSize()52 inline uint32_t Class::GetComponentSize() const
53 {
54 if (component_type_ == nullptr) {
55 return 0;
56 }
57
58 return GetTypeSize(component_type_->GetType());
59 }
60
IsSubClassOf(const Class * klass)61 inline bool Class::IsSubClassOf(const Class *klass) const
62 {
63 const Class *current = this;
64
65 do {
66 if (current == klass) {
67 return true;
68 }
69
70 current = current->GetBase();
71 } while (current != nullptr);
72
73 return false;
74 }
75
IsAssignableFrom(const Class * klass)76 inline bool Class::IsAssignableFrom(const Class *klass) const
77 {
78 if (klass == this) {
79 return true;
80 }
81 if (IsObjectClass()) {
82 return !klass->IsPrimitive();
83 }
84 if (IsInterface()) {
85 return klass->Implements(this);
86 }
87 if (klass->IsArrayClass()) {
88 return IsArrayClass() && GetComponentType()->IsAssignableFrom(klass->GetComponentType());
89 }
90 return !klass->IsInterface() && klass->IsSubClassOf(this);
91 }
92
Implements(const Class * klass)93 inline bool Class::Implements(const Class *klass) const
94 {
95 for (const auto &elem : itable_.Get()) {
96 if (elem.GetInterface() == klass) {
97 return true;
98 }
99 }
100
101 return false;
102 }
103
104 template <Class::FindFilter filter>
GetFields()105 inline Span<Field> Class::GetFields() const
106 {
107 switch (filter) {
108 case FindFilter::STATIC:
109 return GetStaticFields();
110 case FindFilter::INSTANCE:
111 return GetInstanceFields();
112 case FindFilter::ALL:
113 return GetFields();
114 default:
115 UNREACHABLE();
116 }
117 }
118
119 template <Class::FindFilter filter, class Pred>
FindDeclaredField(Pred pred)120 inline Field *Class::FindDeclaredField(Pred pred) const
121 {
122 auto fields = GetFields<filter>();
123 auto it = std::find_if(fields.begin(), fields.end(), pred);
124 if (it != fields.end()) {
125 return &*it;
126 }
127 return nullptr;
128 }
129
130 template <Class::FindFilter filter, class Pred>
FindField(Pred pred)131 inline Field *Class::FindField(Pred pred) const
132 {
133 auto *cls = this;
134 while (cls != nullptr) {
135 auto *field = cls->FindDeclaredField<filter>(pred);
136 if (field != nullptr) {
137 return field;
138 }
139
140 cls = cls->GetBase();
141 }
142
143 if (filter == FindFilter::STATIC || filter == FindFilter::ALL) {
144 auto *kls = this;
145 while (kls != nullptr) {
146 for (auto *iface : kls->GetInterfaces()) {
147 auto *field = iface->FindField<filter>(pred);
148 if (field != nullptr) {
149 return field;
150 }
151 }
152
153 kls = kls->GetBase();
154 }
155 }
156
157 return nullptr;
158 }
159
160 template <Class::FindFilter filter>
GetMethods()161 inline Span<Method> Class::GetMethods() const
162 {
163 switch (filter) {
164 case FindFilter::STATIC:
165 return GetStaticMethods();
166 case FindFilter::INSTANCE:
167 return GetVirtualMethods();
168 case FindFilter::ALL:
169 return GetMethods();
170 case FindFilter::COPIED:
171 return GetCopiedMethods();
172 default:
173 UNREACHABLE();
174 }
175 }
176
177 template <Class::FindFilter filter, class Pred>
FindDirectMethod(Pred pred)178 inline Method *Class::FindDirectMethod(Pred pred) const
179 {
180 auto methods = GetMethods<filter>();
181 auto it = std::find_if(methods.begin(), methods.end(), pred);
182 if (it != methods.end()) {
183 return &*it;
184 }
185 return nullptr;
186 }
187
188 template <Class::FindFilter filter, class Pred>
FindClassMethod(Pred pred)189 inline Method *Class::FindClassMethod(Pred pred) const
190 {
191 auto *cls = this;
192 while (cls != nullptr) {
193 auto *method = cls->FindDirectMethod<filter>(pred);
194 if (method != nullptr) {
195 return method;
196 }
197
198 cls = cls->GetBase();
199 }
200
201 if (filter == FindFilter::ALL || filter == FindFilter::INSTANCE) {
202 return FindClassMethod<FindFilter::COPIED>(pred);
203 }
204
205 return nullptr;
206 }
207
208 template <Class::FindFilter filter, class Pred>
FindInterfaceMethod(Pred pred)209 inline Method *Class::FindInterfaceMethod(Pred pred) const
210 {
211 static_assert(filter != FindFilter::COPIED, "interfaces don't have copied methods");
212
213 if (LIKELY(IsInterface())) {
214 auto *method = FindDirectMethod<filter>(pred);
215 if (method != nullptr) {
216 return method;
217 }
218 }
219
220 if (filter == FindFilter::STATIC) {
221 return nullptr;
222 }
223
224 for (const auto &entry : itable_.Get()) {
225 auto *iface = entry.GetInterface();
226 auto *method = iface->FindDirectMethod<FindFilter::INSTANCE>(pred);
227 if (method != nullptr) {
228 return method;
229 }
230 }
231
232 if (LIKELY(IsInterface())) {
233 return GetBase()->FindDirectMethod<FindFilter::INSTANCE>(
234 [&pred](const Method &method) { return method.IsPublic() && pred(method); });
235 }
236
237 return nullptr;
238 }
239
240 template <class Pred>
FindInterfaceMethod(Pred pred)241 inline Method *Class::FindInterfaceMethod(Pred pred) const
242 {
243 return FindInterfaceMethod<FindFilter::ALL>(pred);
244 }
245
246 template <class Pred>
FindVirtualInterfaceMethod(Pred pred)247 inline Method *Class::FindVirtualInterfaceMethod(Pred pred) const
248 {
249 return FindInterfaceMethod<FindFilter::INSTANCE>(pred);
250 }
251
252 template <class Pred>
FindStaticInterfaceMethod(Pred pred)253 inline Method *Class::FindStaticInterfaceMethod(Pred pred) const
254 {
255 return FindInterfaceMethod<FindFilter::STATIC>(pred);
256 }
257
258 template <class Pred>
FindInstanceField(Pred pred)259 inline Field *Class::FindInstanceField(Pred pred) const
260 {
261 return FindField<FindFilter::INSTANCE>(pred);
262 }
263
264 template <class Pred>
FindStaticField(Pred pred)265 inline Field *Class::FindStaticField(Pred pred) const
266 {
267 return FindField<FindFilter::STATIC>(pred);
268 }
269
270 template <class Pred>
FindField(Pred pred)271 inline Field *Class::FindField(Pred pred) const
272 {
273 return FindField<FindFilter::ALL>(pred);
274 }
275
276 template <class Pred>
FindDeclaredField(Pred pred)277 inline Field *Class::FindDeclaredField(Pred pred) const
278 {
279 return FindDeclaredField<FindFilter::ALL>(pred);
280 }
281
GetInstanceFieldByName(const uint8_t * mutf8_name)282 inline Field *Class::GetInstanceFieldByName(const uint8_t *mutf8_name) const
283 {
284 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
285 return FindInstanceField([sd](const Field &field) { return field.GetName() == sd; });
286 }
287
GetStaticFieldByName(const uint8_t * mutf8_name)288 inline Field *Class::GetStaticFieldByName(const uint8_t *mutf8_name) const
289 {
290 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
291 return FindStaticField([sd](const Field &field) { return field.GetName() == sd; });
292 }
293
GetDeclaredFieldByName(const uint8_t * mutf8_name)294 inline Field *Class::GetDeclaredFieldByName(const uint8_t *mutf8_name) const
295 {
296 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
297 return FindDeclaredField([sd](const Field &field) { return field.GetName() == sd; });
298 }
299
300 template <class Pred>
FindVirtualClassMethod(Pred pred)301 inline Method *Class::FindVirtualClassMethod(Pred pred) const
302 {
303 return FindClassMethod<FindFilter::INSTANCE>(pred);
304 }
305
306 template <class Pred>
FindStaticClassMethod(Pred pred)307 inline Method *Class::FindStaticClassMethod(Pred pred) const
308 {
309 return FindClassMethod<FindFilter::STATIC>(pred);
310 }
311
312 template <class Pred>
FindClassMethod(Pred pred)313 inline Method *Class::FindClassMethod(Pred pred) const
314 {
315 return FindClassMethod<FindFilter::ALL>(pred);
316 }
317
GetDirectMethod(const uint8_t * mutf8_name,const Method::Proto & proto)318 inline Method *Class::GetDirectMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const
319 {
320 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
321 return FindDirectMethod<FindFilter::ALL>(
322 [sd, proto](const Method &method) { return method.GetName() == sd && method.GetProto() == proto; });
323 }
324
GetClassMethod(const uint8_t * mutf8_name,const Method::Proto & proto)325 inline Method *Class::GetClassMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const
326 {
327 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
328 return FindClassMethod(
329 [sd, proto](const Method &method) { return method.GetName() == sd && method.GetProto() == proto; });
330 }
331
GetInterfaceMethod(const uint8_t * mutf8_name,const Method::Proto & proto)332 inline Method *Class::GetInterfaceMethod(const uint8_t *mutf8_name, const Method::Proto &proto) const
333 {
334 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
335 return FindInterfaceMethod(
336 [sd, proto](const Method &method) { return method.GetName() == sd && method.GetProto() == proto; });
337 }
338
GetDirectMethod(const uint8_t * mutf8_name)339 inline Method *Class::GetDirectMethod(const uint8_t *mutf8_name) const
340 {
341 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
342 return FindDirectMethod<FindFilter::ALL>([sd](const Method &method) { return method.GetName() == sd; });
343 }
344
GetClassMethod(const uint8_t * mutf8_name)345 inline Method *Class::GetClassMethod(const uint8_t *mutf8_name) const
346 {
347 panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(mutf8_name)), mutf8_name};
348 return FindClassMethod([sd](const Method &method) { return method.GetName() == sd; });
349 }
350
ResolveVirtualMethod(const Method * method)351 inline Method *Class::ResolveVirtualMethod(const Method *method) const
352 {
353 Method *resolved = nullptr;
354
355 ASSERT(!IsInterface());
356
357 if (method->GetClass()->IsInterface() && !method->IsDefaultInterfaceMethod()) {
358 // find method in imtable
359 auto imtable_size = GetIMTSize();
360 if (LIKELY(imtable_size != 0)) {
361 auto imtable = GetIMT();
362 auto method_id = GetIMTableIndex(method->GetFileId().GetOffset());
363 resolved = imtable[method_id];
364 if (resolved != nullptr) {
365 return resolved;
366 }
367 }
368
369 // find method in itable
370 auto *iface = method->GetClass();
371 auto itable = GetITable();
372 for (size_t i = 0; i < itable.Size(); i++) {
373 auto &entry = itable[i];
374 if (entry.GetInterface() != iface) {
375 continue;
376 }
377
378 resolved = entry.GetMethods()[method->GetVTableIndex()];
379 }
380 } else {
381 // find method in vtable
382 auto vtable = GetVTable();
383 ASSERT(method->GetVTableIndex() < vtable.size());
384 resolved = vtable[method->GetVTableIndex()];
385 }
386
387 return resolved;
388 }
389
390 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
391 template <class T, bool is_volatile /* = false */>
GetFieldPrimitive(size_t offset)392 inline T Class::GetFieldPrimitive(size_t offset) const
393 {
394 ASSERT(IsInitializing() || IsInitialized());
395 return ObjectAccessor::GetPrimitive<T, is_volatile>(this, offset);
396 }
397
398 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
399 template <class T, bool is_volatile /* = false */>
SetFieldPrimitive(size_t offset,T value)400 inline void Class::SetFieldPrimitive(size_t offset, T value)
401 {
402 ObjectAccessor::SetPrimitive<T, is_volatile>(this, offset, value);
403 }
404
405 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
406 template <bool is_volatile /* = false */, bool need_read_barrier /* = true */>
GetFieldObject(size_t offset)407 inline ObjectHeader *Class::GetFieldObject(size_t offset) const
408 {
409 ASSERT(IsInitializing() || IsInitialized());
410 return ObjectAccessor::GetObject<is_volatile, need_read_barrier>(this, offset);
411 }
412
413 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
414 template <bool is_volatile /* = false */, bool need_write_barrier /* = true */>
SetFieldObject(size_t offset,ObjectHeader * value)415 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value)
416 {
417 auto object = GetManagedObject();
418 auto new_offset = offset + (ToUintPtr(this) - ToUintPtr(object));
419 ObjectAccessor::SetObject<is_volatile, need_write_barrier>(object, new_offset, value);
420 }
421
422 template <class T>
GetFieldPrimitive(const Field & field)423 inline T Class::GetFieldPrimitive(const Field &field) const
424 {
425 return ObjectAccessor::GetFieldPrimitive<T>(this, field);
426 }
427
428 template <class T>
SetFieldPrimitive(const Field & field,T value)429 inline void Class::SetFieldPrimitive(const Field &field, T value)
430 {
431 ObjectAccessor::SetFieldPrimitive(this, field, value);
432 }
433
434 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
435 template <bool need_read_barrier /* = true */>
GetFieldObject(const Field & field)436 inline ObjectHeader *Class::GetFieldObject(const Field &field) const
437 {
438 return ObjectAccessor::GetFieldObject<need_read_barrier>(this, field);
439 }
440
441 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
442 template <bool need_write_barrier /* = true */>
SetFieldObject(const Field & field,ObjectHeader * value)443 inline void Class::SetFieldObject(const Field &field, ObjectHeader *value)
444 {
445 auto object = GetManagedObject();
446 auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
447 if (UNLIKELY(field.IsVolatile())) {
448 ObjectAccessor::SetObject<true, need_write_barrier>(object, offset, value);
449 } else {
450 ObjectAccessor::SetObject<false, need_write_barrier>(object, offset, value);
451 }
452 }
453
454 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
455 template <bool need_read_barrier /* = true */>
GetFieldObject(ManagedThread * thread,const Field & field)456 inline ObjectHeader *Class::GetFieldObject(ManagedThread *thread, const Field &field) const
457 {
458 return ObjectAccessor::GetFieldObject<need_read_barrier>(thread, this, field);
459 }
460
461 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_COMMENT_LOCATION)
462 template <bool need_write_barrier /* = true */>
SetFieldObject(ManagedThread * thread,const Field & field,ObjectHeader * value)463 inline void Class::SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value)
464 {
465 auto object = GetManagedObject();
466 auto offset = field.GetOffset() + (ToUintPtr(this) - ToUintPtr(object));
467 if (UNLIKELY(field.IsVolatile())) {
468 ObjectAccessor::SetObject<true, need_write_barrier>(thread, object, offset, value);
469 } else {
470 ObjectAccessor::SetObject<false, need_write_barrier>(thread, object, offset, value);
471 }
472 }
473
474 template <class T>
GetFieldPrimitive(size_t offset,std::memory_order memory_order)475 inline T Class::GetFieldPrimitive(size_t offset, std::memory_order memory_order) const
476 {
477 return ObjectAccessor::GetFieldPrimitive<T>(this, offset, memory_order);
478 }
479
480 template <class T>
SetFieldPrimitive(size_t offset,T value,std::memory_order memory_order)481 inline void Class::SetFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
482 {
483 ObjectAccessor::SetFieldPrimitive(this, offset, value, memory_order);
484 }
485
486 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
487 template <bool need_read_barrier /* = true */>
GetFieldObject(size_t offset,std::memory_order memory_order)488 inline ObjectHeader *Class::GetFieldObject(size_t offset, std::memory_order memory_order) const
489 {
490 return ObjectAccessor::GetFieldObject<need_read_barrier>(this, offset, memory_order);
491 }
492
493 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
494 template <bool need_write_barrier /* = true */>
SetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memory_order)495 inline void Class::SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order)
496 {
497 ObjectAccessor::SetFieldObject<need_write_barrier>(this, offset, value, memory_order);
498 }
499
500 template <typename T>
CompareAndSetFieldPrimitive(size_t offset,T old_value,T new_value,std::memory_order memory_order,bool strong)501 inline bool Class::CompareAndSetFieldPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
502 bool strong)
503 {
504 return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, old_value, new_value, memory_order, strong).first;
505 }
506
507 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
508 template <bool need_write_barrier /* = true */>
CompareAndSetFieldObject(size_t offset,ObjectHeader * old_value,ObjectHeader * new_value,std::memory_order memory_order,bool strong)509 inline bool Class::CompareAndSetFieldObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
510 std::memory_order memory_order, bool strong)
511 {
512 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier>(this, offset, old_value, new_value,
513 memory_order, strong)
514 .first;
515 }
516
517 template <typename T>
CompareAndExchangeFieldPrimitive(size_t offset,T old_value,T new_value,std::memory_order memory_order,bool strong)518 inline T Class::CompareAndExchangeFieldPrimitive(size_t offset, T old_value, T new_value,
519 std::memory_order memory_order, bool strong)
520 {
521 return ObjectAccessor::CompareAndSetFieldPrimitive(this, offset, old_value, new_value, memory_order, strong).second;
522 }
523
524 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
525 template <bool need_write_barrier /* = true */>
CompareAndExchangeFieldObject(size_t offset,ObjectHeader * old_value,ObjectHeader * new_value,std::memory_order memory_order,bool strong)526 inline ObjectHeader *Class::CompareAndExchangeFieldObject(size_t offset, ObjectHeader *old_value,
527 ObjectHeader *new_value, std::memory_order memory_order,
528 bool strong)
529 {
530 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier>(this, offset, old_value, new_value,
531 memory_order, strong)
532 .second;
533 }
534
535 template <typename T>
GetAndSetFieldPrimitive(size_t offset,T value,std::memory_order memory_order)536 inline T Class::GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
537 {
538 return ObjectAccessor::GetAndSetFieldPrimitive(this, offset, value, memory_order);
539 }
540
541 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE, C_RULE_ID_COMMENT_LOCATION)
542 template <bool need_write_barrier /* = true */>
GetAndSetFieldObject(size_t offset,ObjectHeader * value,std::memory_order memory_order)543 inline ObjectHeader *Class::GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memory_order)
544 {
545 return ObjectAccessor::GetAndSetFieldObject<need_write_barrier>(this, offset, value, memory_order);
546 }
547
548 template <typename T>
GetAndAddFieldPrimitive(size_t offset,T value,std::memory_order memory_order)549 inline T Class::GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
550 {
551 return ObjectAccessor::GetAndAddFieldPrimitive(this, offset, value, memory_order);
552 }
553
554 template <typename T>
GetAndBitwiseOrFieldPrimitive(size_t offset,T value,std::memory_order memory_order)555 inline T Class::GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
556 {
557 return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, offset, value, memory_order);
558 }
559
560 template <typename T>
GetAndBitwiseAndFieldPrimitive(size_t offset,T value,std::memory_order memory_order)561 inline T Class::GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
562 {
563 return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, offset, value, memory_order);
564 }
565
566 template <typename T>
GetAndBitwiseXorFieldPrimitive(size_t offset,T value,std::memory_order memory_order)567 inline T Class::GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memory_order)
568 {
569 return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, offset, value, memory_order);
570 }
571
572 } // namespace panda
573
574 #endif // PANDA_RUNTIME_INCLUDE_CLASS_INL_H_
575