• 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 
16 #include "runtime/include/class_linker_extension.h"
17 
18 #include "libpandabase/utils/utf.h"
19 #include "runtime/include/class_linker-inl.h"
20 #include "runtime/include/class_linker.h"
21 #include "runtime/include/coretypes/class.h"
22 #include "runtime/include/runtime.h"
23 #include "runtime/include/thread.h"
24 
25 namespace panda {
26 
~ClassLinkerExtension()27 ClassLinkerExtension::~ClassLinkerExtension()
28 {
29     os::memory::LockHolder lock(contexts_lock_);
30     for (auto *ctx : contexts_) {
31         class_linker_->GetAllocator()->Delete(ctx);
32     }
33 }
34 
LoadClass(const uint8_t * descriptor,bool need_copy_descriptor,ClassLinkerErrorHandler * error_handler)35 Class *ClassLinkerExtension::BootContext::LoadClass(const uint8_t *descriptor, bool need_copy_descriptor,
36                                                     ClassLinkerErrorHandler *error_handler)
37 {
38     ASSERT(extension_->IsInitialized());
39 
40     return extension_->GetClassLinker()->GetClass(descriptor, need_copy_descriptor, this, error_handler);
41 }
42 
EnumeratePandaFiles(const std::function<bool (const panda_file::File &)> & cb) const43 void ClassLinkerExtension::BootContext::EnumeratePandaFiles(
44     const std::function<bool(const panda_file::File &)> &cb) const
45 {
46     extension_->GetClassLinker()->EnumerateBootPandaFiles(cb);
47 }
48 
49 class SuppressErrorHandler : public ClassLinkerErrorHandler {
OnError(ClassLinker::Error error,const PandaString & message)50     void OnError([[maybe_unused]] ClassLinker::Error error, [[maybe_unused]] const PandaString &message) override {}
51 };
52 
LoadClass(const uint8_t * descriptor,bool need_copy_descriptor,ClassLinkerErrorHandler * error_handler)53 Class *ClassLinkerExtension::AppContext::LoadClass(const uint8_t *descriptor, bool need_copy_descriptor,
54                                                    ClassLinkerErrorHandler *error_handler)
55 {
56     ASSERT(extension_->IsInitialized());
57 
58     SuppressErrorHandler handler;
59     auto *cls = extension_->GetClass(descriptor, need_copy_descriptor, nullptr, &handler);
60     if (cls != nullptr) {
61         return cls;
62     }
63 
64     for (auto &pf : pfs_) {
65         auto class_id = pf->GetClassId(descriptor);
66         if (!class_id.IsValid() || pf->IsExternal(class_id)) {
67             continue;
68         }
69         return extension_->GetClassLinker()->LoadClass(*pf, class_id, this, error_handler);
70     }
71 
72     if (error_handler != nullptr) {
73         PandaStringStream ss;
74         ss << "Cannot find class " << descriptor << " in all app panda files";
75         error_handler->OnError(ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
76     }
77     return nullptr;
78 }
79 
InitializeArrayClassRoot(ClassRoot root,ClassRoot component_root,const char * descriptor)80 void ClassLinkerExtension::InitializeArrayClassRoot(ClassRoot root, ClassRoot component_root, const char *descriptor)
81 {
82     ASSERT(IsInitialized());
83 
84     auto *array_class = CreateClass(utf::CStringAsMutf8(descriptor), GetClassVTableSize(root), GetClassIMTSize(root),
85                                     GetClassSize(root));
86     array_class->SetLoadContext(&boot_context_);
87     auto *component_class = GetClassRoot(component_root);
88     InitializeArrayClass(array_class, component_class);
89 
90     AddClass(array_class);
91     SetClassRoot(root, array_class);
92 }
93 
InitializePrimitiveClassRoot(ClassRoot root,panda_file::Type::TypeId type_id,const char * descriptor)94 void ClassLinkerExtension::InitializePrimitiveClassRoot(ClassRoot root, panda_file::Type::TypeId type_id,
95                                                         const char *descriptor)
96 {
97     ASSERT(IsInitialized());
98 
99     auto *primitive_class = CreateClass(utf::CStringAsMutf8(descriptor), GetClassVTableSize(root),
100                                         GetClassIMTSize(root), GetClassSize(root));
101     primitive_class->SetType(panda_file::Type(type_id));
102     primitive_class->SetLoadContext(&boot_context_);
103     InitializePrimitiveClass(primitive_class);
104     AddClass(primitive_class);
105     SetClassRoot(root, primitive_class);
106 }
107 
Initialize(ClassLinker * class_linker,bool compressed_string_enabled)108 bool ClassLinkerExtension::Initialize(ClassLinker *class_linker, bool compressed_string_enabled)
109 {
110     class_linker_ = class_linker;
111     InitializeImpl(compressed_string_enabled);
112 
113     can_initialize_classes_ = true;
114     // Copy classes to separate container as ClassLinkerExtension::InitializeClass
115     // can load more classes and modify boot context
116     PandaVector<Class *> klasses;
117     boot_context_.EnumerateClasses([&klasses](Class *klass) {
118         if (!klass->IsLoaded()) {
119             klasses.push_back(klass);
120         }
121         return true;
122     });
123 
124     for (auto *klass : klasses) {
125         if (klass->IsLoaded()) {
126             continue;
127         }
128 
129         InitializeClass(klass);
130         klass->SetState(Class::State::LOADED);
131     }
132     return true;
133 }
134 
InitializeRoots(ManagedThread * thread)135 bool ClassLinkerExtension::InitializeRoots(ManagedThread *thread)
136 {
137     ASSERT(IsInitialized());
138 
139     for (auto *klass : class_roots_) {
140         if (klass == nullptr) {
141             continue;
142         }
143 
144         if (!class_linker_->InitializeClass(thread, klass)) {
145             LOG(FATAL, CLASS_LINKER) << "Failed to initialize class '" << klass->GetName() << "'";
146             return false;
147         }
148     }
149 
150     return true;
151 }
152 
FindLoadedClass(const uint8_t * descriptor,ClassLinkerContext * context)153 Class *ClassLinkerExtension::FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context /* = nullptr */)
154 {
155     return class_linker_->FindLoadedClass(descriptor, ResolveContext(context));
156 }
157 
GetClass(const uint8_t * descriptor,bool need_copy_descriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * error_handler)158 Class *ClassLinkerExtension::GetClass(const uint8_t *descriptor, bool need_copy_descriptor /* = true */,
159                                       ClassLinkerContext *context /* = nullptr */,
160                                       ClassLinkerErrorHandler *error_handler /* = nullptr */)
161 {
162     ASSERT(IsInitialized());
163 
164     return class_linker_->GetClass(descriptor, need_copy_descriptor, ResolveContext(context),
165                                    ResolveErrorHandler(error_handler));
166 }
167 
WrapClassNotFoundExceptionIfNeeded(ClassLinker * class_linker,const uint8_t * descriptor,const LanguageContext & ctx)168 static void WrapClassNotFoundExceptionIfNeeded(ClassLinker *class_linker, const uint8_t *descriptor,
169                                                const LanguageContext &ctx)
170 {
171     auto *thread = ManagedThread::GetCurrent();
172     if (thread == nullptr || !thread->HasPendingException()) {
173         return;
174     }
175 
176     auto *class_not_found_exception_class =
177         class_linker->GetExtension(ctx)->GetClass(ctx.GetClassNotFoundExceptionDescriptor());
178     if (class_not_found_exception_class == nullptr) {
179         // We've got OOM
180         ASSERT(thread->GetVM()->GetOOMErrorObject() == nullptr ||
181                thread->GetException()->ClassAddr<Class>() == thread->GetVM()->GetOOMErrorObject()->ClassAddr<Class>());
182         return;
183     }
184     ASSERT(class_not_found_exception_class != nullptr);
185 
186     auto *cause = thread->GetException();
187     if (cause->IsInstanceOf(class_not_found_exception_class)) {
188         auto name = ClassHelper::GetName(descriptor);
189         panda::ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(name.c_str()));
190     }
191 }
192 
GetClass(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * error_handler)193 Class *ClassLinkerExtension::GetClass(const panda_file::File &pf, panda_file::File::EntityId id,
194                                       ClassLinkerContext *context /* = nullptr */,
195                                       ClassLinkerErrorHandler *error_handler /* = nullptr */)
196 {
197     ASSERT(IsInitialized());
198 
199     auto *cls = class_linker_->GetClass(pf, id, ResolveContext(context), ResolveErrorHandler(error_handler));
200 
201     if (UNLIKELY(cls == nullptr)) {
202         auto *descriptor = pf.GetStringData(id).data;
203         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(GetLanguage());
204         WrapClassNotFoundExceptionIfNeeded(class_linker_, descriptor, ctx);
205     }
206 
207     return cls;
208 }
209 
AddClass(Class * klass)210 Class *ClassLinkerExtension::AddClass(Class *klass)
211 {
212     ASSERT(IsInitialized());
213 
214     auto *context = klass->GetLoadContext();
215 
216     auto *other_klass = ResolveContext(context)->InsertClass(klass);
217     if (other_klass != nullptr) {
218         class_linker_->FreeClass(klass);
219         return other_klass;
220     }
221     OnClassPrepared(klass);
222 
223     return klass;
224 }
225 
NumLoadedClasses()226 size_t ClassLinkerExtension::NumLoadedClasses()
227 {
228     ASSERT(IsInitialized());
229 
230     size_t sum = boot_context_.NumLoadedClasses();
231 
232     {
233         os::memory::LockHolder lock(contexts_lock_);
234         for (auto *ctx : contexts_) {
235             sum += ctx->NumLoadedClasses();
236         }
237     }
238     return sum;
239 }
240 
VisitLoadedClasses(size_t flag)241 void ClassLinkerExtension::VisitLoadedClasses(size_t flag)
242 {
243     boot_context_.VisitLoadedClasses(flag);
244     {
245         os::memory::LockHolder lock(contexts_lock_);
246         for (auto *ctx : contexts_) {
247             ctx->VisitLoadedClasses(flag);
248         }
249     }
250 }
251 
FreeLoadedClasses()252 void ClassLinkerExtension::FreeLoadedClasses()
253 {
254     ASSERT(IsInitialized());
255 
256     boot_context_.EnumerateClasses([this](Class *klass) {
257         FreeClass(klass);
258         class_linker_->FreeClassData(klass);
259         return true;
260     });
261     {
262         os::memory::LockHolder lock(contexts_lock_);
263         for (auto *ctx : contexts_) {
264             ctx->EnumerateClasses([this](Class *klass) {
265                 FreeClass(klass);
266                 class_linker_->FreeClassData(klass);
267                 return true;
268             });
269         }
270     }
271 }
272 
CreateApplicationClassLinkerContext(const PandaVector<PandaString> & path)273 ClassLinkerContext *ClassLinkerExtension::CreateApplicationClassLinkerContext(const PandaVector<PandaString> &path)
274 {
275     PandaVector<PandaFilePtr> app_files;
276     for (auto &pf_path : path) {
277         auto pf = panda_file::OpenPandaFileOrZip(pf_path);
278         if (pf == nullptr) {
279             return nullptr;
280         }
281         app_files.push_back(std::move(pf));
282     }
283     ClassLinkerContext *ctx = CreateApplicationClassLinkerContext(std::move(app_files));
284     return ctx;
285 }
286 
CreateApplicationClassLinkerContext(PandaVector<PandaFilePtr> && app_files)287 ClassLinkerContext *ClassLinkerExtension::CreateApplicationClassLinkerContext(PandaVector<PandaFilePtr> &&app_files)
288 {
289     PandaVector<const panda_file::File *> app_file_ptrs;
290     app_file_ptrs.reserve(app_files.size());
291     for (auto &pf : app_files) {
292         app_file_ptrs.emplace_back(pf.get());
293     }
294 
295     auto allocator = class_linker_->GetAllocator();
296     auto *ctx = allocator->New<AppContext>(this, std::move(app_file_ptrs));
297     RegisterContext([ctx]() { return ctx; });
298     for (auto &pf : app_files) {
299         class_linker_->AddPandaFile(std::move(pf), ctx);
300     }
301     return ctx;
302 }
303 
AddCreatedClass(Class * klass)304 void ClassLinkerExtension::AddCreatedClass(Class *klass)
305 {
306     os::memory::LockHolder lock(created_classes_lock_);
307     created_classes_.push_back(klass);
308 }
309 
RemoveCreatedClass(Class * klass)310 void ClassLinkerExtension::RemoveCreatedClass(Class *klass)
311 {
312     os::memory::LockHolder lock(created_classes_lock_);
313     auto it = find(created_classes_.begin(), created_classes_.end(), klass);
314     if (it != created_classes_.end()) {
315         created_classes_.erase(it);
316     }
317 }
318 
OnClassPrepared(Class * klass)319 void ClassLinkerExtension::OnClassPrepared(Class *klass)
320 {
321     // Atomic with seq_cst order reason: data race with record_new_class_ with requirement for sequentially
322     // consistent order where threads observe all modifications in the same order
323     if (record_new_class_.load(std::memory_order_seq_cst)) {
324         os::memory::LockHolder new_classes_lock(new_classes_lock_);
325         new_classes_.push_back(klass);
326     }
327 
328     RemoveCreatedClass(klass);
329 }
330 
FromClassObject(ObjectHeader * obj)331 Class *ClassLinkerExtension::FromClassObject(ObjectHeader *obj)
332 {
333     return (obj != nullptr) ? ((reinterpret_cast<panda::coretypes::Class *>(obj))->GetRuntimeClass()) : nullptr;
334 }
335 
GetClassObjectSizeFromClassSize(uint32_t size)336 size_t ClassLinkerExtension::GetClassObjectSizeFromClassSize(uint32_t size)
337 {
338     return panda::coretypes::Class::GetSize(size);
339 }
340 
FreeObsoleteData()341 void ClassLinkerExtension::FreeObsoleteData()
342 {
343     os::memory::LockHolder lock(obsolete_classes_lock_);
344     for (auto &cls : obsolete_classes_) {
345         ASSERT(cls != nullptr);
346         GetClassLinker()->FreeClass(cls);
347     }
348 }
349 
AddObsoleteClass(const PandaVector<Class * > & classes)350 void ClassLinkerExtension::AddObsoleteClass(const PandaVector<Class *> &classes)
351 {
352     if (classes.empty()) {
353         return;
354     }
355     os::memory::LockHolder lock(obsolete_classes_lock_);
356     obsolete_classes_.insert(obsolete_classes_.end(), classes.begin(), classes.end());
357 }
358 
359 }  // namespace panda
360