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