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