7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters
authortwisti
Tue, 10 May 2011 00:45:03 -0700
changeset 9633 92a7a2841a16
parent 9632 cd86c748c12b
child 9634 985153f94e98
7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters Reviewed-by: jrose, never, kvn
hotspot/src/share/vm/ci/ciMethodHandle.cpp
hotspot/src/share/vm/ci/ciMethodHandle.hpp
hotspot/src/share/vm/opto/bytecodeInfo.cpp
hotspot/src/share/vm/opto/doCall.cpp
hotspot/src/share/vm/opto/parse.hpp
hotspot/src/share/vm/prims/methodHandleWalk.cpp
hotspot/src/share/vm/prims/methodHandleWalk.hpp
--- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/ci/ciMethodHandle.hpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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());
--- a/hotspot/src/share/vm/opto/doCall.cpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/opto/parse.hpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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;  }
--- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/prims/methodHandleWalk.hpp	Mon May 09 19:45:52 2011 -0700
+++ b/hotspot/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);