25
#include "precompiled.hpp"
26
#include "utilities/macros.hpp"
28
#include "classfile/classLoaderDataGraph.inline.hpp"
29
#include "classfile/javaClasses.inline.hpp"
30
#include "classfile/symbolTable.hpp"
31
#include "memory/resourceArea.hpp"
32
#include "logging/log.hpp"
33
#include "oops/instanceKlass.inline.hpp"
34
#include "runtime/atomic.hpp"
35
#include "runtime/fieldDescriptor.inline.hpp"
36
#include "runtime/interfaceSupport.inline.hpp"
37
#include "runtime/javaThread.hpp"
38
#include "runtime/mutexLocker.hpp"
39
#include "runtime/synchronizer.hpp"
40
#include "services/finalizerService.hpp"
41
#include "utilities/concurrentHashTableTasks.inline.hpp"
42
#include "utilities/debug.hpp"
44
static const char* allocate(oop string) {
46
const typeArrayOop value = java_lang_String::value(string);
47
if (value != nullptr) {
48
const int length = java_lang_String::utf8_length(string, value);
49
str = NEW_C_HEAP_ARRAY(char, length + 1, mtServiceability);
50
java_lang_String::as_utf8_string(string, value, str, length + 1);
55
static int compute_field_offset(const Klass* klass, const char* field_name, const char* field_signature) {
56
assert(klass != nullptr, "invariant");
57
Symbol* const name = SymbolTable::new_symbol(field_name);
58
assert(name != nullptr, "invariant");
59
Symbol* const signature = SymbolTable::new_symbol(field_signature);
60
assert(signature != nullptr, "invariant");
61
assert(klass->is_instance_klass(), "invariant");
63
InstanceKlass::cast(klass)->find_field(name, signature, false, &fd);
67
static const char* location_no_frag_string(oop codesource) {
68
assert(codesource != nullptr, "invariant");
69
static int loc_no_frag_offset = compute_field_offset(codesource->klass(), "locationNoFragString", "Ljava/lang/String;");
70
oop string = codesource->obj_field(loc_no_frag_offset);
71
return string != nullptr ? allocate(string) : nullptr;
74
static oop codesource(oop pd) {
75
assert(pd != nullptr, "invariant");
76
static int codesource_offset = compute_field_offset(pd->klass(), "codesource", "Ljava/security/CodeSource;");
77
return pd->obj_field(codesource_offset);
80
static const char* get_codesource(const InstanceKlass* ik) {
81
assert(ik != nullptr, "invariant");
82
oop pd = java_lang_Class::protection_domain(ik->java_mirror());
86
oop cs = codesource(pd);
87
return cs != nullptr ? location_no_frag_string(cs) : nullptr;
90
FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) :
92
_codesource(get_codesource(ik)),
94
_total_finalizers_run(0) {}
96
FinalizerEntry::~FinalizerEntry() {
97
FREE_C_HEAP_ARRAY(char, _codesource);
100
const InstanceKlass* FinalizerEntry::klass() const {
104
const char* FinalizerEntry::codesource() const {
108
uintptr_t FinalizerEntry::objects_on_heap() const {
109
return Atomic::load(&_objects_on_heap);
112
uintptr_t FinalizerEntry::total_finalizers_run() const {
113
return Atomic::load(&_total_finalizers_run);
116
void FinalizerEntry::on_register() {
117
Atomic::inc(&_objects_on_heap, memory_order_relaxed);
120
void FinalizerEntry::on_complete() {
121
Atomic::inc(&_total_finalizers_run, memory_order_relaxed);
122
Atomic::dec(&_objects_on_heap, memory_order_relaxed);
125
static inline uintx hash_function(const InstanceKlass* ik) {
126
assert(ik != nullptr, "invariant");
127
return primitive_hash(ik);
130
static inline uintx hash_function(const FinalizerEntry* fe) {
131
return hash_function(fe->klass());
134
class FinalizerEntryLookup : StackObj {
136
const InstanceKlass* const _ik;
138
FinalizerEntryLookup(const InstanceKlass* ik) : _ik(ik) {}
139
uintx get_hash() const { return hash_function(_ik); }
140
bool equals(FinalizerEntry** value) {
141
assert(value != nullptr, "invariant");
142
assert(*value != nullptr, "invariant");
143
return (*value)->klass() == _ik;
145
bool is_dead(FinalizerEntry** value) {
150
class FinalizerTableConfig : public AllStatic {
152
typedef FinalizerEntry* Value;
154
static uintx get_hash(Value const& value, bool* is_dead) {
155
return hash_function(value);
157
static void* allocate_node(void* context, size_t size, Value const& value) {
158
return AllocateHeap(size, mtServiceability);
160
static void free_node(void* context, void* memory, Value const& value) {
165
typedef ConcurrentHashTable<FinalizerTableConfig, mtServiceability> FinalizerHashtable;
166
static FinalizerHashtable* _table = nullptr;
167
static const size_t DEFAULT_TABLE_SIZE = 2048;
169
static const size_t MAX_SIZE = 24;
170
static volatile bool _has_work = false;
172
class FinalizerEntryLookupResult {
174
FinalizerEntry* _result;
176
FinalizerEntryLookupResult() : _result(nullptr) {}
177
void operator()(FinalizerEntry* node) {
178
assert(node != nullptr, "invariant");
181
FinalizerEntry* result() const { return _result; }
184
class FinalizerEntryLookupGet {
186
FinalizerEntry* _result;
188
FinalizerEntryLookupGet() : _result(nullptr) {}
189
void operator()(FinalizerEntry** node) {
190
assert(node != nullptr, "invariant");
193
FinalizerEntry* result() const { return _result; }
196
static inline void set_has_work(bool value) {
197
Atomic::store(&_has_work, value);
200
static inline bool has_work() {
201
return Atomic::load(&_has_work);
204
static void request_resize() {
206
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
209
Service_lock->notify_all();
214
static FinalizerEntry* add_to_table_if_needed(const InstanceKlass* ik, Thread* thread) {
215
FinalizerEntryLookup lookup(ik);
216
FinalizerEntry* entry = nullptr;
217
bool grow_hint = false;
220
entry = new FinalizerEntry(ik);
221
if (_table->insert(thread, lookup, entry, &grow_hint)) {
226
FinalizerEntryLookupGet felg;
227
if (_table->get(thread, lookup, felg, &grow_hint)) {
228
entry = felg.result();
235
assert(entry != nullptr, "invariant");
239
static void do_table_concurrent_work(JavaThread* jt) {
240
if (!_table->is_max_size_reached()) {
241
FinalizerHashtable::GrowTask gt(_table);
242
if (!gt.prepare(jt)) {
245
while (gt.do_task(jt)) {
248
ThreadBlockInVM tbivm(jt);
257
bool FinalizerService::has_work() {
261
void FinalizerService::do_concurrent_work(JavaThread* service_thread) {
262
assert(service_thread != nullptr, "invariant");
263
assert(has_work(), "invariant");
264
do_table_concurrent_work(service_thread);
267
void FinalizerService::init() {
268
assert(_table == nullptr, "invariant");
269
const size_t start_size_log_2 = ceil_log2(DEFAULT_TABLE_SIZE);
270
_table = new FinalizerHashtable(start_size_log_2, MAX_SIZE, FinalizerHashtable::DEFAULT_GROW_HINT);
273
static FinalizerEntry* lookup_entry(const InstanceKlass* ik, Thread* thread) {
274
FinalizerEntryLookup lookup(ik);
275
FinalizerEntryLookupGet felg;
276
_table->get(thread, lookup, felg);
277
return felg.result();
280
const FinalizerEntry* FinalizerService::lookup(const InstanceKlass* ik, Thread* thread) {
281
assert(ik != nullptr, "invariant");
282
assert(thread != nullptr, "invariant");
283
assert(ik->has_finalizer(), "invariant");
284
return lookup_entry(ik, thread);
288
static FinalizerEntry* get_entry(const InstanceKlass* ik, Thread* thread) {
289
assert(ik != nullptr, "invariant");
290
assert(ik->has_finalizer(), "invariant");
291
FinalizerEntry* const entry = lookup_entry(ik, thread);
292
return entry != nullptr ? entry : add_to_table_if_needed(ik, thread);
295
static FinalizerEntry* get_entry(oop finalizee, Thread* thread) {
296
assert(finalizee != nullptr, "invariant");
297
assert(finalizee->is_instance(), "invariant");
298
return get_entry(InstanceKlass::cast(finalizee->klass()), thread);
301
static void log_registered(oop finalizee, Thread* thread) {
302
ResourceMark rm(thread);
303
const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee);
304
log_info(finalizer)("Registered object (" INTPTR_FORMAT ") of class %s as finalizable", identity_hash, finalizee->klass()->external_name());
307
void FinalizerService::on_register(oop finalizee, Thread* thread) {
308
FinalizerEntry* const fe = get_entry(finalizee, thread);
309
assert(fe != nullptr, "invariant");
311
if (log_is_enabled(Info, finalizer)) {
312
log_registered(finalizee, thread);
316
static void log_completed(oop finalizee, Thread* thread) {
317
ResourceMark rm(thread);
318
const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee);
319
log_info(finalizer)("Finalizer was run for object (" INTPTR_FORMAT ") of class %s", identity_hash, finalizee->klass()->external_name());
322
void FinalizerService::on_complete(oop finalizee, JavaThread* finalizer_thread) {
323
FinalizerEntry* const fe = get_entry(finalizee, finalizer_thread);
324
assert(fe != nullptr, "invariant");
326
if (log_is_enabled(Info, finalizer)) {
327
log_completed(finalizee, finalizer_thread);
331
class FinalizerScan : public StackObj {
333
FinalizerEntryClosure* _closure;
335
FinalizerScan(FinalizerEntryClosure* closure) : _closure(closure) {}
336
bool operator()(FinalizerEntry** fe) {
337
return _closure->do_entry(*fe);
341
void FinalizerService::do_entries(FinalizerEntryClosure* closure, Thread* thread) {
342
assert(closure != nullptr, "invariant");
343
FinalizerScan scan(closure);
344
_table->do_scan(thread, scan);
347
static bool remove_entry(const InstanceKlass* ik) {
348
assert(ik != nullptr, "invariant");
349
FinalizerEntryLookup lookup(ik);
350
return _table->remove(Thread::current(), lookup);
353
static void on_unloading(Klass* klass) {
354
assert(klass != nullptr, "invariant");
355
if (!klass->is_instance_klass()) {
358
const InstanceKlass* const ik = InstanceKlass::cast(klass);
359
if (ik->has_finalizer()) {
364
void FinalizerService::purge_unloaded() {
365
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
366
ClassLoaderDataGraph::classes_unloading_do(&on_unloading);