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