• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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