--- old/src/share/vm/opto/graphKit.cpp 2013-10-17 18:54:50.255111960 +0200 +++ new/src/share/vm/opto/graphKit.cpp 2013-10-17 18:54:49.861406192 +0200 @@ -2098,6 +2098,44 @@ } } +// Record profiling data from argument profiling at an invoke with the +// type system so that it can propagate it (speculation) +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 = NULL; + if (method()->argument_profiled_type(bci(), i, better_type)) { + 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 = NULL; + if (method()->parameter_profiled_type(j, better_type)) { + 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 +2673,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 +2684,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 +2704,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 +2715,88 @@ return NULL; } +// Cast obj to type and emit guard unless we had too many traps here +// already +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; +} + +// Record profiling data exact_kls for Node n with the type system so +// that it can propagate it (speculation) +Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) { + assert(UseTypeSpeculation, "type speculation must be on"); + if (exact_kls != NULL) { + 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) +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); +} + //-------------------------------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 +2809,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 +2834,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); + // Dow 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 (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; + } } - if (cast_obj != NULL) - not_null_obj = cast_obj; } // Load the object's klass @@ -2773,7 +2911,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 +2963,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();