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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_ 17 #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_ 18 19 #include <cstdint> 20 #include "include/mem/panda_containers.h" 21 #include "include/object_header.h" 22 #include "include/runtime.h" 23 #include "libpandabase/mem/object_pointer.h" 24 #include "runtime/class_linker_context.h" 25 #include "runtime/include/class-inl.h" 26 #include "runtime/include/thread.h" 27 #include "runtime/include/class_linker.h" 28 #include "plugins/ets/runtime/types/ets_field.h" 29 #include "plugins/ets/runtime/types/ets_type.h" 30 #include "plugins/ets/runtime/ets_panda_file_items.h" 31 #include "plugins/ets/runtime/types/ets_method_signature.h" 32 #include "utils/utf.h" 33 34 namespace ark::ets { 35 36 enum class AccessLevel { PUBLIC, PROTECTED, DEFAULT, PRIVATE }; 37 38 class EtsMethod; 39 class EtsObject; 40 class EtsString; 41 class EtsArray; 42 class EtsPromise; 43 class EtsJob; 44 class EtsErrorOptions; 45 class EtsTypeAPIField; 46 class EtsTypeAPIMethod; 47 class EtsTypeAPIParameter; 48 49 enum class EtsType; 50 51 namespace test { 52 class EtsClassTest; 53 } // namespace test 54 55 class EtsClass { 56 public: 57 // We shouldn't init header_ here - because it has been memset(0) in object allocation, 58 // otherwise it may cause data race while visiting object's class concurrently in gc. InitClass(const uint8_t * descriptor,uint32_t vtableSize,uint32_t imtSize,uint32_t klassSize)59 void InitClass(const uint8_t *descriptor, uint32_t vtableSize, uint32_t imtSize, uint32_t klassSize) 60 { 61 new (&klass_) ark::Class(descriptor, panda_file::SourceLang::ETS, vtableSize, imtSize, klassSize); 62 } 63 GetDescriptor()64 const char *GetDescriptor() const 65 { 66 return utf::Mutf8AsCString(GetRuntimeClass()->GetDescriptor()); 67 } 68 69 PANDA_PUBLIC_API EtsClass *GetBase(); 70 71 uint32_t GetFieldsNumber(); 72 73 uint32_t GetOwnFieldsNumber(); // Without inherited fields 74 GetStaticFieldsNumber()75 uint32_t GetStaticFieldsNumber() 76 { 77 return GetRuntimeClass()->GetStaticFields().size(); 78 } 79 GetInstanceFieldsNumber()80 uint32_t GetInstanceFieldsNumber() 81 { 82 return GetRuntimeClass()->GetInstanceFields().size(); 83 } 84 85 uint32_t GetFieldIndexByName(const char *name); 86 87 PANDA_PUBLIC_API PandaVector<EtsField *> GetFields(); 88 89 EtsField *GetFieldByIndex(uint32_t i); 90 91 EtsField *GetFieldIDByOffset(uint32_t fieldOffset); 92 PANDA_PUBLIC_API EtsField *GetFieldIDByName(const char *name, const char *sig = nullptr); 93 94 EtsField *GetOwnFieldByIndex(uint32_t i); 95 EtsField *GetDeclaredFieldIDByName(const char *name); 96 97 PANDA_PUBLIC_API EtsField *GetStaticFieldIDByName(const char *name, const char *sig = nullptr); 98 EtsField *GetStaticFieldIDByOffset(uint32_t fieldOffset); 99 100 PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name); 101 PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const uint8_t *name, const char *signature); 102 PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name, const char *signature); 103 104 PANDA_PUBLIC_API EtsMethod *GetStaticMethod(const char *name, const char *signature, bool isANIFormat = false) const 105 { 106 if (signature == nullptr) { 107 return GetMethodInternal<FindFilter::STATIC>(name); 108 } 109 return GetMethodInternal<FindFilter::STATIC>(name, signature, isANIFormat); 110 } 111 112 PANDA_PUBLIC_API EtsMethod *GetInstanceMethod(const char *name, const char *signature, 113 bool isANIFormat = false) const 114 { 115 if (signature == nullptr) { 116 return GetMethodInternal<FindFilter::INSTANCE>(name); 117 } 118 return GetMethodInternal<FindFilter::INSTANCE>(name, signature, isANIFormat); 119 } 120 GetDirectMethod(const PandaString & name,const PandaString & signature)121 PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const PandaString &name, const PandaString &signature) 122 { 123 return GetDirectMethod(name.c_str(), signature.c_str()); 124 } 125 126 PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name, const Method::Proto &proto) const; 127 128 EtsMethod *GetMethodByIndex(uint32_t i); 129 130 uint32_t GetMethodsNum(); 131 132 PandaVector<EtsMethod *> GetMethods(); 133 134 PANDA_PUBLIC_API PandaVector<EtsMethod *> GetConstructors(); 135 136 template <class T> GetStaticFieldPrimitive(EtsField * field)137 T GetStaticFieldPrimitive(EtsField *field) 138 { 139 return GetRuntimeClass()->GetFieldPrimitive<T>(*field->GetRuntimeField()); 140 } 141 142 template <class T> GetStaticFieldPrimitive(int32_t fieldOffset,bool isVolatile)143 T GetStaticFieldPrimitive(int32_t fieldOffset, bool isVolatile) 144 { 145 if (isVolatile) { 146 return GetRuntimeClass()->GetFieldPrimitive<T, true>(fieldOffset); 147 } 148 return GetRuntimeClass()->GetFieldPrimitive<T, false>(fieldOffset); 149 } 150 151 template <class T> SetStaticFieldPrimitive(EtsField * field,T value)152 void SetStaticFieldPrimitive(EtsField *field, T value) 153 { 154 GetRuntimeClass()->SetFieldPrimitive<T>(*field->GetRuntimeField(), value); 155 } 156 157 template <class T> SetStaticFieldPrimitive(int32_t fieldOffset,bool isVolatile,T value)158 void SetStaticFieldPrimitive(int32_t fieldOffset, bool isVolatile, T value) 159 { 160 if (isVolatile) { 161 GetRuntimeClass()->SetFieldPrimitive<T, true>(fieldOffset, value); 162 } 163 GetRuntimeClass()->SetFieldPrimitive<T, false>(fieldOffset, value); 164 } 165 166 PANDA_PUBLIC_API EtsObject *GetStaticFieldObject(EtsField *field); 167 EtsObject *GetStaticFieldObject(int32_t fieldOffset, bool isVolatile); 168 169 void SetStaticFieldObject(EtsField *field, EtsObject *value); 170 void SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value); 171 172 EtsObject *CreateInstance(); 173 IsEtsObject()174 bool IsEtsObject() 175 { 176 return GetRuntimeClass()->IsObjectClass(); 177 } 178 IsPrimitive()179 bool IsPrimitive() const 180 { 181 return GetRuntimeClass()->IsPrimitive(); 182 } 183 IsAbstract()184 bool IsAbstract() 185 { 186 return GetRuntimeClass()->IsAbstract(); 187 } 188 IsPublic()189 bool IsPublic() const 190 { 191 return GetRuntimeClass()->IsPublic(); 192 } 193 IsFinal()194 bool IsFinal() const 195 { 196 return GetRuntimeClass()->IsFinal(); 197 } 198 IsAnnotation()199 bool IsAnnotation() const 200 { 201 return GetRuntimeClass()->IsAnnotation(); 202 } 203 IsEnum()204 bool IsEnum() const 205 { 206 return GetRuntimeClass()->IsEnum(); 207 } 208 IsStringClass()209 bool IsStringClass() const 210 { 211 return GetRuntimeClass()->IsStringClass(); 212 } 213 IsClassClass()214 bool IsClassClass() const 215 { 216 return GetRuntimeClass()->IsClassClass(); 217 } 218 IsArrayClass()219 bool IsArrayClass() const 220 { 221 return GetRuntimeClass()->IsArrayClass(); 222 } 223 IsInterface()224 bool IsInterface() const 225 { 226 return GetRuntimeClass()->IsInterface(); 227 } 228 IsClass()229 bool IsClass() const 230 { 231 return GetRuntimeClass()->IsClass(); 232 } 233 234 static bool IsInSamePackage(std::string_view className1, std::string_view className2); 235 236 bool IsInSamePackage(EtsClass *that); 237 GetComponentSize()238 uint32_t GetComponentSize() const 239 { 240 return GetRuntimeClass()->GetComponentSize(); 241 } 242 GetType()243 panda_file::Type GetType() const 244 { 245 return GetRuntimeClass()->GetType(); 246 } 247 IsSubClass(EtsClass * cls)248 bool IsSubClass(EtsClass *cls) 249 { 250 return GetRuntimeClass()->IsSubClassOf(cls->GetRuntimeClass()); 251 } 252 IsAssignableFrom(EtsClass * clazz)253 bool IsAssignableFrom(EtsClass *clazz) const 254 { 255 return GetRuntimeClass()->IsAssignableFrom(clazz->GetRuntimeClass()); 256 } 257 IsGenerated()258 bool IsGenerated() const 259 { 260 return IsArrayClass() || IsPrimitive(); 261 } 262 CanAccess(EtsClass * that)263 bool CanAccess(EtsClass *that) 264 { 265 return that->IsPublic() || IsInSamePackage(that); 266 } 267 268 EtsMethod *ResolveVirtualMethod(const EtsMethod *method) const; 269 270 template <class Callback> EnumerateMethods(const Callback & callback)271 void EnumerateMethods(const Callback &callback) 272 { 273 for (auto &method : GetRuntimeClass()->GetMethods()) { 274 bool finished = callback(reinterpret_cast<EtsMethod *>(&method)); 275 if (finished) { 276 break; 277 } 278 } 279 } 280 281 template <class Callback> EnumerateDirectInterfaces(const Callback & callback)282 void EnumerateDirectInterfaces(const Callback &callback) 283 { 284 for (Class *runtimeInterface : GetRuntimeClass()->GetInterfaces()) { 285 EtsClass *interface = EtsClass::FromRuntimeClass(runtimeInterface); 286 bool finished = callback(interface); 287 if (finished) { 288 break; 289 } 290 } 291 } 292 293 void GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface); 294 295 template <class Callback> EnumerateInterfaces(const Callback & callback)296 void EnumerateInterfaces(const Callback &callback) 297 { 298 PandaUnorderedSet<EtsClass *> ifaces; 299 GetInterfaces(ifaces, this); 300 for (auto iface : ifaces) { 301 bool finished = callback(iface); 302 if (finished) { 303 break; 304 } 305 } 306 } 307 308 template <class Callback> EnumerateBaseClasses(const Callback & callback)309 void EnumerateBaseClasses(const Callback &callback) 310 { 311 PandaVector<EtsClass *> inherChain; 312 auto curClass = this; 313 while (curClass != nullptr) { 314 inherChain.push_back(curClass); 315 curClass = curClass->GetBase(); 316 } 317 for (auto i = inherChain.rbegin(); i != inherChain.rend(); i++) { 318 bool finished = callback(*i); 319 if (finished) { 320 break; 321 } 322 } 323 } 324 GetLoadContext()325 ClassLinkerContext *GetLoadContext() const 326 { 327 return GetRuntimeClass()->GetLoadContext(); 328 } 329 GetRuntimeClass()330 Class *GetRuntimeClass() 331 { 332 return &klass_; 333 } 334 GetRuntimeClass()335 const Class *GetRuntimeClass() const 336 { 337 return &klass_; 338 } 339 GetTypeMetaData()340 EtsLong GetTypeMetaData() const 341 { 342 return typeMetaData_; 343 } 344 SetTypeMetaData(EtsLong metaData)345 void SetTypeMetaData(EtsLong metaData) 346 { 347 typeMetaData_ = metaData; 348 } 349 AsObject()350 EtsObject *AsObject() 351 { 352 return reinterpret_cast<EtsObject *>(this); 353 } 354 AsObject()355 const EtsObject *AsObject() const 356 { 357 return reinterpret_cast<const EtsObject *>(this); 358 } 359 IsInitialized()360 bool IsInitialized() const 361 { 362 return GetRuntimeClass()->IsInitialized(); 363 } 364 365 EtsType GetEtsType(); 366 GetSize(uint32_t klassSize)367 static size_t GetSize(uint32_t klassSize) 368 { 369 return GetRuntimeClassOffset() + klassSize; 370 } 371 GetRuntimeClassOffset()372 static constexpr size_t GetRuntimeClassOffset() 373 { 374 return MEMBER_OFFSET(EtsClass, klass_); 375 } 376 GetTypeMetaDataOffset()377 static constexpr size_t GetTypeMetaDataOffset() 378 { 379 return MEMBER_OFFSET(EtsClass, typeMetaData_); 380 } 381 GetHeaderOffset()382 static constexpr size_t GetHeaderOffset() 383 { 384 return MEMBER_OFFSET(EtsClass, header_); 385 } 386 FromRuntimeClass(const Class * cls)387 static EtsClass *FromRuntimeClass(const Class *cls) 388 { 389 ASSERT(cls != nullptr); 390 return reinterpret_cast<EtsClass *>(reinterpret_cast<uintptr_t>(cls) - GetRuntimeClassOffset()); 391 } 392 FromClassObject(ObjectHeader * obj)393 static EtsClass *FromClassObject(ObjectHeader *obj) 394 { 395 ASSERT(obj->ClassAddr<Class>()->IsClassClass()); 396 return reinterpret_cast<EtsClass *>(obj); 397 } 398 FromEtsClassObject(EtsObject * obj)399 static EtsClass *FromEtsClassObject(EtsObject *obj) 400 { 401 return FromClassObject(reinterpret_cast<ObjectHeader *>(obj)); 402 } 403 404 static EtsClass *GetPrimitiveClass(EtsString *primitiveName); 405 406 void Initialize(EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType, 407 ClassLinkerErrorHandler *errorHandler); 408 409 void SetComponentType(EtsClass *componentType); 410 411 EtsClass *GetComponentType() const; 412 413 void SetName(EtsString *name); 414 415 bool CompareAndSetName(EtsString *oldName, EtsString *newName); 416 417 EtsString *GetName(); 418 static EtsString *CreateEtsClassName([[maybe_unused]] const char *descriptor); 419 SetSuperClass(EtsClass * superClass)420 void SetSuperClass(EtsClass *superClass) 421 { 422 auto obj = reinterpret_cast<ObjectHeader *>(superClass); 423 GetObjectHeader()->SetFieldObject(GetSuperClassOffset(), obj); 424 } 425 GetSuperClass()426 EtsClass *GetSuperClass() const 427 { 428 return reinterpret_cast<EtsClass *>(GetObjectHeader()->GetFieldObject(GetSuperClassOffset())); 429 } 430 SetFlags(uint32_t flags)431 void SetFlags(uint32_t flags) 432 { 433 GetObjectHeader()->SetFieldPrimitive(GetFlagsOffset(), flags); 434 } 435 GetFlags()436 uint32_t GetFlags() const 437 { 438 return GetObjectHeader()->GetFieldPrimitive<uint32_t>(GetFlagsOffset()); 439 } 440 441 void SetWeakReference(); 442 void SetFinalizeReference(); 443 void SetValueTyped(); 444 void SetNullValue(); 445 void SetBoxed(); 446 void SetFunction(); 447 void SetEtsEnum(); 448 void SetBigInt(); 449 IsWeakReference()450 [[nodiscard]] bool IsWeakReference() const 451 { 452 return (flags_ & IS_WEAK_REFERENCE) != 0; 453 } 454 IsFinalizerReference()455 [[nodiscard]] bool IsFinalizerReference() const 456 { 457 return (flags_ & IS_FINALIZE_REFERENCE) != 0; 458 } 459 460 /// True if class inherited from Reference, false otherwise IsReference()461 [[nodiscard]] bool IsReference() const 462 { 463 return (flags_ & IS_REFERENCE) != 0; 464 } 465 IsValueTyped()466 [[nodiscard]] bool IsValueTyped() const 467 { 468 return (GetFlags() & IS_VALUE_TYPED) != 0; 469 } 470 IsNullValue()471 [[nodiscard]] bool IsNullValue() const 472 { 473 return (GetFlags() & IS_NULLVALUE) != 0; 474 } 475 IsBoxed()476 [[nodiscard]] bool IsBoxed() const 477 { 478 return (GetFlags() & IS_BOXED) != 0; 479 } 480 IsFunction()481 [[nodiscard]] bool IsFunction() const 482 { 483 return (GetFlags() & IS_FUNCTION) != 0; 484 } 485 IsFunctionReference()486 [[nodiscard]] bool IsFunctionReference() const 487 { 488 return (GetFlags() & IS_FUNCTION_REFERENCE) != 0; 489 } 490 IsEtsEnum()491 [[nodiscard]] bool IsEtsEnum() const 492 { 493 return (GetFlags() & IS_ETS_ENUM) != 0; 494 } 495 IsBigInt()496 [[nodiscard]] bool IsBigInt() const 497 { 498 return (GetFlags() & IS_BIGINT) != 0; 499 } 500 IsModule()501 [[nodiscard]] bool IsModule() const 502 { 503 return (GetFlags() & IS_MODULE) != 0; 504 } 505 506 EtsClass() = delete; 507 ~EtsClass() = delete; 508 NO_COPY_SEMANTIC(EtsClass); 509 NO_MOVE_SEMANTIC(EtsClass); 510 GetNameOffset()511 static constexpr size_t GetNameOffset() 512 { 513 return MEMBER_OFFSET(EtsClass, name_); 514 } 515 GetSuperClassOffset()516 static constexpr size_t GetSuperClassOffset() 517 { 518 return MEMBER_OFFSET(EtsClass, superClass_); 519 } 520 GetFlagsOffset()521 static constexpr size_t GetFlagsOffset() 522 { 523 return MEMBER_OFFSET(EtsClass, flags_); 524 } 525 GCRefFieldsOffset()526 static constexpr size_t GCRefFieldsOffset() 527 { 528 return GetHeaderOffset() + sizeof(header_); 529 } 530 GCRefFieldsNum()531 static constexpr size_t GCRefFieldsNum() 532 { 533 return (GetFlagsOffset() - GCRefFieldsOffset()) / sizeof(ObjectPointerType); 534 } 535 536 private: 537 enum class FindFilter { STATIC, INSTANCE }; 538 539 template <FindFilter FILTER> GetMethodInternal(const char * name)540 EtsMethod *GetMethodInternal(const char *name) const 541 { 542 const auto *coreName = utf::CStringAsMutf8(name); 543 544 Method *coreMethod = nullptr; 545 auto *runtimeClass = GetRuntimeClass(); 546 if (IsInterface()) { 547 if constexpr (FILTER == FindFilter::STATIC) { 548 coreMethod = runtimeClass->GetStaticInterfaceMethod(coreName); 549 } else { 550 static_assert(FILTER == FindFilter::INSTANCE); 551 coreMethod = runtimeClass->GetVirtualInterfaceMethod(coreName); 552 } 553 } else { 554 if constexpr (FILTER == FindFilter::STATIC) { 555 coreMethod = runtimeClass->GetStaticClassMethod(coreName); 556 } else { 557 static_assert(FILTER == FindFilter::INSTANCE); 558 coreMethod = runtimeClass->GetVirtualClassMethod(coreName); 559 } 560 } 561 return reinterpret_cast<EtsMethod *>(coreMethod); 562 } 563 564 template <FindFilter FILTER> GetMethodInternal(const char * name,const char * signature,bool isANIFormat)565 EtsMethod *GetMethodInternal(const char *name, const char *signature, bool isANIFormat) const 566 { 567 EtsMethodSignature methodSignature(signature, isANIFormat); 568 if (!methodSignature.IsValid()) { 569 LOG(ERROR, ETS_NAPI) << "Wrong method signature:" << signature; 570 return nullptr; 571 } 572 573 const auto *coreName = utf::CStringAsMutf8(name); 574 575 Method *coreMethod = nullptr; 576 auto *runtimeClass = GetRuntimeClass(); 577 if (IsInterface()) { 578 if constexpr (FILTER == FindFilter::STATIC) { 579 coreMethod = runtimeClass->GetStaticInterfaceMethod(coreName, methodSignature.GetProto()); 580 } else { 581 static_assert(FILTER == FindFilter::INSTANCE); 582 coreMethod = runtimeClass->GetVirtualInterfaceMethod(coreName, methodSignature.GetProto()); 583 } 584 } else { 585 if constexpr (FILTER == FindFilter::STATIC) { 586 coreMethod = runtimeClass->GetStaticClassMethod(coreName, methodSignature.GetProto()); 587 } else { 588 static_assert(FILTER == FindFilter::INSTANCE); 589 coreMethod = runtimeClass->GetVirtualClassMethod(coreName, methodSignature.GetProto()); 590 } 591 } 592 return reinterpret_cast<EtsMethod *>(coreMethod); 593 } 594 GetObjectHeader()595 ObjectHeader *GetObjectHeader() 596 { 597 return &header_; 598 } 599 GetObjectHeader()600 const ObjectHeader *GetObjectHeader() const 601 { 602 return &header_; 603 } 604 605 constexpr static uint32_t ETS_ACC_PRIMITIVE = 1U << 16U; 606 /// Class is a WeakReference or successor of this class 607 constexpr static uint32_t IS_WEAK_REFERENCE = 1U << 17U; 608 /// Class is a FinalizerReference or successor of this class 609 constexpr static uint32_t IS_FINALIZE_REFERENCE = 1U << 18U; 610 constexpr static uint32_t IS_REFERENCE = IS_WEAK_REFERENCE | IS_FINALIZE_REFERENCE; 611 612 // Class is a value-semantic type 613 constexpr static uint32_t IS_VALUE_TYPED = 1U << 19U; 614 // Class is an internal "nullvalue" class 615 constexpr static uint32_t IS_NULLVALUE = 1U << 20U; 616 // Class is a boxed type 617 constexpr static uint32_t IS_BOXED = 1U << 21U; 618 // Class is Function 619 constexpr static uint32_t IS_FUNCTION = 1U << 22U; 620 // Class is BigInt 621 constexpr static uint32_t IS_BIGINT = 1U << 23U; 622 // Class is Module 623 constexpr static uint32_t IS_MODULE = 1U << 24U; 624 // Class is enum 625 constexpr static uint32_t IS_ETS_ENUM = 1U << 25U; 626 // Class is Function Reference 627 constexpr static uint32_t IS_FUNCTION_REFERENCE = 1U << 26U; 628 629 ark::ObjectHeader header_; // EtsObject 630 631 // ets.Class fields BEGIN 632 FIELD_UNUSED ObjectPointer<EtsString> name_; // String 633 FIELD_UNUSED ObjectPointer<EtsClass> superClass_; // Class<? super T> 634 FIELD_UNUSED uint32_t flags_; 635 FIELD_UNUSED EtsLong typeMetaData_; 636 // ets.Class fields END 637 638 ark::Class klass_; 639 640 friend class test::EtsClassTest; 641 }; 642 643 // Object header field must be first 644 static_assert(EtsClass::GetHeaderOffset() == 0); 645 646 // Klass field has variable size so it must be last 647 static_assert(EtsClass::GetRuntimeClassOffset() + sizeof(ark::Class) == sizeof(EtsClass)); 648 649 } // namespace ark::ets 650 651 #endif // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_ 652