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