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