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