1 /** 2 * Copyright (c) 2021-2025 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 ark { 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), bootContext_(this) {} 34 35 virtual ~ClassLinkerExtension(); 36 37 bool Initialize(ClassLinker *classLinker, bool compressedStringEnabled); 38 39 bool InitializeFinish(); 40 41 bool InitializeRoots(ManagedThread *thread); 42 43 virtual bool InitializeArrayClass(Class *arrayClass, Class *componentClass) = 0; 44 45 virtual void InitializePrimitiveClass(Class *primitiveClass) = 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 vtableSize, size_t imtSize, size_t size) = 0; 60 61 virtual void FreeClass(Class *klass) = 0; 62 63 virtual bool InitializeClass(Class *klass) = 0; 64 InitializeClass(Class * klass,ClassLinkerErrorHandler * handler)65 virtual bool InitializeClass(Class *klass, [[maybe_unused]] ClassLinkerErrorHandler *handler) 66 { 67 return InitializeClass(klass); 68 } 69 70 virtual const void *GetNativeEntryPointFor(Method *method) const = 0; 71 72 virtual bool CanThrowException(const Method *method) const = 0; 73 IsMethodNativeApi(const Method * method)74 virtual bool IsMethodNativeApi([[maybe_unused]] const Method *method) const 75 { 76 return false; 77 } 78 IsNecessarySwitchThreadState(const Method * method)79 virtual bool IsNecessarySwitchThreadState([[maybe_unused]] const Method *method) const 80 { 81 return false; 82 } 83 CanNativeMethodUseObjects(const Method * method)84 virtual bool CanNativeMethodUseObjects([[maybe_unused]] const Method *method) const 85 { 86 return false; 87 } 88 89 virtual ClassLinkerErrorHandler *GetErrorHandler() = 0; 90 91 virtual ClassLinkerContext *CreateApplicationClassLinkerContext(const PandaVector<PandaString> &path); 92 GetClassRoot(ClassRoot root)93 Class *GetClassRoot(ClassRoot root) const 94 { 95 return classRoots_[ToIndex(root)]; 96 } 97 GetBootContext()98 ClassLinkerContext *GetBootContext() 99 { 100 return &bootContext_; 101 } 102 SetClassRoot(ClassRoot root,Class * klass)103 void SetClassRoot(ClassRoot root, Class *klass) 104 { 105 classRoots_[ToIndex(root)] = klass; 106 bootContext_.InsertClass(klass); 107 } 108 109 Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr); 110 111 PANDA_PUBLIC_API Class *GetClass(const uint8_t *descriptor, bool needCopyDescriptor = true, 112 ClassLinkerContext *context = nullptr, 113 ClassLinkerErrorHandler *errorHandler = nullptr); 114 115 PANDA_PUBLIC_API Class *GetClass(const panda_file::File &pf, panda_file::File::EntityId id, 116 ClassLinkerContext *context = nullptr, 117 ClassLinkerErrorHandler *errorHandler = nullptr); 118 GetLanguage()119 panda_file::SourceLang GetLanguage() const 120 { 121 return lang_; 122 } 123 GetClassLinker()124 ClassLinker *GetClassLinker() const 125 { 126 return classLinker_; 127 } 128 IsInitialized()129 bool IsInitialized() const 130 { 131 return classLinker_ != nullptr; 132 } 133 CanInitializeClasses()134 bool CanInitializeClasses() 135 { 136 return canInitializeClasses_; 137 } 138 RecordNewRoot(mem::VisitGCRootFlags flags)139 void RecordNewRoot(mem::VisitGCRootFlags flags) 140 { 141 ASSERT(BitCount(flags & (mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT | 142 mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT)) <= 1); 143 if ((flags & mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT) != 0) { 144 // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially 145 // consistent order where threads observe all modifications in the same order 146 recordNewClass_.store(true, std::memory_order_seq_cst); 147 } else if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) { 148 // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially 149 // consistent order where threads observe all modifications in the same order 150 recordNewClass_.store(false, std::memory_order_seq_cst); 151 os::memory::LockHolder lock(newClassesLock_); 152 newClasses_.clear(); 153 } 154 } 155 156 template <class Callback> 157 bool EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL) 158 { 159 ASSERT(BitCount(flags & (mem::VisitGCRootFlags::ACCESS_ROOT_ALL | mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW | 160 mem::VisitGCRootFlags::ACCESS_ROOT_NONE)) == 1); 161 if (((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) || 162 ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0)) { 163 os::memory::LockHolder lock(createdClassesLock_); 164 for (const auto &cls : createdClasses_) { 165 if (!cb(cls)) { 166 return false; 167 } 168 } 169 } 170 if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0) { 171 os::memory::LockHolder lock(newClassesLock_); 172 for (const auto &cls : newClasses_) { 173 if (!cb(cls)) { 174 return false; 175 } 176 } 177 } 178 179 if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) { 180 if (!bootContext_.EnumerateClasses(cb)) { 181 return false; 182 } 183 184 { 185 os::memory::LockHolder lock(contextsLock_); 186 for (auto *ctx : contexts_) { 187 if (!ctx->EnumerateClasses(cb)) { 188 return false; 189 } 190 } 191 } 192 } 193 194 { 195 os::memory::LockHolder lock(obsoleteClassesLock_); 196 for (const auto &cls : obsoleteClasses_) { 197 if (!cb(cls)) { 198 return false; 199 } 200 } 201 } 202 203 RecordNewRoot(flags); 204 205 return true; 206 } 207 208 template <class ContextGetterFn> RegisterContext(const ContextGetterFn & fn)209 void RegisterContext(const ContextGetterFn &fn) 210 { 211 os::memory::LockHolder lock(contextsLock_); 212 auto *context = fn(); 213 if (context != nullptr) { 214 contexts_.push_back(context); 215 } 216 } 217 218 template <class Callback> EnumerateContexts(const Callback & cb)219 void EnumerateContexts(const Callback &cb) 220 { 221 if (!cb(&bootContext_)) { 222 return; 223 } 224 225 os::memory::LockHolder lock(contextsLock_); 226 for (auto *context : contexts_) { 227 if (!cb(context)) { 228 return; 229 } 230 } 231 } 232 233 size_t NumLoadedClasses(); 234 235 void VisitLoadedClasses(size_t flag); 236 ResolveContext(ClassLinkerContext * context)237 ClassLinkerContext *ResolveContext(ClassLinkerContext *context) 238 { 239 if (context == nullptr) { 240 return &bootContext_; 241 } 242 243 return context; 244 } 245 246 void OnClassPrepared(Class *klass); 247 248 // Saving obsolete data after hotreload to enable it to be executed 249 void AddObsoleteClass(const PandaVector<ark::Class *> &classes); 250 void FreeObsoleteData(); 251 252 virtual Class *FromClassObject(ObjectHeader *obj); 253 254 virtual size_t GetClassObjectSizeFromClassSize(uint32_t size); 255 CanScalarReplaceObject(Class * klass)256 virtual bool CanScalarReplaceObject([[maybe_unused]] Class *klass) 257 { 258 return true; 259 } 260 261 NO_COPY_SEMANTIC(ClassLinkerExtension); 262 NO_MOVE_SEMANTIC(ClassLinkerExtension); 263 264 protected: 265 void InitializePrimitiveClassRoot(ClassRoot root, panda_file::Type::TypeId typeId, const char *descriptor); 266 267 void InitializeArrayClassRoot(ClassRoot root, ClassRoot componentRoot, const char *descriptor); 268 269 void FreeLoadedClasses(); 270 271 Class *AddClass(Class *klass); 272 273 // Add the class to the list, when it is just be created and not add to class linker context. 274 void AddCreatedClass(Class *klass); 275 276 // Remove class in the list, when it has been added to class linker context. 277 void RemoveCreatedClass(Class *klass); 278 279 using PandaFilePtr = std::unique_ptr<const panda_file::File>; 280 virtual ClassLinkerContext *CreateApplicationClassLinkerContext(PandaVector<PandaFilePtr> &&appFiles); 281 282 private: 283 class BootContext : public ClassLinkerContext { 284 public: BootContext(ClassLinkerExtension * extension)285 explicit BootContext(ClassLinkerExtension *extension) 286 : ClassLinkerContext(extension->GetLanguage()), extension_(extension) 287 { 288 } 289 IsBootContext()290 bool IsBootContext() const override 291 { 292 return true; 293 } 294 295 Class *LoadClass(const uint8_t *descriptor, bool needCopyDescriptor, 296 ClassLinkerErrorHandler *errorHandler) override; 297 298 void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override; 299 300 private: 301 ClassLinkerExtension *extension_; 302 }; 303 304 class AppContext : public ClassLinkerContext { 305 public: AppContext(ClassLinkerExtension * extension,PandaVector<const panda_file::File * > && pfList)306 explicit AppContext(ClassLinkerExtension *extension, PandaVector<const panda_file::File *> &&pfList) 307 : ClassLinkerContext(extension->GetLanguage()), extension_(extension), pfs_(pfList) 308 { 309 } 310 311 Class *LoadClass(const uint8_t *descriptor, bool needCopyDescriptor, 312 ClassLinkerErrorHandler *errorHandler) override; 313 EnumeratePandaFiles(const std::function<bool (const panda_file::File &)> & cb)314 void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override 315 { 316 for (auto &pf : pfs_) { 317 if (pf == nullptr) { 318 continue; 319 } 320 if (!cb(*pf)) { 321 break; 322 } 323 } 324 } 325 GetPandaFilePaths()326 PandaVector<std::string_view> GetPandaFilePaths() const override 327 { 328 PandaVector<std::string_view> filePaths; 329 for (auto &pf : pfs_) { 330 if (pf != nullptr) { 331 filePaths.emplace_back(pf->GetFilename()); 332 } 333 } 334 return filePaths; 335 } 336 337 private: 338 ClassLinkerExtension *extension_; 339 PandaVector<const panda_file::File *> pfs_; 340 }; 341 342 static constexpr size_t CLASS_ROOT_COUNT = static_cast<size_t>(ClassRoot::LAST_CLASS_ROOT_ENTRY) + 1; 343 344 virtual bool InitializeImpl(bool compressedStringEnabled) = 0; 345 ToIndex(ClassRoot root)346 static constexpr size_t ToIndex(ClassRoot root) 347 { 348 return static_cast<size_t>(root); 349 } 350 ResolveErrorHandler(ClassLinkerErrorHandler * errorHandler)351 ClassLinkerErrorHandler *ResolveErrorHandler(ClassLinkerErrorHandler *errorHandler) 352 { 353 if (errorHandler == nullptr) { 354 return GetErrorHandler(); 355 } 356 357 return errorHandler; 358 } 359 360 panda_file::SourceLang lang_; 361 BootContext bootContext_; 362 363 std::array<Class *, CLASS_ROOT_COUNT> classRoots_ {}; 364 ClassLinker *classLinker_ {nullptr}; 365 366 os::memory::RecursiveMutex contextsLock_; 367 PandaVector<ClassLinkerContext *> contexts_ GUARDED_BY(contextsLock_); 368 369 os::memory::RecursiveMutex createdClassesLock_; 370 PandaVector<Class *> createdClasses_ GUARDED_BY(createdClassesLock_); 371 372 os::memory::RecursiveMutex newClassesLock_; 373 std::atomic_bool recordNewClass_ {false}; 374 PandaVector<Class *> newClasses_ GUARDED_BY(newClassesLock_); 375 376 os::memory::RecursiveMutex obsoleteClassesLock_; 377 PandaVector<Class *> obsoleteClasses_ GUARDED_BY(obsoleteClassesLock_); 378 379 bool canInitializeClasses_ {false}; 380 }; 381 382 } // namespace ark 383 384 #endif // PANDA_RUNTIME_CLASS_LINKER_EXTENSION_H_ 385