--- old/src/share/vm/c1/c1_Compiler.cpp 2013-09-25 21:47:58.375646416 +0200 +++ new/src/share/vm/c1/c1_Compiler.cpp 2013-09-25 21:47:58.319646418 +0200 @@ -42,8 +42,6 @@ #include "runtime/interfaceSupport.hpp" #include "runtime/sharedRuntime.hpp" -volatile int Compiler::_runtimes = uninitialized; - Compiler::Compiler() { } @@ -53,7 +51,7 @@ } -void Compiler::initialize_all() { +void Compiler::init_c1_runtime() { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); Arena* arena = new (mtCompiler) Arena(); Runtime1::initialize(buffer_blob); @@ -70,32 +68,39 @@ void Compiler::initialize() { - if (_runtimes != initialized) { - initialize_runtimes( initialize_all, &_runtimes); + // Buffer blob must be allocated per C1 compiler thread at startup + BufferBlob* buffer_blob = init_buffer_blob(); + if (buffer_blob == NULL) { + // If the state is initialized, other compiler threads could have + // had enough space to allocate memory + if (!is_initialized()) { + set_state(failed); + } + // We must always park this compiler thread, since buffer blob + // allocation failed. + CompileBroker::park_compiler_thread(CompilerThread::current()); + } + + bool do_init = should_perform_init(); + if (do_init) { + init_c1_runtime(); + set_state(initialized); } - mark_initialized(); } -BufferBlob* Compiler::get_buffer_blob(ciEnv* env) { +BufferBlob* Compiler::init_buffer_blob() { // Allocate buffer blob once at startup since allocation for each // compilation seems to be too expensive (at least on Intel win32). - BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); - if (buffer_blob != NULL) { - return buffer_blob; - } + assert (CompilerThread::current()->get_buffer_blob() == NULL, "Should initialize only once"); // setup CodeBuffer. Preallocate a BufferBlob of size // NMethodSizeLimit plus some extra space for constants. int code_buffer_size = Compilation::desired_max_code_buffer_size() + Compilation::desired_max_constant_size(); - buffer_blob = BufferBlob::create("Compiler1 temporary CodeBuffer", - code_buffer_size); - if (buffer_blob == NULL) { - CompileBroker::handle_full_code_cache(); - env->record_failure("CodeCache is full"); - } else { + BufferBlob* buffer_blob = BufferBlob::create("C1 temporary CodeBuffer", code_buffer_size); + if (buffer_blob != NULL) { CompilerThread::current()->set_buffer_blob(buffer_blob); } @@ -104,15 +109,8 @@ void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { - BufferBlob* buffer_blob = Compiler::get_buffer_blob(env); - if (buffer_blob == NULL) { - return; - } - - if (!is_initialized()) { - initialize(); - } - + BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + assert(buffer_blob != NULL, "Must exist"); // invoke compilation { // We are nested here because we need for the destructor --- old/src/share/vm/c1/c1_Compiler.hpp 2013-09-25 21:47:58.635646405 +0200 +++ new/src/share/vm/c1/c1_Compiler.hpp 2013-09-25 21:47:58.579646407 +0200 @@ -30,11 +30,9 @@ // There is one instance of the Compiler per CompilerThread. class Compiler: public AbstractCompiler { - private: - - // Tracks whether runtime has been initialized - static volatile int _runtimes; + static void init_c1_runtime(); + BufferBlob* init_buffer_blob(); public: // Creation @@ -46,19 +44,12 @@ virtual bool is_c1() { return true; }; - BufferBlob* get_buffer_blob(ciEnv* env); - // Missing feature tests virtual bool supports_native() { return true; } virtual bool supports_osr () { return true; } - // Customization - virtual bool needs_adapters () { return false; } - virtual bool needs_stubs () { return false; } - // Initialization virtual void initialize(); - static void initialize_all(); // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); --- old/src/share/vm/code/codeBlob.cpp 2013-09-25 21:47:58.863646395 +0200 +++ new/src/share/vm/code/codeBlob.cpp 2013-09-25 21:47:58.811646398 +0200 @@ -245,8 +245,8 @@ } -void* BufferBlob::operator new(size_t s, unsigned size) throw() { - void* p = CodeCache::allocate(size); +void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() { + void* p = CodeCache::allocate(size, is_critical); return p; } @@ -277,7 +277,9 @@ unsigned int size = allocation_size(cb, sizeof(AdapterBlob)); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) AdapterBlob(size, cb); + // The parameter 'true' indicates a critical memory allocation. + // This means that CodeCacheMinimumFreeSpace is used, if necessary + blob = new (size, true) AdapterBlob(size, cb); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -299,7 +301,9 @@ size += round_to(buffer_size, oopSize); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) MethodHandlesAdapterBlob(size); + // The parameter 'true' indicates a critical memory allocation. + // This means that CodeCacheMinimumFreeSpace is used, if necessary + blob = new (size, true) MethodHandlesAdapterBlob(size); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); --- old/src/share/vm/code/codeBlob.hpp 2013-09-25 21:47:59.103646385 +0200 +++ new/src/share/vm/code/codeBlob.hpp 2013-09-25 21:47:59.047646388 +0200 @@ -209,7 +209,7 @@ BufferBlob(const char* name, int size); BufferBlob(const char* name, int size, CodeBuffer* cb); - void* operator new(size_t s, unsigned size) throw(); + void* operator new(size_t s, unsigned size, bool is_critical = false) throw(); public: // Creation @@ -253,7 +253,6 @@ class MethodHandlesAdapterBlob: public BufferBlob { private: MethodHandlesAdapterBlob(int size) : BufferBlob("MethodHandles adapters", size) {} - MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {} public: // Creation --- old/src/share/vm/compiler/abstractCompiler.cpp 2013-09-25 21:47:59.339646375 +0200 +++ new/src/share/vm/compiler/abstractCompiler.cpp 2013-09-25 21:47:59.287646378 +0200 @@ -25,40 +25,29 @@ #include "precompiled.hpp" #include "compiler/abstractCompiler.hpp" #include "runtime/mutexLocker.hpp" -void AbstractCompiler::initialize_runtimes(initializer f, volatile int* state) { - if (*state != initialized) { - // We are thread in native here... - CompilerThread* thread = CompilerThread::current(); - bool do_initialization = false; - { - ThreadInVMfromNative tv(thread); - ResetNoHandleMark rnhm; - MutexLocker only_one(CompileThread_lock, thread); - if ( *state == uninitialized) { - do_initialization = true; - *state = initializing; - } else { - while (*state == initializing ) { - CompileThread_lock->wait(); - } +bool AbstractCompiler::should_perform_init() { + if (_compiler_state != initialized) { + MutexLocker only_one(CompileThread_lock); + + if (_compiler_state == uninitialized) { + _compiler_state = initializing; + return true; + } else { + while (_compiler_state == initializing ) { + CompileThread_lock->wait(); } } - if (do_initialization) { - // We can not hold any locks here since JVMTI events may call agents - - // Compiler(s) run as native - - (*f)(); + } + return false; +} - // To in_vm so we can use the lock +void AbstractCompiler::set_state(int state) { + assert((_compiler_state == initializing) || (_compiler_state == failed), "wrong state"); + MutexLocker only_one(CompileThread_lock); - ThreadInVMfromNative tv(thread); - ResetNoHandleMark rnhm; - MutexLocker only_one(CompileThread_lock, thread); - assert(*state == initializing, "wrong state"); - *state = initialized; - CompileThread_lock->notify_all(); - } - } + // The state of the compiler could have been changed by another thread if + // memory allocation of the buffer blob failed. + _compiler_state = state; + CompileThread_lock->notify_all(); } --- old/src/share/vm/compiler/abstractCompiler.hpp 2013-09-25 21:47:59.579646365 +0200 +++ new/src/share/vm/compiler/abstractCompiler.hpp 2013-09-25 21:47:59.519646368 +0200 @@ -27,22 +27,18 @@ #include "ci/compilerInterface.hpp" -typedef void (*initializer)(void); - class AbstractCompiler : public CHeapObj { - private: - bool _is_initialized; // Mark whether compiler object is initialized - protected: + volatile int _compiler_state; // Used for tracking global state of compiler runtime initialization - enum { uninitialized, initializing, initialized }; + enum { uninitialized, initializing, initialized, failed }; - // This method will call the initialization method "f" once (per compiler class/subclass) - // and do so without holding any locks - void initialize_runtimes(initializer f, volatile int* state); + // This method returns true for the first compiler thread that reaches that methos. + // This thread will initialize the compiler object. + bool should_perform_init(); public: - AbstractCompiler() : _is_initialized(false) {} + AbstractCompiler() : _compiler_state(uninitialized) {} // Name of this compiler virtual const char* name() = 0; @@ -74,17 +70,13 @@ #endif // TIERED // Customization - virtual bool needs_stubs () = 0; - - void mark_initialized() { _is_initialized = true; } - bool is_initialized() { return _is_initialized; } - - virtual void initialize() = 0; - + virtual void initialize () = 0; + bool is_initialized () { return _compiler_state == initialized; } + // Get/set state of compiler objects + bool is_state_failed () { return _compiler_state == failed; } + void set_state (int state); // Compilation entry point for methods - virtual void compile_method(ciEnv* env, - ciMethod* target, - int entry_bci) { + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) { ShouldNotReachHere(); } --- old/src/share/vm/compiler/compileBroker.cpp 2013-09-25 21:47:59.811646356 +0200 +++ new/src/share/vm/compiler/compileBroker.cpp 2013-09-25 21:47:59.755646358 +0200 @@ -186,7 +186,7 @@ CompileQueue* CompileBroker::_c1_method_queue = NULL; CompileTask* CompileBroker::_task_free_list = NULL; -GrowableArray* CompileBroker::_method_threads = NULL; +GrowableArray* CompileBroker::_compiler_threads = NULL; class CompilationLog : public StringEventLog { @@ -874,10 +874,8 @@ } - -// ------------------------------------------------------------------ -// CompileBroker::make_compiler_thread -CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS) { +CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, + AbstractCompiler* comp, TRAPS) { CompilerThread* compiler_thread = NULL; Klass* k = @@ -944,6 +942,7 @@ java_lang_Thread::set_daemon(thread_oop()); compiler_thread->set_threadObj(thread_oop()); + compiler_thread->set_compiler(comp); Threads::add(compiler_thread); Thread::start(compiler_thread); } @@ -955,15 +954,12 @@ } -// ------------------------------------------------------------------ -// CompileBroker::init_compiler_threads -// -// Initialize the compilation queue void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) { EXCEPTION_MARK; #if !defined(ZERO) && !defined(SHARK) assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); #endif // !ZERO && !SHARK + // Initialize the compilation queue if (c2_compiler_count > 0) { _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); } @@ -973,7 +969,7 @@ int compiler_count = c1_compiler_count + c2_compiler_count; - _method_threads = + _compiler_threads = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray(compiler_count, true); char name_buffer[256]; @@ -981,21 +977,22 @@ // Create a name for our thread. sprintf(name_buffer, "C2 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, CHECK); - _method_threads->append(new_thread); + // Shark and C2 + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK); + _compiler_threads->append(new_thread); } for (int i = c2_compiler_count; i < compiler_count; i++) { // Create a name for our thread. sprintf(name_buffer, "C1 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, CHECK); - _method_threads->append(new_thread); + // C1 + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, _compilers[0], CHECK); + _compiler_threads->append(new_thread); } if (UsePerfData) { - PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, - compiler_count, CHECK); + PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK); } } @@ -1012,27 +1009,6 @@ } // ------------------------------------------------------------------ -// CompileBroker::is_idle -bool CompileBroker::is_idle() { - if (_c2_method_queue != NULL && !_c2_method_queue->is_empty()) { - return false; - } else if (_c1_method_queue != NULL && !_c1_method_queue->is_empty()) { - return false; - } else { - int num_threads = _method_threads->length(); - for (int i=0; iat(i)->task() != NULL) { - return false; - } - } - - // No pending or active compilations. - return true; - } -} - - -// ------------------------------------------------------------------ // CompileBroker::compile_method // // Request compilation of a method. @@ -1541,6 +1517,88 @@ free_task(task); } +// Parks the compiler thread; The thread never returns when calling this +// function +void CompileBroker::park_compiler_thread(CompilerThread* thread) { + CompileQueue* queue = thread->queue(); + // Wait forever + while (true) { + MutexLocker l (queue->lock()); + queue->lock()->wait(); + } +} + +// Disables compiler(s) if necessary +void CompileBroker::disable_compiler(AbstractCompiler* c, CompilerThread* thread) { + { + MutexLocker locker(Compile_lock); + // This disables compilation + TieredStopAtLevel = TieredStopAtLevel = 0; + + if (TieredCompilation) { + // Re-enable compilation if either C1 or C2 are good + if (c->is_c1()) { + // We can still try to compile with C2 + if ((TieredStartAtLevel <= CompLevel_full_optimization) && (TieredStopAtLevel == CompLevel_full_optimization)) { + // If we come here, C2 is still good + TieredStartAtLevel = TieredStopAtLevel = CompLevel_full_optimization; + } + } + if (c->is_c2()) { + // We can still try to compile with C1 + if ((TieredStartAtLevel <= CompLevel_simple) && (TieredStopAtLevel >= CompLevel_simple)) { + // If we come here, C1 is still good + TieredStartAtLevel = TieredStopAtLevel = CompLevel_simple; + } + } + } + } // Unlock + + assert (TieredStartAtLevel <= TieredStopAtLevel, " Sanity check"); + park_compiler_thread(thread); +} + + +// Initialize compiler thread(s) + compiler object(s). +void CompileBroker::init_compiler() { + CompilerThread* thread = CompilerThread::current(); + AbstractCompiler* comp = thread->compiler(); + // Final sanity check - the compiler object must exist + guarantee(comp != NULL, "Compiler object must exist"); + + int system_dictionary_modification_counter; + { + MutexLocker locker(Compile_lock, thread); + system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); + } + + { + // Must switch to native to allocate ci_env + ThreadToNativeFromVM ttn(thread); + ciEnv ci_env(NULL, system_dictionary_modification_counter); + // Cache Jvmti state + ci_env.cache_jvmti_state(); + // Cache DTrace flags + ci_env.cache_dtrace_flags(); + + // Switch back to VM state to to compiler initialization + CompilerThread* thread = CompilerThread::current(); + ThreadInVMfromNative tv(thread); + ResetNoHandleMark rnhm; + + if (!comp->is_shark()) { + // Perform per-thread and global initializations + comp->initialize(); + } + } + + if (comp->is_state_failed()) { + warning("Initialization of %s thread failed", comp->name()); + disable_compiler(comp, thread); + park_compiler_thread(thread); + } +} + // ------------------------------------------------------------------ // CompileBroker::compiler_thread_loop // @@ -1577,6 +1635,8 @@ log->end_elem(); } + init_compiler(); + while (true) { { // We need this HandleMark to avoid leaking VM handles. @@ -1800,7 +1860,7 @@ TraceTime t1("compilation", &time); EventCompilation event; - AbstractCompiler *comp = compiler(task_level); + AbstractCompiler *comp = compiler(task->comp_level()); if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { --- old/src/share/vm/compiler/compileBroker.hpp 2013-09-25 21:48:00.051646346 +0200 +++ new/src/share/vm/compiler/compileBroker.hpp 2013-09-25 21:48:00.003646348 +0200 @@ -266,7 +266,7 @@ static CompileQueue* _c1_method_queue; static CompileTask* _task_free_list; - static GrowableArray* _method_threads; + static GrowableArray* _compiler_threads; // performance counters static PerfCounter* _perf_total_compilation; @@ -311,7 +311,7 @@ static int _sum_nmethod_code_size; static long _peak_compilation_time; - static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS); + static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, TRAPS); 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); @@ -351,6 +351,9 @@ if (is_c1_compile(comp_level)) return _c1_method_queue; return NULL; } + static void init_compiler(); + static void disable_compiler (AbstractCompiler* c, CompilerThread* thread); + public: enum { // The entry bci used for non-OSR compilations. @@ -378,9 +381,8 @@ const char* comment, Thread* thread); static void compiler_thread_loop(); - + static void park_compiler_thread(CompilerThread* thread); static uint get_compilation_id() { return _compilation_id; } - static bool is_idle(); // Set _should_block. // Call this from the VM, with Threads_lock held and a safepoint requested. --- old/src/share/vm/opto/c2compiler.cpp 2013-09-25 21:48:00.291646335 +0200 +++ new/src/share/vm/opto/c2compiler.cpp 2013-09-25 21:48:00.235646338 +0200 @@ -44,9 +44,6 @@ # include "adfiles/ad_ppc.hpp" #endif - -volatile int C2Compiler::_runtimes = uninitialized; - // register information defined by ADLC extern const char register_save_policy[]; extern const int register_save_type[]; @@ -57,7 +54,7 @@ const char* C2Compiler::retry_no_escape_analysis() { return "retry without escape analysis"; } -void C2Compiler::initialize_runtime() { +bool C2Compiler::init_c2_runtime() { // Check assumptions used while running ADLC Compile::adlc_verification(); @@ -90,41 +87,33 @@ CompilerThread* thread = CompilerThread::current(); - HandleMark handle_mark(thread); - - OptoRuntime::generate(thread->env()); - + HandleMark handle_mark(thread); + bool successful = OptoRuntime::generate(thread->env()); + return successful; } void C2Compiler::initialize() { - - // This method can only be called once per C2Compiler object // The first compiler thread that gets here will initialize the - // small amount of global state (and runtime stubs) that c2 needs. + // small amount of global state (and runtime stubs) that C2 needs. // There is a race possible once at startup and then we're fine // Note that this is being called from a compiler thread not the // main startup thread. - - if (_runtimes != initialized) { - initialize_runtimes( initialize_runtime, &_runtimes); + bool do_init = should_perform_init(); + if (do_init) { + bool successful = C2Compiler::init_c2_runtime(); + int new_state = (successful) ? initialized : failed; + set_state(new_state); } - - // Mark this compiler object as ready to roll - mark_initialized(); } -void C2Compiler::compile_method(ciEnv* env, - ciMethod* target, - int entry_bci) { - if (!is_initialized()) { - initialize(); - } +void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + assert(is_initialized(), "Compiler thread must be initialized"); + bool subsume_loads = SubsumeLoads; - bool do_escape_analysis = DoEscapeAnalysis && - !env->jvmti_can_access_local_variables(); + bool do_escape_analysis = DoEscapeAnalysis && !env->jvmti_can_access_local_variables(); bool eliminate_boxing = EliminateAutoBox; while (!env->failing()) { // Attempt to compile while subsuming loads into machine instructions. --- old/src/share/vm/opto/c2compiler.hpp 2013-09-25 21:48:00.539646325 +0200 +++ new/src/share/vm/opto/c2compiler.hpp 2013-09-25 21:48:00.483646327 +0200 @@ -28,24 +28,17 @@ #include "compiler/abstractCompiler.hpp" class C2Compiler : public AbstractCompiler { -private: - - static void initialize_runtime(); + private: + static bool init_c2_runtime(); public: // Name const char *name() { return "C2"; } - static volatile int _runtimes; - #ifdef TIERED virtual bool is_c2() { return true; }; #endif // TIERED - // Customization - bool needs_adapters () { return true; } - bool needs_stubs () { return true; } - void initialize(); // Compilation entry point for methods --- old/src/share/vm/opto/runtime.cpp 2013-09-25 21:48:00.787646315 +0200 +++ new/src/share/vm/opto/runtime.cpp 2013-09-25 21:48:00.731646317 +0200 @@ -138,9 +138,10 @@ #define gen(env, var, type_func_gen, c_func, fancy_jump, pass_tls, save_arg_regs, return_pc) \ - var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc) + var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc); \ + if (var == NULL) { return false; } -void OptoRuntime::generate(ciEnv* env) { +bool OptoRuntime::generate(ciEnv* env) { generate_exception_blob(); @@ -158,7 +159,7 @@ gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true , false, false); gen(env, _g1_wb_pre_Java , g1_wb_pre_Type , SharedRuntime::g1_wb_pre , 0 , false, false, false); gen(env, _g1_wb_post_Java , g1_wb_post_Type , SharedRuntime::g1_wb_post , 0 , false, false, false); - gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C , 0 , false, false, false); + gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C, 0, false, false, false); gen(env, _rethrow_Java , rethrow_Type , rethrow_C , 2 , true , false, true ); gen(env, _slow_arraycopy_Java , slow_arraycopy_Type , SharedRuntime::slow_arraycopy_C , 0 , false, false, false); @@ -168,7 +169,7 @@ gen(env, _zap_dead_Java_locals_Java , zap_dead_locals_Type , zap_dead_Java_locals_C , 0 , false, true , false ); gen(env, _zap_dead_native_locals_Java , zap_dead_locals_Type , zap_dead_native_locals_C , 0 , false, true , false ); # endif - + return true; } #undef gen --- old/src/share/vm/opto/runtime.hpp 2013-09-25 21:48:01.035646304 +0200 +++ new/src/share/vm/opto/runtime.hpp 2013-09-25 21:48:00.979646307 +0200 @@ -203,8 +203,10 @@ static bool is_callee_saved_register(MachRegisterNumbers reg); - // One time only generate runtime code stubs - static void generate(ciEnv* env); + // One time only generate runtime code stubs. Returns true + // when runtime stubs have been generated successfully and + // false otherwise. + static bool generate(ciEnv* env); // Returns the name of a stub static const char* stub_name(address entry); --- old/src/share/vm/runtime/advancedThresholdPolicy.cpp 2013-09-25 21:48:01.271646294 +0200 +++ new/src/share/vm/runtime/advancedThresholdPolicy.cpp 2013-09-25 21:48:01.215646297 +0200 @@ -191,7 +191,7 @@ } if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile - && is_method_profiled(max_method)) { + && is_method_profiled(max_method) && CompLevel_limited_profile >= TieredStartAtLevel) { max_task->set_comp_level(CompLevel_limited_profile); if (PrintTieredEvents) { print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); @@ -397,7 +397,8 @@ break; } } - return MIN2(next_level, (CompLevel)TieredStopAtLevel); + next_level = MIN2(next_level, (CompLevel)TieredStopAtLevel); + return MAX2(next_level, (CompLevel)TieredStartAtLevel); } // Determine if a method should be compiled with a normal entry point at a different level. @@ -471,6 +472,12 @@ if (is_compilation_enabled()) { CompLevel next_osr_level = loop_event(imh(), level); CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level(); + next_osr_level = MIN2((CompLevel)TieredStartAtLevel, next_osr_level); + // Do not compile of TieredStartAtLevel > max_osr_level + if (next_osr_level > max_osr_level) { + return; + } + // At the very least compile the OSR version if (!CompileBroker::compilation_is_in_queue(imh, bci) && next_osr_level != level) { compile(imh, bci, next_osr_level, thread); @@ -518,7 +525,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, bci) && next_level != cur_level && next_level >= TieredStartAtLevel) { compile(imh, InvocationEntryBci, next_level, thread); } } --- old/src/share/vm/runtime/arguments.cpp 2013-09-25 21:48:01.519646284 +0200 +++ new/src/share/vm/runtime/arguments.cpp 2013-09-25 21:48:01.459646286 +0200 @@ -2258,6 +2258,17 @@ (2*G)/M); status = false; } + + status = status && verify_interval(TieredStartAtLevel, 0, 4, "TieredStartAtLevel"); + status = status && verify_interval(TieredStopAtLevel, 0, 4, "TieredStopAtLevel"); + + if (TieredStartAtLevel > TieredStopAtLevel) { + jio_fprintf(defaultStream::error_stream(), + "TieredStartAtLevel=%d must be <= TieredStopAtLevel=%d.\n", + TieredStartAtLevel, TieredStopAtLevel); + status = false; + } + return status; } --- old/src/share/vm/runtime/globals.hpp 2013-09-25 21:48:01.787646273 +0200 +++ new/src/share/vm/runtime/globals.hpp 2013-09-25 21:48:01.727646275 +0200 @@ -3456,6 +3456,9 @@ product(intx, TieredStopAtLevel, 4, \ "Stop at given compilation level") \ \ + product(intx, TieredStartAtLevel, 0, \ + "Start at given compilation level") \ + \ product(intx, Tier0ProfilingStartPercentage, 200, \ "Start profiling in interpreter if the counters exceed tier 3" \ "thresholds by the specified percentage") \ --- old/src/share/vm/runtime/simpleThresholdPolicy.cpp 2013-09-25 21:48:02.071646261 +0200 +++ new/src/share/vm/runtime/simpleThresholdPolicy.cpp 2013-09-25 21:48:02.015646263 +0200 @@ -217,7 +217,8 @@ // Check if the method can be compiled, change level if necessary void SimpleThresholdPolicy::compile(methodHandle mh, int bci, CompLevel level, JavaThread* thread) { - assert(level <= TieredStopAtLevel, "Invalid compilation level"); + assert(level <= TieredStopAtLevel, "Invalid compilation level - level too large"); + assert(level >= TieredStartAtLevel, "Invalid compilation level - level too small"); if (level == CompLevel_none) { return; } @@ -330,7 +331,8 @@ break; } } - return MIN2(next_level, (CompLevel)TieredStopAtLevel); + next_level = MIN2(next_level, (CompLevel)TieredStopAtLevel); + return MAX2(next_level, (CompLevel)TieredStartAtLevel); } // Determine if a method should be compiled with a normal entry point at a different level. --- old/src/share/vm/runtime/simpleThresholdPolicy.hpp 2013-09-25 21:48:02.307646251 +0200 +++ new/src/share/vm/runtime/simpleThresholdPolicy.hpp 2013-09-25 21:48:02.247646253 +0200 @@ -98,7 +98,7 @@ if (is_c2_compile(comp_level)) return c2_count(); return 0; } - virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, CompLevel_initial_compile); } + virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, (CompLevel)TieredStartAtLevel); } virtual void do_safepoint_work() { } virtual void delay_compilation(Method* method) { } virtual void disable_compilation(Method* method) { } --- old/src/share/vm/runtime/thread.cpp 2013-09-25 21:48:02.571646240 +0200 +++ new/src/share/vm/runtime/thread.cpp 2013-09-25 21:48:02.507646242 +0200 @@ -1452,7 +1452,6 @@ _interp_only_mode = 0; _special_runtime_exit_condition = _no_async_condition; _pending_async_exception = NULL; - _is_compiling = false; _thread_stat = NULL; _thread_stat = new ThreadStatistics(); _blocked_on_compilation = false; @@ -3237,6 +3236,7 @@ _counters = counters; _buffer_blob = NULL; _scanned_nmethod = NULL; + _compiler = NULL; #ifndef PRODUCT _ideal_graph_printer = NULL; --- old/src/share/vm/runtime/thread.hpp 2013-09-25 21:48:02.915646225 +0200 +++ new/src/share/vm/runtime/thread.hpp 2013-09-25 21:48:02.855646228 +0200 @@ -923,9 +923,6 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. - // support for compilation - bool _is_compiling; // is true if a compilation is active inthis thread (one compilation per thread possible) - // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -1005,10 +1002,6 @@ // Testers virtual bool is_Java_thread() const { return true; } - // compilation - void set_is_compiling(bool f) { _is_compiling = f; } - bool is_compiling() const { return _is_compiling; } - // Thread chain operations JavaThread* next() const { return _next; } void set_next(JavaThread* p) { _next = p; } @@ -1811,13 +1804,14 @@ private: CompilerCounters* _counters; - ciEnv* _env; - CompileLog* _log; - CompileTask* _task; - CompileQueue* _queue; - BufferBlob* _buffer_blob; + ciEnv* _env; + CompileLog* _log; + CompileTask* _task; + CompileQueue* _queue; + BufferBlob* _buffer_blob; - nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + AbstractCompiler* _compiler; public: @@ -1829,14 +1823,17 @@ // Hide this compiler thread from external view. bool is_hidden_from_external_view() const { return true; } - CompileQueue* queue() { return _queue; } - CompilerCounters* counters() { return _counters; } + void set_compiler(AbstractCompiler* c) { _compiler = c; } + AbstractCompiler* compiler() const { return _compiler; } + + CompileQueue* queue() const { return _queue; } + CompilerCounters* counters() const { return _counters; } // Get/set the thread's compilation environment. ciEnv* env() { return _env; } void set_env(ciEnv* env) { _env = env; } - BufferBlob* get_buffer_blob() { return _buffer_blob; } + BufferBlob* get_buffer_blob() const { return _buffer_blob; } void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }; // Get/set the thread's logging information --- old/src/share/vm/runtime/vmStructs.cpp 2013-09-25 21:48:03.175646214 +0200 +++ new/src/share/vm/runtime/vmStructs.cpp 2013-09-25 21:48:03.123646216 +0200 @@ -909,7 +909,6 @@ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ - nonstatic_field(JavaThread, _is_compiling, bool) \ nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \ --- old/src/share/vm/shark/sharkCompiler.cpp 2013-09-25 21:48:03.443646203 +0200 +++ new/src/share/vm/shark/sharkCompiler.cpp 2013-09-25 21:48:03.391646205 +0200 @@ -133,11 +133,10 @@ exit(1); } - execution_engine()->addModule( - _native_context->module()); + execution_engine()->addModule(_native_context->module()); // All done - mark_initialized(); + set_state(initialized); } void SharkCompiler::initialize() { --- old/src/share/vm/shark/sharkCompiler.hpp 2013-09-25 21:48:03.687646193 +0200 +++ new/src/share/vm/shark/sharkCompiler.hpp 2013-09-25 21:48:03.631646195 +0200 @@ -50,10 +50,6 @@ return ! (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()); } - // Customization - bool needs_adapters() { return false; } - bool needs_stubs() { return false; } - // Initialization void initialize();