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