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