1.1 --- a/src/share/vm/opto/callGenerator.cpp Wed Jun 01 23:25:31 2011 -0700 1.2 +++ b/src/share/vm/opto/callGenerator.cpp Thu Jun 02 13:36:11 2011 -0700 1.3 @@ -698,6 +698,46 @@ 1.4 } 1.5 1.6 1.7 +CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms, 1.8 + ciMethod* caller, ciMethod* callee, ciCallProfile profile) { 1.9 + if (method_handle->Opcode() == Op_ConP) { 1.10 + const TypeOopPtr* oop_ptr = method_handle->bottom_type()->is_oopptr(); 1.11 + ciObject* const_oop = oop_ptr->const_oop(); 1.12 + ciMethodHandle* method_handle = const_oop->as_method_handle(); 1.13 + 1.14 + // Set the callee to have access to the class and signature in 1.15 + // the MethodHandleCompiler. 1.16 + method_handle->set_callee(callee); 1.17 + method_handle->set_caller(caller); 1.18 + method_handle->set_call_profile(profile); 1.19 + 1.20 + // Get an adapter for the MethodHandle. 1.21 + ciMethod* target_method = method_handle->get_method_handle_adapter(); 1.22 + if (target_method != NULL) { 1.23 + CallGenerator* hit_cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, 1); 1.24 + if (hit_cg != NULL && hit_cg->is_inline()) 1.25 + return hit_cg; 1.26 + } 1.27 + } else if (method_handle->Opcode() == Op_Phi && method_handle->req() == 3 && 1.28 + method_handle->in(1)->Opcode() == Op_ConP && method_handle->in(2)->Opcode() == Op_ConP) { 1.29 + // selectAlternative idiom merging two constant MethodHandles. 1.30 + // Generate a guard so that each can be inlined. We might want to 1.31 + // do more inputs at later point but this gets the most common 1.32 + // case. 1.33 + const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr(); 1.34 + ciObject* const_oop = oop_ptr->const_oop(); 1.35 + ciMethodHandle* mh = const_oop->as_method_handle(); 1.36 + 1.37 + CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile); 1.38 + CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile); 1.39 + if (cg1 != NULL && cg2 != NULL) { 1.40 + return new PredictedDynamicCallGenerator(mh, cg2, cg1, PROB_FAIR); 1.41 + } 1.42 + } 1.43 + return NULL; 1.44 +} 1.45 + 1.46 + 1.47 JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) { 1.48 GraphKit kit(jvms); 1.49 PhaseGVN& gvn = kit.gvn(); 1.50 @@ -707,33 +747,45 @@ 1.51 log->elem("predicted_dynamic_call bci='%d'", jvms->bci()); 1.52 } 1.53 1.54 - // Get the constant pool cache from the caller class. 1.55 - ciMethod* caller_method = jvms->method(); 1.56 - ciBytecodeStream str(caller_method); 1.57 - str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. 1.58 - ciCPCache* cpcache = str.get_cpcache(); 1.59 - 1.60 - // Get the offset of the CallSite from the constant pool cache 1.61 - // pointer. 1.62 - int index = str.get_method_index(); 1.63 - size_t call_site_offset = cpcache->get_f1_offset(index); 1.64 - 1.65 - // Load the CallSite object from the constant pool cache. 1.66 - const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); 1.67 - Node* cpcache_adr = kit.makecon(cpcache_ptr); 1.68 - Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); 1.69 - Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); 1.70 - 1.71 - // Load the target MethodHandle from the CallSite object. 1.72 - Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes()); 1.73 - Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT); 1.74 - 1.75 - // Check if the MethodHandle is still the same. 1.76 const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true); 1.77 Node* predicted_mh = kit.makecon(predicted_mh_ptr); 1.78 1.79 - Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh)); 1.80 - Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); 1.81 + Node* bol = NULL; 1.82 + int bc = jvms->method()->java_code_at_bci(jvms->bci()); 1.83 + if (bc == Bytecodes::_invokespecial) { 1.84 + // This is the selectAlternative idiom for guardWithTest 1.85 + Node* receiver = kit.argument(0); 1.86 + 1.87 + // Check if the MethodHandle is the expected one 1.88 + Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh)); 1.89 + bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); 1.90 + } else { 1.91 + assert(bc == Bytecodes::_invokedynamic, "must be"); 1.92 + // Get the constant pool cache from the caller class. 1.93 + ciMethod* caller_method = jvms->method(); 1.94 + ciBytecodeStream str(caller_method); 1.95 + str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. 1.96 + ciCPCache* cpcache = str.get_cpcache(); 1.97 + 1.98 + // Get the offset of the CallSite from the constant pool cache 1.99 + // pointer. 1.100 + int index = str.get_method_index(); 1.101 + size_t call_site_offset = cpcache->get_f1_offset(index); 1.102 + 1.103 + // Load the CallSite object from the constant pool cache. 1.104 + const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); 1.105 + Node* cpcache_adr = kit.makecon(cpcache_ptr); 1.106 + Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); 1.107 + Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); 1.108 + 1.109 + // Load the target MethodHandle from the CallSite object. 1.110 + Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes()); 1.111 + Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT); 1.112 + 1.113 + // Check if the MethodHandle is still the same. 1.114 + Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh)); 1.115 + bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); 1.116 + } 1.117 IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN); 1.118 kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff))); 1.119 Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));