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