src/share/vm/opto/ifnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/vm/opto/ifnode.cpp	Mon Dec  1 15:34:26 2014
--- new/src/share/vm/opto/ifnode.cpp	Mon Dec  1 15:34:26 2014

*** 818,827 **** --- 818,832 ---- return iff; } static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff); + struct RangeCheck { + Node* ctl; + jint off; + }; + //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this;
*** 859,942 **** --- 864,1006 ---- // Check for range-check vs other kinds of tests Node *index1, *range1; jint offset1; int flip1 = is_range_check(range1, index1, offset1); if( flip1 ) { Node *first_prev_dom = NULL; // Try to remove extra range checks. All 'up_one_dom' gives up at merges // so all checks we inspect post-dominate the top-most check we find. // If we are going to fail the current check and we reach the top check // then we are guaranteed to fail, so just start interpreting there. ! // We 'expand' the top 2 range checks to include all post-dominating ! // We 'expand' the top 3 range checks to include all post-dominating // checks. ! // The top 2 range checks seen ! Node *prev_chk1 = NULL; ! Node *prev_chk2 = NULL; ! // The top 3 range checks seen ! struct RangeCheck prev_checks[3]; ! int nb_checks = 0; + // Low and high offsets seen so far jint off_lo = offset1; jint off_hi = offset1; // Scan for the top 2 checks and collect range of offsets ! for( int dist = 0; dist < 999; dist++ ) { // Range-Check scan limit ! if( dom->Opcode() == Op_If && // Not same opcode? - prev_dom->in(0) == dom ) { // One path of test does dominate? ! if( dom == this ) return NULL; // dead loop ! for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit ! if (dom->Opcode() == Op_If && // Not same opcode? ! prev_dom->in(0) == dom) { // One path of test does dominate? ! if (dom == this) return NULL; // dead loop // See if this is a range check Node *index2, *range2; jint offset2; int flip2 = dom->as_If()->is_range_check(range2, index2, offset2); // See if this is a _matching_ range check, checking against // the same array bounds. ! if( flip2 == flip1 && range2 == range1 && index2 == index1 && - dom->outcnt() == 2 ) { ! if (flip2 == flip1 && range2 == range1 && index2 == index1 && ! dom->outcnt() == 2) { // Gather expanded bounds off_lo = MIN2(off_lo,offset2); off_hi = MAX2(off_hi,offset2); ! // Record top 2 range checks ! prev_chk2 = prev_chk1; ! prev_chk1 = prev_dom; // If we match the test exactly, then the top test covers // both our lower and upper bounds. if( dom->in(1) == in(1) ) prev_chk2 = prev_chk1; ! // Record top 3 range checks ! prev_checks[nb_checks%3].ctl = prev_dom; ! prev_checks[nb_checks%3].off = offset2; + nb_checks++; } } prev_dom = dom; ! dom = up_one_dom( dom ); ! if( !dom ) break; ! if (!dom) break; } // Attempt to widen the dominating range check to cover some later // ones. Since range checks "fail" by uncommon-trapping to the // interpreter, widening a check can make us speculative enter the // interpreter. If we see range-check deopt's, do not widen! if (!phase->C->allow_range_check_smearing()) return NULL; // Constant indices only need to check the upper bound. ! // Non-constance indices must check both low and high. ! if( index1 ) { // Didn't find 2 prior covering checks, so cannot remove anything. ! if( !prev_chk2 ) return NULL; // 'Widen' the offsets of the 1st and 2nd covering check adjust_check( prev_chk1, range1, index1, flip1, off_lo, igvn ); // Do not call adjust_check twice on the same projection // as the first call may have transformed the BoolNode to a ConI ! if( prev_chk1 != prev_chk2 ) { adjust_check( prev_chk2, range1, index1, flip1, off_hi, igvn ); ! // Non-constant indices must check both low and high. ! int chk0 = (nb_checks - 1) % 3; + if (index1) { ! if (nb_checks == 0) { + return NULL; + } else { + struct RangeCheck rc0 = prev_checks[chk0]; + if (nb_checks == 1) { ! if (rc0.ctl->in(0)->in(1) == in(1)) { + // If we match the test exactly, then the top test covers + // both our lower and upper bounds. Valid only if there's + // a single dominating range check: for all we know this + // range check was widened and accesses that depend on it + // also depend on the previous range checks to be correct. + adjust_check(rc0.ctl, range1, index1, flip1, off_lo, igvn); + prev_dom = rc0.ctl; + } else { + return NULL; + } + } else { + // If the top range check's constant is the min or max of + // all constants we widen the next one to cover the whole + // range of constants. + int chk1 = (nb_checks - 2) % 3; + struct RangeCheck rc1 = prev_checks[chk1]; + if (rc0.off == off_lo) { + adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn); + prev_dom = rc1.ctl; + } else if (rc0.off == off_hi) { + adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn); + prev_dom = rc1.ctl; + } else { + // If the top test's constant is not the min or max of all + // constants, we need 3 range checks. We must leave the + // top test unchanged because widening it would allow the + // accesses it protects to successfully read/write out of + // bounds. + if (nb_checks == 2) { + return NULL; + } + int chk2 = (nb_checks - 3) % 3; + struct RangeCheck rc2 = prev_checks[chk2]; + // The top range check a+i covers interval: -a <= i < length-a + // The second range check b+i covers interval: -b <= i < length-b + if (rc1.off <= rc0.off) { + // if b <= a, we change the second range check to: + // -min_of_all_constants <= i < length-min_of_all_constants + // Together top and second range checks now cover: + // -min_of_all_constants <= i < length-a + // which is more restrictive than -b <= i < length-b: + // -b <= -min_of_all_constants <= i < length-a <= length-b + // The third check is then changed to: + // -max_of_all_constants <= i < length-max_of_all_constants + // so 2nd and 3rd checks restrict allowed values of i to: + // -min_of_all_constants <= i < length-max_of_all_constants + adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn); + adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn); + } else { + // if b > a, we change the second range check to: + // -max_of_all_constants <= i < length-max_of_all_constants + // Together top and second range checks now cover: + // -a <= i < length-max_of_all_constants + // which is more restrictive than -b <= i < length-b: + // -b < -a <= i < length-max_of_all_constants <= length-b + // The third check is then changed to: + // -max_of_all_constants <= i < length-max_of_all_constants + // so 2nd and 3rd checks restrict allowed values of i to: + // -min_of_all_constants <= i < length-max_of_all_constants + adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn); + adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn); + } + prev_dom = rc2.ctl; + } + } } // Test is now covered by prior checks, dominate it out prev_dom = prev_chk2; } else { // Didn't find prior covering check, so cannot remove anything. ! if( !prev_chk1 ) return NULL; ! if (nb_checks == 0) return NULL; + struct RangeCheck rc0 = prev_checks[chk0]; // 'Widen' the offset of the 1st and only covering check ! adjust_check( prev_chk1, range1, index1, flip1, off_hi, igvn ); ! adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn); // Test is now covered by prior checks, dominate it out ! prev_dom = prev_chk1; ! prev_dom = rc0.ctl; } } else { // Scan for an equivalent test

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