--- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Oct 23 10:00:39 2013 +0200
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Oct 23 12:40:23 2013 +0200
@@ -2098,6 +2098,104 @@
}
}
+/**
+ * Record profiling data exact_kls for Node n with the type system so
+ * that it can propagate it (speculation)
+ *
+ * @param n node that the type applies to
+ * @param exact_kls type from profiling
+ *
+ * @return node with improved type
+ */
+Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
+ const TypeOopPtr* current_type = _gvn.type(n)->isa_oopptr();
+ assert(UseTypeSpeculation, "type speculation must be on");
+ if (exact_kls != NULL &&
+ // nothing to improve if type is already exact
+ (current_type == NULL ||
+ (!current_type->klass_is_exact() &&
+ (current_type->speculative() == NULL ||
+ !current_type->speculative()->klass_is_exact())))) {
+ const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
+ const TypeOopPtr* xtype = tklass->as_instance_type();
+ assert(xtype->klass_is_exact(), "Should be exact");
+
+ // Build a type with a speculative type (what we think we know
+ // about the type but will need a guard when we use it)
+ const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, xtype);
+ // We're changing the type, we need a new cast node to carry the
+ // new type. The new type depends on the control: what profiling
+ // tells us is only valid from here as far as we can tell.
+ Node* cast = new(C) CastPPNode(n, spec_type);
+ cast->init_req(0, control());
+ cast = _gvn.transform(cast);
+ replace_in_map(n, cast);
+ n = cast;
+ }
+ return n;
+}
+
+/**
+ * Record profiling data from receiver profiling at an invoke with the
+ * type system so that it can propagate it (speculation)
+ *
+ * @param n receiver node
+ *
+ * @return node with improved type
+ */
+Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
+ if (!UseTypeSpeculation) {
+ return n;
+ }
+ ciKlass* exact_kls = profile_has_unique_klass();
+ return record_profile_for_speculation(n, exact_kls);
+}
+
+/**
+ * Record profiling data from argument profiling at an invoke with the
+ * type system so that it can propagate it (speculation)
+ *
+ * @param dest_method target method for the call
+ * @param bc what invoke bytecode is this?
+ */
+void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc) {
+ if (!UseTypeSpeculation) {
+ return;
+ }
+ const TypeFunc* tf = TypeFunc::make(dest_method);
+ int nargs = tf->_domain->_cnt - TypeFunc::Parms;
+ int skip = Bytecodes::has_receiver(bc) ? 1 : 0;
+ for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
+ const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms);
+ if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) {
+ ciKlass* better_type = method()->argument_profiled_type(bci(), i);
+ if (better_type != NULL) {
+ record_profile_for_speculation(argument(j), better_type);
+ }
+ i++;
+ }
+ }
+}
+
+/**
+ * Record profiling data from parameter profiling at an invoke with
+ * the type system so that it can propagate it (speculation)
+ */
+void GraphKit::record_profiled_parameters_for_speculation() {
+ if (!UseTypeSpeculation) {
+ return;
+ }
+ for (int i = 0, j = 0; i < method()->arg_size() ; i++) {
+ if (_gvn.type(local(i))->isa_oopptr()) {
+ ciKlass* better_type = method()->parameter_profiled_type(j);
+ if (better_type != NULL) {
+ record_profile_for_speculation(local(i), better_type);
+ }
+ j++;
+ }
+ }
+}
+
void GraphKit::round_double_result(ciMethod* dest_method) {
// A non-strict method may return a double value which has an extended
// exponent, but this must not be visible in a caller which is 'strict'
@@ -2635,10 +2733,10 @@
// 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) {
+ ciKlass* require_klass,
+ ciKlass* spec_klass,
+ bool safe_for_replace) {
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))
@@ -2646,15 +2744,15 @@
// (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 we have a speculative type use it instead of profiling (which
+ // may not help us)
+ ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
+ if (exact_kls != NULL) {// no cast failures here
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.
+ // If we narrow the type to match what the type profile sees or
+ // the speculative type, 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.
@@ -2666,7 +2764,9 @@
uncommon_trap(Deoptimization::Reason_class_check,
Deoptimization::Action_maybe_recompile);
}
- replace_in_map(not_null_obj, exact_obj);
+ if (safe_for_replace) {
+ replace_in_map(not_null_obj, exact_obj);
+ }
return exact_obj;
}
// assert(ssc == SSC_always_true)... except maybe the profile lied to us.
@@ -2675,11 +2775,59 @@
return NULL;
}
+/**
+ * Cast obj to type and emit guard unless we had too many traps here
+ * already
+ *
+ * @param obj node being casted
+ * @param type type to cast the node to
+ * @param not_null true if we know node cannot be null
+ */
+Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
+ ciKlass* type,
+ bool not_null) {
+ // type == NULL if profiling tells us this object is always null
+ if (type != NULL) {
+ if (!too_many_traps(Deoptimization::Reason_null_check) &&
+ !too_many_traps(Deoptimization::Reason_class_check)) {
+ Node* not_null_obj = NULL;
+ // not_null is true if we know the object is not null and
+ // there's no need for a null check
+ if (!not_null) {
+ Node* null_ctl = top();
+ not_null_obj = null_check_oop(obj, &null_ctl, true, true);
+ assert(null_ctl->is_top(), "no null control here");
+ } else {
+ not_null_obj = obj;
+ }
+
+ Node* exact_obj = not_null_obj;
+ ciKlass* exact_kls = type;
+ 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);
+ obj = exact_obj;
+ }
+ } else {
+ if (!too_many_traps(Deoptimization::Reason_null_assert)) {
+ Node* exact_obj = null_assert(obj);
+ replace_in_map(obj, exact_obj);
+ obj = exact_obj;
+ }
+ }
+ return obj;
+}
//-------------------------------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* obj, Node* superklass) {
+Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replace) {
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()),
@@ -2692,10 +2840,8 @@
C->set_has_split_ifs(true); // Has chance for split-if optimization
ciProfileData* data = NULL;
- bool safe_for_replace = false;
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
data = method()->method_data()->bci_to_data(bci());
- safe_for_replace = true;
}
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
&& seems_never_null(obj, data));
@@ -2719,14 +2865,37 @@
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);
+ // Do we know the type check always succeed?
+ bool known_statically = false;
+ if (_gvn.type(superklass)->singleton()) {
+ ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
+ ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass();
+ if (subk != NULL && subk->is_loaded()) {
+ int static_res = static_subtype_check(superk, subk);
+ known_statically = (static_res == SSC_always_true || static_res == SSC_always_false);
}
- if (cast_obj != NULL)
- not_null_obj = cast_obj;
+ }
+
+ if (known_statically && UseTypeSpeculation) {
+ // If we know the type check always succeed then we don't use the
+ // profiling data at this bytecode. Don't lose it, feed it to the
+ // type system as a speculative type.
+ not_null_obj = record_profiled_receiver_for_speculation(not_null_obj);
+ } else {
+ const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
+ // We may not have profiling here or it may not help us. If we
+ // have a speculative type use it to perform an exact cast.
+ ciKlass* spec_obj_type = obj_type->speculative_type();
+ if (spec_obj_type != NULL || (ProfileDynamicTypes && data != NULL)) {
+ Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, NULL, spec_obj_type, safe_for_replace);
+ 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
@@ -2773,7 +2942,10 @@
if (objtp != NULL && objtp->klass() != NULL) {
switch (static_subtype_check(tk->klass(), objtp->klass())) {
case SSC_always_true:
- return obj;
+ // If we know the type check always succeed then we don't use
+ // the profiling data at this bytecode. Don't lose it, feed it
+ // to the type system as a speculative type.
+ return record_profiled_receiver_for_speculation(obj);
case SSC_always_false:
// It needs a null check because a null will *pass* the cast check.
// A non-null value will always produce an exception.
@@ -2822,12 +2994,17 @@
}
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) {
- cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, tk->klass());
+ const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
+ // We may not have profiling here or it may not help us. If we have
+ // a speculative type use it to perform an exact cast.
+ ciKlass* spec_obj_type = obj_type->speculative_type();
+ if (spec_obj_type != NULL ||
+ (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)) {
+ cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
if (cast_obj != NULL) {
if (failure_control != NULL) // failure is now impossible
(*failure_control) = top();