mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
6996747: SIGSEGV in nmethod::cleanup_inline_caches / CompiledIC::verify
Reviewed-by: kvn, iveresov
This commit is contained in:
parent
0e10a5ad61
commit
a16e057c0a
5 changed files with 160 additions and 2 deletions
|
@ -2909,6 +2909,12 @@ class CommandLineFlags {
|
|||
product(intx, NmethodSweepCheckInterval, 5, \
|
||||
"Compilers wake up every n seconds to possibly sweep nmethods") \
|
||||
\
|
||||
notproduct(bool, LogSweeper, false, \
|
||||
"Keep a ring buffer of sweeper activity") \
|
||||
\
|
||||
notproduct(intx, SweeperLogEntries, 1024, \
|
||||
"Number of records in the ring buffer of sweeper activity") \
|
||||
\
|
||||
notproduct(intx, MemProfilingInterval, 500, \
|
||||
"Time between each invocation of the MemProfiler") \
|
||||
\
|
||||
|
|
|
@ -37,6 +37,94 @@
|
|||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
#define SWEEP(nm) record_sweep(nm, __LINE__)
|
||||
// Sweeper logging code
|
||||
class SweeperRecord {
|
||||
public:
|
||||
int traversal;
|
||||
int invocation;
|
||||
int compile_id;
|
||||
long traversal_mark;
|
||||
int state;
|
||||
const char* kind;
|
||||
address vep;
|
||||
address uep;
|
||||
int line;
|
||||
|
||||
void print() {
|
||||
tty->print_cr("traversal = %d invocation = %d compile_id = %d %s uep = " PTR_FORMAT " vep = "
|
||||
PTR_FORMAT " state = %d traversal_mark %d line = %d",
|
||||
traversal,
|
||||
invocation,
|
||||
compile_id,
|
||||
kind == NULL ? "" : kind,
|
||||
uep,
|
||||
vep,
|
||||
state,
|
||||
traversal_mark,
|
||||
line);
|
||||
}
|
||||
};
|
||||
|
||||
static int _sweep_index = 0;
|
||||
static SweeperRecord* _records = NULL;
|
||||
|
||||
void NMethodSweeper::report_events(int id, address entry) {
|
||||
if (_records != NULL) {
|
||||
for (int i = _sweep_index; i < SweeperLogEntries; i++) {
|
||||
if (_records[i].uep == entry ||
|
||||
_records[i].vep == entry ||
|
||||
_records[i].compile_id == id) {
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _sweep_index; i++) {
|
||||
if (_records[i].uep == entry ||
|
||||
_records[i].vep == entry ||
|
||||
_records[i].compile_id == id) {
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NMethodSweeper::report_events() {
|
||||
if (_records != NULL) {
|
||||
for (int i = _sweep_index; i < SweeperLogEntries; i++) {
|
||||
// skip empty records
|
||||
if (_records[i].vep == NULL) continue;
|
||||
_records[i].print();
|
||||
}
|
||||
for (int i = 0; i < _sweep_index; i++) {
|
||||
// skip empty records
|
||||
if (_records[i].vep == NULL) continue;
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NMethodSweeper::record_sweep(nmethod* nm, int line) {
|
||||
if (_records != NULL) {
|
||||
_records[_sweep_index].traversal = _traversals;
|
||||
_records[_sweep_index].traversal_mark = nm->_stack_traversal_mark;
|
||||
_records[_sweep_index].invocation = _invocations;
|
||||
_records[_sweep_index].compile_id = nm->compile_id();
|
||||
_records[_sweep_index].kind = nm->compile_kind();
|
||||
_records[_sweep_index].state = nm->_state;
|
||||
_records[_sweep_index].vep = nm->verified_entry_point();
|
||||
_records[_sweep_index].uep = nm->entry_point();
|
||||
_records[_sweep_index].line = line;
|
||||
|
||||
_sweep_index = (_sweep_index + 1) % SweeperLogEntries;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define SWEEP(nm)
|
||||
#endif
|
||||
|
||||
|
||||
long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
|
||||
nmethod* NMethodSweeper::_current = NULL; // Current nmethod
|
||||
int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache
|
||||
|
@ -137,6 +225,13 @@ void NMethodSweeper::possibly_sweep() {
|
|||
if (old != 0) {
|
||||
return;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (LogSweeper && _records == NULL) {
|
||||
// Create the ring buffer for the logging code
|
||||
_records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries);
|
||||
memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries);
|
||||
}
|
||||
#endif
|
||||
if (_invocations > 0) {
|
||||
sweep_code_cache();
|
||||
_invocations--;
|
||||
|
@ -213,10 +308,29 @@ void NMethodSweeper::sweep_code_cache() {
|
|||
}
|
||||
}
|
||||
|
||||
class NMethodMarker: public StackObj {
|
||||
private:
|
||||
CompilerThread* _thread;
|
||||
public:
|
||||
NMethodMarker(nmethod* nm) {
|
||||
_thread = CompilerThread::current();
|
||||
_thread->set_scanned_nmethod(nm);
|
||||
}
|
||||
~NMethodMarker() {
|
||||
_thread->set_scanned_nmethod(NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
assert(!CodeCache_lock->owned_by_self(), "just checking");
|
||||
|
||||
// Make sure this nmethod doesn't get unloaded during the scan,
|
||||
// since the locks acquired below might safepoint.
|
||||
NMethodMarker nmm(nm);
|
||||
|
||||
SWEEP(nm);
|
||||
|
||||
// Skip methods that are currently referenced by the VM
|
||||
if (nm->is_locked_by_vm()) {
|
||||
// But still remember to clean-up inline caches for alive nmethods
|
||||
|
@ -224,8 +338,10 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
// Clean-up all inline caches that points to zombie/non-reentrant methods
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
nm->cleanup_inline_caches();
|
||||
SWEEP(nm);
|
||||
} else {
|
||||
_locked_seen++;
|
||||
SWEEP(nm);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -247,6 +363,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
}
|
||||
nm->mark_for_reclamation();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else if (nm->is_not_entrant()) {
|
||||
// If there is no current activations of this method on the
|
||||
|
@ -257,6 +374,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
}
|
||||
nm->make_zombie();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
} else {
|
||||
// Still alive, clean up its inline caches
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
|
@ -265,6 +383,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
// request a rescan. If this method stays on the stack for a
|
||||
// long time we don't want to keep rescanning the code cache.
|
||||
_not_entrant_seen_on_stack++;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else if (nm->is_unloaded()) {
|
||||
// Unloaded code, just make it a zombie
|
||||
|
@ -273,10 +392,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
if (nm->is_osr_method()) {
|
||||
// No inline caches will ever point to osr methods, so we can just remove it
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
SWEEP(nm);
|
||||
nm->flush();
|
||||
} else {
|
||||
nm->make_zombie();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else {
|
||||
assert(nm->is_alive(), "should be alive");
|
||||
|
@ -293,6 +414,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
|||
// Clean-up all inline caches that points to zombie/non-reentrant methods
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
nm->cleanup_inline_caches();
|
||||
SWEEP(nm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,13 @@ class NMethodSweeper : public AllStatic {
|
|||
public:
|
||||
static long traversal_count() { return _traversals; }
|
||||
|
||||
#ifdef ASSERT
|
||||
// Keep track of sweeper activity in the ring buffer
|
||||
static void record_sweep(nmethod* nm, int line);
|
||||
static void report_events(int id, address entry);
|
||||
static void report_events();
|
||||
#endif
|
||||
|
||||
static void scan_stacks(); // Invoked at the end of each safepoint
|
||||
static void sweep_code_cache(); // Concurrent part of sweep job
|
||||
static void possibly_sweep(); // Compiler threads call this to sweep
|
||||
|
|
|
@ -2942,12 +2942,22 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters)
|
|||
_queue = queue;
|
||||
_counters = counters;
|
||||
_buffer_blob = NULL;
|
||||
_scanned_nmethod = NULL;
|
||||
|
||||
#ifndef PRODUCT
|
||||
_ideal_graph_printer = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CompilerThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||||
JavaThread::oops_do(f, cf);
|
||||
if (_scanned_nmethod != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_nmethod);
|
||||
}
|
||||
}
|
||||
|
||||
// ======= Threads ========
|
||||
|
||||
|
|
|
@ -439,7 +439,7 @@ class Thread: public ThreadShadow {
|
|||
// GC support
|
||||
// Apply "f->do_oop" to all root oops in "this".
|
||||
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
|
||||
void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
virtual void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
||||
// Handles the parallel case for the method below.
|
||||
private:
|
||||
|
@ -1381,7 +1381,7 @@ public:
|
|||
void trace_frames() PRODUCT_RETURN;
|
||||
|
||||
// Print an annotated view of the stack frames
|
||||
void print_frame_layout(int depth = 0, bool validate_only = false) PRODUCT_RETURN;
|
||||
void print_frame_layout(int depth = 0, bool validate_only = false) NOT_DEBUG_RETURN;
|
||||
void validate_frame_layout() {
|
||||
print_frame_layout(0, true);
|
||||
}
|
||||
|
@ -1698,6 +1698,8 @@ class CompilerThread : public JavaThread {
|
|||
CompileQueue* _queue;
|
||||
BufferBlob* _buffer_blob;
|
||||
|
||||
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
|
||||
|
||||
public:
|
||||
|
||||
static CompilerThread* current();
|
||||
|
@ -1726,6 +1728,11 @@ class CompilerThread : public JavaThread {
|
|||
_log = log;
|
||||
}
|
||||
|
||||
// GC support
|
||||
// Apply "f->do_oop" to all root oops in "this".
|
||||
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
|
||||
void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
||||
#ifndef PRODUCT
|
||||
private:
|
||||
IdealGraphPrinter *_ideal_graph_printer;
|
||||
|
@ -1737,6 +1744,12 @@ public:
|
|||
// Get/set the thread's current task
|
||||
CompileTask* task() { return _task; }
|
||||
void set_task(CompileTask* task) { _task = task; }
|
||||
|
||||
// Track the nmethod currently being scanned by the sweeper
|
||||
void set_scanned_nmethod(nmethod* nm) {
|
||||
assert(_scanned_nmethod == NULL || nm == NULL, "should reset to NULL before writing a new value");
|
||||
_scanned_nmethod = nm;
|
||||
}
|
||||
};
|
||||
|
||||
inline CompilerThread* CompilerThread::current() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue