src/share/vm/opto/doCall.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Cdiff src/share/vm/opto/doCall.cpp

src/share/vm/opto/doCall.cpp

Print this page
rev 5462 : 8024069: replace_in_map() should operate on parent maps
Summary: type information gets lost because replace_in_map() doesn't update parent maps
Reviewed-by:
rev 5464 : 8024070: C2 needs some form of type speculation
Summary: record unused type profile information with type system, propagate and use it.
Reviewed-by:
rev 5465 : imported patch speculative-cleanup

*** 61,71 **** } } CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, ! float prof_factor, bool allow_intrinsics, bool delayed_forbidden) { ciMethod* caller = jvms->method(); int bci = jvms->bci(); Bytecodes::Code bytecode = caller->java_code_at_bci(bci); guarantee(callee != NULL, "failed method resolution"); --- 61,72 ---- } } CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, ! float prof_factor, ciKlass* spec_rcvr_type, ! bool allow_intrinsics, bool delayed_forbidden) { ciMethod* caller = jvms->method(); int bci = jvms->bci(); Bytecodes::Code bytecode = caller->java_code_at_bci(bci); guarantee(callee != NULL, "failed method resolution");
*** 115,125 **** CallGenerator* cg = find_intrinsic(callee, call_does_dispatch); if (cg != NULL) { if (cg->is_predicted()) { // Code without intrinsic but, hopefully, inlined. CallGenerator* inline_cg = this->call_generator(callee, ! vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, false); if (inline_cg != NULL) { cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); } } --- 116,126 ---- CallGenerator* cg = find_intrinsic(callee, call_does_dispatch); if (cg != NULL) { if (cg->is_predicted()) { // Code without intrinsic but, hopefully, inlined. CallGenerator* inline_cg = this->call_generator(callee, ! vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, spec_rcvr_type, false); if (inline_cg != NULL) { cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); } }
*** 210,221 **** // Try using the type profile. if (call_does_dispatch && site_count > 0 && receiver_count > 0) { // The major receiver's count >= TypeProfileMajorReceiverPercent of site_count. bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent); ciMethod* receiver_method = NULL; ! if (have_major_receiver || profile.morphism() == 1 || ! (profile.morphism() == 2 && UseBimorphicInlining)) { // receiver_method = profile.method(); // Profiles do not suggest methods now. Look it up in the major receiver. receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(0)); } --- 211,235 ---- // Try using the type profile. if (call_does_dispatch && site_count > 0 && receiver_count > 0) { // The major receiver's count >= TypeProfileMajorReceiverPercent of site_count. bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent); ciMethod* receiver_method = NULL; ! ! if (spec_rcvr_type != NULL) { ! // We have a speculative type, we should be able to resolve ! // the call. We do that before looking at the profiling at ! // this invoke because it may lead to bimorphic inlining which ! // a speculative type should help us avoid. ! receiver_method = callee->resolve_invoke(jvms->method()->holder(), ! spec_rcvr_type); ! if (receiver_method == NULL) { ! spec_rcvr_type = NULL; ! } ! } ! if (receiver_method == NULL && ! (have_major_receiver || profile.morphism() == 1 || ! (profile.morphism() == 2 && UseBimorphicInlining))) { // receiver_method = profile.method(); // Profiles do not suggest methods now. Look it up in the major receiver. receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(0)); }
*** 225,235 **** vtable_index, !call_does_dispatch, jvms, allow_inline, prof_factor); if (hit_cg != NULL) { // Look up second receiver. CallGenerator* next_hit_cg = NULL; ciMethod* next_receiver_method = NULL; ! if (profile.morphism() == 2 && UseBimorphicInlining) { next_receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(1)); if (next_receiver_method != NULL) { next_hit_cg = this->call_generator(next_receiver_method, vtable_index, !call_does_dispatch, jvms, --- 239,249 ---- vtable_index, !call_does_dispatch, jvms, allow_inline, prof_factor); if (hit_cg != NULL) { // Look up second receiver. CallGenerator* next_hit_cg = NULL; ciMethod* next_receiver_method = NULL; ! if (spec_rcvr_type == NULL && profile.morphism() == 2 && UseBimorphicInlining) { next_receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(1)); if (next_receiver_method != NULL) { next_hit_cg = this->call_generator(next_receiver_method, vtable_index, !call_does_dispatch, jvms,
*** 240,254 **** next_hit_cg = NULL; } } } CallGenerator* miss_cg; ! Deoptimization::DeoptReason reason = (profile.morphism() == 2) ? Deoptimization::Reason_bimorphic : Deoptimization::Reason_class_check; ! if (( profile.morphism() == 1 || ! (profile.morphism() == 2 && next_hit_cg != NULL) ) && !too_many_traps(jvms->method(), jvms->bci(), reason) ) { // Generate uncommon trap for class check failure path // in case of monomorphic or bimorphic virtual call site. miss_cg = CallGenerator::for_uncommon_trap(callee, reason, --- 254,268 ---- next_hit_cg = NULL; } } } CallGenerator* miss_cg; ! Deoptimization::DeoptReason reason = (spec_rcvr_type == NULL && profile.morphism() == 2) ? Deoptimization::Reason_bimorphic : Deoptimization::Reason_class_check; ! if ((spec_rcvr_type != NULL || profile.morphism() == 1 || ! (profile.morphism() == 2 && next_hit_cg != NULL)) && !too_many_traps(jvms->method(), jvms->bci(), reason) ) { // Generate uncommon trap for class check failure path // in case of monomorphic or bimorphic virtual call site. miss_cg = CallGenerator::for_uncommon_trap(callee, reason,
*** 258,275 **** // in case of polymorphic virtual call site. miss_cg = CallGenerator::for_virtual_call(callee, vtable_index); } if (miss_cg != NULL) { if (next_hit_cg != NULL) { trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1)); // We don't need to record dependency on a receiver here and below. // Whenever we inline, the dependency is added by Parse::Parse(). miss_cg = CallGenerator::for_predicted_call(profile.receiver(1), miss_cg, next_hit_cg, PROB_MAX); } if (miss_cg != NULL) { trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count); ! CallGenerator* cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0)); if (cg != NULL) return cg; } } } } --- 272,292 ---- // in case of polymorphic virtual call site. miss_cg = CallGenerator::for_virtual_call(callee, vtable_index); } if (miss_cg != NULL) { if (next_hit_cg != NULL) { + assert(spec_rcvr_type == NULL, "shouldn't end up here if we used speculation"); trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1)); // We don't need to record dependency on a receiver here and below. // Whenever we inline, the dependency is added by Parse::Parse(). miss_cg = CallGenerator::for_predicted_call(profile.receiver(1), miss_cg, next_hit_cg, PROB_MAX); } if (miss_cg != NULL) { trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count); ! ciKlass *k = spec_rcvr_type != NULL ? spec_rcvr_type : profile.receiver(0); ! float hit_prob = spec_rcvr_type != NULL ? 1.0 : profile.receiver_prob(0); ! CallGenerator* cg = CallGenerator::for_predicted_call(k, miss_cg, hit_cg, hit_prob); if (cg != NULL) return cg; } } } }
*** 444,460 **** --- 461,480 ---- // Try to get the most accurate receiver type ciMethod* callee = orig_callee; int vtable_index = Method::invalid_vtable_index; bool call_does_dispatch = false; + // Speculative type of the receiver if any + ciKlass* spec_receiver_type = NULL; if (is_virtual_or_interface) { Node* receiver_node = stack(sp() - nargs); const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr(); // call_does_dispatch and vtable_index are out-parameters. They might be changed. callee = C->optimize_virtual_call(method(), bci(), klass, orig_callee, receiver_type, is_virtual, call_does_dispatch, vtable_index); // out-parameters + spec_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL; } // Note: It's OK to try to inline a virtual call. // The call generator will not attempt to inline a polymorphic call // unless it knows how to optimize the receiver dispatch.
*** 466,484 **** // --------------------- // Decide call tactic. // This call checks with CHA, the interpreter profile, intrinsics table, etc. // It decides whether inlining is desirable or not. ! CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor()); // NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead. orig_callee = callee = NULL; // --------------------- // Round double arguments before call round_double_arguments(cg->method()); #ifndef PRODUCT // bump global counters for calls count_compiled_calls(/*at_method_entry*/ false, cg->is_inline()); // Record first part of parsing work for this call --- 486,508 ---- // --------------------- // Decide call tactic. // This call checks with CHA, the interpreter profile, intrinsics table, etc. // It decides whether inlining is desirable or not. ! CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), spec_receiver_type); // NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead. orig_callee = callee = NULL; // --------------------- // Round double arguments before call round_double_arguments(cg->method()); + // Feed profiling data for arguments to the type system so it can + // propagate it as speculative types + record_profiled_arguments_for_speculation(cg->method(), bc()); + #ifndef PRODUCT // bump global counters for calls count_compiled_calls(/*at_method_entry*/ false, cg->is_inline()); // Record first part of parsing work for this call
*** 489,498 **** --- 513,529 ---- assert(jvms_in_sync(), "jvms must carry full info into CG"); // save across call, for a subsequent cast_not_null. Node* receiver = has_receiver ? argument(0) : NULL; + // The extra CheckCastPP for speculative types mess with PhaseStringOpts + if (receiver != NULL && !call_does_dispatch && !cg->is_string_late_inline()) { + // Feed profiling data for a single receiver to the type system so + // it can propagate it as a speculative type + receiver = record_profiled_receiver_for_speculation(receiver); + } + // Bump method data counters (We profile *before* the call is made // because exceptions don't return to the call site.) profile_call(receiver); JVMState* new_jvms = cg->generate(jvms, this);
*** 506,516 **** // This can happen if a library intrinsic is available, but refuses // the call site, perhaps because it did not match a pattern the // intrinsic was expecting to optimize. Should always be possible to // get a normal java call that may inline in that case ! cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false); if ((new_jvms = cg->generate(jvms, this)) == NULL) { guarantee(failing(), "call failed to generate: calls should work"); return; } } --- 537,547 ---- // This can happen if a library intrinsic is available, but refuses // the call site, perhaps because it did not match a pattern the // intrinsic was expecting to optimize. Should always be possible to // get a normal java call that may inline in that case ! cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), spec_receiver_type, /* allow_intrinsics= */ false); if ((new_jvms = cg->generate(jvms, this)) == NULL) { guarantee(failing(), "call failed to generate: calls should work"); return; } }
*** 605,614 **** --- 636,655 ---- // If there is going to be a trap, put it at the next bytecode: set_bci(iter().next_bci()); null_assert(peek()); set_bci(iter().cur_bci()); // put it back } + BasicType ct = ctype->basic_type(); + if (ct == T_OBJECT || ct == T_ARRAY) { + ciKlass* better_type = NULL; + if (UseTypeSpeculation && method()->return_profiled_type(bci(), better_type)) { + // If profiling reports a single type for the return value, + // feed it to the type system so it can propagate it as a + // speculative type + record_profile_for_speculation(stack(sp()-1), better_type); + } + } } // Restart record of parsing work after possible inlining of call #ifndef PRODUCT parse_histogram()->set_initial_state(bc());
src/share/vm/opto/doCall.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File