mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
6912064: type profiles need to be exploited more for dynamic language support
Reviewed-by: kvn
This commit is contained in:
parent
a54b1ff70e
commit
c7e50e8305
8 changed files with 204 additions and 64 deletions
|
@ -2451,11 +2451,79 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
|
|||
}
|
||||
|
||||
|
||||
//------------------------------seems_never_null-------------------------------
|
||||
// Use null_seen information if it is available from the profile.
|
||||
// If we see an unexpected null at a type check we record it and force a
|
||||
// recompile; the offending check will be recompiled to handle NULLs.
|
||||
// If we see several offending BCIs, then all checks in the
|
||||
// method will be recompiled.
|
||||
bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
|
||||
if (UncommonNullCast // Cutout for this technique
|
||||
&& obj != null() // And not the -Xcomp stupid case?
|
||||
&& !too_many_traps(Deoptimization::Reason_null_check)
|
||||
) {
|
||||
if (data == NULL)
|
||||
// Edge case: no mature data. Be optimistic here.
|
||||
return true;
|
||||
// If the profile has not seen a null, assume it won't happen.
|
||||
assert(java_bc() == Bytecodes::_checkcast ||
|
||||
java_bc() == Bytecodes::_instanceof ||
|
||||
java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here");
|
||||
return !data->as_BitData()->null_seen();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------maybe_cast_profiled_receiver-------------------------
|
||||
// If the profile has seen exactly one type, narrow to exactly that type.
|
||||
// Subsequent type checks will always fold up.
|
||||
Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
ciProfileData* data,
|
||||
ciKlass* require_klass) {
|
||||
if (!UseTypeProfile || !TypeProfileCasts) return NULL;
|
||||
if (data == NULL) return NULL;
|
||||
|
||||
// Make sure we haven't already deoptimized from this tactic.
|
||||
if (too_many_traps(Deoptimization::Reason_class_check))
|
||||
return NULL;
|
||||
|
||||
// (No, this isn't a call, but it's enough like a virtual call
|
||||
// to use the same ciMethod accessor to get the profile info...)
|
||||
ciCallProfile profile = method()->call_profile_at_bci(bci());
|
||||
if (profile.count() >= 0 && // no cast failures here
|
||||
profile.has_receiver(0) &&
|
||||
profile.morphism() == 1) {
|
||||
ciKlass* exact_kls = profile.receiver(0);
|
||||
if (require_klass == NULL ||
|
||||
static_subtype_check(require_klass, exact_kls) == SSC_always_true) {
|
||||
// If we narrow the type to match what the type profile sees,
|
||||
// we can then remove the rest of the cast.
|
||||
// This is a win, even if the exact_kls is very specific,
|
||||
// because downstream operations, such as method calls,
|
||||
// will often benefit from the sharper type.
|
||||
Node* exact_obj = not_null_obj; // will get updated in place...
|
||||
Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0,
|
||||
&exact_obj);
|
||||
{ PreserveJVMState pjvms(this);
|
||||
set_control(slow_ctl);
|
||||
uncommon_trap(Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_maybe_recompile);
|
||||
}
|
||||
replace_in_map(not_null_obj, exact_obj);
|
||||
return exact_obj;
|
||||
}
|
||||
// assert(ssc == SSC_always_true)... except maybe the profile lied to us.
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------gen_instanceof--------------------------------
|
||||
// Generate an instance-of idiom. Used by both the instance-of bytecode
|
||||
// and the reflective instance-of call.
|
||||
Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) {
|
||||
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||
Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) {
|
||||
kill_dead_locals(); // Benefit all the uncommon traps
|
||||
assert( !stopped(), "dead parse path should be checked in callers" );
|
||||
assert(!TypePtr::NULL_PTR->higher_equal(_gvn.type(superklass)->is_klassptr()),
|
||||
"must check for not-null not-dead klass in callers");
|
||||
|
@ -2466,9 +2534,16 @@ Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) {
|
|||
Node* phi = new(C, PATH_LIMIT) PhiNode(region, TypeInt::BOOL);
|
||||
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||
|
||||
ciProfileData* data = NULL;
|
||||
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
|
||||
data = method()->method_data()->bci_to_data(bci());
|
||||
}
|
||||
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
|
||||
&& seems_never_null(obj, data));
|
||||
|
||||
// Null check; get casted pointer; set region slot 3
|
||||
Node* null_ctl = top();
|
||||
Node* not_null_obj = null_check_oop(subobj, &null_ctl);
|
||||
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null);
|
||||
|
||||
// If not_null_obj is dead, only null-path is taken
|
||||
if (stopped()) { // Doing instance-of on a NULL?
|
||||
|
@ -2477,6 +2552,23 @@ Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) {
|
|||
}
|
||||
region->init_req(_null_path, null_ctl);
|
||||
phi ->init_req(_null_path, intcon(0)); // Set null path value
|
||||
if (null_ctl == top()) {
|
||||
// Do this eagerly, so that pattern matches like is_diamond_phi
|
||||
// will work even during parsing.
|
||||
assert(_null_path == PATH_LIMIT-1, "delete last");
|
||||
region->del_req(_null_path);
|
||||
phi ->del_req(_null_path);
|
||||
}
|
||||
|
||||
if (ProfileDynamicTypes && data != NULL) {
|
||||
Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, NULL);
|
||||
if (stopped()) { // Profile disagrees with this path.
|
||||
set_control(null_ctl); // Null is the only remaining possibility.
|
||||
return intcon(0);
|
||||
}
|
||||
if (cast_obj != NULL)
|
||||
not_null_obj = cast_obj;
|
||||
}
|
||||
|
||||
// Load the object's klass
|
||||
Node* obj_klass = load_object_klass(not_null_obj);
|
||||
|
@ -2546,20 +2638,8 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||
|
||||
// Use null-cast information if it is available
|
||||
bool never_see_null = false;
|
||||
// If we see an unexpected null at a check-cast we record it and force a
|
||||
// recompile; the offending check-cast will be compiled to handle NULLs.
|
||||
// If we see several offending BCIs, then all checkcasts in the
|
||||
// method will be compiled to handle NULLs.
|
||||
if (UncommonNullCast // Cutout for this technique
|
||||
&& failure_control == NULL // regular case
|
||||
&& obj != null() // And not the -Xcomp stupid case?
|
||||
&& !too_many_traps(Deoptimization::Reason_null_check)) {
|
||||
// Finally, check the "null_seen" bit from the interpreter.
|
||||
if (data == NULL || !data->as_BitData()->null_seen()) {
|
||||
never_see_null = true;
|
||||
}
|
||||
}
|
||||
bool never_see_null = ((failure_control == NULL) // regular case only
|
||||
&& seems_never_null(obj, data));
|
||||
|
||||
// Null check; get casted pointer; set region slot 3
|
||||
Node* null_ctl = top();
|
||||
|
@ -2572,47 +2652,26 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||
}
|
||||
region->init_req(_null_path, null_ctl);
|
||||
phi ->init_req(_null_path, null()); // Set null path value
|
||||
if (null_ctl == top()) {
|
||||
// Do this eagerly, so that pattern matches like is_diamond_phi
|
||||
// will work even during parsing.
|
||||
assert(_null_path == PATH_LIMIT-1, "delete last");
|
||||
region->del_req(_null_path);
|
||||
phi ->del_req(_null_path);
|
||||
}
|
||||
|
||||
Node* cast_obj = NULL; // the casted version of the object
|
||||
|
||||
// If the profile has seen exactly one type, narrow to that type.
|
||||
// (The subsequent subtype check will always fold up.)
|
||||
if (UseTypeProfile && TypeProfileCasts && data != NULL &&
|
||||
Node* cast_obj = NULL;
|
||||
if (data != NULL &&
|
||||
// Counter has never been decremented (due to cast failure).
|
||||
// ...This is a reasonable thing to expect. It is true of
|
||||
// all casts inserted by javac to implement generic types.
|
||||
data->as_CounterData()->count() >= 0 &&
|
||||
!too_many_traps(Deoptimization::Reason_class_check)) {
|
||||
// (No, this isn't a call, but it's enough like a virtual call
|
||||
// to use the same ciMethod accessor to get the profile info...)
|
||||
ciCallProfile profile = method()->call_profile_at_bci(bci());
|
||||
if (profile.count() >= 0 && // no cast failures here
|
||||
profile.has_receiver(0) &&
|
||||
profile.morphism() == 1) {
|
||||
ciKlass* exact_kls = profile.receiver(0);
|
||||
int ssc = static_subtype_check(tk->klass(), exact_kls);
|
||||
if (ssc == SSC_always_true) {
|
||||
// If we narrow the type to match what the type profile sees,
|
||||
// we can then remove the rest of the cast.
|
||||
// This is a win, even if the exact_kls is very specific,
|
||||
// because downstream operations, such as method calls,
|
||||
// will often benefit from the sharper type.
|
||||
Node* exact_obj = not_null_obj; // will get updated in place...
|
||||
Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0,
|
||||
&exact_obj);
|
||||
{ PreserveJVMState pjvms(this);
|
||||
set_control(slow_ctl);
|
||||
uncommon_trap(Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_maybe_recompile);
|
||||
}
|
||||
if (failure_control != NULL) // failure is now impossible
|
||||
(*failure_control) = top();
|
||||
replace_in_map(not_null_obj, exact_obj);
|
||||
// adjust the type of the phi to the exact klass:
|
||||
phi->raise_bottom_type(_gvn.type(exact_obj)->meet(TypePtr::NULL_PTR));
|
||||
cast_obj = exact_obj;
|
||||
}
|
||||
// assert(cast_obj != NULL)... except maybe the profile lied to us.
|
||||
data->as_CounterData()->count() >= 0) {
|
||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, tk->klass());
|
||||
if (cast_obj != NULL) {
|
||||
if (failure_control != NULL) // failure is now impossible
|
||||
(*failure_control) = top();
|
||||
// adjust the type of the phi to the exact klass:
|
||||
phi->raise_bottom_type(_gvn.type(cast_obj)->meet(TypePtr::NULL_PTR));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue