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