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_EXTENSION_H_ 16 #define PANDA_RUNTIME_CLASS_LINKER_EXTENSION_H_ 17 18 #include "libpandabase/os/mutex.h" 19 #include "libpandafile/file.h" 20 #include "libpandafile/file_items.h" 21 #include "runtime/class_linker_context.h" 22 #include "runtime/include/class_root.h" 23 #include "runtime/include/class.h" 24 #include "runtime/include/mem/panda_containers.h" 25 26 namespace panda { 27 28 class ClassLinker; 29 class ClassLinkerErrorHandler; 30 31 class ClassLinkerExtension { 32 public: ClassLinkerExtension(panda_file::SourceLang lang)33 explicit ClassLinkerExtension(panda_file::SourceLang lang) : lang_(lang), boot_context_(this) {} 34 35 virtual ~ClassLinkerExtension(); 36 37 bool Initialize(ClassLinker *class_linker, bool compressed_string_enabled); 38 39 bool InitializeFinish(); 40 41 bool InitializeRoots(ManagedThread *thread); 42 43 virtual void InitializeArrayClass(Class *array_class, Class *component_class) = 0; 44 45 virtual void InitializePrimitiveClass(Class *primitive_class) = 0; 46 47 virtual size_t GetClassVTableSize(ClassRoot root) = 0; 48 49 virtual size_t GetClassIMTSize(ClassRoot root) = 0; 50 51 virtual size_t GetClassSize(ClassRoot root) = 0; 52 53 virtual size_t GetArrayClassVTableSize() = 0; 54 55 virtual size_t GetArrayClassIMTSize() = 0; 56 57 virtual size_t GetArrayClassSize() = 0; 58 59 virtual Class *CreateClass(const uint8_t *descriptor, size_t vtable_size, size_t imt_size, size_t size) = 0; 60 61 virtual void FreeClass(Class *klass) = 0; 62 63 virtual void InitializeClass(Class *klass) = 0; 64 65 virtual const void *GetNativeEntryPointFor(Method *method) const = 0; 66 67 virtual bool CanThrowException(const Method *method) const = 0; 68 69 virtual ClassLinkerErrorHandler *GetErrorHandler() = 0; 70 71 virtual ClassLinkerContext *CreateApplicationClassLinkerContext(const PandaVector<PandaString> &path); 72 GetClassRoot(ClassRoot root)73 Class *GetClassRoot(ClassRoot root) const 74 { 75 return class_roots_[ToIndex(root)]; 76 } 77 GetBootContext()78 ClassLinkerContext *GetBootContext() 79 { 80 return &boot_context_; 81 } 82 SetClassRoot(ClassRoot root,Class * klass)83 void SetClassRoot(ClassRoot root, Class *klass) 84 { 85 class_roots_[ToIndex(root)] = klass; 86 boot_context_.InsertClass(klass); 87 } 88 89 Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr); 90 91 Class *GetClass(const uint8_t *descriptor, bool need_copy_descriptor = true, ClassLinkerContext *context = nullptr, 92 ClassLinkerErrorHandler *error_handler = nullptr); 93 94 Class *GetClass(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context = nullptr, 95 ClassLinkerErrorHandler *error_handler = nullptr); 96 GetLanguage()97 panda_file::SourceLang GetLanguage() const 98 { 99 return lang_; 100 } 101 GetClassLinker()102 ClassLinker *GetClassLinker() const 103 { 104 return class_linker_; 105 } 106 IsInitialized()107 bool IsInitialized() const 108 { 109 return class_linker_ != nullptr; 110 } 111 CanInitializeClasses()112 bool CanInitializeClasses() 113 { 114 return can_initialize_classes_; 115 } 116 117 template <class Callback> 118 bool EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL) 119 { 120 ASSERT(BitCount(flags & (mem::VisitGCRootFlags::ACCESS_ROOT_ALL | mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW | 121 mem::VisitGCRootFlags::ACCESS_ROOT_NONE)) == 1); 122 if (((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) || 123 ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0)) { 124 os::memory::LockHolder lock(created_classes_lock_); 125 for (const auto &cls : created_classes_) { 126 if (!cb(cls)) { 127 return false; 128 } 129 } 130 } 131 if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0) { 132 os::memory::LockHolder lock(new_classes_lock_); 133 for (const auto &cls : new_classes_) { 134 if (!cb(cls)) { 135 return false; 136 } 137 } 138 } 139 140 if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) { 141 if (!boot_context_.EnumerateClasses(cb)) { 142 return false; 143 } 144 145 { 146 os::memory::LockHolder lock(contexts_lock_); 147 for (auto *ctx : contexts_) { 148 if (!ctx->EnumerateClasses(cb)) { 149 return false; 150 } 151 } 152 } 153 } 154 155 { 156 os::memory::LockHolder lock(obsolete_classes_lock_); 157 for (const auto &cls : obsolete_classes_) { 158 if (!cb(cls)) { 159 return false; 160 } 161 } 162 } 163 164 ASSERT(BitCount(flags & (mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT | 165 mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT)) <= 1); 166 if ((flags & mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT) != 0) { 167 // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially 168 // consistent order where threads observe all modifications in the same order 169 record_new_class_.store(true, std::memory_order_seq_cst); 170 } else if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) { 171 // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially 172 // consistent order where threads observe all modifications in the same order 173 record_new_class_.store(false, std::memory_order_seq_cst); 174 os::memory::LockHolder lock(new_classes_lock_); 175 new_classes_.clear(); 176 } 177 178 return true; 179 } 180 181 template <class ContextGetterFn> RegisterContext(const ContextGetterFn & fn)182 void RegisterContext(const ContextGetterFn &fn) 183 { 184 os::memory::LockHolder lock(contexts_lock_); 185 auto *context = fn(); 186 if (context != nullptr) { 187 contexts_.push_back(context); 188 } 189 } 190 191 template <class Callback> EnumerateContexts(const Callback & cb)192 void EnumerateContexts(const Callback &cb) 193 { 194 if (!cb(&boot_context_)) { 195 return; 196 } 197 198 os::memory::LockHolder lock(contexts_lock_); 199 for (auto *context : contexts_) { 200 if (!cb(context)) { 201 return; 202 } 203 } 204 } 205 206 size_t NumLoadedClasses(); 207 208 void VisitLoadedClasses(size_t flag); 209 ResolveContext(ClassLinkerContext * context)210 ClassLinkerContext *ResolveContext(ClassLinkerContext *context) 211 { 212 if (context == nullptr) { 213 return &boot_context_; 214 } 215 216 return context; 217 } 218 219 void OnClassPrepared(Class *klass); 220 221 // Saving obsolete data after hotreload to enable it to be executed 222 void AddObsoleteClass(const PandaVector<panda::Class *> &classes); 223 void FreeObsoleteData(); 224 225 virtual Class *FromClassObject(ObjectHeader *obj); 226 227 virtual size_t GetClassObjectSizeFromClassSize(uint32_t size); 228 229 NO_COPY_SEMANTIC(ClassLinkerExtension); 230 NO_MOVE_SEMANTIC(ClassLinkerExtension); 231 232 protected: 233 void InitializePrimitiveClassRoot(ClassRoot root, panda_file::Type::TypeId type_id, const char *descriptor); 234 235 void InitializeArrayClassRoot(ClassRoot root, ClassRoot component_root, const char *descriptor); 236 237 void FreeLoadedClasses(); 238 239 Class *AddClass(Class *klass); 240 241 // Add the class to the list, when it is just be created and not add to class linker context. 242 void AddCreatedClass(Class *klass); 243 244 // Remove class in the list, when it has been added to class linker context. 245 void RemoveCreatedClass(Class *klass); 246 247 using PandaFilePtr = std::unique_ptr<const panda_file::File>; 248 virtual ClassLinkerContext *CreateApplicationClassLinkerContext(PandaVector<PandaFilePtr> &&app_files); 249 250 private: 251 class BootContext : public ClassLinkerContext { 252 public: BootContext(ClassLinkerExtension * extension)253 explicit BootContext(ClassLinkerExtension *extension) 254 : ClassLinkerContext(extension->GetLanguage()), extension_(extension) 255 { 256 } 257 IsBootContext()258 bool IsBootContext() const override 259 { 260 return true; 261 } 262 263 Class *LoadClass(const uint8_t *descriptor, bool need_copy_descriptor, 264 ClassLinkerErrorHandler *error_handler) override; 265 266 void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override; 267 268 private: 269 ClassLinkerExtension *extension_; 270 }; 271 272 class AppContext : public ClassLinkerContext { 273 public: AppContext(ClassLinkerExtension * extension,PandaVector<const panda_file::File * > && pf_list)274 explicit AppContext(ClassLinkerExtension *extension, PandaVector<const panda_file::File *> &&pf_list) 275 : ClassLinkerContext(extension->GetLanguage()), extension_(extension), pfs_(pf_list) 276 { 277 } 278 279 Class *LoadClass(const uint8_t *descriptor, bool need_copy_descriptor, 280 ClassLinkerErrorHandler *error_handler) override; 281 EnumeratePandaFiles(const std::function<bool (const panda_file::File &)> & cb)282 void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override 283 { 284 for (auto &pf : pfs_) { 285 if (pf == nullptr) { 286 continue; 287 } 288 if (!cb(*pf)) { 289 break; 290 } 291 } 292 } 293 GetPandaFilePaths()294 PandaVector<std::string_view> GetPandaFilePaths() const override 295 { 296 PandaVector<std::string_view> file_paths; 297 for (auto &pf : pfs_) { 298 if (pf != nullptr) { 299 file_paths.emplace_back(pf->GetFilename()); 300 } 301 } 302 return file_paths; 303 } 304 305 private: 306 ClassLinkerExtension *extension_; 307 PandaVector<const panda_file::File *> pfs_; 308 }; 309 310 static constexpr size_t CLASS_ROOT_COUNT = static_cast<size_t>(ClassRoot::LAST_CLASS_ROOT_ENTRY) + 1; 311 312 virtual bool InitializeImpl(bool compressed_string_enabled) = 0; 313 ToIndex(ClassRoot root)314 static constexpr size_t ToIndex(ClassRoot root) 315 { 316 return static_cast<size_t>(root); 317 } ResolveErrorHandler(ClassLinkerErrorHandler * error_handler)318 ClassLinkerErrorHandler *ResolveErrorHandler(ClassLinkerErrorHandler *error_handler) 319 { 320 if (error_handler == nullptr) { 321 return GetErrorHandler(); 322 } 323 324 return error_handler; 325 } 326 327 panda_file::SourceLang lang_; 328 BootContext boot_context_; 329 330 std::array<Class *, CLASS_ROOT_COUNT> class_roots_ {}; 331 ClassLinker *class_linker_ {nullptr}; 332 333 os::memory::RecursiveMutex contexts_lock_; 334 PandaVector<ClassLinkerContext *> contexts_ GUARDED_BY(contexts_lock_); 335 336 os::memory::RecursiveMutex created_classes_lock_; 337 PandaVector<Class *> created_classes_ GUARDED_BY(created_classes_lock_); 338 339 os::memory::RecursiveMutex new_classes_lock_; 340 std::atomic_bool record_new_class_ {false}; 341 PandaVector<Class *> new_classes_ GUARDED_BY(new_classes_lock_); 342 343 os::memory::RecursiveMutex obsolete_classes_lock_; 344 PandaVector<Class *> obsolete_classes_ GUARDED_BY(obsolete_classes_lock_); 345 346 bool can_initialize_classes_ {false}; 347 }; 348 349 } // namespace panda 350 351 #endif // PANDA_RUNTIME_CLASS_LINKER_EXTENSION_H_ 352