• 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_CLASS_LINKER_CONTEXT_H_
17 #define PANDA_RUNTIME_CLASS_LINKER_CONTEXT_H_
18 
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 "runtime/include/class.h"
24 #include "runtime/include/mem/panda_containers.h"
25 #include "runtime/mem/gc/gc.h"
26 #include "runtime/mem/gc/gc_root.h"
27 #include "runtime/mem/object_helpers.h"
28 
29 namespace panda {
30 
31 class ClassLinker;
32 class ClassLinkerErrorHandler;
33 
34 class ClassLinkerContext {
35 public:
FindClass(const uint8_t * descriptor)36     Class *FindClass(const uint8_t *descriptor)
37     {
38         os::memory::LockHolder lock(classes_lock_);
39         auto it = loaded_classes_.find(descriptor);
40         if (it != loaded_classes_.cend()) {
41             return it->second;
42         }
43 
44         return nullptr;
45     }
46 
IsBootContext()47     virtual bool IsBootContext() const
48     {
49         return false;
50     }
51 
LoadClass(const uint8_t * descriptor,bool need_copy_descriptor,ClassLinkerErrorHandler * error_handler)52     virtual Class *LoadClass([[maybe_unused]] const uint8_t *descriptor, [[maybe_unused]] bool need_copy_descriptor,
53                              [[maybe_unused]] ClassLinkerErrorHandler *error_handler)
54     {
55         return nullptr;
56     }
57 
InsertClass(Class * klass)58     Class *InsertClass(Class *klass)
59     {
60         os::memory::LockHolder lock(classes_lock_);
61         auto *other_klass = FindClass(klass->GetDescriptor());
62         if (other_klass != nullptr) {
63             return other_klass;
64         }
65 
66         ASSERT(klass->GetSourceLang() == lang_);
67         loaded_classes_.insert({klass->GetDescriptor(), klass});
68         if (record_new_class_) {
69             new_classes_.push_back(klass);
70         }
71         return nullptr;
72     }
73 
RemoveClass(Class * klass)74     void RemoveClass(Class *klass)
75     {
76         os::memory::LockHolder lock(classes_lock_);
77         loaded_classes_.erase(klass->GetDescriptor());
78     }
79 
80     template <class Callback>
81     bool EnumerateClasses(const Callback &cb, mem::VisitGCRootFlags flags = mem::VisitGCRootFlags::ACCESS_ROOT_ALL)
82     {
83         ASSERT(BitCount(flags & (mem::VisitGCRootFlags::ACCESS_ROOT_ALL | mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW |
84                                  mem::VisitGCRootFlags::ACCESS_ROOT_NONE)) == 1);
85         if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) {
86             os::memory::LockHolder lock(classes_lock_);
87             for (const auto &v : loaded_classes_) {
88                 if (!cb(v.second)) {
89                     return false;
90                 }
91             }
92         } else if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0) {
93             os::memory::LockHolder lock(classes_lock_);
94             for (const auto klass : new_classes_) {
95                 if ((klass != nullptr) && (!cb(klass))) {
96                     return false;
97                 }
98             }
99         } else if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_NONE) != 0) {
100             // Just for starting record new classes.
101         } else {
102             LOG(FATAL, CLASS_LINKER) << "Unknown VisitGCRootFlags: " << static_cast<uint32_t>(flags);
103             UNREACHABLE();
104         }
105 
106         ASSERT(BitCount(flags & (mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT |
107                                  mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT)) <= 1);
108         if ((flags & mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT) != 0) {
109             os::memory::LockHolder lock(classes_lock_);
110             record_new_class_ = true;
111         } else if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) {
112             os::memory::LockHolder lock(classes_lock_);
113             record_new_class_ = false;
114             new_classes_.clear();
115         }
116 
117         return true;
118     }
119 
NumLoadedClasses()120     size_t NumLoadedClasses()
121     {
122         os::memory::LockHolder lock(classes_lock_);
123         return loaded_classes_.size();
124     }
125 
VisitLoadedClasses(size_t flag)126     void VisitLoadedClasses(size_t flag)
127     {
128         os::memory::LockHolder lock(classes_lock_);
129         for (auto &loaded_class : loaded_classes_) {
130             auto class_ptr = loaded_class.second;
131             class_ptr->DumpClass(GET_LOG_STREAM(ERROR, RUNTIME), flag);
132         }
133     }
134 
VisitGCRoots(const ObjectVisitor & cb)135     void VisitGCRoots(const ObjectVisitor &cb)
136     {
137         for (auto root : roots_) {
138             cb(root);
139         }
140     }
141 
AddGCRoot(ObjectHeader * obj)142     bool AddGCRoot(ObjectHeader *obj)
143     {
144         os::memory::LockHolder lock(classes_lock_);
145         for (auto root : roots_) {
146             if (root == obj) {
147                 return false;
148             }
149         }
150 
151         roots_.emplace_back(obj);
152         return true;
153     }
154 
UpdateGCRoots()155     void UpdateGCRoots()
156     {
157         for (auto &root : roots_) {
158             if (root->IsForwarded()) {
159                 root = ::panda::mem::GetForwardAddress(root);
160             }
161         }
162     }
163 
GetPandaFilePaths()164     virtual PandaVector<std::string_view> GetPandaFilePaths() const
165     {
166         return PandaVector<std::string_view>();
167     }
168 
Dump(std::ostream & os)169     virtual void Dump(std::ostream &os)
170     {
171         os << "|Class loader :\"" << this << "\" "
172            << "|Loaded Classes:" << NumLoadedClasses() << "\n";
173     }
174 
FindClassLoaderParent(ClassLinkerContext * parent)175     virtual bool FindClassLoaderParent([[maybe_unused]] ClassLinkerContext *parent)
176     {
177         parent = nullptr;
178         return false;
179     }
180 
181     ClassLinkerContext() = default;
182     virtual ~ClassLinkerContext() = default;
183 
184     NO_COPY_SEMANTIC(ClassLinkerContext);
185     NO_MOVE_SEMANTIC(ClassLinkerContext);
186 
187 #ifndef NDEBUG
188 protected:
189     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
190     panda_file::SourceLang lang_ {panda_file::SourceLang::PANDA_ASSEMBLY};
191 #endif  // NDEBUG
192 
193 private:
194     // Dummy fix of concurrency issues to evaluate degradation
195     os::memory::RecursiveMutex classes_lock_;
196     PandaUnorderedMap<const uint8_t *, Class *, utf::Mutf8Hash, utf::Mutf8Equal> loaded_classes_
197         GUARDED_BY(classes_lock_);
198     PandaVector<ObjectPointer<ObjectHeader>> roots_;
199     bool record_new_class_ {false};
200     PandaVector<Class *> new_classes_;
201 };
202 
203 }  // namespace panda
204 
205 #endif  // PANDA_RUNTIME_CLASS_LINKER_CONTEXT_H_
206