jdk

Форк
0
/
finalizerService.cpp 
369 строк · 11.5 Кб
1
/*
2
 * Copyright (c) 2021, 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 "utilities/macros.hpp"
27
#if INCLUDE_MANAGEMENT
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"
43

44
static const char* allocate(oop string) {
45
  char* str = nullptr;
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);
51
  }
52
  return str;
53
}
54

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");
62
  fieldDescriptor fd;
63
  InstanceKlass::cast(klass)->find_field(name, signature, false, &fd);
64
  return fd.offset();
65
}
66

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;
72
}
73

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);
78
}
79

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());
83
  if (pd == nullptr) {
84
    return nullptr;
85
  }
86
  oop cs = codesource(pd);
87
  return cs != nullptr ? location_no_frag_string(cs) : nullptr;
88
}
89

90
FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) :
91
    _ik(ik),
92
    _codesource(get_codesource(ik)),
93
    _objects_on_heap(0),
94
    _total_finalizers_run(0) {}
95

96
FinalizerEntry::~FinalizerEntry() {
97
  FREE_C_HEAP_ARRAY(char, _codesource);
98
}
99

100
const InstanceKlass* FinalizerEntry::klass() const {
101
  return _ik;
102
}
103

104
const char* FinalizerEntry::codesource() const {
105
  return _codesource;
106
}
107

108
uintptr_t FinalizerEntry::objects_on_heap() const {
109
  return Atomic::load(&_objects_on_heap);
110
}
111

112
uintptr_t FinalizerEntry::total_finalizers_run() const {
113
  return Atomic::load(&_total_finalizers_run);
114
}
115

116
void FinalizerEntry::on_register() {
117
  Atomic::inc(&_objects_on_heap, memory_order_relaxed);
118
}
119

120
void FinalizerEntry::on_complete() {
121
  Atomic::inc(&_total_finalizers_run, memory_order_relaxed);
122
  Atomic::dec(&_objects_on_heap, memory_order_relaxed);
123
}
124

125
static inline uintx hash_function(const InstanceKlass* ik) {
126
  assert(ik != nullptr, "invariant");
127
  return primitive_hash(ik);
128
}
129

130
static inline uintx hash_function(const FinalizerEntry* fe) {
131
  return hash_function(fe->klass());
132
}
133

134
class FinalizerEntryLookup : StackObj {
135
 private:
136
  const InstanceKlass* const _ik;
137
 public:
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;
144
  }
145
  bool is_dead(FinalizerEntry** value) {
146
    return false;
147
  }
148
};
149

150
class FinalizerTableConfig : public AllStatic {
151
 public:
152
  typedef FinalizerEntry* Value;  // value of the Node in the hashtable
153

154
  static uintx get_hash(Value const& value, bool* is_dead) {
155
    return hash_function(value);
156
  }
157
  static void* allocate_node(void* context, size_t size, Value const& value) {
158
    return AllocateHeap(size, mtServiceability);
159
  }
160
  static void free_node(void* context, void* memory, Value const& value) {
161
    FreeHeap(memory);
162
  }
163
};
164

165
typedef ConcurrentHashTable<FinalizerTableConfig, mtServiceability> FinalizerHashtable;
166
static FinalizerHashtable* _table = nullptr;
167
static const size_t DEFAULT_TABLE_SIZE = 2048;
168
// 2^24 is max size, like StringTable.
169
static const size_t MAX_SIZE = 24;
170
static volatile bool _has_work = false;
171

172
class FinalizerEntryLookupResult {
173
 private:
174
  FinalizerEntry* _result;
175
 public:
176
  FinalizerEntryLookupResult() : _result(nullptr) {}
177
  void operator()(FinalizerEntry* node) {
178
    assert(node != nullptr, "invariant");
179
    _result = node;
180
  }
181
  FinalizerEntry* result() const { return _result; }
182
};
183

184
class FinalizerEntryLookupGet {
185
 private:
186
  FinalizerEntry* _result;
187
 public:
188
  FinalizerEntryLookupGet() : _result(nullptr) {}
189
  void operator()(FinalizerEntry** node) {
190
    assert(node != nullptr, "invariant");
191
    _result = *node;
192
  }
193
  FinalizerEntry* result() const { return _result; }
194
};
195

196
static inline void set_has_work(bool value) {
197
  Atomic::store(&_has_work, value);
198
}
199

200
static inline bool has_work() {
201
  return Atomic::load(&_has_work);
202
}
203

204
static void request_resize() {
205
  if (!has_work()) {
206
    MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
207
    if (!has_work()) {
208
      set_has_work(true);
209
      Service_lock->notify_all();
210
    }
211
  }
212
}
213

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;
218
  do {
219
    // We have looked up the entry once, proceed with insertion.
220
    entry = new FinalizerEntry(ik);
221
    if (_table->insert(thread, lookup, entry, &grow_hint)) {
222
      break;
223
    }
224
    // In case another thread did a concurrent add, return value already in the table.
225
    // This could fail if the entry got deleted concurrently, so loop back until success.
226
    FinalizerEntryLookupGet felg;
227
    if (_table->get(thread, lookup, felg, &grow_hint)) {
228
      entry = felg.result();
229
      break;
230
    }
231
  } while (true);
232
  if (grow_hint) {
233
    request_resize();
234
  }
235
  assert(entry != nullptr, "invariant");
236
  return entry;
237
}
238

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)) {
243
      return;
244
    }
245
    while (gt.do_task(jt)) {
246
      gt.pause(jt);
247
      {
248
        ThreadBlockInVM tbivm(jt);
249
      }
250
      gt.cont(jt);
251
    }
252
    gt.done(jt);
253
  }
254
  set_has_work(false);
255
}
256

257
bool FinalizerService::has_work() {
258
  return ::has_work();
259
}
260

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);
265
}
266

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);
271
}
272

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();
278
}
279

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);
285
}
286

287
// Add if not exist.
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);
293
}
294

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);
299
}
300

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());
305
}
306

307
void FinalizerService::on_register(oop finalizee, Thread* thread) {
308
  FinalizerEntry* const fe = get_entry(finalizee, thread);
309
  assert(fe != nullptr, "invariant");
310
  fe->on_register();
311
  if (log_is_enabled(Info, finalizer)) {
312
    log_registered(finalizee, thread);
313
  }
314
}
315

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());
320
}
321

322
void FinalizerService::on_complete(oop finalizee, JavaThread* finalizer_thread) {
323
  FinalizerEntry* const fe = get_entry(finalizee, finalizer_thread);
324
  assert(fe != nullptr, "invariant");
325
  fe->on_complete();
326
  if (log_is_enabled(Info, finalizer)) {
327
    log_completed(finalizee, finalizer_thread);
328
  }
329
}
330

331
class FinalizerScan : public StackObj {
332
 private:
333
  FinalizerEntryClosure* _closure;
334
 public:
335
  FinalizerScan(FinalizerEntryClosure* closure) : _closure(closure) {}
336
  bool operator()(FinalizerEntry** fe) {
337
    return _closure->do_entry(*fe);
338
  }
339
};
340

341
void FinalizerService::do_entries(FinalizerEntryClosure* closure, Thread* thread) {
342
  assert(closure != nullptr, "invariant");
343
  FinalizerScan scan(closure);
344
  _table->do_scan(thread, scan);
345
}
346

347
static bool remove_entry(const InstanceKlass* ik) {
348
  assert(ik != nullptr, "invariant");
349
  FinalizerEntryLookup lookup(ik);
350
  return _table->remove(Thread::current(), lookup);
351
}
352

353
static void on_unloading(Klass* klass) {
354
  assert(klass != nullptr, "invariant");
355
  if (!klass->is_instance_klass()) {
356
    return;
357
  }
358
  const InstanceKlass* const ik = InstanceKlass::cast(klass);
359
  if (ik->has_finalizer()) {
360
    remove_entry(ik);
361
  }
362
}
363

364
void FinalizerService::purge_unloaded() {
365
  assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
366
  ClassLoaderDataGraph::classes_unloading_do(&on_unloading);
367
}
368

369
#endif // INCLUDE_MANAGEMENT
370

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.