1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "include/language_context.h"
17 #include "include/mem/panda_containers.h"
18 #include "libpandabase/utils/utf.h"
19 #include "macros.h"
20 #include "napi/ets_napi.h"
21 #include "runtime/include/runtime.h"
22 #include "plugins/ets/runtime/types/ets_array.h"
23 #include "plugins/ets/runtime/types/ets_object.h"
24 #include "plugins/ets/runtime/types/ets_field.h"
25 #include "plugins/ets/runtime/types/ets_method.h"
26 #include "plugins/ets/runtime/types/ets_method_signature.h"
27 #include "plugins/ets/runtime/types/ets_string.h"
28 #include "plugins/ets/runtime/types/ets_value.h"
29 #include "plugins/ets/runtime/types/ets_class.h"
30
31 namespace ark::ets {
32
GetFieldsNumber()33 uint32_t EtsClass::GetFieldsNumber()
34 {
35 uint32_t fnumber = 0;
36 EnumerateBaseClasses([&](EtsClass *c) {
37 fnumber += c->GetRuntimeClass()->GetFields().Size();
38 return false;
39 });
40 return fnumber;
41 }
42
43 // Without inherited fields
GetOwnFieldsNumber()44 uint32_t EtsClass::GetOwnFieldsNumber()
45 {
46 return GetRuntimeClass()->GetFields().Size();
47 }
48
GetFields()49 PandaVector<EtsField *> EtsClass::GetFields()
50 {
51 auto etsFields = PandaVector<EtsField *>(Runtime::GetCurrent()->GetInternalAllocator()->Adapter());
52 EnumerateBaseClasses([&](EtsClass *c) {
53 auto fields = c->GetRuntimeClass()->GetFields();
54 auto fnum = fields.Size();
55 for (uint32_t i = 0; i < fnum; i++) {
56 etsFields.push_back(EtsField::FromRuntimeField(&fields[i]));
57 }
58 return false;
59 });
60 return etsFields;
61 }
62
GetFieldByIndex(uint32_t i)63 EtsField *EtsClass::GetFieldByIndex(uint32_t i)
64 {
65 EtsField *res = nullptr;
66 EnumerateBaseClasses([&](EtsClass *c) {
67 auto fields = c->GetRuntimeClass()->GetFields();
68 auto fnum = fields.Size();
69 if (i >= fnum) {
70 i -= fnum;
71 return false;
72 }
73 res = EtsField::FromRuntimeField(&fields[i]);
74 return true;
75 });
76 return res;
77 }
78
GetOwnFieldByIndex(uint32_t i)79 EtsField *EtsClass::GetOwnFieldByIndex(uint32_t i)
80 {
81 return EtsField::FromRuntimeField(&GetRuntimeClass()->GetFields()[i]);
82 }
83
GetDirectMethod(const char * name,const char * signature)84 EtsMethod *EtsClass::GetDirectMethod(const char *name, const char *signature)
85 {
86 auto coreName = reinterpret_cast<const uint8_t *>(name);
87 return GetDirectMethod(coreName, signature);
88 }
89
GetDirectMethod(const char * name)90 EtsMethod *EtsClass::GetDirectMethod(const char *name)
91 {
92 const uint8_t *mutf8Name = utf::CStringAsMutf8(name);
93 Method *rtMethod = GetRuntimeClass()->GetDirectMethod(mutf8Name);
94 return EtsMethod::FromRuntimeMethod(rtMethod);
95 }
96
GetDirectMethod(const uint8_t * name,const char * signature)97 EtsMethod *EtsClass::GetDirectMethod(const uint8_t *name, const char *signature)
98 {
99 EtsMethodSignature methodSignature(signature);
100 if (!methodSignature.IsValid()) {
101 LOG(ERROR, ETS_NAPI) << "Wrong method signature: " << signature;
102 return nullptr;
103 }
104
105 auto coreMethod = GetRuntimeClass()->GetDirectMethod(name, methodSignature.GetProto());
106 return reinterpret_cast<EtsMethod *>(coreMethod);
107 }
108
GetDirectMethod(const char * name,const Method::Proto & proto) const109 EtsMethod *EtsClass::GetDirectMethod(const char *name, const Method::Proto &proto) const
110 {
111 Method *method = klass_.GetDirectMethod(utf::CStringAsMutf8(name), proto);
112 return EtsMethod::FromRuntimeMethod(method);
113 }
114
GetMethodsNum()115 uint32_t EtsClass::GetMethodsNum()
116 {
117 return GetMethods().size();
118 }
119
GetMethodByIndex(uint32_t ind)120 EtsMethod *EtsClass::GetMethodByIndex(uint32_t ind)
121 {
122 EtsMethod *res = nullptr;
123 auto methods = GetMethods();
124 ASSERT(ind < methods.size());
125 res = methods[ind];
126 return res;
127 }
128
GetMethod(const char * name)129 EtsMethod *EtsClass::GetMethod(const char *name)
130 {
131 auto coreName = reinterpret_cast<const uint8_t *>(name);
132
133 Method *coreMethod = nullptr;
134 auto *runtimeClass = GetRuntimeClass();
135 if (IsInterface()) {
136 coreMethod = runtimeClass->GetInterfaceMethod(coreName);
137 } else {
138 coreMethod = runtimeClass->GetClassMethod(coreName);
139 }
140 return reinterpret_cast<EtsMethod *>(coreMethod);
141 }
142
GetMethod(const char * name,const char * signature)143 EtsMethod *EtsClass::GetMethod(const char *name, const char *signature)
144 {
145 EtsMethodSignature methodSignature(signature);
146 if (!methodSignature.IsValid()) {
147 LOG(ERROR, ETS_NAPI) << "Wrong method signature:" << signature;
148 return nullptr;
149 }
150
151 auto coreName = reinterpret_cast<const uint8_t *>(name);
152
153 Method *coreMethod = nullptr;
154 auto *runtimeClass = GetRuntimeClass();
155 if (IsInterface()) {
156 coreMethod = runtimeClass->GetInterfaceMethod(coreName, methodSignature.GetProto());
157 } else {
158 coreMethod = runtimeClass->GetClassMethod(coreName, methodSignature.GetProto());
159 }
160 return reinterpret_cast<EtsMethod *>(coreMethod);
161 }
162
163 // NOTE(kirill-mitkin): Cache in EtsClass field later
GetMethods()164 PandaVector<EtsMethod *> EtsClass::GetMethods()
165 {
166 PandaUnorderedMap<PandaString, EtsMethod *> uniqueMethods;
167
168 auto addDirectMethods = [&](const EtsClass *c) {
169 auto directMethods = c->GetRuntimeClass()->GetMethods();
170 for (auto &method : directMethods) {
171 auto name = PandaString(utf::Mutf8AsCString((method.GetName().data)));
172 if (uniqueMethods.find(name) == uniqueMethods.end()) {
173 uniqueMethods[name] = EtsMethod::FromRuntimeMethod(&method);
174 }
175 }
176 };
177
178 if (IsInterface()) {
179 addDirectMethods(this);
180 EnumerateInterfaces([&](const EtsClass *c) {
181 addDirectMethods(c);
182 return false;
183 });
184 } else {
185 EnumerateBaseClasses([&](EtsClass *c) {
186 auto directMethods = c->GetRuntimeClass()->GetMethods();
187 auto fnum = directMethods.Size();
188 for (uint32_t i = 0; i < fnum; i++) {
189 // Skip constructors
190 if (directMethods[i].IsConstructor()) {
191 continue;
192 }
193 auto name = PandaString(utf::Mutf8AsCString((directMethods[i].GetName().data)));
194 uniqueMethods[name] = EtsMethod::FromRuntimeMethod(&directMethods[i]);
195 }
196 return false;
197 });
198 }
199 auto etsMethods = PandaVector<EtsMethod *>();
200 for (auto &iter : uniqueMethods) {
201 etsMethods.push_back(iter.second);
202 }
203 return etsMethods;
204 }
205
GetConstructors()206 PandaVector<EtsMethod *> EtsClass::GetConstructors()
207 {
208 auto constructors = PandaVector<EtsMethod *>();
209 auto methods = GetRuntimeClass()->GetMethods();
210 // NOTE(kirill-mitkin): cache in ets_class field
211 for (auto &method : methods) {
212 // Skip constructors
213 if (method.IsInstanceConstructor()) {
214 constructors.emplace_back(EtsMethod::FromRuntimeMethod(&method));
215 }
216 }
217 return constructors;
218 }
219
ResolveVirtualMethod(const EtsMethod * method) const220 EtsMethod *EtsClass::ResolveVirtualMethod(const EtsMethod *method) const
221 {
222 return reinterpret_cast<EtsMethod *>(GetRuntimeClass()->ResolveVirtualMethod(method->GetPandaMethod()));
223 }
224
GetInterfaces() const225 PandaVector<EtsClass *> EtsClass::GetInterfaces() const
226 {
227 auto runtimeInterfaces = GetRuntimeClass()->GetInterfaces();
228 auto interfaces = PandaVector<EtsClass *>(runtimeInterfaces.Size());
229 for (size_t i = 0; i < interfaces.size(); i++) {
230 interfaces[i] = EtsClass::FromRuntimeClass(runtimeInterfaces[i]);
231 }
232 return interfaces;
233 }
234
235 /* static */
GetPrimitiveClass(EtsString * name)236 EtsClass *EtsClass::GetPrimitiveClass(EtsString *name)
237 {
238 if (name == nullptr || name->GetMUtf8Length() < 2) { // MUtf8Length must be >= 2
239 return nullptr;
240 }
241 const char *primitiveName = nullptr;
242 EtsClassRoot classRoot;
243 char hash = name->At(0) ^ ((name->At(1) & 0x10) << 1); // NOLINT
244 switch (hash) {
245 case 'v':
246 primitiveName = "void";
247 classRoot = EtsClassRoot::VOID;
248 break;
249 case 'b':
250 primitiveName = "boolean";
251 classRoot = EtsClassRoot::BOOLEAN;
252 break;
253 case 'B':
254 primitiveName = "byte";
255 classRoot = EtsClassRoot::BYTE;
256 break;
257 case 'c':
258 primitiveName = "char";
259 classRoot = EtsClassRoot::CHAR;
260 break;
261 case 's':
262 primitiveName = "short";
263 classRoot = EtsClassRoot::SHORT;
264 break;
265 case 'i':
266 primitiveName = "int";
267 classRoot = EtsClassRoot::INT;
268 break;
269 case 'l':
270 primitiveName = "long";
271 classRoot = EtsClassRoot::LONG;
272 break;
273 case 'f':
274 primitiveName = "float";
275 classRoot = EtsClassRoot::FLOAT;
276 break;
277 case 'd':
278 primitiveName = "double";
279 classRoot = EtsClassRoot::DOUBLE;
280 break;
281 default:
282 break;
283 }
284
285 // StringIndexOutOfBoundsException is not thrown by At method above, because index (0, 1) < length (>= 2)
286 if (primitiveName != nullptr && name->IsEqual(primitiveName)) { // SUPPRESS_CSA(alpha.core.WasteObjHeader)
287 return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(classRoot);
288 }
289
290 return nullptr;
291 }
292
CreateEtsClassName(const char * descriptor)293 EtsString *EtsClass::CreateEtsClassName([[maybe_unused]] const char *descriptor)
294 {
295 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
296
297 if (*descriptor == 'L') {
298 std::string_view tmpName(descriptor);
299 tmpName.remove_prefix(1);
300 tmpName.remove_suffix(1);
301 PandaString etsName(tmpName);
302 std::replace(etsName.begin(), etsName.end(), '/', '.');
303 return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
304 }
305 if (*descriptor == '[') {
306 PandaString etsName(descriptor);
307 std::replace(etsName.begin(), etsName.end(), '/', '.');
308 return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
309 }
310
311 switch (*descriptor) {
312 case 'Z':
313 return EtsString::CreateFromMUtf8("boolean");
314 case 'B':
315 return EtsString::CreateFromMUtf8("byte");
316 case 'C':
317 return EtsString::CreateFromMUtf8("char");
318 case 'S':
319 return EtsString::CreateFromMUtf8("short");
320 case 'I':
321 return EtsString::CreateFromMUtf8("int");
322 case 'J':
323 return EtsString::CreateFromMUtf8("long");
324 case 'F':
325 return EtsString::CreateFromMUtf8("float");
326 case 'D':
327 return EtsString::CreateFromMUtf8("double");
328 case 'V':
329 return EtsString::CreateFromMUtf8("void");
330 default:
331 LOG(FATAL, RUNTIME) << "Incorrect primitive name" << descriptor;
332 UNREACHABLE();
333 }
334 }
335
GetName()336 EtsString *EtsClass::GetName()
337 {
338 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
339
340 EtsString *name = nullptr;
341 bool success = false;
342
343 do {
344 name = reinterpret_cast<EtsString *>(GetObjectHeader()->GetFieldObject(GetNameOffset()));
345 if (name != nullptr) {
346 return name;
347 }
348
349 name = CreateEtsClassName(GetDescriptor());
350 if (name == nullptr) {
351 return nullptr;
352 }
353 success = CompareAndSetName(nullptr, name);
354 } while (!success);
355 return name;
356 }
357
IsInSamePackage(std::string_view className1,std::string_view className2)358 bool EtsClass::IsInSamePackage(std::string_view className1, std::string_view className2)
359 {
360 size_t i = 0;
361 size_t minLength = std::min(className1.size(), className2.size());
362 while (i < minLength && className1[i] == className2[i]) {
363 ++i;
364 }
365 return className1.find('/', i) == std::string::npos && className2.find('/', i) == std::string::npos;
366 }
367
IsInSamePackage(EtsClass * that)368 bool EtsClass::IsInSamePackage(EtsClass *that)
369 {
370 if (this == that) {
371 return true;
372 }
373
374 EtsClass *klass1 = this;
375 EtsClass *klass2 = that;
376 while (klass1->IsArrayClass()) {
377 klass1 = klass1->GetComponentType();
378 }
379 while (klass2->IsArrayClass()) {
380 klass2 = klass2->GetComponentType();
381 }
382 if (klass1 == klass2) {
383 return true;
384 }
385
386 // Compare the package part of the descriptor string.
387 return IsInSamePackage(klass1->GetDescriptor(), klass2->GetDescriptor());
388 }
389
SetWeakReference()390 void EtsClass::SetWeakReference()
391 {
392 flags_ = flags_ | IS_WEAK_REFERENCE;
393 ASSERT(IsWeakReference() && IsReference());
394 }
SetFinalizeReference()395 void EtsClass::SetFinalizeReference()
396 {
397 flags_ = flags_ | IS_FINALIZE_REFERENCE;
398 ASSERT(IsFinalizerReference() && IsReference());
399 }
400
SetValueTyped()401 void EtsClass::SetValueTyped()
402 {
403 flags_ = flags_ | IS_VALUE_TYPED;
404 ASSERT(IsValueTyped());
405 }
406
IsWeakReference() const407 bool EtsClass::IsWeakReference() const
408 {
409 return (flags_ & IS_WEAK_REFERENCE) != 0;
410 }
411
IsFinalizerReference() const412 bool EtsClass::IsFinalizerReference() const
413 {
414 return (flags_ & IS_FINALIZE_REFERENCE) != 0;
415 }
416
IsReference() const417 bool EtsClass::IsReference() const
418 {
419 return (flags_ & IS_REFERENCE) != 0;
420 }
421
Initialize(EtsClass * superClass,uint16_t accessFlags,bool isPrimitiveType)422 void EtsClass::Initialize(EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType)
423 {
424 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
425
426 SetName(nullptr);
427 SetSuperClass(superClass);
428
429 uint32_t flags = accessFlags;
430 if (isPrimitiveType) {
431 flags |= ETS_ACC_PRIMITIVE;
432 }
433
434 if (superClass != nullptr) {
435 static constexpr uint32_t COPIED_MASK = IS_WEAK_REFERENCE | IS_FINALIZE_REFERENCE;
436 flags |= superClass->GetFlags() & COPIED_MASK;
437 }
438 SetFlags(flags);
439 }
440
SetComponentType(EtsClass * componentType)441 void EtsClass::SetComponentType(EtsClass *componentType)
442 {
443 if (componentType == nullptr) {
444 GetRuntimeClass()->SetComponentType(nullptr);
445 return;
446 }
447 GetRuntimeClass()->SetComponentType(componentType->GetRuntimeClass());
448 }
449
GetComponentType() const450 EtsClass *EtsClass::GetComponentType() const
451 {
452 ark::Class *componentType = GetRuntimeClass()->GetComponentType();
453 if (componentType == nullptr) {
454 return nullptr;
455 }
456 return FromRuntimeClass(componentType);
457 }
458
SetName(EtsString * name)459 void EtsClass::SetName(EtsString *name)
460 {
461 GetObjectHeader()->SetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(name));
462 }
463
CompareAndSetName(EtsString * oldName,EtsString * newName)464 bool EtsClass::CompareAndSetName(EtsString *oldName, EtsString *newName)
465 {
466 return GetObjectHeader()->CompareAndSetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(oldName),
467 reinterpret_cast<ObjectHeader *>(newName),
468 std::memory_order::memory_order_seq_cst, true);
469 }
470
GetFieldIDByName(const char * name,const char * sig)471 EtsField *EtsClass::GetFieldIDByName(const char *name, const char *sig)
472 {
473 auto u8name = reinterpret_cast<const uint8_t *>(name);
474 auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetInstanceFieldByName(u8name));
475
476 if (sig != nullptr && field != nullptr) {
477 if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
478 return nullptr;
479 }
480 }
481
482 return field;
483 }
484
GetFieldIndexByName(const char * name)485 uint32_t EtsClass::GetFieldIndexByName(const char *name)
486 {
487 auto u8name = reinterpret_cast<const uint8_t *>(name);
488 auto fields = GetRuntimeClass()->GetFields();
489 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(u8name)), u8name};
490 for (uint32_t i = 0; i < GetFieldsNumber(); i++) {
491 if (fields[i].GetName() == sd) {
492 return i;
493 }
494 }
495 return -1;
496 }
497
GetStaticFieldIDByName(const char * name,const char * sig)498 EtsField *EtsClass::GetStaticFieldIDByName(const char *name, const char *sig)
499 {
500 auto u8name = reinterpret_cast<const uint8_t *>(name);
501 auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetStaticFieldByName(u8name));
502
503 if (sig != nullptr && field != nullptr) {
504 if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
505 return nullptr;
506 }
507 }
508
509 return field;
510 }
511
GetDeclaredFieldIDByName(const char * name)512 EtsField *EtsClass::GetDeclaredFieldIDByName(const char *name)
513 {
514 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindDeclaredField([name](const ark::Field &field) -> bool {
515 auto *efield = EtsField::FromRuntimeField(&field);
516 return ::strcmp(efield->GetName(), name) == 0;
517 }));
518 }
519
GetFieldIDByOffset(uint32_t fieldOffset)520 EtsField *EtsClass::GetFieldIDByOffset(uint32_t fieldOffset)
521 {
522 auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
523 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindInstanceField(pred));
524 }
525
GetStaticFieldIDByOffset(uint32_t fieldOffset)526 EtsField *EtsClass::GetStaticFieldIDByOffset(uint32_t fieldOffset)
527 {
528 auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
529 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindStaticField(pred));
530 }
531
GetBase()532 EtsClass *EtsClass::GetBase()
533 {
534 if (IsInterface()) {
535 return nullptr;
536 }
537 auto *base = GetRuntimeClass()->GetBase();
538 if (base == nullptr) {
539 return nullptr;
540 }
541 return FromRuntimeClass(base);
542 }
543
IsAnnotation() const544 bool EtsClass::IsAnnotation() const
545 {
546 return GetRuntimeClass()->IsAnnotation();
547 }
548
IsEnum() const549 bool EtsClass::IsEnum() const
550 {
551 return GetRuntimeClass()->IsEnum();
552 }
553
IsStringClass() const554 bool EtsClass::IsStringClass() const
555 {
556 return GetRuntimeClass()->IsStringClass();
557 }
558
IsFunctionalClass() const559 bool EtsClass::IsFunctionalClass() const
560 {
561 auto *ifuncClass = EtsCoroutine::GetCurrent()->GetPandaVM()->GetClassLinker()->GetIFunctionClass();
562 return ifuncClass->GetRuntimeClass()->IsAssignableFrom(GetRuntimeClass());
563 }
564
IsUnionClass() const565 bool EtsClass::IsUnionClass() const
566 {
567 // NOTE(petr-shumilov): Not implemented
568 return false;
569 }
570
IsUndefined() const571 bool EtsClass::IsUndefined() const
572 {
573 return GetDescriptor() == panda_file_items::class_descriptors::INTERNAL_UNDEFINED;
574 }
575
IsClassClass() const576 bool EtsClass::IsClassClass() const
577 {
578 return GetRuntimeClass()->IsClassClass();
579 }
580
IsInterface() const581 bool EtsClass::IsInterface() const
582 {
583 return GetRuntimeClass()->IsInterface();
584 }
585
IsArrayClass() const586 bool EtsClass::IsArrayClass() const
587 {
588 return GetRuntimeClass()->IsArrayClass();
589 }
590
IsTupleClass() const591 bool EtsClass::IsTupleClass() const
592 {
593 // NOTE(petr-shumilov): Not implemented
594 return false;
595 }
596
IsBoxedClass() const597 bool EtsClass::IsBoxedClass() const
598 {
599 auto typeDesc = GetDescriptor();
600 return (typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_BOOLEAN ||
601 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_BYTE ||
602 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_CHAR ||
603 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_SHORT ||
604 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_INT ||
605 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_LONG ||
606 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_FLOAT ||
607 typeDesc == ark::ets::panda_file_items::class_descriptors::BOX_DOUBLE);
608 }
609
GetInterfaces(PandaUnorderedSet<EtsClass * > & ifaces,EtsClass * iface)610 void EtsClass::GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface)
611 {
612 ifaces.insert(iface);
613 EnumerateDirectInterfaces([&](EtsClass *runtimeInterface) {
614 if (ifaces.find(runtimeInterface) == ifaces.end()) {
615 runtimeInterface->GetInterfaces(ifaces, runtimeInterface);
616 }
617 return false;
618 });
619 }
620
GetStaticFieldObject(EtsField * field)621 EtsObject *EtsClass::GetStaticFieldObject(EtsField *field)
622 {
623 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject(*field->GetRuntimeField()));
624 }
625
GetStaticFieldObject(int32_t fieldOffset,bool isVolatile)626 EtsObject *EtsClass::GetStaticFieldObject(int32_t fieldOffset, bool isVolatile)
627 {
628 if (isVolatile) {
629 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<true>(fieldOffset));
630 }
631 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<false>(fieldOffset));
632 }
633
SetStaticFieldObject(EtsField * field,EtsObject * value)634 void EtsClass::SetStaticFieldObject(EtsField *field, EtsObject *value)
635 {
636 GetRuntimeClass()->SetFieldObject(*field->GetRuntimeField(), reinterpret_cast<ObjectHeader *>(value));
637 }
638
SetStaticFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)639 void EtsClass::SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value)
640 {
641 if (isVolatile) {
642 GetRuntimeClass()->SetFieldObject<true>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
643 }
644 GetRuntimeClass()->SetFieldObject<false>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
645 }
646
647 } // namespace ark::ets
648