# HG changeset patch # User anoll # Date 1398751162 -7200 # Node ID 41dcdd636080fb837033ca7b2ee0811c471b0f59 # Parent ef9eda2c1abe034a8d0bbcb2dbc7bea678115012 8040798: compiler/startup/SmallCodeCacheStartup.java timed out in RT_Baseline Summary: Fixes broken memory freeing of compile queue tasks and makes sure that blocking compiles do not hang the VM if compilation gets disabled due to a full code cache. Reviewed-by: kvn, iveresov diff -r ef9eda2c1abe -r 41dcdd636080 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Oct 30 10:51:06 2014 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Tue Apr 29 07:59:22 2014 +0200 @@ -183,9 +183,8 @@ long CompileBroker::_peak_compilation_time = 0; -CompileQueue* CompileBroker::_c2_method_queue = NULL; -CompileQueue* CompileBroker::_c1_method_queue = NULL; -CompileTask* CompileBroker::_task_free_list = NULL; +CompileQueue* CompileBroker::_c2_compile_queue = NULL; +CompileQueue* CompileBroker::_c1_compile_queue = NULL; GrowableArray* CompileBroker::_compiler_threads = NULL; @@ -253,13 +252,56 @@ // By convention, the compiling thread is responsible for // recycling a non-blocking CompileTask. - CompileBroker::free_task(task); + CompileTask::free(task); } } -// ------------------------------------------------------------------ -// CompileTask::initialize +CompileTask* CompileTask::_task_free_list = NULL; +#ifdef ASSERT +int CompileTask::_num_allocated_tasks = 0; +#endif +/** + * Allocate a CompileTask, from the free list if possible. + */ +CompileTask* CompileTask::allocate() { + MutexLocker locker(CompileTaskAlloc_lock); + CompileTask* task = NULL; + + if (_task_free_list != NULL) { + task = _task_free_list; + _task_free_list = task->next(); + task->set_next(NULL); + } else { + task = new CompileTask(); + DEBUG_ONLY(_num_allocated_tasks++;) + assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?"); + task->set_next(NULL); + task->set_is_free(true); + } + assert(task->is_free(), "Task must be free."); + task->set_is_free(false); + return task; +} + + +/** + * Add a task to the free list. + */ +void CompileTask::free(CompileTask* task) { + MutexLocker locker(CompileTaskAlloc_lock); + if (!task->is_free()) { + task->set_code(NULL); + assert(!task->lock()->is_locked(), "Should not be locked when freed"); + JNIHandles::destroy_global(task->_method_holder); + JNIHandles::destroy_global(task->_hot_method_holder); + + task->set_is_free(true); + task->set_next(_task_free_list); + _task_free_list = task; + } +} + void CompileTask::initialize(int compile_id, methodHandle method, int osr_bci, @@ -318,15 +360,6 @@ if (nm == NULL) _code_handle = NULL; // drop the handle also } -// ------------------------------------------------------------------ -// CompileTask::free -void CompileTask::free() { - set_code(NULL); - assert(!_lock->is_locked(), "Should not be locked when freed"); - JNIHandles::destroy_global(_method_holder); - JNIHandles::destroy_global(_hot_method_holder); -} - void CompileTask::mark_on_stack() { // Mark these methods as something redefine classes cannot remove. @@ -594,9 +627,12 @@ -// Add a CompileTask to a CompileQueue +/** + * Add a CompileTask to a CompileQueue + */ void CompileQueue::add(CompileTask* task) { assert(lock()->owned_by_self(), "must own lock"); + assert(!CompileBroker::is_compilation_disabled_forever(), "Do not add task if compilation is turned off forever"); task->set_next(NULL); task->set_prev(NULL); @@ -618,9 +654,7 @@ // Mark the method as being in the compile queue. task->method()->set_queued_for_compilation(); - if (CIPrintCompileQueue) { - print(); - } + NOT_PRODUCT(print();) if (LogCompilation && xtty != NULL) { task->log_task_queued(); @@ -630,14 +664,19 @@ lock()->notify_all(); } -void CompileQueue::delete_all() { - assert(lock()->owned_by_self(), "must own lock"); +void CompileQueue::free_all() { + MutexLocker mu(lock()); if (_first != NULL) { for (CompileTask* task = _first; task != NULL; task = task->next()) { - delete task; + // Wake up thread that blocks on the compile task. + task->lock()->notify(); + // Puts task back on the freelist. + CompileTask::free(task); } _first = NULL; } + // Wake up all threads that block on the queue. + lock()->notify_all(); } // ------------------------------------------------------------------ @@ -767,18 +806,24 @@ } } -// ------------------------------------------------------------------ -// CompileQueue::print +#ifndef PRODUCT +/** + * Print entire compilation queue. + */ void CompileQueue::print() { - tty->print_cr("Contents of %s", name()); - tty->print_cr("----------------------"); - CompileTask* task = _first; - while (task != NULL) { - task->print_line(); - task = task->next(); + if (CIPrintCompileQueue) { + ttyLocker ttyl; + tty->print_cr("Contents of %s", name()); + tty->print_cr("----------------------"); + CompileTask* task = _first; + while (task != NULL) { + task->print_line(); + task = task->next(); + } + tty->print_cr("----------------------"); } - tty->print_cr("----------------------"); } +#endif // PRODUCT CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) { @@ -851,9 +896,6 @@ _compilers[1] = new SharkCompiler(); #endif // SHARK - // Initialize the CompileTask free list - _task_free_list = NULL; - // Start the CompilerThreads init_compiler_threads(c1_count, c2_count); // totalTime performance counter is always created as it is required @@ -1046,11 +1088,11 @@ #endif // !ZERO && !SHARK // Initialize the compilation queue if (c2_compiler_count > 0) { - _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); + _c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock); _compilers[1]->set_num_compiler_threads(c2_compiler_count); } if (c1_compiler_count > 0) { - _c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock); + _c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock); _compilers[0]->set_num_compiler_threads(c1_compiler_count); } @@ -1065,7 +1107,7 @@ sprintf(name_buffer, "C2 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); // Shark and C2 - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], CHECK); _compiler_threads->append(new_thread); } @@ -1074,7 +1116,7 @@ sprintf(name_buffer, "C1 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); // C1 - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, _compilers[0], CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], CHECK); _compiler_threads->append(new_thread); } @@ -1084,14 +1126,18 @@ } -// Set the methods on the stack as on_stack so that redefine classes doesn't -// reclaim them +/** + * Set the methods on the stack as on_stack so that redefine classes doesn't + * reclaim them + */ void CompileBroker::mark_on_stack() { - if (_c2_method_queue != NULL) { - _c2_method_queue->mark_on_stack(); + if (_c2_compile_queue != NULL) { + MutexLocker locker(_c2_compile_queue->lock()); + _c2_compile_queue->mark_on_stack(); } - if (_c1_method_queue != NULL) { - _c1_method_queue->mark_on_stack(); + if (_c1_compile_queue != NULL) { + MutexLocker locker(_c1_compile_queue->lock()); + _c1_compile_queue->mark_on_stack(); } } @@ -1107,7 +1153,7 @@ const char* comment, Thread* thread) { // do nothing if compiler thread(s) is not available - if (!_initialized ) { + if (!_initialized) { return; } @@ -1154,7 +1200,7 @@ // If this method is already in the compile queue, then // we do not block the current thread. - if (compilation_is_in_queue(method, osr_bci)) { + if (compilation_is_in_queue(method)) { // We may want to decay our counter a bit here to prevent // multiple denied requests for compilation. This is an // open compilation policy issue. Note: The other possibility, @@ -1193,7 +1239,7 @@ // Make sure the method has not slipped into the queues since // last we checked; note that those checks were "fast bail-outs". // Here we need to be more careful, see 14012000 below. - if (compilation_is_in_queue(method, osr_bci)) { + if (compilation_is_in_queue(method)) { return; } @@ -1214,7 +1260,7 @@ } // Should this thread wait for completion of the compile? - blocking = is_compile_blocking(method, osr_bci); + blocking = is_compile_blocking(); // We will enter the compilation in the queue. // 14012000: Note that this sets the queued_for_compile bits in @@ -1406,19 +1452,17 @@ } -// ------------------------------------------------------------------ -// CompileBroker::compilation_is_in_queue -// -// See if this compilation is already requested. -// -// Implementation note: there is only a single "is in queue" bit -// for each method. This means that the check below is overly -// conservative in the sense that an osr compilation in the queue -// will block a normal compilation from entering the queue (and vice -// versa). This can be remedied by a full queue search to disambiguate -// cases. If it is deemed profitible, this may be done. -bool CompileBroker::compilation_is_in_queue(methodHandle method, - int osr_bci) { +/** + * See if this compilation is already requested. + * + * Implementation note: there is only a single "is in queue" bit + * for each method. This means that the check below is overly + * conservative in the sense that an osr compilation in the queue + * will block a normal compilation from entering the queue (and vice + * versa). This can be remedied by a full queue search to disambiguate + * cases. If it is deemed profitable, this may be done. + */ +bool CompileBroker::compilation_is_in_queue(methodHandle method) { return method->queued_for_compilation(); } @@ -1498,13 +1542,11 @@ #endif } - -// ------------------------------------------------------------------ -// CompileBroker::is_compile_blocking -// -// Should the current thread be blocked until this compilation request -// has been fulfilled? -bool CompileBroker::is_compile_blocking(methodHandle method, int osr_bci) { +/** + * Should the current thread block until this compilation request + * has been fulfilled? + */ +bool CompileBroker::is_compile_blocking() { assert(!InstanceRefKlass::owns_pending_list_lock(JavaThread::current()), "possible deadlock"); return !BackgroundCompilation; } @@ -1532,7 +1574,7 @@ int hot_count, const char* comment, bool blocking) { - CompileTask* new_task = allocate_task(); + CompileTask* new_task = CompileTask::allocate(); new_task->initialize(compile_id, method, osr_bci, comp_level, hot_method, hot_count, comment, blocking); @@ -1541,75 +1583,52 @@ } -// ------------------------------------------------------------------ -// CompileBroker::allocate_task -// -// Allocate a CompileTask, from the free list if possible. -CompileTask* CompileBroker::allocate_task() { - MutexLocker locker(CompileTaskAlloc_lock); - CompileTask* task = NULL; - if (_task_free_list != NULL) { - task = _task_free_list; - _task_free_list = task->next(); - task->set_next(NULL); - } else { - task = new CompileTask(); - task->set_next(NULL); - } - return task; -} - - -// ------------------------------------------------------------------ -// CompileBroker::free_task -// -// Add a task to the free list. -void CompileBroker::free_task(CompileTask* task) { - MutexLocker locker(CompileTaskAlloc_lock); - task->free(); - task->set_next(_task_free_list); - _task_free_list = task; -} - - -// ------------------------------------------------------------------ -// CompileBroker::wait_for_completion -// -// Wait for the given method CompileTask to complete. +/** + * Wait for the compilation task to complete. + */ void CompileBroker::wait_for_completion(CompileTask* task) { if (CIPrintCompileQueue) { + ttyLocker ttyl; tty->print_cr("BLOCKING FOR COMPILE"); } assert(task->is_blocking(), "can only wait on blocking task"); - JavaThread *thread = JavaThread::current(); + JavaThread* thread = JavaThread::current(); thread->set_blocked_on_compilation(true); methodHandle method(thread, task->method()); { MutexLocker waiter(task->lock(), thread); - while (!task->is_complete()) + while (!task->is_complete() && !is_compilation_disabled_forever()) { task->lock()->wait(); + } } + + thread->set_blocked_on_compilation(false); + if (is_compilation_disabled_forever()) { + CompileTask::free(task); + return; + } + // It is harmless to check this status without the lock, because // completion is a stable property (until the task object is recycled). assert(task->is_complete(), "Compilation should have completed"); assert(task->code_handle() == NULL, "must be reset"); - thread->set_blocked_on_compilation(false); - // By convention, the waiter is responsible for recycling a // blocking CompileTask. Since there is only one waiter ever // waiting on a CompileTask, we know that no one else will // be using this CompileTask; we can free it. - free_task(task); + CompileTask::free(task); } -// Initialize compiler thread(s) + compiler object(s). The postcondition -// of this function is that the compiler runtimes are initialized and that -//compiler threads can start compiling. +/** + * Initialize compiler thread(s) + compiler object(s). The postcondition + * of this function is that the compiler runtimes are initialized and that + * compiler threads can start compiling. + */ bool CompileBroker::init_compiler_runtime() { CompilerThread* thread = CompilerThread::current(); AbstractCompiler* comp = thread->compiler(); @@ -1646,7 +1665,6 @@ disable_compilation_forever(); // If compiler initialization failed, no compiler thread that is specific to a // particular compiler runtime will ever start to compile methods. - shutdown_compiler_runtime(comp, thread); return false; } @@ -1660,9 +1678,11 @@ return true; } -// If C1 and/or C2 initialization failed, we shut down all compilation. -// We do this to keep things simple. This can be changed if it ever turns out to be -// a problem. +/** + * If C1 and/or C2 initialization failed, we shut down all compilation. + * We do this to keep things simple. This can be changed if it ever turns + * out to be a problem. + */ void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) { // Free buffer blob, if allocated if (thread->get_buffer_blob() != NULL) { @@ -1674,28 +1694,25 @@ // There are two reasons for shutting down the compiler // 1) compiler runtime initialization failed // 2) The code cache is full and the following flag is set: -XX:-UseCodeCacheFlushing - warning("Shutting down compiler %s (no space to run compilers)", comp->name()); + warning("%s initialization failed. Shutting down all compilers", comp->name()); // Only one thread per compiler runtime object enters here // Set state to shut down comp->set_shut_down(); - MutexLocker mu(MethodCompileQueue_lock, thread); - CompileQueue* queue; - if (_c1_method_queue != NULL) { - _c1_method_queue->delete_all(); - queue = _c1_method_queue; - _c1_method_queue = NULL; - delete _c1_method_queue; + // Delete all queued compilation tasks to make compiler threads exit faster. + if (_c1_compile_queue != NULL) { + _c1_compile_queue->free_all(); } - if (_c2_method_queue != NULL) { - _c2_method_queue->delete_all(); - queue = _c2_method_queue; - _c2_method_queue = NULL; - delete _c2_method_queue; + if (_c2_compile_queue != NULL) { + _c2_compile_queue->free_all(); } + // Set flags so that we continue execution with using interpreter only. + UseCompiler = false; + UseInterpreter = true; + // We could delete compiler runtimes also. However, there are references to // the compiler runtime(s) (e.g., nmethod::is_compiled_by_c1()) which then // fail. This can be done later if necessary. diff -r ef9eda2c1abe -r 41dcdd636080 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Thu Oct 30 10:51:06 2014 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Tue Apr 29 07:59:22 2014 +0200 @@ -40,6 +40,11 @@ friend class VMStructs; private: + static CompileTask* _task_free_list; +#ifdef ASSERT + static int _num_allocated_tasks; +#endif + Monitor* _lock; uint _compile_id; Method* _method; @@ -52,7 +57,7 @@ int _num_inlined_bytecodes; nmethodLocker* _code_handle; // holder of eventual result CompileTask* _next, *_prev; - + bool _is_free; // Fields used for logging why the compilation was initiated: jlong _time_queued; // in units of os::elapsed_counter() Method* _hot_method; // which method actually triggered this task @@ -70,7 +75,8 @@ methodHandle hot_method, int hot_count, const char* comment, bool is_blocking); - void free(); + static CompileTask* allocate(); + static void free(CompileTask* task); int compile_id() const { return _compile_id; } Method* method() const { return _method; } @@ -99,6 +105,8 @@ void set_next(CompileTask* next) { _next = next; } CompileTask* prev() const { return _prev; } void set_prev(CompileTask* prev) { _prev = prev; } + bool is_free() const { return _is_free; } + void set_is_free(bool val) { _is_free = val; } private: static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, @@ -225,8 +233,8 @@ // Redefine Classes support void mark_on_stack(); - void delete_all(); - void print(); + void free_all(); + NOT_PRODUCT (void print();) ~CompileQueue() { assert (is_empty(), " Compile Queue must be empty"); @@ -279,9 +287,8 @@ static int _last_compile_level; static char _last_method_compiled[name_buffer_length]; - static CompileQueue* _c2_method_queue; - static CompileQueue* _c1_method_queue; - static CompileTask* _task_free_list; + static CompileQueue* _c2_compile_queue; + static CompileQueue* _c1_compile_queue; static GrowableArray* _compiler_threads; @@ -334,7 +341,7 @@ static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); - static bool is_compile_blocking (methodHandle method, int osr_bci); + static bool is_compile_blocking (); static void preload_classes (methodHandle method, TRAPS); static CompileTask* create_compile_task(CompileQueue* queue, @@ -346,8 +353,6 @@ int hot_count, const char* comment, bool blocking); - static CompileTask* allocate_task(); - static void free_task(CompileTask* task); static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); @@ -365,8 +370,8 @@ const char* comment, Thread* thread); static CompileQueue* compile_queue(int comp_level) { - if (is_c2_compile(comp_level)) return _c2_method_queue; - if (is_c1_compile(comp_level)) return _c1_method_queue; + if (is_c2_compile(comp_level)) return _c2_compile_queue; + if (is_c1_compile(comp_level)) return _c1_compile_queue; return NULL; } static bool init_compiler_runtime(); @@ -384,7 +389,7 @@ return NULL; } - static bool compilation_is_in_queue(methodHandle method, int osr_bci); + static bool compilation_is_in_queue(methodHandle method); static int queue_size(int comp_level) { CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0; diff -r ef9eda2c1abe -r 41dcdd636080 src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Oct 30 10:51:06 2014 +0100 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Tue Apr 29 07:59:22 2014 +0200 @@ -451,7 +451,7 @@ if (should_create_mdo(mh(), level)) { create_mdo(mh, thread); } - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { CompLevel next_level = call_event(mh(), level); if (next_level != level) { compile(mh, InvocationEntryBci, next_level, thread); @@ -475,7 +475,7 @@ CompLevel next_osr_level = loop_event(imh(), level); CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level(); // At the very least compile the OSR version - if (!CompileBroker::compilation_is_in_queue(imh, bci) && next_osr_level != level) { + if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) { compile(imh, bci, next_osr_level, thread); } @@ -509,7 +509,7 @@ nm->make_not_entrant(); } } - if (!CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (!CompileBroker::compilation_is_in_queue(mh)) { // Fix up next_level if necessary to avoid deopts if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) { next_level = CompLevel_full_profile; @@ -521,7 +521,7 @@ } else { cur_level = comp_level(imh()); next_level = call_event(imh(), cur_level); - if (!CompileBroker::compilation_is_in_queue(imh, bci) && next_level != cur_level) { + if (!CompileBroker::compilation_is_in_queue(imh) && (next_level != cur_level)) { compile(imh, InvocationEntryBci, next_level, thread); } } diff -r ef9eda2c1abe -r 41dcdd636080 src/share/vm/runtime/simpleThresholdPolicy.cpp --- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Oct 30 10:51:06 2014 +0100 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Tue Apr 29 07:59:22 2014 +0200 @@ -239,7 +239,7 @@ if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { return; } - if (!CompileBroker::compilation_is_in_queue(mh, bci)) { + if (!CompileBroker::compilation_is_in_queue(mh)) { if (PrintTieredEvents) { print_event(COMPILE, mh, mh, bci, level); } @@ -378,7 +378,7 @@ // Handle the invocation event. void SimpleThresholdPolicy::method_invocation_event(methodHandle mh, methodHandle imh, CompLevel level, nmethod* nm, JavaThread* thread) { - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { CompLevel next_level = call_event(mh(), level); if (next_level != level) { compile(mh, InvocationEntryBci, next_level, thread); @@ -391,8 +391,8 @@ void SimpleThresholdPolicy::method_back_branch_event(methodHandle mh, methodHandle imh, int bci, CompLevel level, nmethod* nm, JavaThread* thread) { // If the method is already compiling, quickly bail out. - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, bci)) { - // Use loop event as an opportinity to also check there's been + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) { + // Use loop event as an opportunity to also check there's been // enough calls. CompLevel cur_level = comp_level(mh()); CompLevel next_level = call_event(mh(), cur_level);