src/share/vm/opto/graphKit.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/vm/opto/graphKit.cpp	Thu Oct 17 18:54:50 2013
--- new/src/share/vm/opto/graphKit.cpp	Thu Oct 17 18:54:49 2013

*** 2096,2105 **** --- 2096,2143 ---- set_argument(j, arg); } } } + // 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' // If a strict caller invokes a non-strict callee, round a double result
*** 2633,2662 **** --- 2671,2700 ---- //------------------------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) { ! 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)) 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 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. Node* exact_obj = not_null_obj; // will get updated in place... Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0,
*** 2664,2687 **** --- 2702,2804 ---- { PreserveJVMState pjvms(this); set_control(slow_ctl); uncommon_trap(Deoptimization::Reason_class_check, Deoptimization::Action_maybe_recompile); } + 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. } 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, 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()), "must check for not-null not-dead klass in callers");
*** 2690,2703 **** --- 2807,2818 ---- RegionNode* region = new(C) RegionNode(PATH_LIMIT); Node* phi = new(C) PhiNode(region, TypeInt::BOOL); 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)); // Null check; get casted pointer; set region slot 3
*** 2717,2735 **** --- 2832,2873 ---- 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); + // 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; } + } + } // Load the object's klass Node* obj_klass = load_object_klass(not_null_obj); // Generate the subtype check
*** 2771,2781 **** --- 2909,2922 ---- if (tk->singleton()) { const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr(); 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. return null_assert(obj); }
*** 2820,2835 **** --- 2961,2981 ---- region->del_req(_null_path); phi ->del_req(_null_path); } Node* cast_obj = NULL; if (data != NULL && + 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, data, tk->klass()); ! 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(); // adjust the type of the phi to the exact klass: phi->raise_bottom_type(_gvn.type(cast_obj)->meet(TypePtr::NULL_PTR));

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