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