1 /*
2  * Copyright (c) 2017, 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 "code/relocInfo.hpp"
26 #include "code/nmethod.hpp"
27 #include "code/icBuffer.hpp"
28 #include "gc/shared/barrierSet.hpp"
29 #include "gc/shared/barrierSetNMethod.hpp"
30 #include "gc/z/zGlobals.hpp"
31 #include "gc/z/zLock.inline.hpp"
32 #include "gc/z/zNMethod.hpp"
33 #include "gc/z/zNMethodData.hpp"
34 #include "gc/z/zNMethodTable.hpp"
35 #include "gc/z/zOopClosures.inline.hpp"
36 #include "gc/z/zTask.hpp"
37 #include "gc/z/zWorkers.hpp"
38 #include "logging/log.hpp"
39 #include "memory/allocation.inline.hpp"
40 #include "memory/iterator.hpp"
41 #include "memory/resourceArea.hpp"
42 #include "memory/universe.hpp"
43 #include "runtime/atomic.hpp"
44 #include "utilities/debug.hpp"
45 
gc_data(const nmethod * nm)46 static ZNMethodData* gc_data(const nmethod* nm) {
47   return nm->gc_data<ZNMethodData>();
48 }
49 
set_gc_data(nmethod * nm,ZNMethodData * data)50 static void set_gc_data(nmethod* nm, ZNMethodData* data) {
51   return nm->set_gc_data<ZNMethodData>(data);
52 }
53 
attach_gc_data(nmethod * nm)54 void ZNMethod::attach_gc_data(nmethod* nm) {
55   GrowableArray<oop*> immediate_oops;
56   bool non_immediate_oops = false;
57 
58   // Find all oops relocations
59   RelocIterator iter(nm);
60   while (iter.next()) {
61     if (iter.type() != relocInfo::oop_type) {
62       // Not an oop
63       continue;
64     }
65 
66     oop_Relocation* r = iter.oop_reloc();
67 
68     if (!r->oop_is_immediate()) {
69       // Non-immediate oop found
70       non_immediate_oops = true;
71       continue;
72     }
73 
74     if (r->oop_value() != NULL) {
75       // Non-NULL immediate oop found. NULL oops can safely be
76       // ignored since the method will be re-registered if they
77       // are later patched to be non-NULL.
78       immediate_oops.push(r->oop_addr());
79     }
80   }
81 
82   // Attach GC data to nmethod
83   ZNMethodData* data = gc_data(nm);
84   if (data == NULL) {
85     data = new ZNMethodData();
86     set_gc_data(nm, data);
87   }
88 
89   // Attach oops in GC data
90   ZNMethodDataOops* const new_oops = ZNMethodDataOops::create(immediate_oops, non_immediate_oops);
91   ZNMethodDataOops* const old_oops = data->swap_oops(new_oops);
92   ZNMethodDataOops::destroy(old_oops);
93 }
94 
lock_for_nmethod(nmethod * nm)95 ZReentrantLock* ZNMethod::lock_for_nmethod(nmethod* nm) {
96   return gc_data(nm)->lock();
97 }
98 
log_register(const nmethod * nm)99 void ZNMethod::log_register(const nmethod* nm) {
100   LogTarget(Trace, gc, nmethod) log;
101   if (!log.is_enabled()) {
102     return;
103   }
104 
105   const ZNMethodDataOops* const oops = gc_data(nm)->oops();
106 
107   log.print("Register NMethod: %s.%s (" PTR_FORMAT "), "
108             "Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s",
109             nm->method()->method_holder()->external_name(),
110             nm->method()->name()->as_C_string(),
111             p2i(nm),
112             nm->compiler_name(),
113             nm->oops_count() - 1,
114             oops->immediates_count(),
115             oops->has_non_immediates() ? "Yes" : "No");
116 
117   LogTarget(Trace, gc, nmethod, oops) log_oops;
118   if (!log_oops.is_enabled()) {
119     return;
120   }
121 
122   // Print nmethod oops table
123   {
124     oop* const begin = nm->oops_begin();
125     oop* const end = nm->oops_end();
126     for (oop* p = begin; p < end; p++) {
127       log_oops.print("           Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)",
128                      (p - begin), p2i(*p), (*p)->klass()->external_name());
129     }
130   }
131 
132   // Print nmethod immediate oops
133   {
134     oop** const begin = oops->immediates_begin();
135     oop** const end = oops->immediates_end();
136     for (oop** p = begin; p < end; p++) {
137       log_oops.print("  ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)",
138                      (p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name());
139     }
140   }
141 }
142 
log_unregister(const nmethod * nm)143 void ZNMethod::log_unregister(const nmethod* nm) {
144   LogTarget(Debug, gc, nmethod) log;
145   if (!log.is_enabled()) {
146     return;
147   }
148 
149   log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")",
150             nm->method()->method_holder()->external_name(),
151             nm->method()->name()->as_C_string(),
152             p2i(nm));
153 }
154 
register_nmethod(nmethod * nm)155 void ZNMethod::register_nmethod(nmethod* nm) {
156   ResourceMark rm;
157 
158   // Create and attach gc data
159   attach_gc_data(nm);
160 
161   log_register(nm);
162 
163   ZNMethodTable::register_nmethod(nm);
164 
165   // Disarm nmethod entry barrier
166   disarm(nm);
167 }
168 
unregister_nmethod(nmethod * nm)169 void ZNMethod::unregister_nmethod(nmethod* nm) {
170   assert(CodeCache_lock->owned_by_self(), "Lock must be held");
171 
172   if (Thread::current()->is_Code_cache_sweeper_thread()) {
173     // The sweeper must wait for any ongoing iteration to complete
174     // before it can unregister an nmethod.
175     ZNMethodTable::wait_until_iteration_done();
176   }
177 
178   ResourceMark rm;
179 
180   log_unregister(nm);
181 
182   ZNMethodTable::unregister_nmethod(nm);
183 }
184 
flush_nmethod(nmethod * nm)185 void ZNMethod::flush_nmethod(nmethod* nm) {
186   // Destroy GC data
187   delete gc_data(nm);
188 }
189 
supports_entry_barrier(nmethod * nm)190 bool ZNMethod::supports_entry_barrier(nmethod* nm) {
191   BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
192   if (bs != NULL) {
193     return bs->supports_entry_barrier(nm);
194   }
195 
196   return false;
197 }
198 
is_armed(nmethod * nm)199 bool ZNMethod::is_armed(nmethod* nm) {
200   BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
201   if (bs != NULL) {
202     return bs->is_armed(nm);
203   }
204 
205   return false;
206 }
207 
disarm(nmethod * nm)208 void ZNMethod::disarm(nmethod* nm) {
209   BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
210   if (bs != NULL) {
211     bs->disarm(nm);
212   }
213 }
214 
nmethod_oops_do(nmethod * nm,OopClosure * cl)215 void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) {
216   // Process oops table
217   {
218     oop* const begin = nm->oops_begin();
219     oop* const end = nm->oops_end();
220     for (oop* p = begin; p < end; p++) {
221       if (*p != Universe::non_oop_word()) {
222         cl->do_oop(p);
223       }
224     }
225   }
226 
227   ZNMethodDataOops* const oops = gc_data(nm)->oops();
228 
229   // Process immediate oops
230   {
231     oop** const begin = oops->immediates_begin();
232     oop** const end = oops->immediates_end();
233     for (oop** p = begin; p < end; p++) {
234       if (**p != Universe::non_oop_word()) {
235         cl->do_oop(*p);
236       }
237     }
238   }
239 
240   // Process non-immediate oops
241   if (oops->has_non_immediates()) {
242     nm->fix_oop_relocations();
243   }
244 }
245 
246 class ZNMethodToOopsDoClosure : public NMethodClosure {
247 private:
248   OopClosure* _cl;
249 
250 public:
ZNMethodToOopsDoClosure(OopClosure * cl)251   ZNMethodToOopsDoClosure(OopClosure* cl) :
252       _cl(cl) {}
253 
do_nmethod(nmethod * nm)254   virtual void do_nmethod(nmethod* nm) {
255     ZNMethod::nmethod_oops_do(nm, _cl);
256   }
257 };
258 
oops_do_begin()259 void ZNMethod::oops_do_begin() {
260   ZNMethodTable::nmethods_do_begin();
261 }
262 
oops_do_end()263 void ZNMethod::oops_do_end() {
264   ZNMethodTable::nmethods_do_end();
265 }
266 
oops_do(OopClosure * cl)267 void ZNMethod::oops_do(OopClosure* cl) {
268   ZNMethodToOopsDoClosure nmethod_cl(cl);
269   ZNMethodTable::nmethods_do(&nmethod_cl);
270 }
271 
272 class ZNMethodUnlinkClosure : public NMethodClosure {
273 private:
274   bool          _unloading_occurred;
275   volatile bool _failed;
276 
set_failed()277   void set_failed() {
278     Atomic::store(&_failed, true);
279   }
280 
unlink(nmethod * nm)281   void unlink(nmethod* nm) {
282     // Unlinking of the dependencies must happen before the
283     // handshake separating unlink and purge.
284     nm->flush_dependencies(false /* delete_immediately */);
285 
286     // unlink_from_method will take the CompiledMethod_lock.
287     // In this case we don't strictly need it when unlinking nmethods from
288     // the Method, because it is only concurrently unlinked by
289     // the entry barrier, which acquires the per nmethod lock.
290     nm->unlink_from_method();
291 
292     if (nm->is_osr_method()) {
293       // Invalidate the osr nmethod before the handshake. The nmethod
294       // will be made unloaded after the handshake. Then invalidate_osr_method()
295       // will be called again, which will be a no-op.
296       nm->invalidate_osr_method();
297     }
298   }
299 
300 public:
ZNMethodUnlinkClosure(bool unloading_occurred)301   ZNMethodUnlinkClosure(bool unloading_occurred) :
302       _unloading_occurred(unloading_occurred),
303       _failed(false) {}
304 
do_nmethod(nmethod * nm)305   virtual void do_nmethod(nmethod* nm) {
306     if (failed()) {
307       return;
308     }
309 
310     if (!nm->is_alive()) {
311       return;
312     }
313 
314     if (nm->is_unloading()) {
315       ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm));
316       unlink(nm);
317       return;
318     }
319 
320     ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm));
321 
322     if (ZNMethod::is_armed(nm)) {
323       // Heal oops and disarm
324       ZNMethodOopClosure cl;
325       ZNMethod::nmethod_oops_do(nm, &cl);
326       ZNMethod::disarm(nm);
327     }
328 
329     // Clear compiled ICs and exception caches
330     if (!nm->unload_nmethod_caches(_unloading_occurred)) {
331       set_failed();
332     }
333   }
334 
failed() const335   bool failed() const {
336     return Atomic::load(&_failed);
337   }
338 };
339 
340 class ZNMethodUnlinkTask : public ZTask {
341 private:
342   ZNMethodUnlinkClosure _cl;
343   ICRefillVerifier*     _verifier;
344 
345 public:
ZNMethodUnlinkTask(bool unloading_occurred,ICRefillVerifier * verifier)346   ZNMethodUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) :
347       ZTask("ZNMethodUnlinkTask"),
348       _cl(unloading_occurred),
349       _verifier(verifier) {
350     ZNMethodTable::nmethods_do_begin();
351   }
352 
~ZNMethodUnlinkTask()353   ~ZNMethodUnlinkTask() {
354     ZNMethodTable::nmethods_do_end();
355   }
356 
work()357   virtual void work() {
358     ICRefillVerifierMark mark(_verifier);
359     ZNMethodTable::nmethods_do(&_cl);
360   }
361 
success() const362   bool success() const {
363     return !_cl.failed();
364   }
365 };
366 
unlink(ZWorkers * workers,bool unloading_occurred)367 void ZNMethod::unlink(ZWorkers* workers, bool unloading_occurred) {
368   for (;;) {
369     ICRefillVerifier verifier;
370 
371     {
372       ZNMethodUnlinkTask task(unloading_occurred, &verifier);
373       workers->run_concurrent(&task);
374       if (task.success()) {
375         return;
376       }
377     }
378 
379     // Cleaning failed because we ran out of transitional IC stubs,
380     // so we have to refill and try again. Refilling requires taking
381     // a safepoint, so we temporarily leave the suspendible thread set.
382     SuspendibleThreadSetLeaver sts;
383     InlineCacheBuffer::refill_ic_stubs();
384   }
385 }
386 
387 class ZNMethodPurgeClosure : public NMethodClosure {
388 public:
do_nmethod(nmethod * nm)389   virtual void do_nmethod(nmethod* nm) {
390     if (nm->is_alive() && nm->is_unloading()) {
391       nm->make_unloaded();
392     }
393   }
394 };
395 
396 class ZNMethodPurgeTask : public ZTask {
397 private:
398   ZNMethodPurgeClosure _cl;
399 
400 public:
ZNMethodPurgeTask()401   ZNMethodPurgeTask() :
402       ZTask("ZNMethodPurgeTask"),
403       _cl() {
404     ZNMethodTable::nmethods_do_begin();
405   }
406 
~ZNMethodPurgeTask()407   ~ZNMethodPurgeTask() {
408     ZNMethodTable::nmethods_do_end();
409   }
410 
work()411   virtual void work() {
412     ZNMethodTable::nmethods_do(&_cl);
413   }
414 };
415 
purge(ZWorkers * workers)416 void ZNMethod::purge(ZWorkers* workers) {
417   ZNMethodPurgeTask task;
418   workers->run_concurrent(&task);
419 }
420