New src/share/vm/prims/resolvedMethodTable.cpp (original) (raw)
1 /*
2 * Copyright (c) 2017, 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 "gc/shared/gcLocker.hpp"
27 #include "memory/allocation.hpp"
28 #include "oops/oop.inline.hpp"
29 #include "oops/method.hpp"
30 #include "oops/symbol.hpp"
31 #include "prims/resolvedMethodTable.hpp"
32 #include "runtime/handles.inline.hpp"
33 #include "runtime/mutexLocker.hpp"
34 #include "utilities/hashtable.inline.hpp"
35 #include "utilities/macros.hpp"
36 #if INCLUDE_ALL_GCS
37 #include "gc/g1/g1CollectedHeap.hpp"
38 #include "gc/g1/g1SATBCardTableModRefBS.hpp"
39 #include "gc/g1/g1StringDedup.hpp"
40 #endif
41
42
43 ResolvedMethodTable::ResolvedMethodTable()
44 : Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
45
46 oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method method) {
47 for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
48 if (p->hash() == hash) {
49 oop target = p->literal();
50 // The method is in the table as a target already
51 if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
52 log_debug(membername, table) ("ResolvedMethod vmtarget entry found for %s index %d",
53 method->name_and_sig_as_C_string(), index);
54 return target;
55 }
56 }
57 }
58 return NULL;
59 }
60
61 unsigned int ResolvedMethodTable::compute_hash(Method* method) {
62 unsigned int name_hash = method->name()->identity_hash();
63 unsigned int signature_hash = method->signature()->identity_hash();
64 return name_hash ^ signature_hash;
65 }
66
67
68 oop ResolvedMethodTable::lookup(Method* method) {
69 unsigned int hash = compute_hash(method);
70 int index = hash_to_index(hash);
71 return lookup(index, hash, method);
72 }
73
74 // Tell the GC that this oop was looked up in the table
75 static void ensure_oop_alive(oop mname) {
76 // A lookup in the ResolvedMethodTable could return an object that was previously
77 // considered dead. The SATB part of G1 needs to get notified about this
78 // potential resurrection, otherwise the marking might not find the object.
79 #if INCLUDE_ALL_GCS
80 if (UseG1GC && mname != NULL) {
81 G1SATBCardTableModRefBS::enqueue(mname);
82 }
83 #endif
84 }
85
86 oop ResolvedMethodTable::basic_add(Method* method, oop vmtarget) {
87 assert_locked_or_safepoint(ResolvedMethodTable_lock);
88
89 unsigned int hash = compute_hash(method);
90 int index = hash_to_index(hash);
91
92 // One was added while aquiring the lock
93 oop entry = lookup(index, hash, method);
94 if (entry != NULL) {
95 ensure_oop_alive(entry);
96 return entry;
97 }
98
99 ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<oop, mtClass>::new_entry(hash, vmtarget);
100 Hashtable<oop, mtClass>::add_entry(index, p);
101 log_debug(membername, table) ("ResolvedMethod vmtarget entry added for %s index %d",
102 method->name_and_sig_as_C_string(), index);
103 return p->literal();
104 }
105
106 ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
107
108 oop ResolvedMethodTable::find_method(Method* vmtarget) {
109 oop entry = _the_table->lookup(vmtarget);
110 ensure_oop_alive(entry);
111 return entry;
112 }
113
114 oop ResolvedMethodTable::add_method(Handle mem_name_target) {
115 MutexLocker ml(ResolvedMethodTable_lock);
116 DEBUG_ONLY(NoSafepointVerifier nsv);
117
118 // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so
119 // use new method.
120 Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name_target());
121 assert(method->is_method(), "must be method");
122 if (method->is_old()) {
123 // Replace method with redefined version
124 InstanceKlass* holder = method->method_holder();
125 method = holder->method_with_idnum(method->method_idnum());
126 java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name_target(), method);
127 }
128 // Set flag in class to indicate this InstanceKlass has entries in the table
129 // to avoid walking table during redefinition if none of the redefined classes
130 // have any membernames in the table
131 method->method_holder()->set_has_resolved_methods();
132
133 return _the_table->basic_add(method, mem_name_target());
134 }
135
136 // Removing entries
137 int ResolvedMethodTable::_oops_removed = 0;
138 int ResolvedMethodTable::_oops_counted = 0;
139
140 // Serially invoke "f->do_oop" on the locations of all oops in the table.
141 // or remove deallocated vmtargets from the table
142 // This is done late during GC.
143 void ResolvedMethodTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
144 _oops_removed = 0;
145 _oops_counted = 0;
146 for (int i = 0; i < _the_table->table_size(); ++i) {
147 ResolvedMethodEntry** p = _the_table->bucket_addr(i);
148 ResolvedMethodEntry* entry = _the_table->bucket(i);
149 while (entry != NULL) {
150 _oops_counted++;
151 if (f != NULL) {
152 f->do_oop((oop*)entry->literal_addr());
153 p = entry->next_addr();
154 } else {
155 if (!is_alive->do_object_b(entry->literal())) {
156 _oops_removed++;
157 if (log_is_enabled(Debug, membername, table)) {
158 ResourceMark rm;
159 Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->literal());
160 log_debug(membername, table) ("ResolvedMethod vmtarget entry removed for %s index %d",
161 m->name_and_sig_as_C_string(), i);
162 }
163 p = entry->next();
164 _the_table->free_entry(entry);
165 } else {
166 p = entry->next_addr();
167 }
168 }
169 // get next entry
170 entry = (ResolvedMethodEntry)HashtableEntry<oop, mtClass>::make_ptr(p);
171 }
172 }
173 }
174
175 #ifndef PRODUCT
176 void ResolvedMethodTable::print() {
177 for (int i = 0; i < table_size(); ++i) {
178 ResolvedMethodEntry* entry = bucket(i);
179 while (entry != NULL) {
180 tty->print("%d : ", i);
181 oop vmtarget = entry->literal();
182 vmtarget->print();
183 Method m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(vmtarget);
184 m->print();
185 entry = entry->next();
186 }
187 }
188 }
189 #endif // PRODUCT
190
191 #if INCLUDE_JVMTI
192 // It is called at safepoint only for RedefineClasses
193 void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
194 assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
195 // For each entry in MNT, change to new method
196 for (int i = 0; i < _the_table->table_size(); ++i) {
197 ResolvedMethodEntry* entry = _the_table->bucket(i);
198 while (entry != NULL) {
199
200 oop mem_name = entry->literal();
201 Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
202
203 if (old_method->is_old()) {
204
205 if (old_method->is_deleted()) {
206 // leave deleted method in ResolvedMethod for now (this is a bug that we don't mark
207 // these on_stack)
208 continue;
209 }
210
211 InstanceKlass* holder = old_method->method_holder();
212 Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
213 assert(holder == new_method->method_holder(), "call after swapping redefined guts");
214
215 assert(new_method != NULL, "method_with_idnum() should not be NULL");
216 assert(old_method != new_method, "sanity check");
217
218 java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method);
219
220 if (log_is_enabled(Info, redefine, class, update)) {
221 ResourceMark rm;
222 if (!(*trace_name_printed)) {
223 log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
224 *trace_name_printed = true;
225 }
226 log_debug(redefine, class, update, constantpool)
227 ("ResolvedMethod method update: %s(%s)",
228 new_method->name()->as_C_string(), new_method->signature()->as_C_string());
229 }
230 }
231 entry = entry->next();
232 }
233 }
234 }
235 #endif // INCLUDE_JVMTI