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 size_t registerIndex = 0; 175 ClassLinkerContext *parent = nullptr; 176 ClassLinkerExtension *ext = nullptr; 177 auto enumCallback = [®isterIndex, &parent, &cb, &os, &ext](ClassLinkerContext *ctx) { 178 os << "#" << registerIndex << " "; 179 if (!cb(ctx, os, parent)) { 180 return true; 181 } 182 if (parent != nullptr) { 183 size_t parentIndex = 0; 184 bool founded = false; 185 ext->EnumerateContexts([parent, &parentIndex, &founded](ClassLinkerContext *ctxPtr) { 186 if (parent == ctxPtr) { 187 founded = true; 188 return false; 189 } 190 parentIndex++; 191 return true; 192 }); 193 if (founded) { 194 os << "|Parent class loader: #" << parentIndex << "\n"; 195 } else { 196 os << "|Parent class loader: unknown\n"; 197 } 198 } else { 199 os << "|Parent class loader: empty\n"; 200 } 201 registerIndex++; 202 return true; 203 }; 204 for (auto &extPtr : extensions_) { 205 if (extPtr == nullptr) { 206 continue; 207 } 208 ext = extPtr.get(); 209 ext->EnumerateContexts(enumCallback); 210 } 211 } 212 213 PANDA_PUBLIC_API bool InitializeClass(ManagedThread *thread, Class *klass); 214 HasExtension(const LanguageContext & ctx)215 bool HasExtension(const LanguageContext &ctx) 216 { 217 return extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get() != nullptr; 218 } 219 HasExtension(panda_file::SourceLang lang)220 bool HasExtension(panda_file::SourceLang lang) 221 { 222 return extensions_[ark::panda_file::GetLangArrIndex(lang)].get() != nullptr; 223 } 224 225 void ResetExtension(panda_file::SourceLang lang); 226 GetExtension(const LanguageContext & ctx)227 ClassLinkerExtension *GetExtension(const LanguageContext &ctx) 228 { 229 ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get(); 230 ASSERT(extension != nullptr); 231 return extension; 232 }; 233 GetExtension(panda_file::SourceLang lang)234 ClassLinkerExtension *GetExtension(panda_file::SourceLang lang) 235 { 236 ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(lang)].get(); 237 ASSERT(extension != nullptr); 238 return extension; 239 }; 240 ObjectToClass(const ObjectHeader * object)241 Class *ObjectToClass(const ObjectHeader *object) 242 { 243 ASSERT(object->ClassAddr<Class>()->IsClassClass()); 244 return extensions_[ark::panda_file::GetLangArrIndex(object->ClassAddr<BaseClass>()->GetSourceLang())] 245 ->FromClassObject(const_cast<ObjectHeader *>(object)); 246 } 247 GetClassObjectSize(Class * cls,panda_file::SourceLang lang)248 size_t GetClassObjectSize(Class *cls, panda_file::SourceLang lang) 249 { 250 // We can't get SourceLang from cls, because it may not be initialized yet (see #12894) 251 return extensions_[ark::panda_file::GetLangArrIndex(lang)]->GetClassObjectSizeFromClassSize( 252 cls->GetClassSize()); 253 } 254 255 void AddClassRoot(ClassRoot root, Class *klass); 256 257 Class *CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor, 258 Class *componentClass); 259 260 void FreeClassData(Class *classPtr); 261 262 void FreeClass(Class *classPtr); 263 GetAllocator()264 mem::InternalAllocatorPtr GetAllocator() const 265 { 266 return allocator_; 267 } 268 IsInitialized()269 bool IsInitialized() const 270 { 271 return isInitialized_; 272 } 273 274 Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr); 275 276 size_t NumLoadedClasses(); 277 278 void VisitLoadedClasses(size_t flag); 279 280 PANDA_PUBLIC_API Class *BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags, 281 Span<Method> methods, Span<Field> fields, Class *baseClass, 282 Span<Class *> interfaces, ClassLinkerContext *context, bool isInterface); 283 IsPandaFileRegistered(const panda_file::File * file)284 bool IsPandaFileRegistered(const panda_file::File *file) 285 { 286 os::memory::LockHolder lock(pandaFilesLock_); 287 for (const auto &data : pandaFiles_) { 288 if (data.pf.get() == file) { 289 return true; 290 } 291 } 292 293 return false; 294 } 295 GetAppContext(std::string_view pandaFile)296 ClassLinkerContext *GetAppContext(std::string_view pandaFile) 297 { 298 ClassLinkerContext *appContext = nullptr; 299 EnumerateContexts([pandaFile, &appContext](ClassLinkerContext *context) -> bool { 300 auto filePaths = context->GetPandaFilePaths(); 301 for (auto &file : filePaths) { 302 if (file == pandaFile) { 303 appContext = context; 304 return false; 305 } 306 } 307 return true; 308 }); 309 return appContext; 310 } 311 312 void RemoveCreatedClassInExtension(Class *klass); 313 314 Class *LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang); 315 316 private: 317 struct ClassInfo { 318 PandaUniquePtr<VTableBuilder> vtableBuilder; 319 PandaUniquePtr<ITableBuilder> itableBuilder; 320 PandaUniquePtr<IMTableBuilder> imtableBuilder; 321 size_t size; 322 size_t numSfields; 323 }; 324 325 bool LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext, 326 const uint8_t *descriptor); 327 328 Field *GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor, 329 ClassLinkerErrorHandler *errorHandler); 330 331 Field *GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor, 332 ClassLinkerErrorHandler *errorHandler); 333 334 Method *GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor, 335 ClassLinkerErrorHandler *errorHandler); 336 337 bool LinkBootClass(Class *klass); 338 339 Class *LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context, 340 ClassLinkerErrorHandler *errorHandler); 341 342 Class *LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor, 343 ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler, bool addToRuntime = true); 344 345 Class *LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor, Class *baseClass, 346 Span<Class *> interfaces, ClassLinkerContext *context, ClassLinkerExtension *ext, 347 ClassLinkerErrorHandler *errorHandler); 348 349 Class *LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx, ClassLinkerContext *context, 350 ClassLinkerErrorHandler *errorHandler); 351 352 std::optional<Span<Class *>> LoadInterfaces(panda_file::ClassDataAccessor *cda, ClassLinkerContext *context, 353 ClassLinkerErrorHandler *errorHandler); 354 355 [[nodiscard]] bool LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler); 356 357 [[nodiscard]] bool LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor, 358 ClassLinkerErrorHandler *errorHandler); 359 360 [[nodiscard]] bool LinkMethods(Class *klass, ClassInfo *classInfo, ClassLinkerErrorHandler *errorHandler); 361 362 [[nodiscard]] bool LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor, 363 ClassLinkerErrorHandler *errorHandler); 364 365 [[nodiscard]] bool SetupClassInfo(ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base, 366 Span<Class *> interfaces, ClassLinkerContext *context, 367 ClassLinkerErrorHandler *errorHandler); 368 369 [[nodiscard]] bool SetupClassInfo(ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base, 370 Span<Class *> interfaces, bool isInterface, 371 ClassLinkerErrorHandler *errorHandler); 372 373 static bool LayoutFields(Class *klass, Span<Field> fields, bool isStatic, ClassLinkerErrorHandler *errorHandler); 374 375 mem::InternalAllocatorPtr allocator_; 376 377 PandaVector<const panda_file::File *> bootPandaFiles_ GUARDED_BY(bootPandaFilesLock_); 378 379 struct PandaFileLoadData { 380 ClassLinkerContext *context; 381 std::unique_ptr<const panda_file::File> pf; 382 }; 383 384 mutable os::memory::Mutex pandaFilesLock_; 385 mutable os::memory::Mutex bootPandaFilesLock_; 386 PandaVector<PandaFileLoadData> pandaFiles_ GUARDED_BY(pandaFilesLock_); 387 388 PandaUniquePtr<AotManager> aotManager_; 389 // Just to free them at destroy 390 os::memory::Mutex copiedNamesLock_; 391 PandaList<const uint8_t *> copiedNames_ GUARDED_BY(copiedNamesLock_); 392 393 std::array<std::unique_ptr<ClassLinkerExtension>, ark::panda_file::LANG_COUNT> extensions_; 394 395 bool isInitialized_ {false}; 396 397 NO_COPY_SEMANTIC(ClassLinker); 398 NO_MOVE_SEMANTIC(ClassLinker); 399 }; 400 401 class ClassLinkerErrorHandler { 402 public: 403 virtual void OnError(ClassLinker::Error error, const PandaString &message) = 0; 404 405 public: 406 ClassLinkerErrorHandler() = default; 407 virtual ~ClassLinkerErrorHandler() = default; 408 409 NO_MOVE_SEMANTIC(ClassLinkerErrorHandler); 410 NO_COPY_SEMANTIC(ClassLinkerErrorHandler); 411 }; 412 413 } // namespace ark 414 415 #endif // PANDA_RUNTIME_CLASS_LINKER_H_ 416