Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions hotspot/src/share/vm/c1/c1_RangeCheckElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,11 @@ void RangeCheckEliminator::add_access_indexed_info(InstructionList &indices, int
aii->_max = idx;
aii->_list = new AccessIndexedList();
} else if (idx >= aii->_min && idx <= aii->_max) {
remove_range_check(ai);
return;
// Guard against underflow/overflow (see 'range_cond' check in RangeCheckEliminator::in_block_motion)
if (aii->_max < 0 || (aii->_max + min_jint) <= aii->_min) {
remove_range_check(ai);
return;
}
}
aii->_min = MIN2(aii->_min, idx);
aii->_max = MAX2(aii->_max, idx);
Expand Down Expand Up @@ -423,9 +426,9 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList
}
}
} else {
int last_integer = 0;
jint last_integer = 0;
Instruction *last_instruction = index;
int base = 0;
jint base = 0;
ArithmeticOp *ao = index->as_ArithmeticOp();

while (ao != NULL && (ao->x()->as_Constant() || ao->y()->as_Constant()) && (ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub)) {
Expand All @@ -437,12 +440,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList
}

if (c) {
int value = c->type()->as_IntConstant()->value();
jint value = c->type()->as_IntConstant()->value();
if (value != min_jint) {
if (ao->op() == Bytecodes::_isub) {
value = -value;
}
base += value;
base = java_add(base, value);
last_integer = base;
last_instruction = other;
}
Expand All @@ -464,12 +467,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList
assert(info != NULL, "Info must not be null");

// if idx < 0, max > 0, max + idx may fall between 0 and
// length-1 and if min < 0, min + idx may overflow and be >=
// length-1 and if min < 0, min + idx may underflow/overflow and be >=
// 0. The predicate wouldn't trigger but some accesses could
// be with a negative index. This test guarantees that for the
// min and max value that are kept the predicate can't let
// some incorrect accesses happen.
bool range_cond = (info->_max < 0 || info->_max + min_jint <= info->_min);
bool range_cond = (info->_max < 0 || (info->_max + min_jint) <= info->_min);

// Generate code only if more than 2 range checks can be eliminated because of that.
// 2 because at least 2 comparisons are done
Expand Down Expand Up @@ -809,7 +812,7 @@ void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, Block
);

remove_range_check(ai);
} else if (_optimistic && loop_header) {
} else if (false && _optimistic && loop_header) {
assert(ai->array(), "Array must not be null!");
assert(ai->index(), "Index must not be null!");

Expand Down
5 changes: 3 additions & 2 deletions hotspot/src/share/vm/classfile/verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2081,11 +2081,12 @@ void ClassVerifier::verify_switch(
"low must be less than or equal to high in tableswitch");
return;
}
keys = high - low + 1;
if (keys < 0) {
int64_t keys64 = ((int64_t)high - low) + 1;
if (keys64 > 65535) { // Max code length
verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch");
return;
}
keys = (int)keys64;
delta = 1;
} else {
keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
Expand Down
22 changes: 16 additions & 6 deletions hotspot/src/share/vm/interpreter/bytecodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,18 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end)
if (end != NULL && aligned_bcp + 3*jintSize >= end) {
return -1; // don't read past end of code buffer
}
// Promote calculation to signed 64 bits to do range checks, used by the verifier.
jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize);
jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize;
// only return len if it can be represented as a positive int;
// return -1 otherwise
return (len > 0 && len == (int)len) ? len : -1;
// Only return len if it can be represented as a positive int and lo <= hi.
// The caller checks for bytecode stream overflow.
if (lo <= hi && len == (int)len) {
assert(len > 0, "must be");
return (int)len;
} else {
return -1;
}
}

case _lookupswitch: // fall through
Expand All @@ -131,9 +137,13 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end)
}
jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize;
// only return len if it can be represented as a positive int;
// return -1 otherwise
return (len > 0 && len == (int)len) ? len : -1;
// Only return len if it can be represented as a positive int and npairs >= 0.
if (npairs >= 0 && len == (int)len) {
assert(len > 0, "must be");
return (int)len;
} else {
return -1;
}
}
}
// Note: Length functions must return <=0 for invalid bytecodes.
Expand Down
59 changes: 52 additions & 7 deletions hotspot/src/share/vm/opto/ifnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,46 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// then we are guaranteed to fail, so just start interpreting there.
// We 'expand' the top 3 range checks to include all post-dominating
// checks.
//
// Example:
// a[i+x] // (1) 1 < x < 6
// a[i+3] // (2)
// a[i+4] // (3)
// a[i+6] // max = max of all constants
// a[i+2]
// a[i+1] // min = min of all constants
//
// If x < 3:
// (1) a[i+x]: Leave unchanged
// (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6 -> (2) is covered
// (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered
// Remove all other a[i+c] checks
//
// If x >= 3:
// (1) a[i+x]: Leave unchanged
// (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x -> (2) is covered
// (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered
// Remove all other a[i+c] checks
//
// We only need the top 2 range checks if x is the min or max of all constants.
//
// This, however, only works if the interval [i+min,i+max] is not larger than max_int (i.e. abs(max - min) < max_int):
// The theoretical max size of an array is max_int with:
// - Valid index space: [0,max_int-1]
// - Invalid index space: [max_int,-1] // max_int, min_int, min_int - 1 ..., -1
//
// The size of the consecutive valid index space is smaller than the size of the consecutive invalid index space.
// If we choose min and max in such a way that:
// - abs(max - min) < max_int
// - i+max and i+min are inside the valid index space
// then all indices [i+min,i+max] must be in the valid index space. Otherwise, the invalid index space must be
// smaller than the valid index space which is never the case for any array size.
//
// Choosing a smaller array size only makes the valid index space smaller and the invalid index space larger and
// the argument above still holds.
//
// Note that the same optimization with the same maximal accepted interval size can also be found in C1.
const jlong maximum_number_of_min_max_interval_indices = (jlong)max_jint;

// The top 3 range checks seen
const int NRC =3;
Expand Down Expand Up @@ -915,13 +955,18 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
found_immediate_dominator = true;
break;
}
// Gather expanded bounds
off_lo = MIN2(off_lo,offset2);
off_hi = MAX2(off_hi,offset2);
// Record top NRC range checks
prev_checks[nb_checks%NRC].ctl = prev_dom;
prev_checks[nb_checks%NRC].off = offset2;
nb_checks++;

// "x - y" -> must add one to the difference for number of elements in [x,y]
const jlong diff = (jlong)MIN2(offset2, off_lo) - (jlong)MAX2(offset2, off_hi);
if (ABS(diff) < maximum_number_of_min_max_interval_indices) {
// Gather expanded bounds
off_lo = MIN2(off_lo, offset2);
off_hi = MAX2(off_hi, offset2);
// Record top NRC range checks
prev_checks[nb_checks % NRC].ctl = prev_dom;
prev_checks[nb_checks % NRC].off = offset2;
nb_checks++;
}
}
}
prev_dom = dom;
Expand Down
Loading