• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 
InitializeClass(Class * klass,ClassLinkerErrorHandler * handler)65     virtual bool InitializeClass(Class *klass, [[maybe_unused]] ClassLinkerErrorHandler *handler)
66     {
67         return InitializeClass(klass);
68     }
69 
70     virtual const void *GetNativeEntryPointFor(Method *method) const = 0;
71 
72     virtual bool CanThrowException(const Method *method) const = 0;
73 
IsMethodNativeApi(const Method * method)74     virtual bool IsMethodNativeApi([[maybe_unused]] const Method *method) const
75     {
76         return false;
77     }
78 
IsNecessarySwitchThreadState(const Method * method)79     virtual bool IsNecessarySwitchThreadState([[maybe_unused]] const Method *method) const
80     {
81         return false;
82     }
83 
CanNativeMethodUseObjects(const Method * method)84     virtual bool CanNativeMethodUseObjects([[maybe_unused]] const Method *method) const
85     {
86         return false;
87     }
88 
89     virtual ClassLinkerErrorHandler *GetErrorHandler() = 0;
90 
91     virtual ClassLinkerContext *CreateApplicationClassLinkerContext(const PandaVector<PandaString> &path);
92 
GetClassRoot(ClassRoot root)93     Class *GetClassRoot(ClassRoot root) const
94     {
95         return classRoots_[ToIndex(root)];
96     }
97 
GetBootContext()98     ClassLinkerContext *GetBootContext()
99     {
100         return &bootContext_;
101     }
102 
SetClassRoot(ClassRoot root,Class * klass)103     void SetClassRoot(ClassRoot root, Class *klass)
104     {
105         classRoots_[ToIndex(root)] = klass;
106         bootContext_.InsertClass(klass);
107     }
108 
109     Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr);
110 
111     PANDA_PUBLIC_API Class *GetClass(const uint8_t *descriptor, bool needCopyDescriptor = true,
112                                      ClassLinkerContext *context = nullptr,
113                                      ClassLinkerErrorHandler *errorHandler = nullptr);
114 
115     PANDA_PUBLIC_API Class *GetClass(const panda_file::File &pf, panda_file::File::EntityId id,
116                                      ClassLinkerContext *context = nullptr,
117                                      ClassLinkerErrorHandler *errorHandler = nullptr);
118 
GetLanguage()119     panda_file::SourceLang GetLanguage() const
120     {
121         return lang_;
122     }
123 
GetClassLinker()124     ClassLinker *GetClassLinker() const
125     {
126         return classLinker_;
127     }
128 
IsInitialized()129     bool IsInitialized() const
130     {
131         return classLinker_ != nullptr;
132     }
133 
CanInitializeClasses()134     bool CanInitializeClasses()
135     {
136         return canInitializeClasses_;
137     }
138 
RecordNewRoot(mem::VisitGCRootFlags flags)139     void RecordNewRoot(mem::VisitGCRootFlags flags)
140     {
141         ASSERT(BitCount(flags & (mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT |
142                                  mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT)) <= 1);
143         if ((flags & mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT) != 0) {
144             // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially
145             // consistent order where threads observe all modifications in the same order
146             recordNewClass_.store(true, std::memory_order_seq_cst);
147         } else if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) {
148             // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially
149             // consistent order where threads observe all modifications in the same order
150             recordNewClass_.store(false, std::memory_order_seq_cst);
151             os::memory::LockHolder lock(newClassesLock_);
152             newClasses_.clear();
153         }
154     }
155 
156     template <class Callback>
157     bool EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL)
158     {
159         ASSERT(BitCount(flags & (mem::VisitGCRootFlags::ACCESS_ROOT_ALL | mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW |
160                                  mem::VisitGCRootFlags::ACCESS_ROOT_NONE)) == 1);
161         if (((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) ||
162             ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0)) {
163             os::memory::LockHolder lock(createdClassesLock_);
164             for (const auto &cls : createdClasses_) {
165                 if (!cb(cls)) {
166                     return false;
167                 }
168             }
169         }
170         if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0) {
171             os::memory::LockHolder lock(newClassesLock_);
172             for (const auto &cls : newClasses_) {
173                 if (!cb(cls)) {
174                     return false;
175                 }
176             }
177         }
178 
179         if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) {
180             if (!bootContext_.EnumerateClasses(cb)) {
181                 return false;
182             }
183 
184             {
185                 os::memory::LockHolder lock(contextsLock_);
186                 for (auto *ctx : contexts_) {
187                     if (!ctx->EnumerateClasses(cb)) {
188                         return false;
189                     }
190                 }
191             }
192         }
193 
194         {
195             os::memory::LockHolder lock(obsoleteClassesLock_);
196             for (const auto &cls : obsoleteClasses_) {
197                 if (!cb(cls)) {
198                     return false;
199                 }
200             }
201         }
202 
203         RecordNewRoot(flags);
204 
205         return true;
206     }
207 
208     template <class ContextGetterFn>
RegisterContext(const ContextGetterFn & fn)209     void RegisterContext(const ContextGetterFn &fn)
210     {
211         os::memory::LockHolder lock(contextsLock_);
212         auto *context = fn();
213         if (context != nullptr) {
214             contexts_.push_back(context);
215         }
216     }
217 
218     template <class Callback>
EnumerateContexts(const Callback & cb)219     void EnumerateContexts(const Callback &cb)
220     {
221         if (!cb(&bootContext_)) {
222             return;
223         }
224 
225         os::memory::LockHolder lock(contextsLock_);
226         for (auto *context : contexts_) {
227             if (!cb(context)) {
228                 return;
229             }
230         }
231     }
232 
233     size_t NumLoadedClasses();
234 
235     void VisitLoadedClasses(size_t flag);
236 
ResolveContext(ClassLinkerContext * context)237     ClassLinkerContext *ResolveContext(ClassLinkerContext *context)
238     {
239         if (context == nullptr) {
240             return &bootContext_;
241         }
242 
243         return context;
244     }
245 
246     void OnClassPrepared(Class *klass);
247 
248     // Saving obsolete data after hotreload to enable it to be executed
249     void AddObsoleteClass(const PandaVector<ark::Class *> &classes);
250     void FreeObsoleteData();
251 
252     virtual Class *FromClassObject(ObjectHeader *obj);
253 
254     virtual size_t GetClassObjectSizeFromClassSize(uint32_t size);
255 
CanScalarReplaceObject(Class * klass)256     virtual bool CanScalarReplaceObject([[maybe_unused]] Class *klass)
257     {
258         return true;
259     }
260 
261     NO_COPY_SEMANTIC(ClassLinkerExtension);
262     NO_MOVE_SEMANTIC(ClassLinkerExtension);
263 
264 protected:
265     void InitializePrimitiveClassRoot(ClassRoot root, panda_file::Type::TypeId typeId, const char *descriptor);
266 
267     void InitializeArrayClassRoot(ClassRoot root, ClassRoot componentRoot, const char *descriptor);
268 
269     void FreeLoadedClasses();
270 
271     Class *AddClass(Class *klass);
272 
273     // Add the class to the list, when it is just be created and not add to class linker context.
274     void AddCreatedClass(Class *klass);
275 
276     // Remove class in the list, when it has been added to class linker context.
277     void RemoveCreatedClass(Class *klass);
278 
279     using PandaFilePtr = std::unique_ptr<const panda_file::File>;
280     virtual ClassLinkerContext *CreateApplicationClassLinkerContext(PandaVector<PandaFilePtr> &&appFiles);
281 
282 private:
283     class BootContext : public ClassLinkerContext {
284     public:
BootContext(ClassLinkerExtension * extension)285         explicit BootContext(ClassLinkerExtension *extension)
286             : ClassLinkerContext(extension->GetLanguage()), extension_(extension)
287         {
288         }
289 
IsBootContext()290         bool IsBootContext() const override
291         {
292             return true;
293         }
294 
295         Class *LoadClass(const uint8_t *descriptor, bool needCopyDescriptor,
296                          ClassLinkerErrorHandler *errorHandler) override;
297 
298         void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override;
299 
300     private:
301         ClassLinkerExtension *extension_;
302     };
303 
304     class AppContext : public ClassLinkerContext {
305     public:
AppContext(ClassLinkerExtension * extension,PandaVector<const panda_file::File * > && pfList)306         explicit AppContext(ClassLinkerExtension *extension, PandaVector<const panda_file::File *> &&pfList)
307             : ClassLinkerContext(extension->GetLanguage()), extension_(extension), pfs_(pfList)
308         {
309         }
310 
311         Class *LoadClass(const uint8_t *descriptor, bool needCopyDescriptor,
312                          ClassLinkerErrorHandler *errorHandler) override;
313 
EnumeratePandaFiles(const std::function<bool (const panda_file::File &)> & cb)314         void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> &cb) const override
315         {
316             for (auto &pf : pfs_) {
317                 if (pf == nullptr) {
318                     continue;
319                 }
320                 if (!cb(*pf)) {
321                     break;
322                 }
323             }
324         }
325 
GetPandaFilePaths()326         PandaVector<std::string_view> GetPandaFilePaths() const override
327         {
328             PandaVector<std::string_view> filePaths;
329             for (auto &pf : pfs_) {
330                 if (pf != nullptr) {
331                     filePaths.emplace_back(pf->GetFilename());
332                 }
333             }
334             return filePaths;
335         }
336 
337     private:
338         ClassLinkerExtension *extension_;
339         PandaVector<const panda_file::File *> pfs_;
340     };
341 
342     static constexpr size_t CLASS_ROOT_COUNT = static_cast<size_t>(ClassRoot::LAST_CLASS_ROOT_ENTRY) + 1;
343 
344     virtual bool InitializeImpl(bool compressedStringEnabled) = 0;
345 
ToIndex(ClassRoot root)346     static constexpr size_t ToIndex(ClassRoot root)
347     {
348         return static_cast<size_t>(root);
349     }
350 
ResolveErrorHandler(ClassLinkerErrorHandler * errorHandler)351     ClassLinkerErrorHandler *ResolveErrorHandler(ClassLinkerErrorHandler *errorHandler)
352     {
353         if (errorHandler == nullptr) {
354             return GetErrorHandler();
355         }
356 
357         return errorHandler;
358     }
359 
360     panda_file::SourceLang lang_;
361     BootContext bootContext_;
362 
363     std::array<Class *, CLASS_ROOT_COUNT> classRoots_ {};
364     ClassLinker *classLinker_ {nullptr};
365 
366     os::memory::RecursiveMutex contextsLock_;
367     PandaVector<ClassLinkerContext *> contexts_ GUARDED_BY(contextsLock_);
368 
369     os::memory::RecursiveMutex createdClassesLock_;
370     PandaVector<Class *> createdClasses_ GUARDED_BY(createdClassesLock_);
371 
372     os::memory::RecursiveMutex newClassesLock_;
373     std::atomic_bool recordNewClass_ {false};
374     PandaVector<Class *> newClasses_ GUARDED_BY(newClassesLock_);
375 
376     os::memory::RecursiveMutex obsoleteClassesLock_;
377     PandaVector<Class *> obsoleteClasses_ GUARDED_BY(obsoleteClassesLock_);
378 
379     bool canInitializeClasses_ {false};
380 };
381 
382 }  // namespace ark
383 
384 #endif  // PANDA_RUNTIME_CLASS_LINKER_EXTENSION_H_
385