1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include "precompiled.hpp" 25 #include "classfile/classLoaderDataGraph.hpp" 26 #include "classfile/systemDictionary.hpp" 27 #include "code/codeBehaviours.hpp" 28 #include "code/codeCache.hpp" 29 #include "code/dependencyContext.hpp" 30 #include "gc/shared/gcBehaviours.hpp" 31 #include "gc/shared/suspendibleThreadSet.hpp" 32 #include "gc/z/zLock.inline.hpp" 33 #include "gc/z/zNMethod.hpp" 34 #include "gc/z/zOopClosures.hpp" 35 #include "gc/z/zStat.hpp" 36 #include "gc/z/zUnload.hpp" 37 #include "oops/access.inline.hpp" 38 39 static const ZStatSubPhase ZSubPhaseConcurrentClassesUnload("Concurrent Classes Unload"); 40 41 class ZIsUnloadingOopClosure : public OopClosure { 42 private: 43 ZPhantomIsAliveObjectClosure _is_alive; 44 bool _is_unloading; 45 46 public: 47 ZIsUnloadingOopClosure() : 48 _is_alive(), 49 _is_unloading(false) {} 50 51 virtual void do_oop(oop* p) { 52 const oop o = RawAccess<>::oop_load(p); 53 if (o != NULL && !_is_alive.do_object_b(o)) { 54 _is_unloading = true; 55 } 56 } 57 58 virtual void do_oop(narrowOop* p) { 59 ShouldNotReachHere(); 60 } 61 62 bool is_unloading() const { 63 return _is_unloading; 64 } 65 }; 66 67 class ZIsUnloadingBehaviour : public IsUnloadingBehaviour { 68 private: 69 bool is_unloading(nmethod* nm) const { 70 ZIsUnloadingOopClosure cl; 71 nm->oops_do(&cl, true /* allow_zombie */); 72 return cl.is_unloading(); 73 } 74 75 public: 76 virtual bool is_unloading(CompiledMethod* method) const { 77 nmethod* const nm = method->as_nmethod(); 78 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 79 if (lock == NULL) { 80 return is_unloading(nm); 81 } else { 82 ZLocker<ZReentrantLock> locker(lock); 83 return is_unloading(nm); 84 } 85 } 86 }; 87 88 class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { 89 public: 90 virtual bool lock(CompiledMethod* method) { 91 nmethod* const nm = method->as_nmethod(); 92 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 93 if (lock != NULL) { 94 lock->lock(); 95 } 96 return true; 97 } 98 99 virtual void unlock(CompiledMethod* method) { 100 nmethod* const nm = method->as_nmethod(); 101 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 102 if (lock != NULL) { 103 lock->unlock(); 104 } 105 } 106 107 virtual bool is_safe(CompiledMethod* method) { 108 if (SafepointSynchronize::is_at_safepoint()) { 109 return true; 110 } 111 112 nmethod* const nm = method->as_nmethod(); 113 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 114 return lock == NULL || lock->is_owned(); 115 } 116 }; 117 118 ZUnload::ZUnload(ZWorkers* workers) : 119 _workers(workers) { 120 121 if (!ClassUnloading) { 122 return; 123 } 124 125 static ZIsUnloadingBehaviour is_unloading_behaviour; 126 IsUnloadingBehaviour::set_current(&is_unloading_behaviour); 127 128 static ZCompiledICProtectionBehaviour ic_protection_behaviour; 129 CompiledICProtectionBehaviour::set_current(&ic_protection_behaviour); 130 } 131 132 void ZUnload::prepare() { 133 if (!ClassUnloading) { 134 return; 135 } 136 137 CodeCache::increment_unloading_cycle(); 138 DependencyContext::cleaning_start(); 139 } 140 141 void ZUnload::unlink() { 142 SuspendibleThreadSetJoiner sts; 143 bool unloading_occurred; 144 145 { 146 MutexLockerEx ml(ClassLoaderDataGraph_lock); 147 unloading_occurred = SystemDictionary::do_unloading(ZStatPhase::timer()); 148 } 149 150 Klass::clean_weak_klass_links(unloading_occurred); 151 152 ZNMethod::unlink(_workers, unloading_occurred); 153 154 DependencyContext::cleaning_end(); 155 } 156 157 void ZUnload::purge() { 158 { 159 SuspendibleThreadSetJoiner sts; 160 ZNMethod::purge(_workers); 161 } 162 163 ClassLoaderDataGraph::purge(); 164 CodeCache::purge_exception_caches(); 165 } 166 167 class ZUnloadRendezvousClosure : public ThreadClosure { 168 public: 169 void do_thread(Thread* thread) {} 170 }; 171 172 void ZUnload::unload() { 173 if (!ClassUnloading) { 174 return; 175 } 176 177 ZStatTimer timer(ZSubPhaseConcurrentClassesUnload); 178 179 // Unlink stale metadata and nmethods 180 unlink(); 181 182 // Make sure stale metadata and nmethods are no longer observable 183 ZUnloadRendezvousClosure cl; 184 Handshake::execute(&cl); 185 186 // Purge stale metadata and nmethods that were unlinked 187 purge(); 188 } 189 190 void ZUnload::finish() { 191 // Resize and verify metaspace 192 MetaspaceGC::compute_new_size(); 193 MetaspaceUtils::verify_metrics(); 194 }