• 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         auto findParent = [](ClassLinkerContext *parent, ClassLinkerContext *ctxPtr, size_t &parentIndex,
175                              bool &founded) {
176             if (parent == ctxPtr) {
177                 founded = true;
178                 return false;
179             }
180             parentIndex++;
181             return true;
182         };
183 
184         size_t registerIndex = 0;
185         ClassLinkerContext *parent = nullptr;
186         ClassLinkerExtension *ext = nullptr;
187 
188         auto enumCallback = [&registerIndex, &parent, &cb, &os, &ext, &findParent](ClassLinkerContext *ctx) {
189             os << "#" << registerIndex << " ";
190             if (!cb(ctx, os, parent)) {
191                 return true;
192             }
193             if (parent != nullptr) {
194                 size_t parentIndex = 0;
195                 bool founded = false;
196                 ext->EnumerateContexts([parent, &parentIndex, &founded, &findParent](ClassLinkerContext *ctxPtr) {
197                     return findParent(parent, ctxPtr, parentIndex, founded);
198                 });
199                 if (founded) {
200                     os << "|Parent class loader: #" << parentIndex << "\n";
201                 } else {
202                     os << "|Parent class loader: unknown\n";
203                 }
204             } else {
205                 os << "|Parent class loader: empty\n";
206             }
207             registerIndex++;
208             return true;
209         };
210         for (auto &extPtr : extensions_) {
211             if (extPtr == nullptr) {
212                 continue;
213             }
214             ext = extPtr.get();
215             ext->EnumerateContexts(enumCallback);
216         }
217     }
218 
219     PANDA_PUBLIC_API bool InitializeClass(ManagedThread *thread, Class *klass);
220 
HasExtension(const LanguageContext & ctx)221     bool HasExtension(const LanguageContext &ctx)
222     {
223         return extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get() != nullptr;
224     }
225 
HasExtension(panda_file::SourceLang lang)226     bool HasExtension(panda_file::SourceLang lang)
227     {
228         return extensions_[ark::panda_file::GetLangArrIndex(lang)].get() != nullptr;
229     }
230 
231     void ResetExtension(panda_file::SourceLang lang);
232 
GetExtension(const LanguageContext & ctx)233     ClassLinkerExtension *GetExtension(const LanguageContext &ctx)
234     {
235         ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(ctx.GetLanguage())].get();
236         ASSERT(extension != nullptr);
237         return extension;
238     };
239 
GetExtension(panda_file::SourceLang lang)240     ClassLinkerExtension *GetExtension(panda_file::SourceLang lang)
241     {
242         ClassLinkerExtension *extension = extensions_[ark::panda_file::GetLangArrIndex(lang)].get();
243         ASSERT(extension != nullptr);
244         return extension;
245     };
246 
ObjectToClass(const ObjectHeader * object)247     Class *ObjectToClass(const ObjectHeader *object)
248     {
249         ASSERT(object->ClassAddr<Class>()->IsClassClass());
250         return extensions_[ark::panda_file::GetLangArrIndex(object->ClassAddr<BaseClass>()->GetSourceLang())]
251             ->FromClassObject(const_cast<ObjectHeader *>(object));
252     }
253 
GetClassObjectSize(Class * cls,panda_file::SourceLang lang)254     size_t GetClassObjectSize(Class *cls, panda_file::SourceLang lang)
255     {
256         // We can't get SourceLang from cls, because it may not be initialized yet (see #12894)
257         return extensions_[ark::panda_file::GetLangArrIndex(lang)]->GetClassObjectSizeFromClassSize(
258             cls->GetClassSize());
259     }
260 
261     void AddClassRoot(ClassRoot root, Class *klass);
262 
263     Class *CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor,
264                             Class *componentClass);
265 
266     void FreeClassData(Class *classPtr);
267 
268     void FreeClass(Class *classPtr);
269 
GetAllocator()270     mem::InternalAllocatorPtr GetAllocator() const
271     {
272         return allocator_;
273     }
274 
IsInitialized()275     bool IsInitialized() const
276     {
277         return isInitialized_;
278     }
279 
280     Class *FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context = nullptr);
281 
282     size_t NumLoadedClasses();
283 
284     void VisitLoadedClasses(size_t flag);
285 
286     PANDA_PUBLIC_API Class *BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags,
287                                        Span<Method> methods, Span<Field> fields, Class *baseClass,
288                                        Span<Class *> interfaces, ClassLinkerContext *context, bool isInterface);
289 
IsPandaFileRegistered(const panda_file::File * file)290     bool IsPandaFileRegistered(const panda_file::File *file)
291     {
292         os::memory::LockHolder lock(pandaFilesLock_);
293         for (const auto &data : pandaFiles_) {
294             if (data.pf.get() == file) {
295                 return true;
296             }
297         }
298 
299         return false;
300     }
301 
GetAppContext(std::string_view pandaFile)302     ClassLinkerContext *GetAppContext(std::string_view pandaFile)
303     {
304         ClassLinkerContext *appContext = nullptr;
305         EnumerateContexts([pandaFile, &appContext](ClassLinkerContext *context) -> bool {
306             auto filePaths = context->GetPandaFilePaths();
307             for (auto &file : filePaths) {
308                 if (file == pandaFile) {
309                     appContext = context;
310                     return false;
311                 }
312             }
313             return true;
314         });
315         return appContext;
316     }
317 
318     void RemoveCreatedClassInExtension(Class *klass);
319 
320     Class *LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang);
321 
322 private:
323     struct ClassInfo {
324         PandaUniquePtr<VTableBuilder> vtableBuilder;
325         PandaUniquePtr<ITableBuilder> itableBuilder;
326         PandaUniquePtr<IMTableBuilder> imtableBuilder;
327         size_t size;
328         size_t numSfields;
329     };
330 
331     bool LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext,
332                                   const uint8_t *descriptor);
333 
334     Field *GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
335                         ClassLinkerErrorHandler *errorHandler);
336 
337     Field *GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
338                                ClassLinkerErrorHandler *errorHandler);
339 
340     Method *GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor,
341                       ClassLinkerErrorHandler *errorHandler);
342 
343     bool LinkBootClass(Class *klass);
344 
345     Class *LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
346                           ClassLinkerErrorHandler *errorHandler);
347 
348     Class *LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor,
349                      ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler, bool addToRuntime = true);
350 
351     Class *LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor, Class *baseClass,
352                      Span<Class *> interfaces, ClassLinkerContext *context, ClassLinkerExtension *ext,
353                      ClassLinkerErrorHandler *errorHandler);
354 
355     Class *LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx, ClassLinkerContext *context,
356                          ClassLinkerErrorHandler *errorHandler);
357 
358     std::optional<Span<Class *>> LoadInterfaces(panda_file::ClassDataAccessor *cda, ClassLinkerContext *context,
359                                                 ClassLinkerErrorHandler *errorHandler);
360 
361     [[nodiscard]] bool LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler);
362 
363     [[nodiscard]] bool LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor,
364                                   ClassLinkerErrorHandler *errorHandler);
365 
366     [[nodiscard]] bool LinkMethods(Class *klass, ClassInfo *classInfo, ClassLinkerErrorHandler *errorHandler);
367 
368     [[nodiscard]] bool LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor,
369                                    ClassLinkerErrorHandler *errorHandler);
370 
371     [[nodiscard]] bool SetupClassInfo(ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base,
372                                       Span<Class *> interfaces, ClassLinkerContext *context,
373                                       ClassLinkerErrorHandler *errorHandler);
374 
375     [[nodiscard]] bool SetupClassInfo(ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base,
376                                       Span<Class *> interfaces, bool isInterface,
377                                       ClassLinkerErrorHandler *errorHandler);
378 
379     static bool LayoutFields(Class *klass, Span<Field> fields, bool isStatic, ClassLinkerErrorHandler *errorHandler);
380 
381     mem::InternalAllocatorPtr allocator_;
382 
383     PandaVector<const panda_file::File *> bootPandaFiles_ GUARDED_BY(bootPandaFilesLock_);
384 
385     struct PandaFileLoadData {
386         ClassLinkerContext *context;
387         std::unique_ptr<const panda_file::File> pf;
388     };
389 
390     mutable os::memory::Mutex pandaFilesLock_;
391     mutable os::memory::Mutex bootPandaFilesLock_;
392     PandaVector<PandaFileLoadData> pandaFiles_ GUARDED_BY(pandaFilesLock_);
393 
394     PandaUniquePtr<AotManager> aotManager_;
395     // Just to free them at destroy
396     os::memory::Mutex copiedNamesLock_;
397     PandaList<const uint8_t *> copiedNames_ GUARDED_BY(copiedNamesLock_);
398 
399     std::array<std::unique_ptr<ClassLinkerExtension>, ark::panda_file::LANG_COUNT> extensions_;
400 
401     bool isInitialized_ {false};
402 
403     NO_COPY_SEMANTIC(ClassLinker);
404     NO_MOVE_SEMANTIC(ClassLinker);
405 };
406 
407 class ClassLinkerErrorHandler {
408 public:
409     virtual void OnError(ClassLinker::Error error, const PandaString &message) = 0;
410 
411 public:
412     ClassLinkerErrorHandler() = default;
413     virtual ~ClassLinkerErrorHandler() = default;
414 
415     NO_MOVE_SEMANTIC(ClassLinkerErrorHandler);
416     NO_COPY_SEMANTIC(ClassLinkerErrorHandler);
417 };
418 
419 }  // namespace ark
420 
421 #endif  // PANDA_RUNTIME_CLASS_LINKER_H_
422