提交 e5f7b8b0 编写于 作者: N never

6996747: SIGSEGV in nmethod::cleanup_inline_caches / CompiledIC::verify

Reviewed-by: kvn, iveresov
上级 82666eba
...@@ -2909,6 +2909,12 @@ class CommandLineFlags { ...@@ -2909,6 +2909,12 @@ class CommandLineFlags {
product(intx, NmethodSweepCheckInterval, 5, \ product(intx, NmethodSweepCheckInterval, 5, \
"Compilers wake up every n seconds to possibly sweep nmethods") \ "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, \ notproduct(intx, MemProfilingInterval, 500, \
"Time between each invocation of the MemProfiler") \ "Time between each invocation of the MemProfiler") \
\ \
......
...@@ -37,6 +37,94 @@ ...@@ -37,6 +37,94 @@
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/xmlstream.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 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
nmethod* NMethodSweeper::_current = NULL; // Current nmethod nmethod* NMethodSweeper::_current = NULL; // Current nmethod
int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache
...@@ -137,6 +225,13 @@ void NMethodSweeper::possibly_sweep() { ...@@ -137,6 +225,13 @@ void NMethodSweeper::possibly_sweep() {
if (old != 0) { if (old != 0) {
return; 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) { if (_invocations > 0) {
sweep_code_cache(); sweep_code_cache();
_invocations--; _invocations--;
...@@ -213,10 +308,29 @@ void NMethodSweeper::sweep_code_cache() { ...@@ -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) { void NMethodSweeper::process_nmethod(nmethod *nm) {
assert(!CodeCache_lock->owned_by_self(), "just checking"); 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 // Skip methods that are currently referenced by the VM
if (nm->is_locked_by_vm()) { if (nm->is_locked_by_vm()) {
// But still remember to clean-up inline caches for alive nmethods // But still remember to clean-up inline caches for alive nmethods
...@@ -224,8 +338,10 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -224,8 +338,10 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
// Clean-up all inline caches that points to zombie/non-reentrant methods // Clean-up all inline caches that points to zombie/non-reentrant methods
MutexLocker cl(CompiledIC_lock); MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches(); nm->cleanup_inline_caches();
SWEEP(nm);
} else { } else {
_locked_seen++; _locked_seen++;
SWEEP(nm);
} }
return; return;
} }
...@@ -247,6 +363,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -247,6 +363,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
} }
nm->mark_for_reclamation(); nm->mark_for_reclamation();
_rescan = true; _rescan = true;
SWEEP(nm);
} }
} else if (nm->is_not_entrant()) { } else if (nm->is_not_entrant()) {
// If there is no current activations of this method on the // If there is no current activations of this method on the
...@@ -257,6 +374,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -257,6 +374,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
} }
nm->make_zombie(); nm->make_zombie();
_rescan = true; _rescan = true;
SWEEP(nm);
} else { } else {
// Still alive, clean up its inline caches // Still alive, clean up its inline caches
MutexLocker cl(CompiledIC_lock); MutexLocker cl(CompiledIC_lock);
...@@ -265,6 +383,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -265,6 +383,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
// request a rescan. If this method stays on the stack for a // request a rescan. If this method stays on the stack for a
// long time we don't want to keep rescanning the code cache. // long time we don't want to keep rescanning the code cache.
_not_entrant_seen_on_stack++; _not_entrant_seen_on_stack++;
SWEEP(nm);
} }
} else if (nm->is_unloaded()) { } else if (nm->is_unloaded()) {
// Unloaded code, just make it a zombie // Unloaded code, just make it a zombie
...@@ -273,10 +392,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -273,10 +392,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
if (nm->is_osr_method()) { if (nm->is_osr_method()) {
// No inline caches will ever point to osr methods, so we can just remove it // No inline caches will ever point to osr methods, so we can just remove it
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
SWEEP(nm);
nm->flush(); nm->flush();
} else { } else {
nm->make_zombie(); nm->make_zombie();
_rescan = true; _rescan = true;
SWEEP(nm);
} }
} else { } else {
assert(nm->is_alive(), "should be alive"); assert(nm->is_alive(), "should be alive");
...@@ -293,6 +414,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -293,6 +414,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
// Clean-up all inline caches that points to zombie/non-reentrant methods // Clean-up all inline caches that points to zombie/non-reentrant methods
MutexLocker cl(CompiledIC_lock); MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches(); nm->cleanup_inline_caches();
SWEEP(nm);
} }
} }
......
...@@ -57,6 +57,13 @@ class NMethodSweeper : public AllStatic { ...@@ -57,6 +57,13 @@ class NMethodSweeper : public AllStatic {
public: public:
static long traversal_count() { return _traversals; } 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 scan_stacks(); // Invoked at the end of each safepoint
static void sweep_code_cache(); // Concurrent part of sweep job static void sweep_code_cache(); // Concurrent part of sweep job
static void possibly_sweep(); // Compiler threads call this to sweep static void possibly_sweep(); // Compiler threads call this to sweep
......
...@@ -2942,12 +2942,22 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) ...@@ -2942,12 +2942,22 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters)
_queue = queue; _queue = queue;
_counters = counters; _counters = counters;
_buffer_blob = NULL; _buffer_blob = NULL;
_scanned_nmethod = NULL;
#ifndef PRODUCT #ifndef PRODUCT
_ideal_graph_printer = NULL; _ideal_graph_printer = NULL;
#endif #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 ======== // ======= Threads ========
......
...@@ -439,7 +439,7 @@ class Thread: public ThreadShadow { ...@@ -439,7 +439,7 @@ class Thread: public ThreadShadow {
// GC support // GC support
// Apply "f->do_oop" to all root oops in "this". // Apply "f->do_oop" to all root oops in "this".
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames // 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. // Handles the parallel case for the method below.
private: private:
...@@ -1381,7 +1381,7 @@ public: ...@@ -1381,7 +1381,7 @@ public:
void trace_frames() PRODUCT_RETURN; void trace_frames() PRODUCT_RETURN;
// Print an annotated view of the stack frames // 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() { void validate_frame_layout() {
print_frame_layout(0, true); print_frame_layout(0, true);
} }
...@@ -1698,6 +1698,8 @@ class CompilerThread : public JavaThread { ...@@ -1698,6 +1698,8 @@ class CompilerThread : public JavaThread {
CompileQueue* _queue; CompileQueue* _queue;
BufferBlob* _buffer_blob; BufferBlob* _buffer_blob;
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
public: public:
static CompilerThread* current(); static CompilerThread* current();
...@@ -1726,6 +1728,11 @@ class CompilerThread : public JavaThread { ...@@ -1726,6 +1728,11 @@ class CompilerThread : public JavaThread {
_log = log; _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 #ifndef PRODUCT
private: private:
IdealGraphPrinter *_ideal_graph_printer; IdealGraphPrinter *_ideal_graph_printer;
...@@ -1737,6 +1744,12 @@ public: ...@@ -1737,6 +1744,12 @@ public:
// Get/set the thread's current task // Get/set the thread's current task
CompileTask* task() { return _task; } CompileTask* task() { return _task; }
void set_task(CompileTask* task) { _task = 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() { inline CompilerThread* CompilerThread::current() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册