6996747: SIGSEGV in nmethod::cleanup_inline_caches / CompiledIC::verify
Reviewed-by: kvn, iveresov
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon May 16 14:21:16 2011 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Mon May 16 22:16:44 2011 -0700
@@ -2909,6 +2909,12 @@
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") \
\
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Mon May 16 14:21:16 2011 -0700
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Mon May 16 22:16:44 2011 -0700
@@ -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 @@
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 @@
}
}
+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 @@
// 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 @@
}
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 @@
}
nm->make_zombie();
_rescan = true;
+ SWEEP(nm);
} else {
// Still alive, clean up its inline caches
MutexLocker cl(CompiledIC_lock);
@@ -265,6 +383,7 @@
// 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 @@
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 @@
// Clean-up all inline caches that points to zombie/non-reentrant methods
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
+ SWEEP(nm);
}
}
--- a/hotspot/src/share/vm/runtime/sweeper.hpp Mon May 16 14:21:16 2011 -0700
+++ b/hotspot/src/share/vm/runtime/sweeper.hpp Mon May 16 22:16:44 2011 -0700
@@ -57,6 +57,13 @@
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
--- a/hotspot/src/share/vm/runtime/thread.cpp Mon May 16 14:21:16 2011 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Mon May 16 22:16:44 2011 -0700
@@ -2942,12 +2942,22 @@
_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 ========
--- a/hotspot/src/share/vm/runtime/thread.hpp Mon May 16 14:21:16 2011 -0700
+++ b/hotspot/src/share/vm/runtime/thread.hpp Mon May 16 22:16:44 2011 -0700
@@ -439,7 +439,7 @@
// 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 @@
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 @@
CompileQueue* _queue;
BufferBlob* _buffer_blob;
+ nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
+
public:
static CompilerThread* current();
@@ -1726,6 +1728,11 @@
_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 @@
// 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() {