# HG changeset patch # User twisti # Date 1305013503 25200 # Node ID e2a92dd0d3d26313c3e405b1c173189010c7181e # Parent 3cfb240033d156123796c3f21133b92d7a6f6fb3 7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters Reviewed-by: jrose, never, kvn diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/ci/ciMethodHandle.cpp --- a/src/share/vm/ci/ciMethodHandle.cpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/ci/ciMethodHandle.cpp Tue May 10 00:45:03 2011 -0700 @@ -42,7 +42,7 @@ methodHandle callee(_callee->get_methodOop()); // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. - MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD); + MethodHandleCompiler mhc(h, callee, call_profile()->count(), is_invokedynamic, THREAD); if (!HAS_PENDING_EXCEPTION) { methodHandle m = mhc.compile(THREAD); if (!HAS_PENDING_EXCEPTION) { diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/ci/ciMethodHandle.hpp --- a/src/share/vm/ci/ciMethodHandle.hpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/ci/ciMethodHandle.hpp Tue May 10 00:45:03 2011 -0700 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_CI_CIMETHODHANDLE_HPP #define SHARE_VM_CI_CIMETHODHANDLE_HPP +#include "ci/ciCallProfile.hpp" #include "ci/ciInstance.hpp" #include "prims/methodHandles.hpp" @@ -33,7 +34,8 @@ // The class represents a java.lang.invoke.MethodHandle object. class ciMethodHandle : public ciInstance { private: - ciMethod* _callee; + ciMethod* _callee; + ciCallProfile* _profile; // Return an adapter for this MethodHandle. ciMethod* get_adapter(bool is_invokedynamic) const; @@ -50,6 +52,9 @@ ciMethod* callee() const { return _callee; } void set_callee(ciMethod* m) { _callee = m; } + ciCallProfile* call_profile() const { return _profile; } + void set_call_profile(ciCallProfile* profile) { _profile = profile; } + // Return an adapter for a MethodHandle call. ciMethod* get_method_handle_adapter() const { return get_adapter(false); diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/opto/bytecodeInfo.cpp Tue May 10 00:45:03 2011 -0700 @@ -89,7 +89,7 @@ } // positive filter: should send be inlined? returns NULL, if yes, or rejection msg -const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const { +const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const { // Allows targeted inlining if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); @@ -102,8 +102,7 @@ // positive filter: should send be inlined? returns NULL (--> yes) // or rejection msg - int max_size = C->max_inline_size(); - int size = callee_method->code_size(); + int size = callee_method->code_size(); // Check for too many throws (and not too huge) if(callee_method->interpreter_throwout_count() > InlineThrowCount && @@ -120,18 +119,36 @@ return NULL; // size and frequency are represented in a new way } + int default_max_inline_size = C->max_inline_size(); + int inline_small_code_size = InlineSmallCode / 4; + int max_inline_size = default_max_inline_size; + int call_site_count = method()->scale_count(profile.count()); int invoke_count = method()->interpreter_invocation_count(); - assert( invoke_count != 0, "Require invokation count greater than zero"); - int freq = call_site_count/invoke_count; + + // Bytecoded method handle adapters do not have interpreter + // profiling data but only made up MDO data. Get the counter from + // there. + if (caller_method->is_method_handle_adapter()) { + assert(method()->method_data_or_null(), "must have an MDO"); + ciMethodData* mdo = method()->method_data(); + ciProfileData* mha_profile = mdo->bci_to_data(caller_bci); + assert(mha_profile, "must exist"); + CounterData* cd = mha_profile->as_CounterData(); + invoke_count = cd->count(); + call_site_count = invoke_count; // use the same value + } + + assert(invoke_count != 0, "require invocation count greater than zero"); + int freq = call_site_count / invoke_count; // bump the max size if the call is frequent if ((freq >= InlineFrequencyRatio) || (call_site_count >= InlineFrequencyCount) || is_init_with_ea(callee_method, caller_method, C)) { - max_size = C->freq_inline_size(); - if (size <= max_size && TraceFrequencyInlining) { + max_inline_size = C->freq_inline_size(); + if (size <= max_inline_size && TraceFrequencyInlining) { CompileTask::print_inline_indent(inline_depth()); tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count); CompileTask::print_inline_indent(inline_depth()); @@ -141,11 +158,11 @@ } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. if (callee_method->has_compiled_code() && - callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode/4) + callee_method->instructions_size(CompLevel_full_optimization) > inline_small_code_size) return "already compiled into a medium method"; } - if (size > max_size) { - if (max_size > C->max_inline_size()) + if (size > max_inline_size) { + if (max_inline_size > default_max_inline_size) return "hot method too big"; return "too big"; } @@ -154,7 +171,7 @@ // negative filter: should send NOT be inlined? returns NULL, ok to inline, or rejection msg -const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const { +const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const { // negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg if (!UseOldInlining) { const char* fail = NULL; @@ -269,14 +286,13 @@ } const char *msg = NULL; - if ((msg = shouldInline(callee_method, caller_method, caller_bci, - profile, wci_result)) != NULL) { + msg = should_inline(callee_method, caller_method, caller_bci, profile, wci_result); + if (msg != NULL) return msg; - } - if ((msg = shouldNotInline(callee_method, caller_method, - wci_result)) != NULL) { + + msg = should_not_inline(callee_method, caller_method, wci_result); + if (msg != NULL) return msg; - } if (InlineAccessors && callee_method->is_accessor()) { // accessor methods are not subject to any of the following limits. @@ -492,9 +508,8 @@ new_depth_adjust -= 1; // don't count method handle calls from java.lang.invoke implem } if (new_depth_adjust != 0 && PrintInlining) { - stringStream nm1; caller_jvms->method()->print_name(&nm1); - stringStream nm2; callee_method->print_name(&nm2); - tty->print_cr("discounting inlining depth from %s to %s", nm1.base(), nm2.base()); + CompileTask::print_inline_indent(inline_depth()); + tty->print_cr(" \\-> discounting inline depth"); } if (new_depth_adjust != 0 && C->log()) { int id1 = C->log()->identify(caller_jvms->method()); diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/opto/doCall.cpp Tue May 10 00:45:03 2011 -0700 @@ -73,7 +73,8 @@ // Note: When we get profiling during stage-1 compiles, we want to pull // from more specific profile data which pertains to this inlining. // Right now, ignore the information in jvms->caller(), and do method[bci]. - ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci()); + ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci()); + Bytecodes::Code bytecode = jvms->method()->java_code_at_bci(jvms->bci()); // See how many times this site has been invoked. int site_count = profile.count(); @@ -116,7 +117,7 @@ // MethodHandle.invoke* are native methods which obviously don't // have bytecodes and so normal inlining fails. if (call_method->is_method_handle_invoke()) { - if (jvms->method()->java_code_at_bci(jvms->bci()) != Bytecodes::_invokedynamic) { + if (bytecode != Bytecodes::_invokedynamic) { GraphKit kit(jvms); Node* n = kit.argument(0); @@ -128,14 +129,15 @@ // Set the actually called method to have access to the class // and signature in the MethodHandleCompiler. method_handle->set_callee(call_method); + method_handle->set_call_profile(&profile); // Get an adapter for the MethodHandle. ciMethod* target_method = method_handle->get_method_handle_adapter(); - CallGenerator* hit_cg = NULL; - if (target_method != NULL) - hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); - if (hit_cg != NULL && hit_cg->is_inline()) - return hit_cg; + if (target_method != NULL) { + CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + if (hit_cg != NULL && hit_cg->is_inline()) + return hit_cg; + } } return CallGenerator::for_direct_call(call_method); @@ -151,15 +153,16 @@ // Set the actually called method to have access to the class // and signature in the MethodHandleCompiler. method_handle->set_callee(call_method); + method_handle->set_call_profile(&profile); // Get an adapter for the MethodHandle. ciMethod* target_method = method_handle->get_invokedynamic_adapter(); - CallGenerator* hit_cg = NULL; - if (target_method != NULL) - hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); - if (hit_cg != NULL && hit_cg->is_inline()) { - CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method); - return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor); + if (target_method != NULL) { + CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + if (hit_cg != NULL && hit_cg->is_inline()) { + CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method); + return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor); + } } // If something failed, generate a normal dynamic call. diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/opto/parse.hpp Tue May 10 00:45:03 2011 -0700 @@ -68,8 +68,8 @@ JVMState* caller_jvms, int caller_bci); const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result); - const char* shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; - const char* shouldNotInline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const; + const char* should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; + const char* should_not_inline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const; void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const; InlineTree *caller_tree() const { return _caller_tree; } diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.cpp Tue May 10 00:45:03 2011 -0700 @@ -616,9 +616,10 @@ // ----------------------------------------------------------------------------- // MethodHandleCompiler -MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, bool is_invokedynamic, TRAPS) +MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS) : MethodHandleWalker(root, is_invokedynamic, THREAD), _callee(callee), + _invoke_count(invoke_count), _thread(THREAD), _bytecode(THREAD, 50), _constants(THREAD, 10), @@ -1182,7 +1183,7 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const { - methodHandle nullHandle; + methodHandle empty; // Create a method that holds the generated bytecode. invokedynamic // has no receiver, normal MH calls do. int flags_bits; @@ -1191,13 +1192,16 @@ else flags_bits = (/*JVM_MH_INVOKE_BITS |*/ JVM_ACC_PUBLIC | JVM_ACC_FINAL | JVM_ACC_SYNTHETIC); - methodOop m_oop = oopFactory::new_method(bytecode_length(), - accessFlags_from(flags_bits), - 0, 0, 0, oopDesc::IsSafeConc, CHECK_(nullHandle)); - methodHandle m(THREAD, m_oop); - m_oop = NULL; // oop not GC safe + // Create a new method + methodHandle m; + { + methodOop m_oop = oopFactory::new_method(bytecode_length(), + accessFlags_from(flags_bits), + 0, 0, 0, oopDesc::IsSafeConc, CHECK_(empty)); + m = methodHandle(THREAD, m_oop); + } - constantPoolHandle cpool = get_constant_pool(CHECK_(nullHandle)); + constantPoolHandle cpool = get_constant_pool(CHECK_(empty)); m->set_constants(cpool()); m->set_name_index(_name_index); @@ -1212,16 +1216,32 @@ typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array()); m->set_exception_table(exception_handlers()); - // Set the carry bit of the invocation counter to force inlining of - // the adapter. + // Set the invocation counter's count to the invoke count of the + // original call site. InvocationCounter* ic = m->invocation_counter(); - ic->set_carry_flag(); + ic->set(InvocationCounter::wait_for_compile, _invoke_count); // Rewrite the method and set up the constant pool cache. - objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(nullHandle)); + objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty)); objArrayHandle methods(THREAD, m_array); methods->obj_at_put(0, m()); - Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(nullHandle)); // Use fake class. + Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class. + + // Create a new MDO + { + methodDataOop mdo = oopFactory::new_methodData(m, CHECK_(empty)); + assert(m->method_data() == NULL, "there should not be an MDO yet"); + m->set_method_data(mdo); + + // Iterate over all profile data and set the count of the counter + // data entries to the original call site counter. + for (ProfileData* pd = mdo->first_data(); mdo->is_valid(pd); pd = mdo->next_data(pd)) { + if (pd->is_CounterData()) { + CounterData* cd = pd->as_CounterData(); + cd->set_count(_invoke_count); + } + } + } #ifndef PRODUCT if (TraceMethodHandles) { diff -r 3cfb240033d1 -r e2a92dd0d3d2 src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Mon May 09 19:45:52 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.hpp Tue May 10 00:45:03 2011 -0700 @@ -247,6 +247,7 @@ class MethodHandleCompiler : public MethodHandleWalker { private: methodHandle _callee; + int _invoke_count; // count the original call site has been executed KlassHandle _rklass; // Return type for casting. BasicType _rtype; KlassHandle _target_klass; @@ -416,7 +417,7 @@ methodHandle get_method_oop(TRAPS) const; public: - MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS); + MethodHandleCompiler(Handle root, methodHandle call_method, int invoke_count, bool for_invokedynamic, TRAPS); // Compile the given MH chain into bytecode. methodHandle compile(TRAPS);