• 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), 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