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