1 | /* |
2 | * Copyright (c) 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 | |
25 | #include "precompiled.hpp" |
26 | #include "code/codeCache.hpp" |
27 | #include "code/nmethod.hpp" |
28 | #include "gc/shared/scavengableNMethods.hpp" |
29 | #include "gc/shared/scavengableNMethodsData.hpp" |
30 | #include "runtime/mutexLocker.hpp" |
31 | #include "utilities/debug.hpp" |
32 | |
33 | static ScavengableNMethodsData gc_data(nmethod* nm) { |
34 | return ScavengableNMethodsData(nm); |
35 | } |
36 | |
37 | nmethod* ScavengableNMethods::_head = NULL; |
38 | BoolObjectClosure* ScavengableNMethods::_is_scavengable = NULL; |
39 | |
40 | void ScavengableNMethods::initialize(BoolObjectClosure* is_scavengable) { |
41 | _is_scavengable = is_scavengable; |
42 | } |
43 | |
44 | // Conditionally adds the nmethod to the list if it is |
45 | // not already on the list and has a scavengeable root. |
46 | void ScavengableNMethods::register_nmethod(nmethod* nm) { |
47 | assert_locked_or_safepoint(CodeCache_lock); |
48 | |
49 | ScavengableNMethodsData data = gc_data(nm); |
50 | |
51 | if (data.on_list() || !has_scavengable_oops(nm)) { |
52 | return; |
53 | } |
54 | |
55 | data.set_on_list(); |
56 | data.set_next(_head); |
57 | |
58 | _head = nm; |
59 | } |
60 | |
61 | void ScavengableNMethods::unregister_nmethod(nmethod* nm) { |
62 | assert_locked_or_safepoint(CodeCache_lock); |
63 | |
64 | if (gc_data(nm).on_list()) { |
65 | nmethod* prev = NULL; |
66 | for (nmethod* cur = _head; cur != NULL; cur = gc_data(cur).next()) { |
67 | if (cur == nm) { |
68 | unlist_nmethod(cur, prev); |
69 | return; |
70 | } |
71 | prev = cur; |
72 | } |
73 | } |
74 | } |
75 | |
76 | #ifndef PRODUCT |
77 | |
78 | class DebugScavengableOops: public OopClosure { |
79 | BoolObjectClosure* _is_scavengable; |
80 | nmethod* _nm; |
81 | bool _ok; |
82 | public: |
83 | DebugScavengableOops(BoolObjectClosure* is_scavengable, nmethod* nm) : |
84 | _is_scavengable(is_scavengable), |
85 | _nm(nm), |
86 | _ok(true) { } |
87 | |
88 | bool ok() { return _ok; } |
89 | virtual void do_oop(oop* p) { |
90 | if (*p == NULL || !_is_scavengable->do_object_b(*p)) { |
91 | return; |
92 | } |
93 | |
94 | if (_ok) { |
95 | _nm->print_nmethod(true); |
96 | _ok = false; |
97 | } |
98 | tty->print_cr("*** scavengable oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)" , |
99 | p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm)); |
100 | (*p)->print(); |
101 | } |
102 | virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } |
103 | }; |
104 | |
105 | #endif // PRODUCT |
106 | |
107 | void ScavengableNMethods::verify_nmethod(nmethod* nm) { |
108 | #ifndef PRODUCT |
109 | if (!gc_data(nm).on_list()) { |
110 | // Actually look inside, to verify the claim that it's clean. |
111 | DebugScavengableOops cl(_is_scavengable, nm); |
112 | nm->oops_do(&cl); |
113 | if (!cl.ok()) |
114 | fatal("found an unadvertised bad scavengable oop in the code cache" ); |
115 | } |
116 | assert(gc_data(nm).not_marked(), "" ); |
117 | #endif // PRODUCT |
118 | } |
119 | |
120 | class HasScavengableOops: public OopClosure { |
121 | BoolObjectClosure* _is_scavengable; |
122 | bool _found; |
123 | public: |
124 | HasScavengableOops(BoolObjectClosure* is_scavengable, nmethod* nm) : |
125 | _is_scavengable(is_scavengable), |
126 | _found(false) {} |
127 | |
128 | bool found() { return _found; } |
129 | virtual void do_oop(oop* p) { |
130 | if (!_found && *p != NULL && _is_scavengable->do_object_b(*p)) { |
131 | _found = true; |
132 | } |
133 | } |
134 | virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } |
135 | }; |
136 | |
137 | bool ScavengableNMethods::has_scavengable_oops(nmethod* nm) { |
138 | HasScavengableOops cl(_is_scavengable, nm); |
139 | nm->oops_do(&cl); |
140 | return cl.found(); |
141 | } |
142 | |
143 | // Walk the list of methods which might contain oops to the java heap. |
144 | void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) { |
145 | assert_locked_or_safepoint(CodeCache_lock); |
146 | |
147 | debug_only(mark_on_list_nmethods()); |
148 | |
149 | nmethod* prev = NULL; |
150 | nmethod* cur = _head; |
151 | while (cur != NULL) { |
152 | assert(cur->is_alive(), "Must be" ); |
153 | |
154 | ScavengableNMethodsData data = gc_data(cur); |
155 | debug_only(data.clear_marked()); |
156 | assert(data.on_list(), "else shouldn't be on this list" ); |
157 | |
158 | if (cl != NULL) { |
159 | cl->do_code_blob(cur); |
160 | } |
161 | |
162 | nmethod* const next = data.next(); |
163 | |
164 | if (!has_scavengable_oops(cur)) { |
165 | unlist_nmethod(cur, prev); |
166 | } else { |
167 | prev = cur; |
168 | } |
169 | |
170 | cur = next; |
171 | } |
172 | |
173 | // Check for stray marks. |
174 | debug_only(verify_unlisted_nmethods(NULL)); |
175 | } |
176 | |
177 | void ScavengableNMethods::prune_nmethods() { |
178 | nmethods_do_and_prune(NULL /* No closure */); |
179 | } |
180 | |
181 | // Walk the list of methods which might contain oops to the java heap. |
182 | void ScavengableNMethods::nmethods_do(CodeBlobToOopClosure* cl) { |
183 | nmethods_do_and_prune(cl); |
184 | } |
185 | |
186 | #ifndef PRODUCT |
187 | void ScavengableNMethods::asserted_non_scavengable_nmethods_do(CodeBlobClosure* cl) { |
188 | // While we are here, verify the integrity of the list. |
189 | mark_on_list_nmethods(); |
190 | for (nmethod* cur = _head; cur != NULL; cur = gc_data(cur).next()) { |
191 | assert(gc_data(cur).on_list(), "else shouldn't be on this list" ); |
192 | gc_data(cur).clear_marked(); |
193 | } |
194 | verify_unlisted_nmethods(cl); |
195 | } |
196 | #endif // PRODUCT |
197 | |
198 | void ScavengableNMethods::unlist_nmethod(nmethod* nm, nmethod* prev) { |
199 | assert_locked_or_safepoint(CodeCache_lock); |
200 | |
201 | assert((prev == NULL && _head == nm) || |
202 | (prev != NULL && gc_data(prev).next() == nm), "precondition" ); |
203 | |
204 | ScavengableNMethodsData data = gc_data(nm); |
205 | |
206 | if (prev == NULL) { |
207 | _head = data.next(); |
208 | } else { |
209 | gc_data(prev).set_next(data.next()); |
210 | } |
211 | data.set_next(NULL); |
212 | data.clear_on_list(); |
213 | } |
214 | |
215 | #ifndef PRODUCT |
216 | // Temporarily mark nmethods that are claimed to be on the scavenge list. |
217 | void ScavengableNMethods::mark_on_list_nmethods() { |
218 | NMethodIterator iter(NMethodIterator::only_alive); |
219 | while(iter.next()) { |
220 | nmethod* nm = iter.method(); |
221 | ScavengableNMethodsData data = gc_data(nm); |
222 | assert(data.not_marked(), "clean state" ); |
223 | if (data.on_list()) |
224 | data.set_marked(); |
225 | } |
226 | } |
227 | |
228 | // If the closure is given, run it on the unlisted nmethods. |
229 | // Also make sure that the effects of mark_on_list_nmethods is gone. |
230 | void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) { |
231 | NMethodIterator iter(NMethodIterator::only_alive); |
232 | while(iter.next()) { |
233 | nmethod* nm = iter.method(); |
234 | |
235 | verify_nmethod(nm); |
236 | |
237 | if (cl != NULL && !gc_data(nm).on_list()) { |
238 | cl->do_code_blob(nm); |
239 | } |
240 | } |
241 | } |
242 | |
243 | #endif //PRODUCT |
244 | |