8042997: Make intrinsic some or all check index/range methods

Objects.checkIndex() intrinsic

Reviewed-by: vlivanov, shade
This commit is contained in:
Roland Westrelin 2015-11-16 09:55:25 +01:00
parent 6de50f10f5
commit baaa8f79ed
6 changed files with 65 additions and 4 deletions

View File

@ -109,6 +109,7 @@
template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \
template(java_io_Serializable, "java/io/Serializable") \
template(java_util_Arrays, "java/util/Arrays") \
template(java_util_Objects, "java/util/Objects") \
template(java_util_Properties, "java/util/Properties") \
template(java_util_Vector, "java/util/Vector") \
template(java_util_AbstractList, "java/util/AbstractList") \
@ -883,6 +884,9 @@
do_intrinsic(_equalsL, java_lang_StringLatin1,equals_name, equalsB_signature, F_S) \
do_intrinsic(_equalsU, java_lang_StringUTF16, equals_name, equalsB_signature, F_S) \
\
do_intrinsic(_Objects_checkIndex, java_util_Objects, checkIndex_name, Objects_checkIndex_signature, F_S) \
do_signature(Objects_checkIndex_signature, "(IILjava/util/function/BiFunction;)I") \
\
do_class(java_nio_Buffer, "java/nio/Buffer") \
do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \
do_name( checkIndex_name, "checkIndex") \

View File

@ -451,6 +451,7 @@ bool C2Compiler::is_intrinsic_supported(methodHandle method, bool is_virtual) {
case vmIntrinsics::_updateByteBufferAdler32:
case vmIntrinsics::_profileBoolean:
case vmIntrinsics::_isCompileConstant:
case vmIntrinsics::_Objects_checkIndex:
break;
default:
return false;

View File

@ -485,7 +485,7 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) {
return NULL;
}
if (l->is_top()) return NULL; // Top input means dead test
if (r->Opcode() != Op_LoadRange) return NULL;
if (r->Opcode() != Op_LoadRange && !is_RangeCheck()) return NULL;
// We have recognized one of these forms:
// Flip 1: If (Bool[<] CmpU(l, LoadRange)) ...
@ -525,9 +525,9 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) {
return 0;
} else if (l->Opcode() == Op_AddI) {
if ((off = l->in(1)->find_int_con(0)) != 0) {
ind = l->in(2);
ind = l->in(2)->uncast();
} else if ((off = l->in(2)->find_int_con(0)) != 0) {
ind = l->in(1);
ind = l->in(1)->uncast();
}
} else if ((off = l->find_int_con(-1)) >= 0) {
// constant offset with no variable index

View File

@ -256,6 +256,7 @@ class LibraryCallKit : public GraphKit {
bool inline_native_getLength();
bool inline_array_copyOf(bool is_copyOfRange);
bool inline_array_equals(StrIntrinsicNode::ArgEnc ae);
bool inline_objects_checkIndex();
void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark);
bool inline_native_clone(bool is_virtual);
bool inline_native_Reflection_getCallerClass();
@ -647,6 +648,7 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_copyOfRange: return inline_array_copyOf(true);
case vmIntrinsics::_equalsB: return inline_array_equals(StrIntrinsicNode::LL);
case vmIntrinsics::_equalsC: return inline_array_equals(StrIntrinsicNode::UU);
case vmIntrinsics::_Objects_checkIndex: return inline_objects_checkIndex();
case vmIntrinsics::_clone: return inline_native_clone(intrinsic()->is_virtual());
case vmIntrinsics::_isAssignableFrom: return inline_native_subtype_check();
@ -1045,6 +1047,54 @@ bool LibraryCallKit::inline_hasNegatives() {
return true;
}
bool LibraryCallKit::inline_objects_checkIndex() {
Node* index = argument(0);
Node* length = argument(1);
if (too_many_traps(Deoptimization::Reason_intrinsic) || too_many_traps(Deoptimization::Reason_range_check)) {
return false;
}
Node* len_pos_cmp = _gvn.transform(new CmpINode(length, intcon(0)));
Node* len_pos_bol = _gvn.transform(new BoolNode(len_pos_cmp, BoolTest::ge));
{
BuildCutout unless(this, len_pos_bol, PROB_MAX);
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
}
if (stopped()) {
return false;
}
Node* rc_cmp = _gvn.transform(new CmpUNode(index, length));
BoolTest::mask btest = BoolTest::lt;
Node* rc_bool = _gvn.transform(new BoolNode(rc_cmp, btest));
RangeCheckNode* rc = new RangeCheckNode(control(), rc_bool, PROB_MAX, COUNT_UNKNOWN);
_gvn.set_type(rc, rc->Value(&_gvn));
if (!rc_bool->is_Con()) {
record_for_igvn(rc);
}
set_control(_gvn.transform(new IfTrueNode(rc)));
{
PreserveJVMState pjvms(this);
set_control(_gvn.transform(new IfFalseNode(rc)));
uncommon_trap(Deoptimization::Reason_range_check,
Deoptimization::Action_make_not_entrant);
}
if (stopped()) {
return false;
}
Node* result = new CastIINode(index, TypeInt::make(0, _gvn.type(length)->is_int()->_hi, Type::WidenMax));
result->set_req(0, control());
result = _gvn.transform(result);
set_result(result);
replace_in_map(index, result);
return true;
}
//------------------------------inline_string_indexOf------------------------
bool LibraryCallKit::inline_string_indexOf(StrIntrinsicNode::ArgEnc ae) {
if (!Matcher::has_match_rule(Op_StrIndexOf) || !UseSSE42Intrinsics) {

View File

@ -569,7 +569,7 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari
return false;
}
Node* range = cmp->in(2);
if (range->Opcode() != Op_LoadRange) {
if (range->Opcode() != Op_LoadRange && !iff->is_RangeCheck()) {
const TypeInt* tint = phase->_igvn.type(range)->isa_int();
if (tint == NULL || tint->empty() || tint->_lo < 0) {
// Allow predication on positive values that aren't LoadRanges.

View File

@ -329,6 +329,9 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
Node* phi_incr = NULL;
// Trip-counter increment must be commutative & associative.
if (incr->Opcode() == Op_CastII) {
incr = incr->in(1);
}
if (incr->is_Phi()) {
if (incr->as_Phi()->region() != x || incr->req() != 3)
return false; // Not simple trip counter expression
@ -356,6 +359,9 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
xphi = stride;
stride = tmp;
}
if (xphi->Opcode() == Op_CastII) {
xphi = xphi->in(1);
}
// Stride must be constant
int stride_con = stride->get_int();
if (stride_con == 0)