Thu, 02 Jun 2011 13:36:11 -0700
7050554: JSR 292 - need optimization for selectAlternative
Reviewed-by: kvn, jrose
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();