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