7050554: JSR 292 - need optimization for selectAlternative
authornever
Thu, 02 Jun 2011 13:36:11 -0700
changeset 9975 82190b49ce14
parent 9968 d46e7bd87c27
child 9976 6fef34e63df1
7050554: JSR 292 - need optimization for selectAlternative Reviewed-by: kvn, jrose
hotspot/src/share/vm/ci/ciCallProfile.hpp
hotspot/src/share/vm/ci/ciMethodHandle.cpp
hotspot/src/share/vm/ci/ciMethodHandle.hpp
hotspot/src/share/vm/compiler/compileBroker.cpp
hotspot/src/share/vm/opto/callGenerator.cpp
hotspot/src/share/vm/opto/callGenerator.hpp
hotspot/src/share/vm/opto/doCall.cpp
--- a/hotspot/src/share/vm/ci/ciCallProfile.hpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciCallProfile.hpp	Thu Jun 02 13:36:11 2011 -0700
@@ -36,6 +36,7 @@
 private:
   // Fields are initialized directly by ciMethod::call_profile_at_bci.
   friend class ciMethod;
+  friend class ciMethodHandle;
 
   enum { MorphismLimit = 2 }; // Max call site's morphism we care about
   int  _limit;                // number of receivers have been determined
@@ -58,10 +59,10 @@
 
 public:
   // Note:  The following predicates return false for invalid profiles:
-  bool      has_receiver(int i) { return _limit > i; }
-  int       morphism()          { return _morphism; }
+  bool      has_receiver(int i) const { return _limit > i; }
+  int       morphism() const          { return _morphism; }
 
-  int       count()             { return _count; }
+  int       count() const             { return _count; }
   int       receiver_count(int i)  {
     assert(i < _limit, "out of Call Profile MorphismLimit");
     return _receiver_count[i];
--- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp	Thu Jun 02 13:36:11 2011 -0700
@@ -43,7 +43,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->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD);
+  MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _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	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.hpp	Thu Jun 02 13:36:11 2011 -0700
@@ -36,7 +36,7 @@
 private:
   ciMethod*      _callee;
   ciMethod*      _caller;
-  ciCallProfile* _profile;
+  ciCallProfile  _profile;
 
   // Return an adapter for this MethodHandle.
   ciMethod* get_adapter_impl(bool is_invokedynamic) const;
@@ -49,8 +49,7 @@
   ciMethodHandle(instanceHandle h_i) :
     ciInstance(h_i),
     _callee(NULL),
-    _caller(NULL),
-    _profile(NULL)
+    _caller(NULL)
   {}
 
   // What kind of ciObject is this?
@@ -58,7 +57,7 @@
 
   void set_callee(ciMethod* m)                  { _callee  = m;       }
   void set_caller(ciMethod* m)                  { _caller  = m;       }
-  void set_call_profile(ciCallProfile* profile) { _profile = 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/compiler/compileBroker.cpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Thu Jun 02 13:36:11 2011 -0700
@@ -300,12 +300,23 @@
   st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
   st->print("%4d ", compile_id);    // print compilation number
 
+  // For unloaded methods the transition to zombie occurs after the
+  // method is cleared so it's impossible to report accurate
+  // information for that case.
+  bool is_synchronized = false;
+  bool has_exception_handler = false;
+  bool is_native = false;
+  if (method != NULL) {
+    is_synchronized       = method->is_synchronized();
+    has_exception_handler = method->has_exception_handler();
+    is_native             = method->is_native();
+  }
   // method attributes
   const char compile_type   = is_osr_method                   ? '%' : ' ';
-  const char sync_char      = method->is_synchronized()       ? 's' : ' ';
-  const char exception_char = method->has_exception_handler() ? '!' : ' ';
+  const char sync_char      = is_synchronized                 ? 's' : ' ';
+  const char exception_char = has_exception_handler           ? '!' : ' ';
   const char blocking_char  = is_blocking                     ? 'b' : ' ';
-  const char native_char    = method->is_native()             ? 'n' : ' ';
+  const char native_char    = is_native                       ? 'n' : ' ';
 
   // print method attributes
   st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);
@@ -316,11 +327,15 @@
   }
   st->print("     ");  // more indent
 
-  method->print_short_name(st);
-  if (is_osr_method) {
-    st->print(" @ %d", osr_bci);
+  if (method == NULL) {
+    st->print("(method)");
+  } else {
+    method->print_short_name(st);
+    if (is_osr_method) {
+      st->print(" @ %d", osr_bci);
+    }
+    st->print(" (%d bytes)", method->code_size());
   }
-  st->print(" (%d bytes)", method->code_size());
 
   if (msg != NULL) {
     st->print("   %s", msg);
--- a/hotspot/src/share/vm/opto/callGenerator.cpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp	Thu Jun 02 13:36:11 2011 -0700
@@ -698,6 +698,46 @@
 }
 
 
+CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms,
+                                                       ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
+  if (method_handle->Opcode() == Op_ConP) {
+    const TypeOopPtr* oop_ptr = method_handle->bottom_type()->is_oopptr();
+    ciObject* const_oop = oop_ptr->const_oop();
+    ciMethodHandle* method_handle = const_oop->as_method_handle();
+
+    // Set the callee to have access to the class and signature in
+    // the MethodHandleCompiler.
+    method_handle->set_callee(callee);
+    method_handle->set_caller(caller);
+    method_handle->set_call_profile(profile);
+
+    // Get an adapter for the MethodHandle.
+    ciMethod* target_method = method_handle->get_method_handle_adapter();
+    if (target_method != NULL) {
+      CallGenerator* hit_cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, 1);
+      if (hit_cg != NULL && hit_cg->is_inline())
+        return hit_cg;
+    }
+  } else if (method_handle->Opcode() == Op_Phi && method_handle->req() == 3 &&
+             method_handle->in(1)->Opcode() == Op_ConP && method_handle->in(2)->Opcode() == Op_ConP) {
+    // selectAlternative idiom merging two constant MethodHandles.
+    // Generate a guard so that each can be inlined.  We might want to
+    // do more inputs at later point but this gets the most common
+    // case.
+    const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr();
+    ciObject* const_oop = oop_ptr->const_oop();
+    ciMethodHandle* mh = const_oop->as_method_handle();
+
+    CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile);
+    CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile);
+    if (cg1 != NULL && cg2 != NULL) {
+      return new PredictedDynamicCallGenerator(mh, cg2, cg1, PROB_FAIR);
+    }
+  }
+  return NULL;
+}
+
+
 JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   PhaseGVN& gvn = kit.gvn();
@@ -707,33 +747,45 @@
     log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
   }
 
-  // Get the constant pool cache from the caller class.
-  ciMethod* caller_method = jvms->method();
-  ciBytecodeStream str(caller_method);
-  str.force_bci(jvms->bci());  // Set the stream to the invokedynamic bci.
-  ciCPCache* cpcache = str.get_cpcache();
-
-  // Get the offset of the CallSite from the constant pool cache
-  // pointer.
-  int index = str.get_method_index();
-  size_t call_site_offset = cpcache->get_f1_offset(index);
-
-  // Load the CallSite object from the constant pool cache.
-  const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
-  Node* cpcache_adr   = kit.makecon(cpcache_ptr);
-  Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
-  Node* call_site     = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
-
-  // Load the target MethodHandle from the CallSite object.
-  Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
-  Node* target_mh  = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
-
-  // Check if the MethodHandle is still the same.
   const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true);
   Node* predicted_mh = kit.makecon(predicted_mh_ptr);
 
-  Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
-  Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
+  Node* bol = NULL;
+  int bc = jvms->method()->java_code_at_bci(jvms->bci());
+  if (bc == Bytecodes::_invokespecial) {
+    // This is the selectAlternative idiom for guardWithTest
+    Node* receiver = kit.argument(0);
+
+    // Check if the MethodHandle is the expected one
+    Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh));
+    bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
+  } else {
+    assert(bc == Bytecodes::_invokedynamic, "must be");
+    // Get the constant pool cache from the caller class.
+    ciMethod* caller_method = jvms->method();
+    ciBytecodeStream str(caller_method);
+    str.force_bci(jvms->bci());  // Set the stream to the invokedynamic bci.
+    ciCPCache* cpcache = str.get_cpcache();
+
+    // Get the offset of the CallSite from the constant pool cache
+    // pointer.
+    int index = str.get_method_index();
+    size_t call_site_offset = cpcache->get_f1_offset(index);
+
+    // Load the CallSite object from the constant pool cache.
+    const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
+    Node* cpcache_adr   = kit.makecon(cpcache_ptr);
+    Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
+    Node* call_site     = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
+
+    // Load the target MethodHandle from the CallSite object.
+    Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
+    Node* target_mh  = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
+
+    // Check if the MethodHandle is still the same.
+    Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
+    bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
+  }
   IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN);
   kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff)));
   Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));
--- a/hotspot/src/share/vm/opto/callGenerator.hpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/opto/callGenerator.hpp	Thu Jun 02 13:36:11 2011 -0700
@@ -111,6 +111,8 @@
   static CallGenerator* for_dynamic_call(ciMethod* m);   // invokedynamic
   static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index);  // virtual, interface
 
+  static CallGenerator* for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
+
   // How to generate a replace a direct call with an inline version
   static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
 
--- a/hotspot/src/share/vm/opto/doCall.cpp	Wed Jun 01 23:25:31 2011 -0700
+++ b/hotspot/src/share/vm/opto/doCall.cpp	Thu Jun 02 13:36:11 2011 -0700
@@ -123,24 +123,9 @@
       GraphKit kit(jvms);
       Node* n = kit.argument(0);
 
-      if (n->Opcode() == Op_ConP) {
-        const TypeOopPtr* oop_ptr = n->bottom_type()->is_oopptr();
-        ciObject* const_oop = oop_ptr->const_oop();
-        ciMethodHandle* method_handle = const_oop->as_method_handle();
-
-        // Set the callee to have access to the class and signature in
-        // the MethodHandleCompiler.
-        method_handle->set_callee(call_method);
-        method_handle->set_caller(caller);
-        method_handle->set_call_profile(&profile);
-
-        // Get an adapter for the MethodHandle.
-        ciMethod* target_method = method_handle->get_method_handle_adapter();
-        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;
-        }
+      CallGenerator* cg = CallGenerator::for_method_handle_inline(n, jvms, caller, call_method, profile);
+      if (cg != NULL) {
+        return cg;
       }
 
       return CallGenerator::for_direct_call(call_method);
@@ -157,7 +142,7 @@
       // the MethodHandleCompiler.
       method_handle->set_callee(call_method);
       method_handle->set_caller(caller);
-      method_handle->set_call_profile(&profile);
+      method_handle->set_call_profile(profile);
 
       // Get an adapter for the MethodHandle.
       ciMethod* target_method = method_handle->get_invokedynamic_adapter();