7050554: JSR 292 - need optimization for selectAlternative

Thu, 02 Jun 2011 13:36:11 -0700

author
never
date
Thu, 02 Jun 2011 13:36:11 -0700
changeset 2949
f918d6096e23
parent 2942
a93146d0e4be
child 2950
cba7b5c2d53f

7050554: JSR 292 - need optimization for selectAlternative
Reviewed-by: kvn, jrose

src/share/vm/ci/ciCallProfile.hpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciMethodHandle.cpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciMethodHandle.hpp file | annotate | diff | comparison | revisions
src/share/vm/compiler/compileBroker.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callGenerator.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/callGenerator.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/doCall.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/ci/ciCallProfile.hpp	Wed Jun 01 23:25:31 2011 -0700
     1.2 +++ b/src/share/vm/ci/ciCallProfile.hpp	Thu Jun 02 13:36:11 2011 -0700
     1.3 @@ -36,6 +36,7 @@
     1.4  private:
     1.5    // Fields are initialized directly by ciMethod::call_profile_at_bci.
     1.6    friend class ciMethod;
     1.7 +  friend class ciMethodHandle;
     1.8  
     1.9    enum { MorphismLimit = 2 }; // Max call site's morphism we care about
    1.10    int  _limit;                // number of receivers have been determined
    1.11 @@ -58,10 +59,10 @@
    1.12  
    1.13  public:
    1.14    // Note:  The following predicates return false for invalid profiles:
    1.15 -  bool      has_receiver(int i) { return _limit > i; }
    1.16 -  int       morphism()          { return _morphism; }
    1.17 +  bool      has_receiver(int i) const { return _limit > i; }
    1.18 +  int       morphism() const          { return _morphism; }
    1.19  
    1.20 -  int       count()             { return _count; }
    1.21 +  int       count() const             { return _count; }
    1.22    int       receiver_count(int i)  {
    1.23      assert(i < _limit, "out of Call Profile MorphismLimit");
    1.24      return _receiver_count[i];
     2.1 --- a/src/share/vm/ci/ciMethodHandle.cpp	Wed Jun 01 23:25:31 2011 -0700
     2.2 +++ b/src/share/vm/ci/ciMethodHandle.cpp	Thu Jun 02 13:36:11 2011 -0700
     2.3 @@ -43,7 +43,7 @@
     2.4    methodHandle callee(_callee->get_methodOop());
     2.5    // We catch all exceptions here that could happen in the method
     2.6    // handle compiler and stop the VM.
     2.7 -  MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD);
     2.8 +  MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD);
     2.9    if (!HAS_PENDING_EXCEPTION) {
    2.10      methodHandle m = mhc.compile(THREAD);
    2.11      if (!HAS_PENDING_EXCEPTION) {
     3.1 --- a/src/share/vm/ci/ciMethodHandle.hpp	Wed Jun 01 23:25:31 2011 -0700
     3.2 +++ b/src/share/vm/ci/ciMethodHandle.hpp	Thu Jun 02 13:36:11 2011 -0700
     3.3 @@ -36,7 +36,7 @@
     3.4  private:
     3.5    ciMethod*      _callee;
     3.6    ciMethod*      _caller;
     3.7 -  ciCallProfile* _profile;
     3.8 +  ciCallProfile  _profile;
     3.9  
    3.10    // Return an adapter for this MethodHandle.
    3.11    ciMethod* get_adapter_impl(bool is_invokedynamic) const;
    3.12 @@ -49,8 +49,7 @@
    3.13    ciMethodHandle(instanceHandle h_i) :
    3.14      ciInstance(h_i),
    3.15      _callee(NULL),
    3.16 -    _caller(NULL),
    3.17 -    _profile(NULL)
    3.18 +    _caller(NULL)
    3.19    {}
    3.20  
    3.21    // What kind of ciObject is this?
    3.22 @@ -58,7 +57,7 @@
    3.23  
    3.24    void set_callee(ciMethod* m)                  { _callee  = m;       }
    3.25    void set_caller(ciMethod* m)                  { _caller  = m;       }
    3.26 -  void set_call_profile(ciCallProfile* profile) { _profile = profile; }
    3.27 +  void set_call_profile(ciCallProfile profile)  { _profile = profile; }
    3.28  
    3.29    // Return an adapter for a MethodHandle call.
    3.30    ciMethod* get_method_handle_adapter() const { return get_adapter(false); }
     4.1 --- a/src/share/vm/compiler/compileBroker.cpp	Wed Jun 01 23:25:31 2011 -0700
     4.2 +++ b/src/share/vm/compiler/compileBroker.cpp	Thu Jun 02 13:36:11 2011 -0700
     4.3 @@ -300,12 +300,23 @@
     4.4    st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
     4.5    st->print("%4d ", compile_id);    // print compilation number
     4.6  
     4.7 +  // For unloaded methods the transition to zombie occurs after the
     4.8 +  // method is cleared so it's impossible to report accurate
     4.9 +  // information for that case.
    4.10 +  bool is_synchronized = false;
    4.11 +  bool has_exception_handler = false;
    4.12 +  bool is_native = false;
    4.13 +  if (method != NULL) {
    4.14 +    is_synchronized       = method->is_synchronized();
    4.15 +    has_exception_handler = method->has_exception_handler();
    4.16 +    is_native             = method->is_native();
    4.17 +  }
    4.18    // method attributes
    4.19    const char compile_type   = is_osr_method                   ? '%' : ' ';
    4.20 -  const char sync_char      = method->is_synchronized()       ? 's' : ' ';
    4.21 -  const char exception_char = method->has_exception_handler() ? '!' : ' ';
    4.22 +  const char sync_char      = is_synchronized                 ? 's' : ' ';
    4.23 +  const char exception_char = has_exception_handler           ? '!' : ' ';
    4.24    const char blocking_char  = is_blocking                     ? 'b' : ' ';
    4.25 -  const char native_char    = method->is_native()             ? 'n' : ' ';
    4.26 +  const char native_char    = is_native                       ? 'n' : ' ';
    4.27  
    4.28    // print method attributes
    4.29    st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);
    4.30 @@ -316,11 +327,15 @@
    4.31    }
    4.32    st->print("     ");  // more indent
    4.33  
    4.34 -  method->print_short_name(st);
    4.35 -  if (is_osr_method) {
    4.36 -    st->print(" @ %d", osr_bci);
    4.37 +  if (method == NULL) {
    4.38 +    st->print("(method)");
    4.39 +  } else {
    4.40 +    method->print_short_name(st);
    4.41 +    if (is_osr_method) {
    4.42 +      st->print(" @ %d", osr_bci);
    4.43 +    }
    4.44 +    st->print(" (%d bytes)", method->code_size());
    4.45    }
    4.46 -  st->print(" (%d bytes)", method->code_size());
    4.47  
    4.48    if (msg != NULL) {
    4.49      st->print("   %s", msg);
     5.1 --- a/src/share/vm/opto/callGenerator.cpp	Wed Jun 01 23:25:31 2011 -0700
     5.2 +++ b/src/share/vm/opto/callGenerator.cpp	Thu Jun 02 13:36:11 2011 -0700
     5.3 @@ -698,6 +698,46 @@
     5.4  }
     5.5  
     5.6  
     5.7 +CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms,
     5.8 +                                                       ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
     5.9 +  if (method_handle->Opcode() == Op_ConP) {
    5.10 +    const TypeOopPtr* oop_ptr = method_handle->bottom_type()->is_oopptr();
    5.11 +    ciObject* const_oop = oop_ptr->const_oop();
    5.12 +    ciMethodHandle* method_handle = const_oop->as_method_handle();
    5.13 +
    5.14 +    // Set the callee to have access to the class and signature in
    5.15 +    // the MethodHandleCompiler.
    5.16 +    method_handle->set_callee(callee);
    5.17 +    method_handle->set_caller(caller);
    5.18 +    method_handle->set_call_profile(profile);
    5.19 +
    5.20 +    // Get an adapter for the MethodHandle.
    5.21 +    ciMethod* target_method = method_handle->get_method_handle_adapter();
    5.22 +    if (target_method != NULL) {
    5.23 +      CallGenerator* hit_cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, 1);
    5.24 +      if (hit_cg != NULL && hit_cg->is_inline())
    5.25 +        return hit_cg;
    5.26 +    }
    5.27 +  } else if (method_handle->Opcode() == Op_Phi && method_handle->req() == 3 &&
    5.28 +             method_handle->in(1)->Opcode() == Op_ConP && method_handle->in(2)->Opcode() == Op_ConP) {
    5.29 +    // selectAlternative idiom merging two constant MethodHandles.
    5.30 +    // Generate a guard so that each can be inlined.  We might want to
    5.31 +    // do more inputs at later point but this gets the most common
    5.32 +    // case.
    5.33 +    const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr();
    5.34 +    ciObject* const_oop = oop_ptr->const_oop();
    5.35 +    ciMethodHandle* mh = const_oop->as_method_handle();
    5.36 +
    5.37 +    CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile);
    5.38 +    CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile);
    5.39 +    if (cg1 != NULL && cg2 != NULL) {
    5.40 +      return new PredictedDynamicCallGenerator(mh, cg2, cg1, PROB_FAIR);
    5.41 +    }
    5.42 +  }
    5.43 +  return NULL;
    5.44 +}
    5.45 +
    5.46 +
    5.47  JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
    5.48    GraphKit kit(jvms);
    5.49    PhaseGVN& gvn = kit.gvn();
    5.50 @@ -707,33 +747,45 @@
    5.51      log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
    5.52    }
    5.53  
    5.54 -  // Get the constant pool cache from the caller class.
    5.55 -  ciMethod* caller_method = jvms->method();
    5.56 -  ciBytecodeStream str(caller_method);
    5.57 -  str.force_bci(jvms->bci());  // Set the stream to the invokedynamic bci.
    5.58 -  ciCPCache* cpcache = str.get_cpcache();
    5.59 -
    5.60 -  // Get the offset of the CallSite from the constant pool cache
    5.61 -  // pointer.
    5.62 -  int index = str.get_method_index();
    5.63 -  size_t call_site_offset = cpcache->get_f1_offset(index);
    5.64 -
    5.65 -  // Load the CallSite object from the constant pool cache.
    5.66 -  const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
    5.67 -  Node* cpcache_adr   = kit.makecon(cpcache_ptr);
    5.68 -  Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
    5.69 -  Node* call_site     = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
    5.70 -
    5.71 -  // Load the target MethodHandle from the CallSite object.
    5.72 -  Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
    5.73 -  Node* target_mh  = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
    5.74 -
    5.75 -  // Check if the MethodHandle is still the same.
    5.76    const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true);
    5.77    Node* predicted_mh = kit.makecon(predicted_mh_ptr);
    5.78  
    5.79 -  Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
    5.80 -  Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
    5.81 +  Node* bol = NULL;
    5.82 +  int bc = jvms->method()->java_code_at_bci(jvms->bci());
    5.83 +  if (bc == Bytecodes::_invokespecial) {
    5.84 +    // This is the selectAlternative idiom for guardWithTest
    5.85 +    Node* receiver = kit.argument(0);
    5.86 +
    5.87 +    // Check if the MethodHandle is the expected one
    5.88 +    Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh));
    5.89 +    bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
    5.90 +  } else {
    5.91 +    assert(bc == Bytecodes::_invokedynamic, "must be");
    5.92 +    // Get the constant pool cache from the caller class.
    5.93 +    ciMethod* caller_method = jvms->method();
    5.94 +    ciBytecodeStream str(caller_method);
    5.95 +    str.force_bci(jvms->bci());  // Set the stream to the invokedynamic bci.
    5.96 +    ciCPCache* cpcache = str.get_cpcache();
    5.97 +
    5.98 +    // Get the offset of the CallSite from the constant pool cache
    5.99 +    // pointer.
   5.100 +    int index = str.get_method_index();
   5.101 +    size_t call_site_offset = cpcache->get_f1_offset(index);
   5.102 +
   5.103 +    // Load the CallSite object from the constant pool cache.
   5.104 +    const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
   5.105 +    Node* cpcache_adr   = kit.makecon(cpcache_ptr);
   5.106 +    Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
   5.107 +    Node* call_site     = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
   5.108 +
   5.109 +    // Load the target MethodHandle from the CallSite object.
   5.110 +    Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
   5.111 +    Node* target_mh  = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
   5.112 +
   5.113 +    // Check if the MethodHandle is still the same.
   5.114 +    Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
   5.115 +    bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
   5.116 +  }
   5.117    IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN);
   5.118    kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff)));
   5.119    Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));
     6.1 --- a/src/share/vm/opto/callGenerator.hpp	Wed Jun 01 23:25:31 2011 -0700
     6.2 +++ b/src/share/vm/opto/callGenerator.hpp	Thu Jun 02 13:36:11 2011 -0700
     6.3 @@ -111,6 +111,8 @@
     6.4    static CallGenerator* for_dynamic_call(ciMethod* m);   // invokedynamic
     6.5    static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index);  // virtual, interface
     6.6  
     6.7 +  static CallGenerator* for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
     6.8 +
     6.9    // How to generate a replace a direct call with an inline version
    6.10    static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
    6.11  
     7.1 --- a/src/share/vm/opto/doCall.cpp	Wed Jun 01 23:25:31 2011 -0700
     7.2 +++ b/src/share/vm/opto/doCall.cpp	Thu Jun 02 13:36:11 2011 -0700
     7.3 @@ -123,24 +123,9 @@
     7.4        GraphKit kit(jvms);
     7.5        Node* n = kit.argument(0);
     7.6  
     7.7 -      if (n->Opcode() == Op_ConP) {
     7.8 -        const TypeOopPtr* oop_ptr = n->bottom_type()->is_oopptr();
     7.9 -        ciObject* const_oop = oop_ptr->const_oop();
    7.10 -        ciMethodHandle* method_handle = const_oop->as_method_handle();
    7.11 -
    7.12 -        // Set the callee to have access to the class and signature in
    7.13 -        // the MethodHandleCompiler.
    7.14 -        method_handle->set_callee(call_method);
    7.15 -        method_handle->set_caller(caller);
    7.16 -        method_handle->set_call_profile(&profile);
    7.17 -
    7.18 -        // Get an adapter for the MethodHandle.
    7.19 -        ciMethod* target_method = method_handle->get_method_handle_adapter();
    7.20 -        if (target_method != NULL) {
    7.21 -          CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
    7.22 -          if (hit_cg != NULL && hit_cg->is_inline())
    7.23 -            return hit_cg;
    7.24 -        }
    7.25 +      CallGenerator* cg = CallGenerator::for_method_handle_inline(n, jvms, caller, call_method, profile);
    7.26 +      if (cg != NULL) {
    7.27 +        return cg;
    7.28        }
    7.29  
    7.30        return CallGenerator::for_direct_call(call_method);
    7.31 @@ -157,7 +142,7 @@
    7.32        // the MethodHandleCompiler.
    7.33        method_handle->set_callee(call_method);
    7.34        method_handle->set_caller(caller);
    7.35 -      method_handle->set_call_profile(&profile);
    7.36 +      method_handle->set_call_profile(profile);
    7.37  
    7.38        // Get an adapter for the MethodHandle.
    7.39        ciMethod* target_method = method_handle->get_invokedynamic_adapter();

mercurial