Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.
/ jdk16 Public archive

Commit 42d2d6d

Browse files
committed
8259063: Possible deadlock with vtable/itable creation vs concurrent class unloading
Reviewed-by: pliden, neliasso
1 parent 6bb6093 commit 42d2d6d

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

src/hotspot/share/code/codeBlob.cpp

+25-2
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,22 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
304304
return blob;
305305
}
306306

307+
void* VtableBlob::operator new(size_t s, unsigned size) throw() {
308+
// Handling of allocation failure stops compilation and prints a bunch of
309+
// stuff, which requires unlocking the CodeCache_lock, so that the Compile_lock
310+
// can be locked, and then re-locking the CodeCache_lock. That is not safe in
311+
// this context as we hold the CompiledICLocker. So we just don't handle code
312+
// cache exhaustion here; we leave that for a later allocation that does not
313+
// hold the CompiledICLocker.
314+
return CodeCache::allocate(size, CodeBlobType::NonNMethod, false /* handle_alloc_failure */);
315+
}
316+
307317
VtableBlob::VtableBlob(const char* name, int size) :
308318
BufferBlob(name, size) {
309319
}
310320

311321
VtableBlob* VtableBlob::create(const char* name, int buffer_size) {
312-
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
322+
assert(JavaThread::current()->thread_state() == _thread_in_vm, "called with the wrong state");
313323

314324
VtableBlob* blob = NULL;
315325
unsigned int size = sizeof(VtableBlob);
@@ -318,8 +328,21 @@ VtableBlob* VtableBlob::create(const char* name, int buffer_size) {
318328
size += align_up(buffer_size, oopSize);
319329
assert(name != NULL, "must provide a name");
320330
{
321-
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
331+
if (!CodeCache_lock->try_lock()) {
332+
// If we can't take the CodeCache_lock, then this is a bad time to perform the ongoing
333+
// IC transition to megamorphic, for which this stub will be needed. It is better to
334+
// bail out the transition, and wait for a more opportune moment. Not only is it not
335+
// worth waiting for the lock blockingly for the megamorphic transition, it might
336+
// also result in a deadlock to blockingly wait, when concurrent class unloading is
337+
// performed. At this point in time, the CompiledICLocker is taken, so we are not
338+
// allowed to blockingly wait for the CodeCache_lock, as these two locks are otherwise
339+
// consistently taken in the opposite order. Bailing out results in an IC transition to
340+
// the clean state instead, which will cause subsequent calls to retry the transitioning
341+
// eventually.
342+
return NULL;
343+
}
322344
blob = new (size) VtableBlob(name, size);
345+
CodeCache_lock->unlock();
323346
}
324347
// Track memory usage statistic after releasing CodeCache_lock
325348
MemoryService::track_code_cache_memory_usage();

src/hotspot/share/code/codeBlob.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ class VtableBlob: public BufferBlob {
441441
private:
442442
VtableBlob(const char*, int);
443443

444+
void* operator new(size_t s, unsigned size) throw();
445+
444446
public:
445447
// Creation
446448
static VtableBlob* create(const char* name, int buffer_size);

src/hotspot/share/code/codeCache.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ CodeBlob* CodeCache::next_blob(CodeHeap* heap, CodeBlob* cb) {
483483
* run the constructor for the CodeBlob subclass he is busy
484484
* instantiating.
485485
*/
486-
CodeBlob* CodeCache::allocate(int size, int code_blob_type, int orig_code_blob_type) {
486+
CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool handle_alloc_failure, int orig_code_blob_type) {
487487
// Possibly wakes up the sweeper thread.
488488
NMethodSweeper::report_allocation(code_blob_type);
489489
assert_locked_or_safepoint(CodeCache_lock);
@@ -531,11 +531,13 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, int orig_code_blob_t
531531
tty->print_cr("Extension of %s failed. Trying to allocate in %s.",
532532
heap->name(), get_code_heap(type)->name());
533533
}
534-
return allocate(size, type, orig_code_blob_type);
534+
return allocate(size, type, handle_alloc_failure, orig_code_blob_type);
535535
}
536536
}
537-
MutexUnlocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
538-
CompileBroker::handle_full_code_cache(orig_code_blob_type);
537+
if (handle_alloc_failure) {
538+
MutexUnlocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
539+
CompileBroker::handle_full_code_cache(orig_code_blob_type);
540+
}
539541
return NULL;
540542
}
541543
if (PrintCodeCacheExtension) {

src/hotspot/share/code/codeCache.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class CodeCache : AllStatic {
136136
static const GrowableArray<CodeHeap*>* nmethod_heaps() { return _nmethod_heaps; }
137137

138138
// Allocation/administration
139-
static CodeBlob* allocate(int size, int code_blob_type, int orig_code_blob_type = CodeBlobType::All); // allocates a new CodeBlob
139+
static CodeBlob* allocate(int size, int code_blob_type, bool handle_alloc_failure = true, int orig_code_blob_type = CodeBlobType::All); // allocates a new CodeBlob
140140
static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled
141141
static int alignment_unit(); // guaranteed alignment of all CodeBlobs
142142
static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)

0 commit comments

Comments
 (0)