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