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