• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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