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