# HG changeset patch # User never # Date 1307046971 25200 # Node ID f56542cb325a47448720e5d4fd1cfcef96f2e4a5 # Parent e5ae807761b8c08f31582a4f1057addd97e03e4b 7050554: JSR 292 - need optimization for selectAlternative Reviewed-by: kvn, jrose diff -r e5ae807761b8 -r f56542cb325a src/share/vm/ci/ciCallProfile.hpp --- a/src/share/vm/ci/ciCallProfile.hpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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]; diff -r e5ae807761b8 -r f56542cb325a src/share/vm/ci/ciMethodHandle.cpp --- a/src/share/vm/ci/ciMethodHandle.cpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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) { diff -r e5ae807761b8 -r f56542cb325a src/share/vm/ci/ciMethodHandle.hpp --- a/src/share/vm/ci/ciMethodHandle.hpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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); } diff -r e5ae807761b8 -r f56542cb325a src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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); diff -r e5ae807761b8 -r f56542cb325a src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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)); diff -r e5ae807761b8 -r f56542cb325a src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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); diff -r e5ae807761b8 -r f56542cb325a src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Fri Jun 03 17:09:33 2011 -0700 +++ b/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();