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 #ifndef PANDA_RUNTIME_CLASS_LINKER_H_ 16 #define PANDA_RUNTIME_CLASS_LINKER_H_ 17 18 #include <memory> 19 #include <optional> 20 #include <string> 21 #include <string_view> 22 #include <vector> 23 24 #include "compiler/aot/aot_manager.h" 25 #include "libpandabase/mem/arena_allocator.h" 26 #include "libpandabase/os/mutex.h" 27 #include "libpandabase/utils/utf.h" 28 #include "libpandafile/class_data_accessor-inl.h" 29 #include "libpandafile/file.h" 30 #include "libpandafile/file_items.h" 31 #include "runtime/class_linker_context.h" 32 #include "runtime/include/class.h" 33 #include "runtime/include/field.h" 34 #include "runtime/include/itable_builder.h" 35 #include "runtime/include/imtable_builder.h" 36 #include "runtime/include/language_context.h" 37 #include "runtime/include/mem/panda_containers.h" 38 #include "runtime/include/mem/panda_smart_pointers.h" 39 #include "runtime/include/mem/panda_string.h" 40 #include "runtime/include/method.h" 41 #include "runtime/include/vtable_builder_interface.h" 42 43 namespace ark { 44 45 using compiler::AotManager; 46 47 class ClassLinkerErrorHandler; 48 49 class ClassLinker { 50 public: 51 enum class Error { 52 CLASS_NOT_FOUND, 53 FIELD_NOT_FOUND, 54 METHOD_NOT_FOUND, 55 NO_CLASS_DEF, 56 CLASS_CIRCULARITY, 57 OVERRIDES_FINAL, 58 MULTIPLE_OVERRIDE, 59 MULTIPLE_IMPLEMENT, 60 INVALID_LAMBDA_CLASS, 61 }; 62 63 ClassLinker(mem::InternalAllocatorPtr allocator, std::vector<std::unique_ptr<ClassLinkerExtension>> &&extensions); 64 65 ~ClassLinker(); 66 67 bool Initialize(bool compressedStringEnabled = true); 68 69 bool InitializeRoots(ManagedThread *thread); 70 71 PANDA_PUBLIC_API Class *GetClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context, 72 ClassLinkerErrorHandler *errorHandler = nullptr); 73 74 PANDA_PUBLIC_API Class *GetClass(const panda_file::File &pf, panda_file::File::EntityId id, 75 ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler = nullptr); 76 77 PANDA_PUBLIC_API Class *GetClass(const Method &caller, panda_file::File::EntityId id, 78 ClassLinkerErrorHandler *errorHandler = nullptr); 79 80 inline Class *GetLoadedClass(const panda_file::File &pf, panda_file::File::EntityId id, 81 ClassLinkerContext *context); 82 83 Class *LoadClass(const panda_file::File &pf, panda_file::File::EntityId classId, ClassLinkerContext *context, 84 ClassLinkerErrorHandler *errorHandler = nullptr, bool addToRuntime = true) 85 { 86 return LoadClass(&pf, classId, pf.GetStringData(classId).data, context, errorHandler, addToRuntime); 87 } 88 89 Method *GetMethod(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context = nullptr, 90 ClassLinkerErrorHandler *errorHandler = nullptr); 91 92 Method *GetMethod(const Method &caller, panda_file::File::EntityId id, 93 ClassLinkerErrorHandler *errorHandler = nullptr); 94 95 Field *GetField(const panda_file::File &pf, panda_file::File::EntityId id, bool isStatic, 96 ClassLinkerContext *context = nullptr, ClassLinkerErrorHandler *errorHandler = nullptr); 97 98 Field *GetField(const Method &caller, panda_file::File::EntityId id, bool isStatic, 99 ClassLinkerErrorHandler *errorHandler = nullptr); 100 101 PANDA_PUBLIC_API void AddPandaFile(std::unique_ptr<const panda_file::File> &&pf, 102 ClassLinkerContext *context = nullptr); 103 104 template <typename Callback> 105 void EnumeratePandaFiles(Callback cb, bool skipIntrinsics = true) const 106 { 107 os::memory::LockHolder lock(pandaFilesLock_); 108 for (const auto &fileData : pandaFiles_) { 109 if (skipIntrinsics && fileData.pf->GetFilename().empty()) { 110 continue; 111 } 112 113 if (!cb(*fileData.pf)) { 114 break; 115 } 116 } 117 } 118 119 template <typename Callback> EnumerateBootPandaFiles(Callback cb)120 void EnumerateBootPandaFiles(Callback cb) const 121 { 122 os::memory::LockHolder lock {bootPandaFilesLock_}; 123 for (const auto &file : bootPandaFiles_) { 124 if (!cb(*file)) { 125 break; 126 } 127 } 128 } 129 GetBootPandaFiles()130 const PandaVector<const panda_file::File *> &GetBootPandaFiles() const 131 { 132 return bootPandaFiles_; 133 } 134 GetAotManager()135 AotManager *GetAotManager() 136 { 137 return aotManager_.get(); 138 } 139 140 PandaString GetClassContextForAot(bool useAbsPath = true) 141 { 142 PandaString aotCtx; 143 EnumeratePandaFiles(compiler::AotClassContextCollector(&aotCtx, useAbsPath)); 144 return aotCtx; 145 } 146 147 template <class Callback> 148 void EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL) 149 { 150 for (auto &ext : extensions_) { 151 if (ext == nullptr) { 152 continue; 153 } 154 155 if (!ext->EnumerateClasses(cb, flags)) { 156 return; 157 } 158 } 159 } 160 161 template <class Callback> EnumerateContexts(const Callback & cb)162 void EnumerateContexts(const Callback &cb) 163 { 164 for (auto &ext : extensions_) { 165 if (ext == nullptr) { 166 continue; 167 } 168 ext->EnumerateContexts(cb); 169 } 170 } 171 172 template <class Callback> EnumerateContextsForDump(const Callback & cb,std::ostream & os)173 void EnumerateContextsForDump(const Callback &cb, std::ostream &os) 174 { 175 auto findParent = [](ClassLinkerContext *parent, ClassLinkerContext *ctxPtr, size_t &parentIndex, 176 bool &founded) { 177 if (parent == ctxPtr) { 178 founded = true; 179 return false; 180 } 181 parentIndex++; 182 return true; 183 }; 184 185 size_t registerIndex = 0; 186 ClassLinkerContext *parent = nullptr; 187 ClassLinkerExtension *ext = nullptr; 188 189 auto enumCallback = [®isterIndex, &parent, &cb, &os, &ext, &findParent](ClassLinkerContext *ctx) { 190 os << "#" << registerIndex << " "; 191 if (!cb(ctx, os, parent)) { 192 return true; 193 } 194 if (parent != nullptr) { 195 size_t parentIndex = 0; 196 bool founded = false; 197 ext->EnumerateContexts([parent, &parentIndex, &founded, &findParent](ClassLinkerContext *ctxPtr) { 198 return findParent(parent, ctxPtr, parentIndex, founded); 199 }); 200 if (founded) { 201 os << "|Parent class loader: #" << parentIndex << "\n"; 202 } else { 203 os << "|Parent class loader: unknown\n"; 204 } 205 } else { 206 os << "|Parent class loader: empty\n"; 207 } 208 registerIndex++; 209 return true; 210 }; 211 for (auto &extPtr : extensions_) { 212 if (extPtr == nullptr) { 213 continue; 214 } 215 ext = extPtr.get(); 216 ext->EnumerateContexts(enumCallback); 217 } 218 } 219 220 PANDA_PUBLIC_API bool InitializeClass(ManagedThread *thread, Class *klass); 221 HasExtension(const LanguageContext & ctx)222 bool HasExtension(const LanguageContext &ctx) 223 { 224 return extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get() != nullptr; 225 } 226 HasExtension(panda_file::SourceLang lang)227 bool HasExtension(panda_file::SourceLang lang) 228 { 229 return extensions_[ark::panda_file::GetLangArrIndex(lang)].get() != nullptr; 230 } 231 232 void ResetExtension(panda_file::SourceLang lang); 233 GetExtension(const LanguageContext & ctx)234 ClassLinkerExtension *GetExtension(const LanguageContext &ctx) 235 { 236 ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get(); 237 ASSERT(extension != nullptr); 238 return extension; 239 }; 240 GetExtension(panda_file::SourceLang lang)241 ClassLinkerExtension *GetExtension(panda_file::SourceLang lang) 242 { 243 ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(lang)].get(); 244 ASSERT(extension != nullptr); 245 return extension; 246 }; 247 ObjectToClass(const ObjectHeader * object)248 Class *ObjectToClass(const ObjectHeader *object) 249 { 250 ASSERT(object); 251 ASSERT(object->ClassAddr<Class>()); 252 ASSERT(object->ClassAddr<Class>()->IsClassClass()); 253 return extensions_[ark::panda_file::GetLangArrIndex(object->ClassAddr<BaseClass>()->GetSourceLang())] 254 ->FromClassObject(const_cast<ObjectHeader *>(object)); 255 } 256 GetClassObjectSize(Class * cls,panda_file::SourceLang lang)257 size_t GetClassObjectSize(Class *cls, panda_file::SourceLang lang) 258 { 259 // We can't get SourceLang from cls, because it may not be initialized yet (see #12894) 260 return extensions_[ark::panda_file::GetLangArrIndex(lang)]->GetClassObjectSizeFromClassSize( 261 cls->GetClassSize()); 262 } 263 264 void AddClassRoot(ClassRoot root, Class *klass); 265 266 Class *CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor, 267 Class *componentClass); 268 269 void FreeClassData(Class *classPtr); 270 271 void FreeClass(Class *classPtr); 272 GetAllocator()273 mem::InternalAllocatorPtr GetAllocator() const 274 { 275 return allocator_; 276 } 277 IsInitialized()278 bool IsInitialized() const 279 { 280 return isInitialized_; 281 } 282 283 Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr); 284 285 size_t NumLoadedClasses(); 286 287 void VisitLoadedClasses(size_t flag); 288 289 PANDA_PUBLIC_API Class *BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags, 290 Span<Method> methods, Span<Field> fields, Class *baseClass, 291 Span<Class *> interfaces, ClassLinkerContext *context, bool isInterface); 292 IsPandaFileRegistered(const panda_file::File * file)293 bool IsPandaFileRegistered(const panda_file::File *file) 294 { 295 os::memory::LockHolder lock(pandaFilesLock_); 296 for (const auto &data : pandaFiles_) { 297 if (data.pf.get() == file) { 298 return true; 299 } 300 } 301 302 return false; 303 } 304 GetAppContext(std::string_view pandaFile)305 ClassLinkerContext *GetAppContext(std::string_view pandaFile) 306 { 307 ClassLinkerContext *appContext = nullptr; 308 EnumerateContexts([pandaFile, &appContext](ClassLinkerContext *context) -> bool { 309 auto filePaths = context->GetPandaFilePaths(); 310 for (auto &file : filePaths) { 311 if (file == pandaFile) { 312 appContext = context; 313 return false; 314 } 315 } 316 return true; 317 }); 318 return appContext; 319 } 320 321 void RemoveCreatedClassInExtension(Class *klass); 322 323 Class *LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang); 324 325 private: 326 struct ClassInfo { 327 PandaUniquePtr<VTableBuilder> vtableBuilder; 328 PandaUniquePtr<ITableBuilder> itableBuilder; 329 PandaUniquePtr<IMTableBuilder> imtableBuilder; 330 size_t size; 331 size_t numSfields; 332 }; 333 334 bool LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext, 335 const uint8_t *descriptor); 336 337 Field *GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor, 338 ClassLinkerErrorHandler *errorHandler, bool isStatic); 339 340 Field *GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor, 341 ClassLinkerErrorHandler *errorHandler, bool isStatic); 342 343 Method *GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor, 344 ClassLinkerErrorHandler *errorHandler); 345 346 bool LinkBootClass(Class *klass); 347 348 Class *LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context, 349 ClassLinkerErrorHandler *errorHandler); 350 351 Class *LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor, 352 ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler, bool addToRuntime = true); 353 354 Class *LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor, Class *baseClass, 355 Span<Class *> interfaces, ClassLinkerContext *context, ClassLinkerExtension *ext, 356 ClassLinkerErrorHandler *errorHandler); 357 358 Class *LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx, ClassLinkerContext *context, 359 ClassLinkerErrorHandler *errorHandler); 360 361 std::optional<Span<Class *>> LoadInterfaces(panda_file::ClassDataAccessor *cda, ClassLinkerContext *context, 362 ClassLinkerErrorHandler *errorHandler); 363 364 void FreeITableAndInterfaces(ITable itable, Span<Class *> &interfaces); 365 366 [[nodiscard]] bool LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler); 367 368 [[nodiscard]] bool LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor, 369 ClassLinkerErrorHandler *errorHandler); 370 371 [[nodiscard]] bool LinkMethods(Class *klass, ClassInfo *classInfo, ClassLinkerErrorHandler *errorHandler); 372 373 [[nodiscard]] bool LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor, 374 ClassLinkerErrorHandler *errorHandler); 375 376 [[nodiscard]] bool SetupClassInfo(ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base, 377 Span<Class *> interfaces, ClassLinkerContext *context, 378 ClassLinkerErrorHandler *errorHandler); 379 380 [[nodiscard]] bool SetupClassInfo(ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base, 381 Span<Class *> interfaces, bool isInterface, 382 ClassLinkerErrorHandler *errorHandler); 383 384 static bool LayoutFields(Class *klass, Span<Field> fields, bool isStatic, ClassLinkerErrorHandler *errorHandler); 385 386 mem::InternalAllocatorPtr allocator_; 387 388 PandaVector<const panda_file::File *> bootPandaFiles_ GUARDED_BY(bootPandaFilesLock_); 389 390 struct PandaFileLoadData { 391 ClassLinkerContext *context; 392 std::unique_ptr<const panda_file::File> pf; 393 }; 394 395 mutable os::memory::Mutex pandaFilesLock_; 396 mutable os::memory::Mutex bootPandaFilesLock_; 397 PandaVector<PandaFileLoadData> pandaFiles_ GUARDED_BY(pandaFilesLock_); 398 399 PandaUniquePtr<AotManager> aotManager_; 400 // Just to free them at destroy 401 os::memory::Mutex copiedNamesLock_; 402 PandaList<const uint8_t *> copiedNames_ GUARDED_BY(copiedNamesLock_); 403 404 std::array<std::unique_ptr<ClassLinkerExtension>, ark::panda_file::LANG_COUNT> extensions_; 405 406 bool isInitialized_ {false}; 407 408 NO_COPY_SEMANTIC(ClassLinker); 409 NO_MOVE_SEMANTIC(ClassLinker); 410 }; 411 412 class ClassLinkerErrorHandler { 413 public: 414 virtual void OnError(ClassLinker::Error error, const PandaString &message) = 0; 415 416 public: 417 ClassLinkerErrorHandler() = default; 418 virtual ~ClassLinkerErrorHandler() = default; 419 420 NO_MOVE_SEMANTIC(ClassLinkerErrorHandler); 421 NO_COPY_SEMANTIC(ClassLinkerErrorHandler); 422 }; 423 424 } // namespace ark 425 426 #endif // PANDA_RUNTIME_CLASS_LINKER_H_ 427