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
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 "plugins/ets/runtime/ets_class_linker_extension.h"
22 #include "plugins/ets/runtime/ets_exceptions.h"
23 #include "plugins/ets/runtime/types/ets_array.h"
24 #include "plugins/ets/runtime/types/ets_object.h"
25 #include "plugins/ets/runtime/types/ets_field.h"
26 #include "plugins/ets/runtime/types/ets_method.h"
27 #include "plugins/ets/runtime/types/ets_method_signature.h"
28 #include "plugins/ets/runtime/types/ets_string.h"
29 #include "plugins/ets/runtime/types/ets_value.h"
30 #include "plugins/ets/runtime/types/ets_class.h"
31 #include "runtime/include/runtime.h"
32 #include "runtime/mem/local_object_handle.h"
33
34 namespace ark::ets {
35
VerifyLambdaClass(EtsClass * etsClass,Method * method,ClassLinkerErrorHandler * errorHandler)36 static bool VerifyLambdaClass(EtsClass *etsClass, Method *method, ClassLinkerErrorHandler *errorHandler)
37 {
38 ASSERT(etsClass != nullptr);
39 ASSERT(method != nullptr);
40 auto fields = etsClass->GetFields();
41 if (method->IsStatic()) {
42 return fields.empty();
43 }
44 if (fields.size() != 1) {
45 LOG(ERROR, CLASS_LINKER) << "Invalid LambdaClass: Expected at most 1 field, but got " << fields.size();
46 return false;
47 }
48 auto klass = etsClass->GetFieldByIndex(0)->GetRuntimeField()->ResolveTypeClass(errorHandler);
49 if (klass == nullptr) {
50 return false;
51 }
52 auto baseClass = method->GetClass();
53 return baseClass->IsAssignableFrom(klass);
54 }
55
ReportInvalidLambdaClass(const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)56 static void ReportInvalidLambdaClass(const uint8_t *descriptor, [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
57 {
58 if (errorHandler != nullptr) {
59 PandaStringStream ss;
60 ss << "Found invalid lambda class " << descriptor;
61 errorHandler->OnError(ClassLinker::Error::INVALID_LAMBDA_CLASS, ss.str());
62 }
63 }
64
FunctionalReferenceAnnotationCallBack(EtsClass * etsClass,const panda_file::File * pfile,panda_file::AnnotationDataAccessor * ada,ClassLinkerErrorHandler * errorHandler)65 static void FunctionalReferenceAnnotationCallBack(EtsClass *etsClass, const panda_file::File *pfile,
66 panda_file::AnnotationDataAccessor *ada,
67 ClassLinkerErrorHandler *errorHandler)
68 {
69 // methodOffset is passed by FE
70 auto implMethod = ada->GetElement(0).GetScalarValue().Get<panda_file::File::EntityId>();
71 auto methodOffset = implMethod.GetOffset();
72 auto *linker = PandaEtsVM::GetCurrent()->GetClassLinker();
73 auto *method = linker->GetMethod(*pfile, panda_file::File::EntityId(methodOffset), etsClass->GetLoadContext());
74
75 etsClass->SetTypeMetaData(reinterpret_cast<EtsLong>(method));
76 if (!VerifyLambdaClass(etsClass, method, errorHandler)) {
77 auto descriptor = utf::CStringAsMutf8(etsClass->GetDescriptor());
78 ReportInvalidLambdaClass(descriptor, errorHandler);
79 }
80 }
81
GetFieldsNumber()82 uint32_t EtsClass::GetFieldsNumber()
83 {
84 uint32_t fnumber = 0;
85 EnumerateBaseClasses([&](EtsClass *c) {
86 fnumber += c->GetRuntimeClass()->GetFields().Size();
87 return false;
88 });
89 return fnumber;
90 }
91
92 // Without inherited fields
GetOwnFieldsNumber()93 uint32_t EtsClass::GetOwnFieldsNumber()
94 {
95 return GetRuntimeClass()->GetFields().Size();
96 }
97
GetFields()98 PandaVector<EtsField *> EtsClass::GetFields()
99 {
100 auto etsFields = PandaVector<EtsField *>(Runtime::GetCurrent()->GetInternalAllocator()->Adapter());
101 EnumerateBaseClasses([&](EtsClass *c) {
102 auto fields = c->GetRuntimeClass()->GetFields();
103 auto fnum = fields.Size();
104 for (uint32_t i = 0; i < fnum; i++) {
105 etsFields.push_back(EtsField::FromRuntimeField(&fields[i]));
106 }
107 return false;
108 });
109 return etsFields;
110 }
111
GetFieldByIndex(uint32_t i)112 EtsField *EtsClass::GetFieldByIndex(uint32_t i)
113 {
114 EtsField *res = nullptr;
115 EnumerateBaseClasses([&](EtsClass *c) {
116 auto fields = c->GetRuntimeClass()->GetFields();
117 auto fnum = fields.Size();
118 if (i >= fnum) {
119 i -= fnum;
120 return false;
121 }
122 res = EtsField::FromRuntimeField(&fields[i]);
123 return true;
124 });
125 return res;
126 }
127
GetOwnFieldByIndex(uint32_t i)128 EtsField *EtsClass::GetOwnFieldByIndex(uint32_t i)
129 {
130 return EtsField::FromRuntimeField(&GetRuntimeClass()->GetFields()[i]);
131 }
132
GetDirectMethod(const char * name,const char * signature)133 EtsMethod *EtsClass::GetDirectMethod(const char *name, const char *signature)
134 {
135 auto coreName = reinterpret_cast<const uint8_t *>(name);
136 return GetDirectMethod(coreName, signature);
137 }
138
GetDirectMethod(const char * name)139 EtsMethod *EtsClass::GetDirectMethod(const char *name)
140 {
141 const uint8_t *mutf8Name = utf::CStringAsMutf8(name);
142 Method *rtMethod = GetRuntimeClass()->GetDirectMethod(mutf8Name);
143 return EtsMethod::FromRuntimeMethod(rtMethod);
144 }
145
GetDirectMethod(const uint8_t * name,const char * signature)146 EtsMethod *EtsClass::GetDirectMethod(const uint8_t *name, const char *signature)
147 {
148 EtsMethodSignature methodSignature(signature);
149 if (!methodSignature.IsValid()) {
150 LOG(ERROR, ETS_NAPI) << "Wrong method signature: " << signature;
151 return nullptr;
152 }
153
154 auto coreMethod = GetRuntimeClass()->GetDirectMethod(name, methodSignature.GetProto());
155 return reinterpret_cast<EtsMethod *>(coreMethod);
156 }
157
GetDirectMethod(const char * name,const Method::Proto & proto) const158 EtsMethod *EtsClass::GetDirectMethod(const char *name, const Method::Proto &proto) const
159 {
160 Method *method = klass_.GetDirectMethod(utf::CStringAsMutf8(name), proto);
161 return EtsMethod::FromRuntimeMethod(method);
162 }
163
GetMethodsNum()164 uint32_t EtsClass::GetMethodsNum()
165 {
166 return GetMethods().size();
167 }
168
GetMethodByIndex(uint32_t ind)169 EtsMethod *EtsClass::GetMethodByIndex(uint32_t ind)
170 {
171 EtsMethod *res = nullptr;
172 auto methods = GetMethods();
173 ASSERT(ind < methods.size());
174 res = methods[ind];
175 return res;
176 }
177
178 // NOTE(kirill-mitkin): Cache in EtsClass field later
GetMethods()179 PandaVector<EtsMethod *> EtsClass::GetMethods()
180 {
181 PandaUnorderedMap<PandaString, EtsMethod *> uniqueMethods;
182
183 auto addDirectMethods = [&](const EtsClass *c) {
184 auto directMethods = c->GetRuntimeClass()->GetMethods();
185 for (auto &method : directMethods) {
186 PandaString methodFullName = utf::Mutf8AsCString(method.GetName().data);
187 methodFullName += method.GetProto().GetSignature();
188 if (uniqueMethods.find(methodFullName) == uniqueMethods.end()) {
189 uniqueMethods[methodFullName] = EtsMethod::FromRuntimeMethod(&method);
190 }
191 }
192 };
193
194 auto addDirectMethodsForBaseClass = [&uniqueMethods](EtsClass *c) {
195 auto directMethods = c->GetRuntimeClass()->GetMethods();
196 auto fnum = directMethods.Size();
197 for (uint32_t i = 0; i < fnum; i++) {
198 Method *method = &directMethods[i];
199 // Skip constructors
200 if (method->IsConstructor()) {
201 continue;
202 }
203
204 PandaString methodFullName = utf::Mutf8AsCString((method->GetName().data));
205 methodFullName += method->GetProto().GetSignature();
206
207 uniqueMethods[methodFullName] = EtsMethod::FromRuntimeMethod(method);
208 }
209 };
210
211 if (IsInterface()) {
212 addDirectMethods(this);
213 EnumerateInterfaces([&](const EtsClass *c) {
214 addDirectMethods(c);
215 return false;
216 });
217 } else {
218 EnumerateBaseClasses([&](EtsClass *c) {
219 addDirectMethodsForBaseClass(c);
220 return false;
221 });
222 }
223 auto etsMethods = PandaVector<EtsMethod *>();
224 for (auto &iter : uniqueMethods) {
225 etsMethods.push_back(iter.second);
226 }
227 return etsMethods;
228 }
229
GetConstructors()230 PandaVector<EtsMethod *> EtsClass::GetConstructors()
231 {
232 auto constructors = PandaVector<EtsMethod *>();
233 auto methods = GetRuntimeClass()->GetMethods();
234 // NOTE(kirill-mitkin): cache in ets_class field
235 for (auto &method : methods) {
236 // Skip constructors
237 if (method.IsInstanceConstructor()) {
238 constructors.emplace_back(EtsMethod::FromRuntimeMethod(&method));
239 }
240 }
241 return constructors;
242 }
243
ResolveVirtualMethod(const EtsMethod * method) const244 EtsMethod *EtsClass::ResolveVirtualMethod(const EtsMethod *method) const
245 {
246 return reinterpret_cast<EtsMethod *>(GetRuntimeClass()->ResolveVirtualMethod(method->GetPandaMethod()));
247 }
248
GetNameAndClassRoot(char hash)249 static std::pair<char const *, EtsClassRoot> GetNameAndClassRoot(char hash)
250 {
251 const char *primitiveName = nullptr;
252 EtsClassRoot classRoot;
253
254 switch (hash) {
255 case 'v':
256 primitiveName = "void";
257 classRoot = EtsClassRoot::VOID;
258 break;
259 case 'b':
260 primitiveName = "boolean";
261 classRoot = EtsClassRoot::BOOLEAN;
262 break;
263 case 'B':
264 primitiveName = "byte";
265 classRoot = EtsClassRoot::BYTE;
266 break;
267 case 'c':
268 primitiveName = "char";
269 classRoot = EtsClassRoot::CHAR;
270 break;
271 case 's':
272 primitiveName = "short";
273 classRoot = EtsClassRoot::SHORT;
274 break;
275 case 'i':
276 primitiveName = "int";
277 classRoot = EtsClassRoot::INT;
278 break;
279 case 'l':
280 primitiveName = "long";
281 classRoot = EtsClassRoot::LONG;
282 break;
283 case 'f':
284 primitiveName = "float";
285 classRoot = EtsClassRoot::FLOAT;
286 break;
287 case 'd':
288 primitiveName = "double";
289 classRoot = EtsClassRoot::DOUBLE;
290 break;
291 default:
292 break;
293 }
294
295 return {primitiveName, classRoot};
296 }
297
298 /* static */
GetPrimitiveClass(EtsString * name)299 EtsClass *EtsClass::GetPrimitiveClass(EtsString *name)
300 {
301 if (name == nullptr || name->GetMUtf8Length() < 2) { // MUtf8Length must be >= 2
302 return nullptr;
303 }
304 // StringIndexOutOfBoundsException is not thrown by At method, because index (0, 1) < length (>= 2)
305 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
306 char hash = name->At(0) ^ ((name->At(1) & 0x10) << 1); // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
307 auto [primitiveName, classRoot] = GetNameAndClassRoot(hash);
308
309 if (primitiveName != nullptr && name->IsEqual(primitiveName)) { // SUPPRESS_CSA(alpha.core.WasteObjHeader)
310 return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(classRoot);
311 }
312
313 return nullptr;
314 }
315
CreateEtsClassName(const char * descriptor)316 EtsString *EtsClass::CreateEtsClassName([[maybe_unused]] const char *descriptor)
317 {
318 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
319
320 if (*descriptor == 'L') {
321 std::string_view tmpName(descriptor);
322 tmpName.remove_prefix(1);
323 tmpName.remove_suffix(1);
324 PandaString etsName(tmpName);
325 std::replace(etsName.begin(), etsName.end(), '/', '.');
326 return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
327 }
328 if (*descriptor == '[') {
329 PandaString etsName(descriptor);
330 std::replace(etsName.begin(), etsName.end(), '/', '.');
331 return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
332 }
333
334 switch (*descriptor) {
335 case 'Z':
336 return EtsString::CreateFromMUtf8("boolean");
337 case 'B':
338 return EtsString::CreateFromMUtf8("byte");
339 case 'C':
340 return EtsString::CreateFromMUtf8("char");
341 case 'S':
342 return EtsString::CreateFromMUtf8("short");
343 case 'I':
344 return EtsString::CreateFromMUtf8("int");
345 case 'J':
346 return EtsString::CreateFromMUtf8("long");
347 case 'F':
348 return EtsString::CreateFromMUtf8("float");
349 case 'D':
350 return EtsString::CreateFromMUtf8("double");
351 case 'V':
352 return EtsString::CreateFromMUtf8("void");
353 default:
354 LOG(FATAL, RUNTIME) << "Incorrect primitive name" << descriptor;
355 UNREACHABLE();
356 }
357 }
358
GetName()359 EtsString *EtsClass::GetName()
360 {
361 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
362
363 EtsString *name = nullptr;
364 bool success = false;
365
366 do {
367 name = reinterpret_cast<EtsString *>(GetObjectHeader()->GetFieldObject(GetNameOffset()));
368 if (name != nullptr) {
369 return name;
370 }
371
372 name = CreateEtsClassName(GetDescriptor());
373 if (name == nullptr) {
374 return nullptr;
375 }
376 success = CompareAndSetName(nullptr, name);
377 } while (!success);
378 return name;
379 }
380
IsInSamePackage(std::string_view className1,std::string_view className2)381 bool EtsClass::IsInSamePackage(std::string_view className1, std::string_view className2)
382 {
383 size_t i = 0;
384 size_t minLength = std::min(className1.size(), className2.size());
385 while (i < minLength && className1[i] == className2[i]) {
386 ++i;
387 }
388 return className1.find('/', i) == std::string::npos && className2.find('/', i) == std::string::npos;
389 }
390
IsInSamePackage(EtsClass * that)391 bool EtsClass::IsInSamePackage(EtsClass *that)
392 {
393 if (this == that) {
394 return true;
395 }
396
397 EtsClass *klass1 = this;
398 EtsClass *klass2 = that;
399 while (klass1->IsArrayClass()) {
400 klass1 = klass1->GetComponentType();
401 }
402 while (klass2->IsArrayClass()) {
403 klass2 = klass2->GetComponentType();
404 }
405 if (klass1 == klass2) {
406 return true;
407 }
408
409 // Compare the package part of the descriptor string.
410 return IsInSamePackage(klass1->GetDescriptor(), klass2->GetDescriptor());
411 }
412
SetWeakReference()413 void EtsClass::SetWeakReference()
414 {
415 flags_ = flags_ | IS_WEAK_REFERENCE;
416 ASSERT(IsWeakReference() && IsReference());
417 }
SetFinalizeReference()418 void EtsClass::SetFinalizeReference()
419 {
420 flags_ = flags_ | IS_FINALIZE_REFERENCE;
421 ASSERT(IsFinalizerReference() && IsReference());
422 }
423
SetValueTyped()424 void EtsClass::SetValueTyped()
425 {
426 flags_ = flags_ | IS_VALUE_TYPED;
427 ASSERT(IsValueTyped());
428 }
SetNullValue()429 void EtsClass::SetNullValue()
430 {
431 flags_ = flags_ | IS_NULLVALUE;
432 ASSERT(IsNullValue());
433 }
SetBoxed()434 void EtsClass::SetBoxed()
435 {
436 flags_ = flags_ | IS_BOXED;
437 ASSERT(IsBoxed());
438 }
SetFunction()439 void EtsClass::SetFunction()
440 {
441 flags_ = flags_ | IS_FUNCTION;
442 ASSERT(IsFunction());
443 }
SetEtsEnum()444 void EtsClass::SetEtsEnum()
445 {
446 flags_ = flags_ | IS_ETS_ENUM;
447 ASSERT(IsEtsEnum());
448 }
SetBigInt()449 void EtsClass::SetBigInt()
450 {
451 flags_ = flags_ | IS_BIGINT;
452 ASSERT(IsBigInt());
453 }
454
HasFunctionTypeInSuperClasses(EtsClass * cls)455 static bool HasFunctionTypeInSuperClasses(EtsClass *cls)
456 {
457 if (EtsClass *base = cls->GetBase(); base != nullptr) {
458 if (UNLIKELY(base->IsFunction())) {
459 return true;
460 }
461 }
462 for (Class *iface : cls->GetRuntimeClass()->GetInterfaces()) {
463 if (UNLIKELY(EtsClass::FromRuntimeClass(iface)->IsFunction())) {
464 return true;
465 }
466 }
467 return false;
468 }
469
Initialize(EtsClass * superClass,uint16_t accessFlags,bool isPrimitiveType,ClassLinkerErrorHandler * errorHandler)470 void EtsClass::Initialize(EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType,
471 ClassLinkerErrorHandler *errorHandler)
472 {
473 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
474
475 SetName(nullptr);
476 SetSuperClass(superClass);
477
478 uint32_t flags = accessFlags;
479 if (isPrimitiveType) {
480 flags |= ETS_ACC_PRIMITIVE;
481 }
482
483 if (superClass != nullptr) {
484 static constexpr uint32_t COPIED_MASK = IS_WEAK_REFERENCE | IS_FINALIZE_REFERENCE;
485 flags |= superClass->GetFlags() & COPIED_MASK;
486 ASSERT(!superClass->IsValueTyped() || superClass->IsEtsEnum());
487 }
488 if (UNLIKELY(HasFunctionTypeInSuperClasses(this))) {
489 flags |= IS_FUNCTION;
490 }
491 if (UNLIKELY(GetBase() != nullptr && GetBase()->IsEtsEnum())) {
492 flags |= (IS_ETS_ENUM | IS_VALUE_TYPED);
493 }
494
495 auto *runtimeClass = GetRuntimeClass();
496 auto *pfile = runtimeClass->GetPandaFile();
497 if (pfile != nullptr) {
498 panda_file::ClassDataAccessor cda(*pfile, runtimeClass->GetFileId());
499
500 cda.EnumerateAnnotations([this, &pfile, &flags, &errorHandler](panda_file::File::EntityId annotationId) {
501 panda_file::AnnotationDataAccessor ada(*pfile, annotationId);
502 auto *annotationName = pfile->GetStringData(ada.GetClassId()).data;
503 auto *annotationModuleName = panda_file_items::class_descriptors::ANNOTATION_MODULE.data();
504 auto *annotationFunctionalReferenceName =
505 panda_file_items::class_descriptors::ANNOTATION_FUNCTIONAL_REFERENCE.data();
506 if (utf::IsEqual(utf::CStringAsMutf8(annotationModuleName), annotationName)) {
507 flags |= IS_MODULE;
508 } else if (utf::IsEqual(utf::CStringAsMutf8(annotationFunctionalReferenceName), annotationName)) {
509 flags |= (IS_FUNCTION_REFERENCE | IS_VALUE_TYPED);
510 FunctionalReferenceAnnotationCallBack(this, pfile, &ada, errorHandler);
511 }
512 });
513 }
514
515 SetFlags(flags);
516 }
517
SetComponentType(EtsClass * componentType)518 void EtsClass::SetComponentType(EtsClass *componentType)
519 {
520 if (componentType == nullptr) {
521 GetRuntimeClass()->SetComponentType(nullptr);
522 return;
523 }
524 GetRuntimeClass()->SetComponentType(componentType->GetRuntimeClass());
525 }
526
GetComponentType() const527 EtsClass *EtsClass::GetComponentType() const
528 {
529 ark::Class *componentType = GetRuntimeClass()->GetComponentType();
530 if (componentType == nullptr) {
531 return nullptr;
532 }
533 return FromRuntimeClass(componentType);
534 }
535
SetName(EtsString * name)536 void EtsClass::SetName(EtsString *name)
537 {
538 GetObjectHeader()->SetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(name));
539 }
540
CompareAndSetName(EtsString * oldName,EtsString * newName)541 bool EtsClass::CompareAndSetName(EtsString *oldName, EtsString *newName)
542 {
543 return GetObjectHeader()->CompareAndSetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(oldName),
544 reinterpret_cast<ObjectHeader *>(newName),
545 std::memory_order::memory_order_seq_cst, true);
546 }
547
GetFieldIDByName(const char * name,const char * sig)548 EtsField *EtsClass::GetFieldIDByName(const char *name, const char *sig)
549 {
550 auto u8name = reinterpret_cast<const uint8_t *>(name);
551 auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetInstanceFieldByName(u8name));
552
553 if (sig != nullptr && field != nullptr) {
554 if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
555 return nullptr;
556 }
557 }
558
559 return field;
560 }
561
GetFieldIndexByName(const char * name)562 uint32_t EtsClass::GetFieldIndexByName(const char *name)
563 {
564 auto u8name = reinterpret_cast<const uint8_t *>(name);
565 auto fields = GetRuntimeClass()->GetFields();
566 panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(u8name)), u8name};
567 for (uint32_t i = 0; i < GetFieldsNumber(); i++) {
568 if (fields[i].GetName() == sd) {
569 return i;
570 }
571 }
572 return -1;
573 }
574
GetStaticFieldIDByName(const char * name,const char * sig)575 EtsField *EtsClass::GetStaticFieldIDByName(const char *name, const char *sig)
576 {
577 auto u8name = reinterpret_cast<const uint8_t *>(name);
578 auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetStaticFieldByName(u8name));
579
580 if (sig != nullptr && field != nullptr) {
581 if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
582 return nullptr;
583 }
584 }
585
586 return field;
587 }
588
GetDeclaredFieldIDByName(const char * name)589 EtsField *EtsClass::GetDeclaredFieldIDByName(const char *name)
590 {
591 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindDeclaredField([name](const ark::Field &field) -> bool {
592 auto *efield = EtsField::FromRuntimeField(&field);
593 return ::strcmp(efield->GetName(), name) == 0;
594 }));
595 }
596
GetFieldIDByOffset(uint32_t fieldOffset)597 EtsField *EtsClass::GetFieldIDByOffset(uint32_t fieldOffset)
598 {
599 auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
600 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindInstanceField(pred));
601 }
602
GetStaticFieldIDByOffset(uint32_t fieldOffset)603 EtsField *EtsClass::GetStaticFieldIDByOffset(uint32_t fieldOffset)
604 {
605 auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
606 return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindStaticField(pred));
607 }
608
GetBase()609 EtsClass *EtsClass::GetBase()
610 {
611 if (IsInterface()) {
612 return nullptr;
613 }
614 auto *base = GetRuntimeClass()->GetBase();
615 if (base == nullptr) {
616 return nullptr;
617 }
618 return FromRuntimeClass(base);
619 }
620
GetInterfaces(PandaUnorderedSet<EtsClass * > & ifaces,EtsClass * iface)621 void EtsClass::GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface)
622 {
623 ifaces.insert(iface);
624 EnumerateDirectInterfaces([&](EtsClass *runtimeInterface) {
625 if (ifaces.find(runtimeInterface) == ifaces.end()) {
626 runtimeInterface->GetInterfaces(ifaces, runtimeInterface);
627 }
628 return false;
629 });
630 }
631
GetStaticFieldObject(EtsField * field)632 EtsObject *EtsClass::GetStaticFieldObject(EtsField *field)
633 {
634 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject(*field->GetRuntimeField()));
635 }
636
GetStaticFieldObject(int32_t fieldOffset,bool isVolatile)637 EtsObject *EtsClass::GetStaticFieldObject(int32_t fieldOffset, bool isVolatile)
638 {
639 if (isVolatile) {
640 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<true>(fieldOffset));
641 }
642 return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<false>(fieldOffset));
643 }
644
SetStaticFieldObject(EtsField * field,EtsObject * value)645 void EtsClass::SetStaticFieldObject(EtsField *field, EtsObject *value)
646 {
647 GetRuntimeClass()->SetFieldObject(*field->GetRuntimeField(), reinterpret_cast<ObjectHeader *>(value));
648 }
649
SetStaticFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)650 void EtsClass::SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value)
651 {
652 if (isVolatile) {
653 GetRuntimeClass()->SetFieldObject<true>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
654 }
655 GetRuntimeClass()->SetFieldObject<false>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
656 }
657
CreateInstance()658 EtsObject *EtsClass::CreateInstance()
659 {
660 auto coro = EtsCoroutine::GetCurrent();
661 const auto throwCreateInstanceErr = [coro, this](std::string_view msg) {
662 ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ERROR,
663 PandaString(msg) + " " + GetDescriptor());
664 };
665
666 if (UNLIKELY(!GetRuntimeClass()->IsInstantiable() || IsArrayClass())) {
667 throwCreateInstanceErr("Cannot instantiate");
668 return nullptr;
669 }
670
671 if (IsStringClass()) {
672 auto emptyString = EtsString::CreateNewEmptyString();
673 ASSERT(emptyString != nullptr);
674 return emptyString->AsObject();
675 }
676
677 EtsMethod *ctor = GetDirectMethod(panda_file_items::CTOR.data(), ":V");
678 if (UNLIKELY(ctor == nullptr)) {
679 throwCreateInstanceErr("No default constructor in");
680 return nullptr;
681 }
682
683 EtsClassLinker *linker = coro->GetPandaVM()->GetClassLinker();
684 if (UNLIKELY(!IsInitialized() && !linker->InitializeClass(coro, this))) {
685 return nullptr;
686 }
687 EtsObject *obj = EtsObject::Create(this);
688 if (UNLIKELY(obj == nullptr)) {
689 return nullptr;
690 }
691
692 LocalObjectHandle objHandle(coro, obj);
693 std::array<Value, 1> args {Value(obj->GetCoreType())};
694 ctor->GetPandaMethod()->Invoke(coro, args.data());
695 if (UNLIKELY(coro->HasPendingException())) {
696 return nullptr;
697 }
698 return objHandle.GetPtr();
699 }
700
701 } // namespace ark::ets
702