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