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