• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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_CONTEXT_H_
16 #define PANDA_RUNTIME_CLASS_LINKER_CONTEXT_H_
17 
18 #include <atomic>
19 #include "libpandabase/macros.h"
20 #include "libpandabase/mem/object_pointer.h"
21 #include "libpandabase/os/mutex.h"
22 #include "libpandabase/utils/bit_utils.h"
23 #include "mem/refstorage/reference.h"
24 #include "runtime/include/class.h"
25 #include "runtime/include/mem/panda_containers.h"
26 #include "runtime/mem/gc/gc.h"
27 #include "runtime/mem/gc/gc_root.h"
28 #include "runtime/mem/object_helpers.h"
29 
30 namespace ark {
31 
32 class ClassLinker;
33 class ClassLinkerErrorHandler;
34 
35 class ClassLinkerContext {
36 public:
ClassLinkerContext(panda_file::SourceLang lang)37     explicit ClassLinkerContext(panda_file::SourceLang lang) : lang_(lang) {}
38 
FindClass(const uint8_t * descriptor)39     Class *FindClass(const uint8_t *descriptor)
40     {
41         os::memory::LockHolder lock(classesLock_);
42         auto it = loadedClasses_.find(descriptor);
43         if (it != loadedClasses_.cend()) {
44             return it->second;
45         }
46 
47         return nullptr;
48     }
49 
IsBootContext()50     virtual bool IsBootContext() const
51     {
52         return false;
53     }
54 
GetSourceLang()55     panda_file::SourceLang GetSourceLang()
56     {
57         return lang_;
58     }
59 
LoadClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerErrorHandler * errorHandler)60     virtual Class *LoadClass([[maybe_unused]] const uint8_t *descriptor, [[maybe_unused]] bool needCopyDescriptor,
61                              [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
62     {
63         return nullptr;
64     }
65 
InsertClass(Class * klass)66     Class *InsertClass(Class *klass)
67     {
68         os::memory::LockHolder lock(classesLock_);
69         auto *otherKlass = FindClass(klass->GetDescriptor());
70         if (otherKlass != nullptr) {
71             return otherKlass;
72         }
73 
74         ASSERT(klass->GetSourceLang() == lang_);
75         loadedClasses_.insert({klass->GetDescriptor(), klass});
76         return nullptr;
77     }
78 
RemoveClass(Class * klass)79     void RemoveClass(Class *klass)
80     {
81         os::memory::LockHolder lock(classesLock_);
82         loadedClasses_.erase(klass->GetDescriptor());
83     }
84 
85     template <class Callback>
EnumerateClasses(const Callback & cb)86     bool EnumerateClasses(const Callback &cb)
87     {
88         os::memory::LockHolder lock(classesLock_);
89         for (const auto &v : loadedClasses_) {
90             if (!cb(v.second)) {
91                 return false;
92             }
93         }
94         return true;
95     }
96 
EnumeratePandaFiles(const std::function<bool (const panda_file::File &)> &)97     virtual void EnumeratePandaFiles(const std::function<bool(const panda_file::File &)> & /* cb */) const {}
98 
99     /// @brief Enumerate panda files in chained contexts
EnumeratePandaFilesInChain(const std::function<bool (const panda_file::File &)> & cb)100     virtual void EnumeratePandaFilesInChain(const std::function<bool(const panda_file::File &)> &cb) const
101     {
102         EnumeratePandaFiles(cb);
103     }
104 
NumLoadedClasses()105     size_t NumLoadedClasses()
106     {
107         os::memory::LockHolder lock(classesLock_);
108         return loadedClasses_.size();
109     }
110 
VisitLoadedClasses(size_t flag)111     void VisitLoadedClasses(size_t flag)
112     {
113         os::memory::LockHolder lock(classesLock_);
114         for (auto &loadedClass : loadedClasses_) {
115             auto classPtr = loadedClass.second;
116             classPtr->DumpClass(GET_LOG_STREAM(ERROR, RUNTIME), flag);
117         }
118     }
119 
VisitGCRoots(const ObjectVisitor & cb)120     void VisitGCRoots(const ObjectVisitor &cb)
121     {
122         for (auto root : roots_) {
123             cb(root);
124         }
125     }
126 
AddGCRoot(ObjectHeader * obj)127     bool AddGCRoot(ObjectHeader *obj)
128     {
129         os::memory::LockHolder lock(classesLock_);
130         for (auto root : roots_) {
131             if (root == obj) {
132                 return false;
133             }
134         }
135 
136         roots_.emplace_back(obj);
137         return true;
138     }
139 
UpdateGCRoots(const GCRootUpdater & gcRootUpdater)140     void UpdateGCRoots(const GCRootUpdater &gcRootUpdater)
141     {
142         for (auto &root : roots_) {
143             gcRootUpdater(&root);
144         }
145     }
146 
GetRefToLinker()147     mem::Reference *GetRefToLinker() const
148     {
149         // Atomic with relaxed order reason: read of field
150         return refToLinker_.load(std::memory_order_relaxed);
151     }
152 
SetRefToLinker(mem::Reference * ref)153     void SetRefToLinker(mem::Reference *ref)
154     {
155         // Atomic with release order reason: write to field, other threads should see correct value
156         refToLinker_.store(ref, std::memory_order_release);
157     }
158 
CompareAndSetRefToLinker(mem::Reference * oldRef,mem::Reference * newRef)159     bool CompareAndSetRefToLinker(mem::Reference *oldRef, mem::Reference *newRef)
160     {
161         // Atomic with release order reason: write to field, other threads should see correct value
162         return refToLinker_.compare_exchange_strong(oldRef, newRef, std::memory_order_release,
163                                                     std::memory_order_relaxed);
164     }
165 
GetPandaFilePaths()166     virtual PandaVector<std::string_view> GetPandaFilePaths() const
167     {
168         return PandaVector<std::string_view>();
169     }
170 
Dump(std::ostream & os)171     virtual void Dump(std::ostream &os)
172     {
173         os << "|Class loader :\"" << this << "\" "
174            << "|Loaded Classes:" << NumLoadedClasses() << "\n";
175     }
176 
FindClassLoaderParent(ClassLinkerContext * parent)177     virtual bool FindClassLoaderParent([[maybe_unused]] ClassLinkerContext *parent)
178     {
179         parent = nullptr;
180         return false;
181     }
182 
183     ClassLinkerContext() = default;
184     virtual ~ClassLinkerContext() = default;
185 
186     NO_COPY_SEMANTIC(ClassLinkerContext);
187     NO_MOVE_SEMANTIC(ClassLinkerContext);
188 
189 private:
190     // Dummy fix of concurrency issues to evaluate degradation
191     os::memory::RecursiveMutex classesLock_;
192     PandaUnorderedMap<const uint8_t *, Class *, utf::Mutf8Hash, utf::Mutf8Equal> loadedClasses_
193         GUARDED_BY(classesLock_);
194     PandaVector<ObjectHeader *> roots_;
195     std::atomic<mem::Reference *> refToLinker_ {nullptr};
196     panda_file::SourceLang lang_ {panda_file::SourceLang::PANDA_ASSEMBLY};
197 };
198 
199 }  // namespace ark
200 
201 #endif  // PANDA_RUNTIME_CLASS_LINKER_CONTEXT_H_
202