• 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_H_
16 #define PANDA_RUNTIME_CLASS_LINKER_H_
17 
18 #include <memory>
19 #include <optional>
20 #include <string>
21 #include <string_view>
22 #include <vector>
23 
24 #include "compiler/aot/aot_manager.h"
25 #include "libpandabase/mem/arena_allocator.h"
26 #include "libpandabase/os/mutex.h"
27 #include "libpandabase/utils/utf.h"
28 #include "libpandafile/class_data_accessor-inl.h"
29 #include "libpandafile/file.h"
30 #include "libpandafile/file_items.h"
31 #include "runtime/class_linker_context.h"
32 #include "runtime/include/class.h"
33 #include "runtime/include/field.h"
34 #include "runtime/include/itable_builder.h"
35 #include "runtime/include/imtable_builder.h"
36 #include "runtime/include/language_context.h"
37 #include "runtime/include/mem/panda_containers.h"
38 #include "runtime/include/mem/panda_smart_pointers.h"
39 #include "runtime/include/mem/panda_string.h"
40 #include "runtime/include/method.h"
41 #include "runtime/include/vtable_builder_interface.h"
42 
43 namespace ark {
44 
45 using compiler::AotManager;
46 
47 class ClassLinkerErrorHandler;
48 
49 class ClassLinker {
50 public:
51     enum class Error {
52         CLASS_NOT_FOUND,
53         FIELD_NOT_FOUND,
54         METHOD_NOT_FOUND,
55         NO_CLASS_DEF,
56         CLASS_CIRCULARITY,
57         OVERRIDES_FINAL,
58         MULTIPLE_OVERRIDE,
59         MULTIPLE_IMPLEMENT,
60         INVALID_LAMBDA_CLASS,
61     };
62 
63     ClassLinker(mem::InternalAllocatorPtr allocator, std::vector<std::unique_ptr<ClassLinkerExtension>> &&extensions);
64 
65     ~ClassLinker();
66 
67     bool Initialize(bool compressedStringEnabled = true);
68 
69     bool InitializeRoots(ManagedThread *thread);
70 
71     PANDA_PUBLIC_API Class *GetClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
72                                      ClassLinkerErrorHandler *errorHandler = nullptr);
73 
74     PANDA_PUBLIC_API Class *GetClass(const panda_file::File &pf, panda_file::File::EntityId id,
75                                      ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler = nullptr);
76 
77     PANDA_PUBLIC_API Class *GetClass(const Method &caller, panda_file::File::EntityId id,
78                                      ClassLinkerErrorHandler *errorHandler = nullptr);
79 
80     inline Class *GetLoadedClass(const panda_file::File &pf, panda_file::File::EntityId id,
81                                  ClassLinkerContext *context);
82 
83     Class *LoadClass(const panda_file::File &pf, panda_file::File::EntityId classId, ClassLinkerContext *context,
84                      ClassLinkerErrorHandler *errorHandler = nullptr, bool addToRuntime = true)
85     {
86         return LoadClass(&pf, classId, pf.GetStringData(classId).data, context, errorHandler, addToRuntime);
87     }
88 
89     Method *GetMethod(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context = nullptr,
90                       ClassLinkerErrorHandler *errorHandler = nullptr);
91 
92     Method *GetMethod(const Method &caller, panda_file::File::EntityId id,
93                       ClassLinkerErrorHandler *errorHandler = nullptr);
94 
95     Field *GetField(const panda_file::File &pf, panda_file::File::EntityId id, bool isStatic,
96                     ClassLinkerContext *context = nullptr, ClassLinkerErrorHandler *errorHandler = nullptr);
97 
98     Field *GetField(const Method &caller, panda_file::File::EntityId id, bool isStatic,
99                     ClassLinkerErrorHandler *errorHandler = nullptr);
100 
101     PANDA_PUBLIC_API void AddPandaFile(std::unique_ptr<const panda_file::File> &&pf,
102                                        ClassLinkerContext *context = nullptr);
103 
104     template <typename Callback>
105     void EnumeratePandaFiles(Callback cb, bool skipIntrinsics = true) const
106     {
107         os::memory::LockHolder lock(pandaFilesLock_);
108         for (const auto &fileData : pandaFiles_) {
109             if (skipIntrinsics && fileData.pf->GetFilename().empty()) {
110                 continue;
111             }
112 
113             if (!cb(*fileData.pf)) {
114                 break;
115             }
116         }
117     }
118 
119     template <typename Callback>
EnumerateBootPandaFiles(Callback cb)120     void EnumerateBootPandaFiles(Callback cb) const
121     {
122         os::memory::LockHolder lock {bootPandaFilesLock_};
123         for (const auto &file : bootPandaFiles_) {
124             if (!cb(*file)) {
125                 break;
126             }
127         }
128     }
129 
GetBootPandaFiles()130     const PandaVector<const panda_file::File *> &GetBootPandaFiles() const
131     {
132         return bootPandaFiles_;
133     }
134 
GetAotManager()135     AotManager *GetAotManager()
136     {
137         return aotManager_.get();
138     }
139 
140     PandaString GetClassContextForAot(bool useAbsPath = true)
141     {
142         PandaString aotCtx;
143         EnumeratePandaFiles(compiler::AotClassContextCollector(&aotCtx, useAbsPath));
144         return aotCtx;
145     }
146 
147     template <class Callback>
148     void EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL)
149     {
150         for (auto &ext : extensions_) {
151             if (ext == nullptr) {
152                 continue;
153             }
154 
155             if (!ext->EnumerateClasses(cb, flags)) {
156                 return;
157             }
158         }
159     }
160 
161     template <class Callback>
EnumerateContexts(const Callback & cb)162     void EnumerateContexts(const Callback &cb)
163     {
164         for (auto &ext : extensions_) {
165             if (ext == nullptr) {
166                 continue;
167             }
168             ext->EnumerateContexts(cb);
169         }
170     }
171 
172     template <class Callback>
EnumerateContextsForDump(const Callback & cb,std::ostream & os)173     void EnumerateContextsForDump(const Callback &cb, std::ostream &os)
174     {
175         auto findParent = [](ClassLinkerContext *parent, ClassLinkerContext *ctxPtr, size_t &parentIndex,
176                              bool &founded) {
177             if (parent == ctxPtr) {
178                 founded = true;
179                 return false;
180             }
181             parentIndex++;
182             return true;
183         };
184 
185         size_t registerIndex = 0;
186         ClassLinkerContext *parent = nullptr;
187         ClassLinkerExtension *ext = nullptr;
188 
189         auto enumCallback = [&registerIndex, &parent, &cb, &os, &ext, &findParent](ClassLinkerContext *ctx) {
190             os << "#" << registerIndex << " ";
191             if (!cb(ctx, os, parent)) {
192                 return true;
193             }
194             if (parent != nullptr) {
195                 size_t parentIndex = 0;
196                 bool founded = false;
197                 ext->EnumerateContexts([parent, &parentIndex, &founded, &findParent](ClassLinkerContext *ctxPtr) {
198                     return findParent(parent, ctxPtr, parentIndex, founded);
199                 });
200                 if (founded) {
201                     os << "|Parent class loader: #" << parentIndex << "\n";
202                 } else {
203                     os << "|Parent class loader: unknown\n";
204                 }
205             } else {
206                 os << "|Parent class loader: empty\n";
207             }
208             registerIndex++;
209             return true;
210         };
211         for (auto &extPtr : extensions_) {
212             if (extPtr == nullptr) {
213                 continue;
214             }
215             ext = extPtr.get();
216             ext->EnumerateContexts(enumCallback);
217         }
218     }
219 
220     PANDA_PUBLIC_API bool InitializeClass(ManagedThread *thread, Class *klass);
221 
HasExtension(const LanguageContext & ctx)222     bool HasExtension(const LanguageContext &ctx)
223     {
224         return extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get() != nullptr;
225     }
226 
HasExtension(panda_file::SourceLang lang)227     bool HasExtension(panda_file::SourceLang lang)
228     {
229         return extensions_[ark::panda_file::GetLangArrIndex(lang)].get() != nullptr;
230     }
231 
232     void ResetExtension(panda_file::SourceLang lang);
233 
GetExtension(const LanguageContext & ctx)234     ClassLinkerExtension *GetExtension(const LanguageContext &ctx)
235     {
236         ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get();
237         ASSERT(extension != nullptr);
238         return extension;
239     };
240 
GetExtension(panda_file::SourceLang lang)241     ClassLinkerExtension *GetExtension(panda_file::SourceLang lang)
242     {
243         ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(lang)].get();
244         ASSERT(extension != nullptr);
245         return extension;
246     };
247 
ObjectToClass(const ObjectHeader * object)248     Class *ObjectToClass(const ObjectHeader *object)
249     {
250         ASSERT(object);
251         ASSERT(object->ClassAddr<Class>());
252         ASSERT(object->ClassAddr<Class>()->IsClassClass());
253         return extensions_[ark::panda_file::GetLangArrIndex(object->ClassAddr<BaseClass>()->GetSourceLang())]
254             ->FromClassObject(const_cast<ObjectHeader *>(object));
255     }
256 
GetClassObjectSize(Class * cls,panda_file::SourceLang lang)257     size_t GetClassObjectSize(Class *cls, panda_file::SourceLang lang)
258     {
259         // We can't get SourceLang from cls, because it may not be initialized yet (see #12894)
260         return extensions_[ark::panda_file::GetLangArrIndex(lang)]->GetClassObjectSizeFromClassSize(
261             cls->GetClassSize());
262     }
263 
264     void AddClassRoot(ClassRoot root, Class *klass);
265 
266     Class *CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor,
267                             Class *componentClass);
268 
269     void FreeClassData(Class *classPtr);
270 
271     void FreeClass(Class *classPtr);
272 
GetAllocator()273     mem::InternalAllocatorPtr GetAllocator() const
274     {
275         return allocator_;
276     }
277 
IsInitialized()278     bool IsInitialized() const
279     {
280         return isInitialized_;
281     }
282 
283     Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr);
284 
285     size_t NumLoadedClasses();
286 
287     void VisitLoadedClasses(size_t flag);
288 
289     PANDA_PUBLIC_API Class *BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags,
290                                        Span<Method> methods, Span<Field> fields, Class *baseClass,
291                                        Span<Class *> interfaces, ClassLinkerContext *context, bool isInterface);
292 
IsPandaFileRegistered(const panda_file::File * file)293     bool IsPandaFileRegistered(const panda_file::File *file)
294     {
295         os::memory::LockHolder lock(pandaFilesLock_);
296         for (const auto &data : pandaFiles_) {
297             if (data.pf.get() == file) {
298                 return true;
299             }
300         }
301 
302         return false;
303     }
304 
GetAppContext(std::string_view pandaFile)305     ClassLinkerContext *GetAppContext(std::string_view pandaFile)
306     {
307         ClassLinkerContext *appContext = nullptr;
308         EnumerateContexts([pandaFile, &appContext](ClassLinkerContext *context) -> bool {
309             auto filePaths = context->GetPandaFilePaths();
310             for (auto &file : filePaths) {
311                 if (file == pandaFile) {
312                     appContext = context;
313                     return false;
314                 }
315             }
316             return true;
317         });
318         return appContext;
319     }
320 
321     void RemoveCreatedClassInExtension(Class *klass);
322 
323     Class *LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang);
324 
325 private:
326     struct ClassInfo {
327         PandaUniquePtr<VTableBuilder> vtableBuilder;
328         PandaUniquePtr<ITableBuilder> itableBuilder;
329         PandaUniquePtr<IMTableBuilder> imtableBuilder;
330         size_t size;
331         size_t numSfields;
332     };
333 
334     bool LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext,
335                                   const uint8_t *descriptor);
336 
337     Field *GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
338                         ClassLinkerErrorHandler *errorHandler, bool isStatic);
339 
340     Field *GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
341                                ClassLinkerErrorHandler *errorHandler, bool isStatic);
342 
343     Method *GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor,
344                       ClassLinkerErrorHandler *errorHandler);
345 
346     bool LinkBootClass(Class *klass);
347 
348     Class *LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
349                           ClassLinkerErrorHandler *errorHandler);
350 
351     Class *LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor,
352                      ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler, bool addToRuntime = true);
353 
354     Class *LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor, Class *baseClass,
355                      Span<Class *> interfaces, ClassLinkerContext *context, ClassLinkerExtension *ext,
356                      ClassLinkerErrorHandler *errorHandler);
357 
358     Class *LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx, ClassLinkerContext *context,
359                          ClassLinkerErrorHandler *errorHandler);
360 
361     std::optional<Span<Class *>> LoadInterfaces(panda_file::ClassDataAccessor *cda, ClassLinkerContext *context,
362                                                 ClassLinkerErrorHandler *errorHandler);
363 
364     void FreeITableAndInterfaces(ITable itable, Span<Class *> &interfaces);
365 
366     [[nodiscard]] bool LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler);
367 
368     [[nodiscard]] bool LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor,
369                                   ClassLinkerErrorHandler *errorHandler);
370 
371     [[nodiscard]] bool LinkMethods(Class *klass, ClassInfo *classInfo, ClassLinkerErrorHandler *errorHandler);
372 
373     [[nodiscard]] bool LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor,
374                                    ClassLinkerErrorHandler *errorHandler);
375 
376     [[nodiscard]] bool SetupClassInfo(ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base,
377                                       Span<Class *> interfaces, ClassLinkerContext *context,
378                                       ClassLinkerErrorHandler *errorHandler);
379 
380     [[nodiscard]] bool SetupClassInfo(ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base,
381                                       Span<Class *> interfaces, bool isInterface,
382                                       ClassLinkerErrorHandler *errorHandler);
383 
384     static bool LayoutFields(Class *klass, Span<Field> fields, bool isStatic, ClassLinkerErrorHandler *errorHandler);
385 
386     mem::InternalAllocatorPtr allocator_;
387 
388     PandaVector<const panda_file::File *> bootPandaFiles_ GUARDED_BY(bootPandaFilesLock_);
389 
390     struct PandaFileLoadData {
391         ClassLinkerContext *context;
392         std::unique_ptr<const panda_file::File> pf;
393     };
394 
395     mutable os::memory::Mutex pandaFilesLock_;
396     mutable os::memory::Mutex bootPandaFilesLock_;
397     PandaVector<PandaFileLoadData> pandaFiles_ GUARDED_BY(pandaFilesLock_);
398 
399     PandaUniquePtr<AotManager> aotManager_;
400     // Just to free them at destroy
401     os::memory::Mutex copiedNamesLock_;
402     PandaList<const uint8_t *> copiedNames_ GUARDED_BY(copiedNamesLock_);
403 
404     std::array<std::unique_ptr<ClassLinkerExtension>, ark::panda_file::LANG_COUNT> extensions_;
405 
406     bool isInitialized_ {false};
407 
408     NO_COPY_SEMANTIC(ClassLinker);
409     NO_MOVE_SEMANTIC(ClassLinker);
410 };
411 
412 class ClassLinkerErrorHandler {
413 public:
414     virtual void OnError(ClassLinker::Error error, const PandaString &message) = 0;
415 
416 public:
417     ClassLinkerErrorHandler() = default;
418     virtual ~ClassLinkerErrorHandler() = default;
419 
420     NO_MOVE_SEMANTIC(ClassLinkerErrorHandler);
421     NO_COPY_SEMANTIC(ClassLinkerErrorHandler);
422 };
423 
424 }  // namespace ark
425 
426 #endif  // PANDA_RUNTIME_CLASS_LINKER_H_
427