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