1 /* 2 * Copyright (c) 2018, 2019, 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 public: 69 virtual bool is_unloading(CompiledMethod* method) const { 70 nmethod* const nm = method->as_nmethod(); 71 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 72 ZLocker<ZReentrantLock> locker(lock); 73 ZIsUnloadingOopClosure cl; 74 ZNMethod::nmethod_oops_do(nm, &cl); 75 return cl.is_unloading(); 76 } 77 }; 78 79 class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { 80 public: 81 virtual bool lock(CompiledMethod* method) { 82 nmethod* const nm = method->as_nmethod(); 83 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 84 lock->lock(); 85 return true; 86 } 87 88 virtual void unlock(CompiledMethod* method) { 89 nmethod* const nm = method->as_nmethod(); 90 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 91 lock->unlock(); 92 } 93 94 virtual bool is_safe(CompiledMethod* method) { 95 if (SafepointSynchronize::is_at_safepoint()) { 96 return true; 97 } 98 99 nmethod* const nm = method->as_nmethod(); 100 ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); 101 return lock->is_owned(); 102 } 103 }; 104 105 ZUnload::ZUnload(ZWorkers* workers) : 106 _workers(workers) { 107 108 if (!ClassUnloading) { 109 return; 110 } 111 112 static ZIsUnloadingBehaviour is_unloading_behaviour; 113 IsUnloadingBehaviour::set_current(&is_unloading_behaviour); 114 115 static ZCompiledICProtectionBehaviour ic_protection_behaviour; 116 CompiledICProtectionBehaviour::set_current(&ic_protection_behaviour); 117 } 118 119 void ZUnload::prepare() { 120 if (!ClassUnloading) { 121 return; 122 } 123 124 CodeCache::increment_unloading_cycle(); 125 DependencyContext::cleaning_start(); 126 } 127 128 void ZUnload::unlink() { 129 SuspendibleThreadSetJoiner sts; 130 bool unloading_occurred; 131 132 { 133 MutexLocker ml(ClassLoaderDataGraph_lock); 134 unloading_occurred = SystemDictionary::do_unloading(ZStatPhase::timer()); 135 } 136 137 Klass::clean_weak_klass_links(unloading_occurred); 138 139 ZNMethod::unlink(_workers, unloading_occurred); 140 141 DependencyContext::cleaning_end(); 142 } 143 144 void ZUnload::purge() { 145 { 146 SuspendibleThreadSetJoiner sts; 147 ZNMethod::purge(_workers); 148 } 149 150 ClassLoaderDataGraph::purge(); 151 CodeCache::purge_exception_caches(); 152 } 153 154 class ZUnloadRendezvousClosure : public ThreadClosure { 155 public: 156 void do_thread(Thread* thread) {} 157 }; 158 159 void ZUnload::unload() { 160 if (!ClassUnloading) { 161 return; 162 } 163 164 ZStatTimer timer(ZSubPhaseConcurrentClassesUnload); 165 166 // Unlink stale metadata and nmethods 167 unlink(); 168 169 // Make sure stale metadata and nmethods are no longer observable 170 ZUnloadRendezvousClosure cl; 171 Handshake::execute(&cl); 172 173 // Purge stale metadata and nmethods that were unlinked 174 purge(); 175 } 176 177 void ZUnload::finish() { 178 // Resize and verify metaspace 179 MetaspaceGC::compute_new_size(); 180 DEBUG_ONLY(MetaspaceUtils::verify(false);) 181 }