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