8255150: Add utility methods to check long indexes and ranges
Co-authored-by: Paul Sandoz <psandoz@openjdk.org> Reviewed-by: jvernee, dlong, vlivanov
This commit is contained in:
parent
6d878565f8
commit
a7422ac2f4
@ -8860,6 +8860,17 @@ instruct castII(iRegI dst)
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
instruct castLL(iRegL dst)
|
||||
%{
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
size(0);
|
||||
format %{ "# castLL of $dst" %}
|
||||
ins_encode(/* empty encoding */);
|
||||
ins_cost(0);
|
||||
ins_pipe(pipe_class_empty);
|
||||
%}
|
||||
|
||||
// ============================================================================
|
||||
// Atomic operation instructions
|
||||
//
|
||||
|
@ -5277,6 +5277,14 @@ instruct castII( iRegI dst ) %{
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct castLL( iRegL dst ) %{
|
||||
match(Set dst (CastLL dst));
|
||||
format %{ "! castLL of $dst" %}
|
||||
ins_encode( /*empty encoding*/ );
|
||||
ins_cost(0);
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
//----------Arithmetic Instructions--------------------------------------------
|
||||
// Addition Instructions
|
||||
// Register Addition
|
||||
|
@ -10348,6 +10348,14 @@ instruct castII(iRegIdst dst) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct castLL(iRegLdst dst) %{
|
||||
match(Set dst (CastLL dst));
|
||||
format %{ " -- \t// castLL of $dst" %}
|
||||
size(0);
|
||||
ins_encode( /*empty*/ );
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct checkCastPP(iRegPdst dst) %{
|
||||
match(Set dst (CheckCastPP dst));
|
||||
format %{ " -- \t// checkcastPP of $dst" %}
|
||||
|
@ -5345,6 +5345,13 @@ instruct castII(iRegI dst) %{
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
||||
instruct castLL(iRegL dst) %{
|
||||
match(Set dst (CastLL dst));
|
||||
size(0);
|
||||
format %{ "# castLL of $dst" %}
|
||||
ins_encode(/*empty*/);
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
||||
//----------Conditional_store--------------------------------------------------
|
||||
// Conditional-store of the updated heap-top.
|
||||
|
@ -7147,6 +7147,14 @@ instruct castII( rRegI dst ) %{
|
||||
ins_pipe( empty );
|
||||
%}
|
||||
|
||||
instruct castLL( eRegL dst ) %{
|
||||
match(Set dst (CastLL dst));
|
||||
format %{ "#castLL of $dst" %}
|
||||
ins_encode( /*empty encoding*/ );
|
||||
ins_cost(0);
|
||||
ins_pipe( empty );
|
||||
%}
|
||||
|
||||
// Load-locked - same as a regular pointer load when used with compare-swap
|
||||
instruct loadPLocked(eRegP dst, memory mem) %{
|
||||
match(Set dst (LoadPLocked mem));
|
||||
|
@ -7445,6 +7445,17 @@ instruct castII(rRegI dst)
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct castLL(rRegL dst)
|
||||
%{
|
||||
match(Set dst (CastLL dst));
|
||||
|
||||
size(0);
|
||||
format %{ "# castLL of $dst" %}
|
||||
ins_encode(/* empty encoding */);
|
||||
ins_cost(0);
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
// LoadP-locked same as a regular LoadP when used with compare-swap
|
||||
instruct loadPLocked(rRegP dst, memory mem)
|
||||
%{
|
||||
|
@ -337,6 +337,8 @@ class methodHandle;
|
||||
\
|
||||
do_intrinsic(_Preconditions_checkIndex, jdk_internal_util_Preconditions, checkIndex_name, Preconditions_checkIndex_signature, F_S) \
|
||||
do_signature(Preconditions_checkIndex_signature, "(IILjava/util/function/BiFunction;)I") \
|
||||
do_intrinsic(_Preconditions_checkLongIndex, jdk_internal_util_Preconditions, checkIndex_name, Preconditions_checkLongIndex_signature, F_S) \
|
||||
do_signature(Preconditions_checkLongIndex_signature, "(JJLjava/util/function/BiFunction;)J") \
|
||||
\
|
||||
do_class(java_nio_Buffer, "java/nio/Buffer") \
|
||||
do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \
|
||||
|
@ -649,6 +649,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
||||
case vmIntrinsics::_profileBoolean:
|
||||
case vmIntrinsics::_isCompileConstant:
|
||||
case vmIntrinsics::_Preconditions_checkIndex:
|
||||
case vmIntrinsics::_Preconditions_checkLongIndex:
|
||||
case vmIntrinsics::_getObjectSize:
|
||||
break;
|
||||
|
||||
|
@ -96,6 +96,11 @@ Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node *n, const Type *t,
|
||||
cast->set_req(0, c);
|
||||
return cast;
|
||||
}
|
||||
case Op_CastLL: {
|
||||
Node* cast = new CastLLNode(n, t, carry_dependency);
|
||||
cast->set_req(0, c);
|
||||
return cast;
|
||||
}
|
||||
case Op_CastPP: {
|
||||
Node* cast = new CastPPNode(n, t, carry_dependency);
|
||||
cast->set_req(0, c);
|
||||
@ -108,6 +113,20 @@ Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node *n, const Type *t,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* ConstraintCastNode::make(Node* c, Node *n, const Type *t, BasicType bt) {
|
||||
switch(bt) {
|
||||
case T_INT: {
|
||||
return make_cast(Op_CastII, c, n, t, false);
|
||||
}
|
||||
case T_LONG: {
|
||||
return make_cast(Op_CastLL, c, n, t, false);
|
||||
}
|
||||
default:
|
||||
fatal("Bad basic type %s", type2name(bt));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const {
|
||||
Node* val = in(1);
|
||||
Node* ctl = in(0);
|
||||
|
@ -53,6 +53,7 @@ class ConstraintCastNode: public TypeNode {
|
||||
bool carry_dependency() const { return _carry_dependency; }
|
||||
TypeNode* dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const;
|
||||
static Node* make_cast(int opcode, Node* c, Node *n, const Type *t, bool carry_dependency);
|
||||
static Node* make(Node* c, Node *n, const Type *t, BasicType bt);
|
||||
|
||||
#ifndef PRODUCT
|
||||
virtual void dump_spec(outputStream *st) const;
|
||||
@ -92,6 +93,16 @@ class CastIINode: public ConstraintCastNode {
|
||||
#endif
|
||||
};
|
||||
|
||||
class CastLLNode: public ConstraintCastNode {
|
||||
public:
|
||||
CastLLNode(Node* n, const Type* t, bool carry_dependency = false)
|
||||
: ConstraintCastNode(n, t, carry_dependency){
|
||||
init_class_id(Class_CastLL);
|
||||
}
|
||||
virtual int Opcode() const;
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
|
||||
//------------------------------CastPPNode-------------------------------------
|
||||
// cast pointer to pointer (different type)
|
||||
class CastPPNode: public ConstraintCastNode {
|
||||
|
@ -1970,12 +1970,14 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// Wait until after parsing for the type information to propagate from the casts.
|
||||
assert(can_reshape, "Invalid during parsing");
|
||||
const Type* phi_type = bottom_type();
|
||||
assert(phi_type->isa_int() || phi_type->isa_ptr(), "bad phi type");
|
||||
assert(phi_type->isa_int() || phi_type->isa_ptr() || phi_type->isa_long(), "bad phi type");
|
||||
// Add casts to carry the control dependency of the Phi that is
|
||||
// going away
|
||||
Node* cast = NULL;
|
||||
if (phi_type->isa_int()) {
|
||||
cast = ConstraintCastNode::make_cast(Op_CastII, r, uin, phi_type, true);
|
||||
} else if (phi_type->isa_long()) {
|
||||
cast = ConstraintCastNode::make_cast(Op_CastLL, r, uin, phi_type, true);
|
||||
} else {
|
||||
const Type* uin_type = phase->type(uin);
|
||||
if (!phi_type->isa_oopptr() && !uin_type->isa_oopptr()) {
|
||||
|
@ -61,6 +61,7 @@ macro(CallLeafNoFP)
|
||||
macro(CallRuntime)
|
||||
macro(CallStaticJava)
|
||||
macro(CastII)
|
||||
macro(CastLL)
|
||||
macro(CastX2P)
|
||||
macro(CastP2X)
|
||||
macro(CastPP)
|
||||
|
@ -103,6 +103,13 @@ class GraphKit : public Phase {
|
||||
// Create or find a constant node
|
||||
Node* intcon(jint con) const { return _gvn.intcon(con); }
|
||||
Node* longcon(jlong con) const { return _gvn.longcon(con); }
|
||||
Node* integercon(jlong con, BasicType bt) const {
|
||||
if (bt == T_INT) {
|
||||
return intcon(checked_cast<jint>(con));
|
||||
}
|
||||
assert(bt == T_LONG, "basic type not an int or long");
|
||||
return longcon(con);
|
||||
}
|
||||
Node* makecon(const Type *t) const { return _gvn.makecon(t); }
|
||||
Node* zerocon(BasicType bt) const { return _gvn.zerocon(bt); }
|
||||
// (See also macro MakeConX in type.hpp, which uses intcon or longcon.)
|
||||
|
@ -483,7 +483,8 @@ 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::_Preconditions_checkIndex: return inline_preconditions_checkIndex();
|
||||
case vmIntrinsics::_Preconditions_checkIndex: return inline_preconditions_checkIndex(T_INT);
|
||||
case vmIntrinsics::_Preconditions_checkLongIndex: return inline_preconditions_checkIndex(T_LONG);
|
||||
case vmIntrinsics::_clone: return inline_native_clone(intrinsic()->is_virtual());
|
||||
|
||||
case vmIntrinsics::_allocateUninitializedArray: return inline_unsafe_newArray(true);
|
||||
@ -1001,14 +1002,15 @@ bool LibraryCallKit::inline_hasNegatives() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_preconditions_checkIndex() {
|
||||
bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) {
|
||||
Node* index = argument(0);
|
||||
Node* length = argument(1);
|
||||
Node* length = bt == T_INT ? argument(1) : argument(2);
|
||||
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)));
|
||||
// check that length is positive
|
||||
Node* len_pos_cmp = _gvn.transform(CmpNode::make(length, integercon(0, bt), bt));
|
||||
Node* len_pos_bol = _gvn.transform(new BoolNode(len_pos_cmp, BoolTest::ge));
|
||||
|
||||
{
|
||||
@ -1017,11 +1019,19 @@ bool LibraryCallKit::inline_preconditions_checkIndex() {
|
||||
Deoptimization::Action_make_not_entrant);
|
||||
}
|
||||
|
||||
// length is now known postive, add a cast node to make this explicit
|
||||
jlong upper_bound = _gvn.type(length)->is_integer(bt)->hi_as_long();
|
||||
Node* casted_length = ConstraintCastNode::make(control(), length, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), bt);
|
||||
casted_length = _gvn.transform(casted_length);
|
||||
replace_in_map(length, casted_length);
|
||||
length = casted_length;
|
||||
|
||||
if (stopped()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Node* rc_cmp = _gvn.transform(new CmpUNode(index, length));
|
||||
// Use an unsigned comparison for the range check itself
|
||||
Node* rc_cmp = _gvn.transform(CmpNode::make(index, length, bt, true));
|
||||
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);
|
||||
@ -1041,8 +1051,8 @@ bool LibraryCallKit::inline_preconditions_checkIndex() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Node* result = new CastIINode(index, TypeInt::make(0, _gvn.type(length)->is_int()->_hi, Type::WidenMax));
|
||||
result->set_req(0, control());
|
||||
// index is now known to be >= 0 and < length, cast it
|
||||
Node* result = ConstraintCastNode::make(control(), index, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), bt);
|
||||
result = _gvn.transform(result);
|
||||
set_result(result);
|
||||
replace_in_map(index, result);
|
||||
|
@ -241,7 +241,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_preconditions_checkIndex();
|
||||
bool inline_preconditions_checkIndex(BasicType bt);
|
||||
void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array);
|
||||
bool inline_native_clone(bool is_virtual);
|
||||
bool inline_native_Reflection_getCallerClass();
|
||||
|
@ -52,6 +52,7 @@ class CallNode;
|
||||
class CallRuntimeNode;
|
||||
class CallStaticJavaNode;
|
||||
class CastIINode;
|
||||
class CastLLNode;
|
||||
class CatchNode;
|
||||
class CatchProjNode;
|
||||
class CheckCastPPNode;
|
||||
@ -671,6 +672,7 @@ public:
|
||||
DEFINE_CLASS_ID(ConstraintCast, Type, 1)
|
||||
DEFINE_CLASS_ID(CastII, ConstraintCast, 0)
|
||||
DEFINE_CLASS_ID(CheckCastPP, ConstraintCast, 1)
|
||||
DEFINE_CLASS_ID(CastLL, ConstraintCast, 2)
|
||||
DEFINE_CLASS_ID(CMove, Type, 3)
|
||||
DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
|
||||
DEFINE_CLASS_ID(DecodeNarrowPtr, Type, 5)
|
||||
@ -819,6 +821,7 @@ public:
|
||||
DEFINE_CLASS_QUERY(CatchProj)
|
||||
DEFINE_CLASS_QUERY(CheckCastPP)
|
||||
DEFINE_CLASS_QUERY(CastII)
|
||||
DEFINE_CLASS_QUERY(CastLL)
|
||||
DEFINE_CLASS_QUERY(ConstraintCast)
|
||||
DEFINE_CLASS_QUERY(ClearArray)
|
||||
DEFINE_CLASS_QUERY(CMove)
|
||||
|
@ -274,6 +274,7 @@ public:
|
||||
// Fast int or long constant. Same as TypeInt::make(i) or TypeLong::make(l).
|
||||
ConINode* intcon(jint i);
|
||||
ConLNode* longcon(jlong l);
|
||||
ConNode* integercon(jlong l, BasicType bt);
|
||||
|
||||
// Fast zero or null constant. Same as makecon(Type::get_zero_type(bt)).
|
||||
ConNode* zerocon(BasicType bt);
|
||||
|
@ -563,8 +563,27 @@ void CmpNode::related(GrowableArray<Node*> *in_rel, GrowableArray<Node*> *out_re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CmpNode *CmpNode::make(Node *in1, Node *in2, BasicType bt, bool unsigned_comp) {
|
||||
switch (bt) {
|
||||
case T_INT:
|
||||
if (unsigned_comp) {
|
||||
return new CmpUNode(in1, in2);
|
||||
}
|
||||
return new CmpINode(in1, in2);
|
||||
case T_LONG:
|
||||
if (unsigned_comp) {
|
||||
return new CmpULNode(in1, in2);
|
||||
}
|
||||
return new CmpLNode(in1, in2);
|
||||
default:
|
||||
fatal("Not implemented for %s", type2name(bt));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------cmp--------------------------------------------
|
||||
// Simplify a CmpI (compare 2 integers) node, based on local information.
|
||||
|
@ -140,6 +140,8 @@ public:
|
||||
const Type *bottom_type() const { return TypeInt::CC; }
|
||||
virtual uint ideal_reg() const { return Op_RegFlags; }
|
||||
|
||||
static CmpNode *make(Node *in1, Node *in2, BasicType bt, bool unsigned_comp = false);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// CmpNode and subclasses include all data inputs (until hitting a control
|
||||
// boundary) in their related node set, as well as all outputs until and
|
||||
|
@ -1338,6 +1338,14 @@ bool TypeD::empty(void) const {
|
||||
return false; // always exactly a singleton
|
||||
}
|
||||
|
||||
const TypeInteger* TypeInteger::make(jlong lo, jlong hi, int w, BasicType bt) {
|
||||
if (bt == T_INT) {
|
||||
return TypeInt::make(checked_cast<jint>(lo), checked_cast<jint>(hi), w);
|
||||
}
|
||||
assert(bt == T_LONG, "basic type not an int or long");
|
||||
return TypeLong::make(lo, hi, w);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Convience common pre-built types.
|
||||
const TypeInt *TypeInt::MAX; // INT_MAX
|
||||
@ -1363,7 +1371,7 @@ const TypeInt *TypeInt::SYMINT; // symmetric range [-max_jint..max_jint]
|
||||
const TypeInt *TypeInt::TYPE_DOMAIN; // alias for TypeInt::INT
|
||||
|
||||
//------------------------------TypeInt----------------------------------------
|
||||
TypeInt::TypeInt( jint lo, jint hi, int w ) : Type(Int), _lo(lo), _hi(hi), _widen(w) {
|
||||
TypeInt::TypeInt( jint lo, jint hi, int w ) : TypeInteger(Int), _lo(lo), _hi(hi), _widen(w) {
|
||||
}
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
@ -1623,7 +1631,7 @@ const TypeLong *TypeLong::UINT; // 32-bit unsigned subrange
|
||||
const TypeLong *TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG
|
||||
|
||||
//------------------------------TypeLong---------------------------------------
|
||||
TypeLong::TypeLong( jlong lo, jlong hi, int w ) : Type(Long), _lo(lo), _hi(hi), _widen(w) {
|
||||
TypeLong::TypeLong(jlong lo, jlong hi, int w) : TypeInteger(Long), _lo(lo), _hi(hi), _widen(w) {
|
||||
}
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
|
@ -45,8 +45,9 @@ class Dict;
|
||||
class Type;
|
||||
class TypeD;
|
||||
class TypeF;
|
||||
class TypeInt;
|
||||
class TypeLong;
|
||||
class TypeInteger;
|
||||
class TypeInt;
|
||||
class TypeLong;
|
||||
class TypeNarrowPtr;
|
||||
class TypeNarrowOop;
|
||||
class TypeNarrowKlass;
|
||||
@ -283,6 +284,9 @@ public:
|
||||
|
||||
const TypeInt *is_int() const;
|
||||
const TypeInt *isa_int() const; // Returns NULL if not an Int
|
||||
const TypeInteger* isa_integer() const;
|
||||
const TypeInteger* is_integer(BasicType bt) const;
|
||||
const TypeInteger* isa_integer(BasicType bt) const;
|
||||
const TypeLong *is_long() const;
|
||||
const TypeLong *isa_long() const; // Returns NULL if not a Long
|
||||
const TypeD *isa_double() const; // Returns NULL if not a Double{Top,Con,Bot}
|
||||
@ -525,10 +529,24 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
class TypeInteger : public Type {
|
||||
protected:
|
||||
TypeInteger(TYPES t) : Type(t) {}
|
||||
|
||||
public:
|
||||
virtual jlong hi_as_long() const = 0;
|
||||
virtual jlong lo_as_long() const = 0;
|
||||
jlong get_con_as_long(BasicType bt) const;
|
||||
|
||||
static const TypeInteger* make(jlong lo, jlong hi, int w, BasicType bt);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------TypeInt----------------------------------------
|
||||
// Class of integer ranges, the set of integers between a lower bound and an
|
||||
// upper bound, inclusive.
|
||||
class TypeInt : public Type {
|
||||
class TypeInt : public TypeInteger {
|
||||
TypeInt( jint lo, jint hi, int w );
|
||||
protected:
|
||||
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
|
||||
@ -557,6 +575,10 @@ public:
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
virtual const Type *widen( const Type *t, const Type* limit_type ) const;
|
||||
virtual const Type *narrow( const Type *t ) const;
|
||||
|
||||
virtual jlong hi_as_long() const { return _hi; }
|
||||
virtual jlong lo_as_long() const { return _lo; }
|
||||
|
||||
// Do not kill _widen bits.
|
||||
// Convenience common pre-built types.
|
||||
static const TypeInt *MAX;
|
||||
@ -591,7 +613,7 @@ public:
|
||||
//------------------------------TypeLong---------------------------------------
|
||||
// Class of long integer ranges, the set of integers between a lower bound and
|
||||
// an upper bound, inclusive.
|
||||
class TypeLong : public Type {
|
||||
class TypeLong : public TypeInteger {
|
||||
TypeLong( jlong lo, jlong hi, int w );
|
||||
protected:
|
||||
// Do not kill _widen bits.
|
||||
@ -620,6 +642,8 @@ public:
|
||||
|
||||
virtual bool is_finite() const; // Has a finite value
|
||||
|
||||
virtual jlong hi_as_long() const { return _hi; }
|
||||
virtual jlong lo_as_long() const { return _lo; }
|
||||
|
||||
virtual const Type *xmeet( const Type *t ) const;
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
@ -1575,6 +1599,15 @@ inline double Type::getd() const {
|
||||
return ((TypeD*)this)->_d;
|
||||
}
|
||||
|
||||
inline const TypeInteger *Type::is_integer(BasicType bt) const {
|
||||
assert((bt == T_INT && _base == Int) || (bt == T_LONG && _base == Long), "Not an Int");
|
||||
return (TypeInteger*)this;
|
||||
}
|
||||
|
||||
inline const TypeInteger *Type::isa_integer(BasicType bt) const {
|
||||
return (((bt == T_INT && _base == Int) || (bt == T_LONG && _base == Long)) ? (TypeInteger*)this : NULL);
|
||||
}
|
||||
|
||||
inline const TypeInt *Type::is_int() const {
|
||||
assert( _base == Int, "Not an Int" );
|
||||
return (TypeInt*)this;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -68,4 +68,18 @@ public class IndexOutOfBoundsException extends RuntimeException {
|
||||
public IndexOutOfBoundsException(int index) {
|
||||
super("Index out of range: " + index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IndexOutOfBoundsException} class with an
|
||||
* argument indicating the illegal index.
|
||||
*
|
||||
* <p>The index is included in this exception's detail message. The
|
||||
* exact presentation format of the detail message is unspecified.
|
||||
*
|
||||
* @param index the illegal index.
|
||||
* @since 16
|
||||
*/
|
||||
public IndexOutOfBoundsException(long index) {
|
||||
super("Index out of range: " + index);
|
||||
}
|
||||
}
|
||||
|
@ -2146,7 +2146,7 @@ public abstract class VarHandle implements Constable {
|
||||
UNSAFE.fullFence();
|
||||
}
|
||||
|
||||
static final BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException>
|
||||
static final BiFunction<String, List<Number>, ArrayIndexOutOfBoundsException>
|
||||
AIOOBE_SUPPLIER = Preconditions.outOfBoundsExceptionFormatter(
|
||||
new Function<String, ArrayIndexOutOfBoundsException>() {
|
||||
@Override
|
||||
|
@ -411,4 +411,79 @@ public final class Objects {
|
||||
return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@code index} is within the bounds of the range from
|
||||
* {@code 0} (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The {@code index} is defined to be out of bounds if any of the
|
||||
* following inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code index < 0}</li>
|
||||
* <li>{@code index >= length}</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param index the index
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @return {@code index} if it is within bounds of the range
|
||||
* @throws IndexOutOfBoundsException if the {@code index} is out of bounds
|
||||
* @since 16
|
||||
*/
|
||||
@ForceInline
|
||||
public static
|
||||
long checkIndex(long index, long length) {
|
||||
return Preconditions.checkIndex(index, length, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sub-range from {@code fromIndex} (inclusive) to
|
||||
* {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
|
||||
* (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The sub-range is defined to be out of bounds if any of the following
|
||||
* inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code fromIndex < 0}</li>
|
||||
* <li>{@code fromIndex > toIndex}</li>
|
||||
* <li>{@code toIndex > length}</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fromIndex the lower-bound (inclusive) of the sub-range
|
||||
* @param toIndex the upper-bound (exclusive) of the sub-range
|
||||
* @param length the upper-bound (exclusive) the range
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws IndexOutOfBoundsException if the sub-range is out of bounds
|
||||
* @since 16
|
||||
*/
|
||||
public static
|
||||
long checkFromToIndex(long fromIndex, long toIndex, long length) {
|
||||
return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sub-range from {@code fromIndex} (inclusive) to
|
||||
* {@code fromIndex + size} (exclusive) is within the bounds of range from
|
||||
* {@code 0} (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The sub-range is defined to be out of bounds if any of the following
|
||||
* inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code fromIndex < 0}</li>
|
||||
* <li>{@code size < 0}</li>
|
||||
* <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param fromIndex the lower-bound (inclusive) of the sub-interval
|
||||
* @param size the size of the sub-range
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws IndexOutOfBoundsException if the sub-range is out of bounds
|
||||
* @since 16
|
||||
*/
|
||||
public static
|
||||
long checkFromIndexSize(long fromIndex, long size, long length) {
|
||||
return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
|
||||
}
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ public class Preconditions {
|
||||
* @return the runtime exception
|
||||
*/
|
||||
private static RuntimeException outOfBounds(
|
||||
BiFunction<String, List<Integer>, ? extends RuntimeException> oobef,
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobef,
|
||||
String checkKind,
|
||||
Integer... args) {
|
||||
List<Integer> largs = List.of(args);
|
||||
Number... args) {
|
||||
List<Number> largs = List.of(args);
|
||||
RuntimeException e = oobef == null
|
||||
? null : oobef.apply(checkKind, largs);
|
||||
return e == null
|
||||
@ -65,23 +65,41 @@ public class Preconditions {
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckIndex(
|
||||
BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
int index, int length) {
|
||||
return outOfBounds(oobe, "checkIndex", index, length);
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckFromToIndex(
|
||||
BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
int fromIndex, int toIndex, int length) {
|
||||
return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckFromIndexSize(
|
||||
BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
int fromIndex, int size, int length) {
|
||||
return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckIndex(
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
long index, long length) {
|
||||
return outOfBounds(oobe, "checkIndex", index, length);
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckFromToIndex(
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
long fromIndex, long toIndex, long length) {
|
||||
return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
|
||||
}
|
||||
|
||||
private static RuntimeException outOfBoundsCheckFromIndexSize(
|
||||
BiFunction<String, List<Number>, ? extends RuntimeException> oobe,
|
||||
long fromIndex, long size, long length) {
|
||||
return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an out-of-bounds exception formatter from an given exception
|
||||
* factory. The exception formatter is a function that formats an
|
||||
@ -90,8 +108,8 @@ public class Preconditions {
|
||||
*
|
||||
* <p>The exception formatter accepts two arguments: a {@code String}
|
||||
* describing the out-of-bounds range check that failed, referred to as the
|
||||
* <em>check kind</em>; and a {@code List<Integer>} containing the
|
||||
* out-of-bound integer values that failed the check. The list of
|
||||
* <em>check kind</em>; and a {@code List<Number>} containing the
|
||||
* out-of-bound integral values that failed the check. The list of
|
||||
* out-of-bound values is not modified.
|
||||
*
|
||||
* <p>Three check kinds are supported {@code checkIndex},
|
||||
@ -102,7 +120,7 @@ public class Preconditions {
|
||||
* {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and
|
||||
* {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}.
|
||||
* Thus a supported check kind corresponds to a method name and the
|
||||
* out-of-bound integer values correspond to method argument values, in
|
||||
* out-of-bound integral values correspond to method argument values, in
|
||||
* order, preceding the exception formatter argument (similar in many
|
||||
* respects to the form of arguments required for a reflective invocation of
|
||||
* such a range check method).
|
||||
@ -123,7 +141,7 @@ public class Preconditions {
|
||||
* {@code static final} field as follows:
|
||||
* <pre>{@code
|
||||
* static final
|
||||
* BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException> AIOOBEF =
|
||||
* BiFunction<String, List<Number>, ArrayIndexOutOfBoundsException> AIOOBEF =
|
||||
* outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
|
||||
* }</pre>
|
||||
* The formatter instance {@code AIOOBEF} may be passed as an argument to an
|
||||
@ -150,18 +168,18 @@ public class Preconditions {
|
||||
* @return the out-of-bounds exception formatter
|
||||
*/
|
||||
public static <X extends RuntimeException>
|
||||
BiFunction<String, List<Integer>, X> outOfBoundsExceptionFormatter(Function<String, X> f) {
|
||||
BiFunction<String, List<Number>, X> outOfBoundsExceptionFormatter(Function<String, X> f) {
|
||||
// Use anonymous class to avoid bootstrap issues if this method is
|
||||
// used early in startup
|
||||
return new BiFunction<String, List<Integer>, X>() {
|
||||
return new BiFunction<String, List<Number>, X>() {
|
||||
@Override
|
||||
public X apply(String checkKind, List<Integer> args) {
|
||||
public X apply(String checkKind, List<Number> args) {
|
||||
return f.apply(outOfBoundsMessage(checkKind, args));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String outOfBoundsMessage(String checkKind, List<Integer> args) {
|
||||
private static String outOfBoundsMessage(String checkKind, List<? extends Number> args) {
|
||||
if (checkKind == null && args == null) {
|
||||
return String.format("Range check failed");
|
||||
} else if (checkKind == null) {
|
||||
@ -213,7 +231,7 @@ public class Preconditions {
|
||||
* <p>If the {@code index} is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkIndex};
|
||||
* and an unmodifiable list integers whose values are, in order, the
|
||||
* and an unmodifiable list of integers whose values are, in order, the
|
||||
* out-of-bounds arguments {@code index} and {@code length}.
|
||||
*
|
||||
* @param <X> the type of runtime exception to throw if the arguments are
|
||||
@ -243,7 +261,7 @@ public class Preconditions {
|
||||
@IntrinsicCandidate
|
||||
public static <X extends RuntimeException>
|
||||
int checkIndex(int index, int length,
|
||||
BiFunction<String, List<Integer>, X> oobef) {
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if (index < 0 || index >= length)
|
||||
throw outOfBoundsCheckIndex(oobef, index, length);
|
||||
return index;
|
||||
@ -266,7 +284,7 @@ public class Preconditions {
|
||||
* <p>If the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkFromToIndex};
|
||||
* and an unmodifiable list integers whose values are, in order, the
|
||||
* and an unmodifiable list of integers whose values are, in order, the
|
||||
* out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}.
|
||||
*
|
||||
* @param <X> the type of runtime exception to throw if the arguments are
|
||||
@ -290,7 +308,7 @@ public class Preconditions {
|
||||
*/
|
||||
public static <X extends RuntimeException>
|
||||
int checkFromToIndex(int fromIndex, int toIndex, int length,
|
||||
BiFunction<String, List<Integer>, X> oobef) {
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if (fromIndex < 0 || fromIndex > toIndex || toIndex > length)
|
||||
throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length);
|
||||
return fromIndex;
|
||||
@ -313,7 +331,7 @@ public class Preconditions {
|
||||
* <p>If the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkFromIndexSize};
|
||||
* and an unmodifiable list integers whose values are, in order, the
|
||||
* and an unmodifiable list of integers whose values are, in order, the
|
||||
* out-of-bounds arguments {@code fromIndex}, {@code size}, and
|
||||
* {@code length}.
|
||||
*
|
||||
@ -338,7 +356,153 @@ public class Preconditions {
|
||||
*/
|
||||
public static <X extends RuntimeException>
|
||||
int checkFromIndexSize(int fromIndex, int size, int length,
|
||||
BiFunction<String, List<Integer>, X> oobef) {
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if ((length | fromIndex | size) < 0 || size > length - fromIndex)
|
||||
throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@code index} is within the bounds of the range from
|
||||
* {@code 0} (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The {@code index} is defined to be out of bounds if any of the
|
||||
* following inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code index < 0}</li>
|
||||
* <li>{@code index >= length}</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If the {@code index} is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkIndex};
|
||||
* and an unmodifiable list of longs whose values are, in order, the
|
||||
* out-of-bounds arguments {@code index} and {@code length}.
|
||||
*
|
||||
* @param <X> the type of runtime exception to throw if the arguments are
|
||||
* out of bounds
|
||||
* @param index the index
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @param oobef the exception formatter that when applied with this
|
||||
* method name and out-of-bounds arguments returns a runtime
|
||||
* exception. If {@code null} or returns {@code null} then, it is as
|
||||
* if an exception formatter produced from an invocation of
|
||||
* {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
|
||||
* instead (though it may be more efficient).
|
||||
* Exceptions thrown by the formatter are relayed to the caller.
|
||||
* @return {@code index} if it is within bounds of the range
|
||||
* @throws X if the {@code index} is out of bounds and the exception
|
||||
* formatter is non-{@code null}
|
||||
* @throws IndexOutOfBoundsException if the {@code index} is out of bounds
|
||||
* and the exception formatter is {@code null}
|
||||
* @since 16
|
||||
*
|
||||
* @implNote
|
||||
* This method is made intrinsic in optimizing compilers to guide them to
|
||||
* perform unsigned comparisons of the index and length when it is known the
|
||||
* length is a non-negative value (such as that of an array length or from
|
||||
* the upper bound of a loop)
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
public static <X extends RuntimeException>
|
||||
long checkIndex(long index, long length,
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if (index < 0 || index >= length)
|
||||
throw outOfBoundsCheckIndex(oobef, index, length);
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sub-range from {@code fromIndex} (inclusive) to
|
||||
* {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
|
||||
* (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The sub-range is defined to be out of bounds if any of the following
|
||||
* inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code fromIndex < 0}</li>
|
||||
* <li>{@code fromIndex > toIndex}</li>
|
||||
* <li>{@code toIndex > length}</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkFromToIndex};
|
||||
* and an unmodifiable list of longs whose values are, in order, the
|
||||
* out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}.
|
||||
*
|
||||
* @param <X> the type of runtime exception to throw if the arguments are
|
||||
* out of bounds
|
||||
* @param fromIndex the lower-bound (inclusive) of the sub-range
|
||||
* @param toIndex the upper-bound (exclusive) of the sub-range
|
||||
* @param length the upper-bound (exclusive) the range
|
||||
* @param oobef the exception formatter that when applied with this
|
||||
* method name and out-of-bounds arguments returns a runtime
|
||||
* exception. If {@code null} or returns {@code null} then, it is as
|
||||
* if an exception formatter produced from an invocation of
|
||||
* {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
|
||||
* instead (though it may be more efficient).
|
||||
* Exceptions thrown by the formatter are relayed to the caller.
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws X if the sub-range is out of bounds and the exception factory
|
||||
* function is non-{@code null}
|
||||
* @throws IndexOutOfBoundsException if the sub-range is out of bounds and
|
||||
* the exception factory function is {@code null}
|
||||
* @since 16
|
||||
*/
|
||||
public static <X extends RuntimeException>
|
||||
long checkFromToIndex(long fromIndex, long toIndex, long length,
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if (fromIndex < 0 || fromIndex > toIndex || toIndex > length)
|
||||
throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length);
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sub-range from {@code fromIndex} (inclusive) to
|
||||
* {@code fromIndex + size} (exclusive) is within the bounds of range from
|
||||
* {@code 0} (inclusive) to {@code length} (exclusive).
|
||||
*
|
||||
* <p>The sub-range is defined to be out of bounds if any of the following
|
||||
* inequalities is true:
|
||||
* <ul>
|
||||
* <li>{@code fromIndex < 0}</li>
|
||||
* <li>{@code size < 0}</li>
|
||||
* <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
|
||||
* <li>{@code length < 0}, which is implied from the former inequalities</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the following arguments to the
|
||||
* exception formatter: the name of this method, {@code checkFromIndexSize};
|
||||
* and an unmodifiable list of longs whose values are, in order, the
|
||||
* out-of-bounds arguments {@code fromIndex}, {@code size}, and
|
||||
* {@code length}.
|
||||
*
|
||||
* @param <X> the type of runtime exception to throw if the arguments are
|
||||
* out of bounds
|
||||
* @param fromIndex the lower-bound (inclusive) of the sub-interval
|
||||
* @param size the size of the sub-range
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @param oobef the exception formatter that when applied with this
|
||||
* method name and out-of-bounds arguments returns a runtime
|
||||
* exception. If {@code null} or returns {@code null} then, it is as
|
||||
* if an exception formatter produced from an invocation of
|
||||
* {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
|
||||
* instead (though it may be more efficient).
|
||||
* Exceptions thrown by the formatter are relayed to the caller.
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws X if the sub-range is out of bounds and the exception factory
|
||||
* function is non-{@code null}
|
||||
* @throws IndexOutOfBoundsException if the sub-range is out of bounds and
|
||||
* the exception factory function is {@code null}
|
||||
* @since 16
|
||||
*/
|
||||
public static <X extends RuntimeException>
|
||||
long checkFromIndexSize(long fromIndex, long size, long length,
|
||||
BiFunction<String, List<Number>, X> oobef) {
|
||||
if ((length | fromIndex | size) < 0 || size > length - fromIndex)
|
||||
throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
|
||||
return fromIndex;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -37,7 +37,7 @@ import jdk.internal.util.Preconditions;
|
||||
|
||||
public final class ArrayUtil {
|
||||
|
||||
private static final BiFunction<String, List<Integer>,
|
||||
private static final BiFunction<String, List<Number>,
|
||||
ArrayIndexOutOfBoundsException> AIOOBE_SUPPLIER =
|
||||
Preconditions.outOfBoundsExceptionFormatter
|
||||
(ArrayIndexOutOfBoundsException::new);
|
||||
|
@ -436,6 +436,7 @@ public class CheckGraalIntrinsics extends GraalTest {
|
||||
"java/lang/Math.copySign(FF)F",
|
||||
"java/lang/Math.signum(D)D",
|
||||
"java/lang/Math.signum(F)F",
|
||||
"jdk/internal/util/Preconditions.checkIndex(JJLjava/util/function/BiFunction;)J",
|
||||
"sun/security/provider/MD5.implCompress0([BI)V");
|
||||
if (config.useBase64Intrinsics()) {
|
||||
// Currently implemented on ppc64le only, but could be implemented on others
|
||||
|
133
test/hotspot/jtreg/compiler/intrinsics/TestCheckIndex.java
Normal file
133
test/hotspot/jtreg/compiler/intrinsics/TestCheckIndex.java
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8255150
|
||||
* @summary Add utility methods to check long indexes and ranges
|
||||
* @requires vm.compiler2.enabled
|
||||
* @requires vm.compMode != "Xcomp"
|
||||
* @library /test/lib /
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
|
||||
*
|
||||
* @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestCheckIndex
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Objects;
|
||||
import sun.hotspot.WhiteBox;
|
||||
import java.lang.reflect.Method;
|
||||
import compiler.whitebox.CompilerWhiteBoxTest;
|
||||
|
||||
public class TestCheckIndex {
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
Objects.checkIndex(0, 10); // Load class
|
||||
Method m1 = TestCheckIndex.class.getDeclaredMethod("test1", int.class, int.class);
|
||||
Method m2 = TestCheckIndex.class.getDeclaredMethod("test2", long.class, long.class);
|
||||
Method m3 = TestCheckIndex.class.getDeclaredMethod("test3", int.class, int.class);
|
||||
Method m4 = TestCheckIndex.class.getDeclaredMethod("test4", long.class, long.class);
|
||||
assert m1 != null && m2 != null && m3 != null && m4 != null;
|
||||
WHITE_BOX.enqueueMethodForCompilation(m1, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
|
||||
if (!WHITE_BOX.isMethodCompiled(m1)) {
|
||||
throw new RuntimeException("should be compiled");
|
||||
}
|
||||
WHITE_BOX.enqueueMethodForCompilation(m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
|
||||
if (!WHITE_BOX.isMethodCompiled(m2)) {
|
||||
throw new RuntimeException("should be compiled");
|
||||
}
|
||||
WHITE_BOX.enqueueMethodForCompilation(m3, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
|
||||
if (!WHITE_BOX.isMethodCompiled(m3)) {
|
||||
throw new RuntimeException("should be compiled");
|
||||
}
|
||||
WHITE_BOX.enqueueMethodForCompilation(m4, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
|
||||
if (!WHITE_BOX.isMethodCompiled(m4)) {
|
||||
throw new RuntimeException("should be compiled");
|
||||
}
|
||||
|
||||
if (test1(0, 10) != 0) {
|
||||
throw new RuntimeException("incorrect result");
|
||||
}
|
||||
if (!WHITE_BOX.isMethodCompiled(m1)) {
|
||||
throw new RuntimeException("should still be compiled");
|
||||
}
|
||||
if (test2(0, 10) != 0) {
|
||||
throw new RuntimeException("incorrect result");
|
||||
}
|
||||
if (!WHITE_BOX.isMethodCompiled(m2)) {
|
||||
throw new RuntimeException("should still be compiled");
|
||||
}
|
||||
|
||||
try {
|
||||
test1(0, -10);
|
||||
throw new RuntimeException("exception not thrown");
|
||||
} catch (IndexOutOfBoundsException ioobe) {
|
||||
}
|
||||
if (WHITE_BOX.isMethodCompiled(m1)) {
|
||||
throw new RuntimeException("should have deoptimized");
|
||||
}
|
||||
try {
|
||||
test2(0, -10);
|
||||
throw new RuntimeException("exception not thrown");
|
||||
} catch (IndexOutOfBoundsException ioobe) {
|
||||
}
|
||||
if (WHITE_BOX.isMethodCompiled(m2)) {
|
||||
throw new RuntimeException("should have deoptimized");
|
||||
}
|
||||
|
||||
try {
|
||||
test3(42, 10);
|
||||
throw new RuntimeException("exception not thrown");
|
||||
} catch (IndexOutOfBoundsException ioobe) {
|
||||
}
|
||||
if (WHITE_BOX.isMethodCompiled(m3)) {
|
||||
throw new RuntimeException("should have deoptimized");
|
||||
}
|
||||
try {
|
||||
test4(42, 10);
|
||||
throw new RuntimeException("exception not thrown");
|
||||
} catch (IndexOutOfBoundsException ioobe) {
|
||||
}
|
||||
if (WHITE_BOX.isMethodCompiled(m4)) {
|
||||
throw new RuntimeException("should have deoptimized");
|
||||
}
|
||||
}
|
||||
|
||||
static int test1(int index, int length) {
|
||||
return Objects.checkIndex(index, length);
|
||||
}
|
||||
|
||||
static long test2(long index, long length) {
|
||||
return Objects.checkIndex(index, length);
|
||||
}
|
||||
|
||||
static int test3(int index, int length) {
|
||||
return Objects.checkIndex(index, length);
|
||||
}
|
||||
|
||||
static long test4(long index, long length) {
|
||||
return Objects.checkIndex(index, length);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Objects.checkIndex/jdk.internal.util.Preconditions.checkIndex tests
|
||||
* @summary Objects.checkIndex/jdk.internal.util.Preconditions.checkIndex tests for int values
|
||||
* @run testng CheckIndex
|
||||
* @bug 8135248 8142493 8155794
|
||||
* @modules java.base/jdk.internal.util
|
||||
@ -50,7 +50,7 @@ public class CheckIndex {
|
||||
}
|
||||
}
|
||||
|
||||
static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBounds(
|
||||
static BiFunction<String, List<Number>, AssertingOutOfBoundsException> assertingOutOfBounds(
|
||||
String message, String expCheckKind, Integer... expArgs) {
|
||||
return (checkKind, args) -> {
|
||||
assertEquals(checkKind, expCheckKind);
|
||||
@ -64,7 +64,7 @@ public class CheckIndex {
|
||||
};
|
||||
}
|
||||
|
||||
static BiFunction<String, List<Integer>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull(
|
||||
static BiFunction<String, List<Number>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull(
|
||||
String expCheckKind, Integer... expArgs) {
|
||||
return (checkKind, args) -> {
|
||||
assertEquals(checkKind, expCheckKind);
|
||||
@ -86,11 +86,7 @@ public class CheckIndex {
|
||||
l.add(new Object[]{index, length, withinBounds});
|
||||
}
|
||||
}
|
||||
return l.toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
interface X {
|
||||
int apply(int a, int b, int c);
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkIndexProvider")
|
||||
@ -152,7 +148,7 @@ public class CheckIndex {
|
||||
}
|
||||
}
|
||||
}
|
||||
return l.toArray(new Object[0][0]);
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkFromToIndexProvider")
|
||||
@ -221,7 +217,7 @@ public class CheckIndex {
|
||||
}
|
||||
}
|
||||
}
|
||||
return l.toArray(new Object[0][0]);
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkFromIndexSizeProvider")
|
||||
@ -269,7 +265,7 @@ public class CheckIndex {
|
||||
|
||||
@Test
|
||||
public void uniqueMessagesForCheckKinds() {
|
||||
BiFunction<String, List<Integer>, IndexOutOfBoundsException> f =
|
||||
BiFunction<String, List<Number>, IndexOutOfBoundsException> f =
|
||||
Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new);
|
||||
|
||||
List<String> messages = new ArrayList<>();
|
||||
|
287
test/jdk/java/util/Objects/CheckLongIndex.java
Normal file
287
test/jdk/java/util/Objects/CheckLongIndex.java
Normal file
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Objects.checkIndex/jdk.internal.util.Preconditions.checkIndex tests for long values
|
||||
* @run testng CheckLongIndex
|
||||
* @modules java.base/jdk.internal.util
|
||||
*/
|
||||
|
||||
import jdk.internal.util.Preconditions;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class CheckLongIndex {
|
||||
|
||||
static class AssertingOutOfBoundsException extends RuntimeException {
|
||||
public AssertingOutOfBoundsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
static BiFunction<String, List<Number>, AssertingOutOfBoundsException> assertingOutOfBounds(
|
||||
String message, String expCheckKind, Long... expArgs) {
|
||||
return (checkKind, args) -> {
|
||||
assertEquals(checkKind, expCheckKind);
|
||||
assertEquals(args, List.of(expArgs));
|
||||
try {
|
||||
args.clear();
|
||||
fail("Out of bounds List<Long> argument should be unmodifiable");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return new AssertingOutOfBoundsException(message);
|
||||
};
|
||||
}
|
||||
|
||||
static BiFunction<String, List<Number>, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull(
|
||||
String expCheckKind, Long... expArgs) {
|
||||
return (checkKind, args) -> {
|
||||
assertEquals(checkKind, expCheckKind);
|
||||
assertEquals(args, List.of(expArgs));
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
static final long[] VALUES = {0, 1, Long.MAX_VALUE - 1, Long.MAX_VALUE, -1, Long.MIN_VALUE + 1, Long.MIN_VALUE};
|
||||
|
||||
@DataProvider
|
||||
static Object[][] checkIndexProvider() {
|
||||
List<Object[]> l = new ArrayList<>();
|
||||
for (long index : VALUES) {
|
||||
for (long length : VALUES) {
|
||||
boolean withinBounds = index >= 0 &&
|
||||
length >= 0 &&
|
||||
index < length;
|
||||
l.add(new Object[]{index, length, withinBounds});
|
||||
}
|
||||
}
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkIndexProvider")
|
||||
public void testCheckIndex(long index, long length, boolean withinBounds) {
|
||||
String expectedMessage = withinBounds
|
||||
? null
|
||||
: Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
|
||||
apply("checkIndex", List.of(index, length)).getMessage();
|
||||
|
||||
BiConsumer<Class<? extends RuntimeException>, LongSupplier> checker = (ec, s) -> {
|
||||
try {
|
||||
long rIndex = s.getAsLong();
|
||||
if (!withinBounds)
|
||||
fail(String.format(
|
||||
"Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length));
|
||||
assertEquals(rIndex, index);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertTrue(ec.isInstance(e));
|
||||
if (withinBounds)
|
||||
fail(String.format(
|
||||
"Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length));
|
||||
else
|
||||
assertEquals(e.getMessage(), expectedMessage);
|
||||
}
|
||||
};
|
||||
|
||||
checker.accept(AssertingOutOfBoundsException.class,
|
||||
() -> Preconditions.checkIndex(index, length,
|
||||
assertingOutOfBounds(expectedMessage, "checkIndex", index, length)));
|
||||
checker.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkIndex(index, length,
|
||||
assertingOutOfBoundsReturnNull("checkIndex", index, length)));
|
||||
checker.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkIndex(index, length, null));
|
||||
checker.accept(IndexOutOfBoundsException.class,
|
||||
() -> Objects.checkIndex(index, length));
|
||||
checker.accept(ArrayIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkIndex(index, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
|
||||
checker.accept(StringIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkIndex(index, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
|
||||
}
|
||||
|
||||
|
||||
@DataProvider
|
||||
static Object[][] checkFromToIndexProvider() {
|
||||
List<Object[]> l = new ArrayList<>();
|
||||
for (long fromIndex : VALUES) {
|
||||
for (long toIndex : VALUES) {
|
||||
for (long length : VALUES) {
|
||||
boolean withinBounds = fromIndex >= 0 &&
|
||||
toIndex >= 0 &&
|
||||
length >= 0 &&
|
||||
fromIndex <= toIndex &&
|
||||
toIndex <= length;
|
||||
l.add(new Object[]{fromIndex, toIndex, length, withinBounds});
|
||||
}
|
||||
}
|
||||
}
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkFromToIndexProvider")
|
||||
public void testCheckFromToIndex(long fromIndex, long toIndex, long length, boolean withinBounds) {
|
||||
String expectedMessage = withinBounds
|
||||
? null
|
||||
: Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
|
||||
apply("checkFromToIndex", List.of(fromIndex, toIndex, length)).getMessage();
|
||||
|
||||
BiConsumer<Class<? extends RuntimeException>, LongSupplier> check = (ec, s) -> {
|
||||
try {
|
||||
long rIndex = s.getAsLong();
|
||||
if (!withinBounds)
|
||||
fail(String.format(
|
||||
"Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length));
|
||||
assertEquals(rIndex, fromIndex);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertTrue(ec.isInstance(e));
|
||||
if (withinBounds)
|
||||
fail(String.format(
|
||||
"Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length));
|
||||
else
|
||||
assertEquals(e.getMessage(), expectedMessage);
|
||||
}
|
||||
};
|
||||
|
||||
check.accept(AssertingOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromToIndex(fromIndex, toIndex, length,
|
||||
assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length)));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromToIndex(fromIndex, toIndex, length,
|
||||
assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length)));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, null));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Objects.checkFromToIndex(fromIndex, toIndex, length));
|
||||
check.accept(ArrayIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromToIndex(fromIndex, toIndex, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
|
||||
check.accept(StringIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromToIndex(fromIndex, toIndex, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
|
||||
}
|
||||
|
||||
|
||||
@DataProvider
|
||||
static Object[][] checkFromIndexSizeProvider() {
|
||||
List<Object[]> l = new ArrayList<>();
|
||||
for (long fromIndex : VALUES) {
|
||||
for (long size : VALUES) {
|
||||
for (long length : VALUES) {
|
||||
long toIndex = fromIndex + size;
|
||||
|
||||
boolean withinBounds = fromIndex >= 0L &&
|
||||
size >= 0L &&
|
||||
length >= 0L &&
|
||||
fromIndex <= toIndex && // overflow
|
||||
toIndex <= length;
|
||||
l.add(new Object[]{fromIndex, size, length, withinBounds});
|
||||
}
|
||||
}
|
||||
}
|
||||
return l.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "checkFromIndexSizeProvider")
|
||||
public void testCheckFromIndexSize(long fromIndex, long size, long length, boolean withinBounds) {
|
||||
String expectedMessage = withinBounds
|
||||
? null
|
||||
: Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new).
|
||||
apply("checkFromIndexSize", List.of(fromIndex, size, length)).getMessage();
|
||||
|
||||
BiConsumer<Class<? extends RuntimeException>, LongSupplier> check = (ec, s) -> {
|
||||
try {
|
||||
long rIndex = s.getAsLong();
|
||||
if (!withinBounds)
|
||||
fail(String.format(
|
||||
"Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length));
|
||||
assertEquals(rIndex, fromIndex);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertTrue(ec.isInstance(e));
|
||||
if (withinBounds)
|
||||
fail(String.format(
|
||||
"Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length));
|
||||
else
|
||||
assertEquals(e.getMessage(), expectedMessage);
|
||||
}
|
||||
};
|
||||
|
||||
check.accept(AssertingOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromIndexSize(fromIndex, size, length,
|
||||
assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length)));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromIndexSize(fromIndex, size, length,
|
||||
assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length)));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromIndexSize(fromIndex, size, length, null));
|
||||
check.accept(IndexOutOfBoundsException.class,
|
||||
() -> Objects.checkFromIndexSize(fromIndex, size, length));
|
||||
check.accept(ArrayIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromIndexSize(fromIndex, size, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new)));
|
||||
check.accept(StringIndexOutOfBoundsException.class,
|
||||
() -> Preconditions.checkFromIndexSize(fromIndex, size, length,
|
||||
Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uniqueMessagesForCheckKinds() {
|
||||
BiFunction<String, List<Number>, IndexOutOfBoundsException> f =
|
||||
Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new);
|
||||
|
||||
List<String> messages = new ArrayList<>();
|
||||
// Exact arguments
|
||||
messages.add(f.apply("checkIndex", List.of(-1L, 0L)).getMessage());
|
||||
messages.add(f.apply("checkFromToIndex", List.of(-1L, 0L, 0L)).getMessage());
|
||||
messages.add(f.apply("checkFromIndexSize", List.of(-1L, 0L, 0L)).getMessage());
|
||||
// Unknown check kind
|
||||
messages.add(f.apply("checkUnknown", List.of(-1L, 0L, 0L)).getMessage());
|
||||
// Known check kind with more arguments
|
||||
messages.add(f.apply("checkIndex", List.of(-1L, 0L, 0L)).getMessage());
|
||||
messages.add(f.apply("checkFromToIndex", List.of(-1L, 0L, 0L, 0L)).getMessage());
|
||||
messages.add(f.apply("checkFromIndexSize", List.of(-1L, 0L, 0L, 0L)).getMessage());
|
||||
// Known check kind with fewer arguments
|
||||
messages.add(f.apply("checkIndex", List.of(-1L)).getMessage());
|
||||
messages.add(f.apply("checkFromToIndex", List.of(-1L, 0L)).getMessage());
|
||||
messages.add(f.apply("checkFromIndexSize", List.of(-1L, 0L)).getMessage());
|
||||
// Null arguments
|
||||
messages.add(f.apply(null, null).getMessage());
|
||||
messages.add(f.apply("checkNullArguments", null).getMessage());
|
||||
messages.add(f.apply(null, List.of(-1L)).getMessage());
|
||||
|
||||
assertEquals(messages.size(), messages.stream().distinct().count());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user