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