Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8265518: C1: Intrinsic support for Preconditions.checkIndex #3615

Closed
wants to merge 11 commits into from
@@ -207,7 +207,8 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
case vmIntrinsics::_putCharUnaligned:
case vmIntrinsics::_putIntUnaligned:
case vmIntrinsics::_putLongUnaligned:
case vmIntrinsics::_checkIndex:
case vmIntrinsics::_Preconditions_checkIndex:
case vmIntrinsics::_Preconditions_checkLongIndex:
case vmIntrinsics::_updateCRC32:
case vmIntrinsics::_updateBytesCRC32:
case vmIntrinsics::_updateByteBufferCRC32:
@@ -485,22 +485,6 @@ void LIRGenerator::array_range_check(LIR_Opr array, LIR_Opr index,
}
}


void LIRGenerator::nio_range_check(LIR_Opr buffer, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info) {
CodeStub* stub = new RangeCheckStub(info, index);
if (index->is_constant()) {
cmp_mem_int(lir_cond_belowEqual, buffer, java_nio_Buffer::limit_offset(), index->as_jint(), info);
__ branch(lir_cond_belowEqual, stub); // forward branch
} else {
cmp_reg_mem(lir_cond_aboveEqual, index, buffer,
java_nio_Buffer::limit_offset(), T_INT, info);
__ branch(lir_cond_aboveEqual, stub); // forward branch
}
__ move(index, result);
}



void LIRGenerator::arithmetic_op(Bytecodes::Code code, LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr tmp_op, CodeEmitInfo* info) {
LIR_Opr result_op = result;
LIR_Opr left_op = left;
@@ -1859,40 +1843,71 @@ void LIRGenerator::do_LoadField(LoadField* x) {
info ? new CodeEmitInfo(info) : NULL, info);
}

// int/long jdk.internal.util.Preconditions.checkIndex
void LIRGenerator::do_PreconditionsCheckIndex(Intrinsic* x, BasicType type) {
assert(x->number_of_arguments() == 3, "wrong type");
LIRItem index(x->argument_at(0), this);
LIRItem length(x->argument_at(1), this);
LIRItem oobef(x->argument_at(2), this);

//------------------------java.nio.Buffer.checkIndex------------------------

// int java.nio.Buffer.checkIndex(int)
void LIRGenerator::do_NIOCheckIndex(Intrinsic* x) {
// NOTE: by the time we are in checkIndex() we are guaranteed that
// the buffer is non-null (because checkIndex is package-private and
// only called from within other methods in the buffer).
assert(x->number_of_arguments() == 2, "wrong type");
LIRItem buf (x->argument_at(0), this);
LIRItem index(x->argument_at(1), this);
buf.load_item();
index.load_item();
length.load_item();
oobef.load_item();

LIR_Opr result = rlock_result(x);
if (GenerateRangeChecks) {
CodeEmitInfo* info = state_for(x);
CodeStub* stub = new RangeCheckStub(info, index.result());
if (index.result()->is_constant()) {
cmp_mem_int(lir_cond_belowEqual, buf.result(), java_nio_Buffer::limit_offset(), index.result()->as_jint(), info);
__ branch(lir_cond_belowEqual, stub);
} else {
cmp_reg_mem(lir_cond_aboveEqual, index.result(), buf.result(),
java_nio_Buffer::limit_offset(), T_INT, info);
__ branch(lir_cond_aboveEqual, stub);
// x->state() is created from copy_state_for_exception, it does not contains arguments
// we should prepare them before entering into interpreter mode due to deoptimization.
ValueStack* state = x->state();
for (int i = 0; i < x->number_of_arguments(); i++) {
Value arg = x->argument_at(i);
state->push(arg->type(), arg);
}
CodeEmitInfo* info = state_for(x, state);

LIR_Opr len = length.result();
LIR_Opr zero = NULL;
if (type == T_INT) {
zero = LIR_OprFact::intConst(0);
if (length.result()->is_constant()){
len = LIR_OprFact::intConst(length.result()->as_jint());
}
__ move(index.result(), result);
} else {
// Just load the index into the result register
__ move(index.result(), result);
assert(type == T_LONG, "sanity check");
zero = LIR_OprFact::longConst(0);
if (length.result()->is_constant()){
len = LIR_OprFact::longConst(length.result()->as_jlong());
}
}
// C1 can not handle the case that comparing index with constant value while condition
// is neither lir_cond_equal nor lir_cond_notEqual, see LIR_Assembler::comp_op.
LIR_Opr zero_reg = new_register(type);
__ move(zero, zero_reg);
#if defined(X86) && !defined(_LP64)
// BEWARE! On 32-bit x86 cmp clobbers its left argument so we need a temp copy.
LIR_Opr index_copy = new_register(index.type());
// index >= 0
__ move(index.result(), index_copy);
__ cmp(lir_cond_less, index_copy, zero_reg);
__ branch(lir_cond_less, new DeoptimizeStub(info, Deoptimization::Reason_range_check,
Deoptimization::Action_make_not_entrant));
// index < length
__ move(index.result(), index_copy);
__ cmp(lir_cond_greaterEqual, index_copy, len);
__ branch(lir_cond_greaterEqual, new DeoptimizeStub(info, Deoptimization::Reason_range_check,
Deoptimization::Action_make_not_entrant));
#else
// index >= 0
__ cmp(lir_cond_less, index.result(), zero_reg);
__ branch(lir_cond_less, new DeoptimizeStub(info, Deoptimization::Reason_range_check,
Deoptimization::Action_make_not_entrant));
// index < length
__ cmp(lir_cond_greaterEqual, index.result(), len);
__ branch(lir_cond_greaterEqual, new DeoptimizeStub(info, Deoptimization::Reason_range_check,
Deoptimization::Action_make_not_entrant));
#endif
__ move(index.result(), result);
}


//------------------------array access--------------------------------------


@@ -3115,8 +3130,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
case vmIntrinsics::_fmaD: do_FmaIntrinsic(x); break;
case vmIntrinsics::_fmaF: do_FmaIntrinsic(x); break;

// java.nio.Buffer.checkIndex
case vmIntrinsics::_checkIndex: do_NIOCheckIndex(x); break;
case vmIntrinsics::_Preconditions_checkIndex:
do_PreconditionsCheckIndex(x, T_INT);
break;
case vmIntrinsics::_Preconditions_checkLongIndex:
do_PreconditionsCheckIndex(x, T_LONG);
break;

case vmIntrinsics::_compareAndSetReference:
do_CompareAndSwap(x, objectType);
@@ -260,7 +260,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_LibmIntrinsic(Intrinsic* x);
void do_ArrayCopy(Intrinsic* x);
void do_CompareAndSwap(Intrinsic* x, ValueType* type);
void do_NIOCheckIndex(Intrinsic* x);
void do_PreconditionsCheckIndex(Intrinsic* x, BasicType type);
void do_FPIntrinsics(Intrinsic* x);
void do_Reference_get(Intrinsic* x);
void do_update_CRC32(Intrinsic* x);
@@ -348,8 +348,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {

// this loads the length and compares against the index
void array_range_check (LIR_Opr array, LIR_Opr index, CodeEmitInfo* null_check_info, CodeEmitInfo* range_check_info);
// For java.nio.Buffer.checkIndex
void nio_range_check (LIR_Opr buffer, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info);

void arithmetic_op_int (Bytecodes::Code code, LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr tmp);
void arithmetic_op_long (Bytecodes::Code code, LIR_Opr result, LIR_Opr left, LIR_Opr right, CodeEmitInfo* info = NULL);
@@ -153,9 +153,6 @@
product(bool, InlineSynchronizedMethods, true, \
"Inline synchronized methods") \
\
product(bool, InlineNIOCheckIndex, true, DIAGNOSTIC, \
"Intrinsify java.nio.Buffer.checkIndex") \
\
develop(bool, CanonicalizeNodes, true, \
"Canonicalize graph nodes") \
\
@@ -4653,26 +4653,6 @@ void java_lang_AssertionStatusDirectives::set_deflt(oop o, bool val) {
o->bool_field_put(_deflt_offset, val);
}


// Support for intrinsification of java.nio.Buffer.checkIndex

int java_nio_Buffer::_limit_offset;

#define BUFFER_FIELDS_DO(macro) \
macro(_limit_offset, k, "limit", int_signature, false)

void java_nio_Buffer::compute_offsets() {
InstanceKlass* k = vmClasses::nio_Buffer_klass();
assert(k != NULL, "must be loaded in 1.4+");
BUFFER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_nio_Buffer::serialize_offsets(SerializeClosure* f) {
BUFFER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
}
#endif

int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset;

#define AOS_FIELDS_DO(macro) \
@@ -66,7 +66,6 @@ class RecordComponent;
f(java_lang_reflect_Constructor) \
f(java_lang_reflect_Field) \
f(java_lang_reflect_RecordComponent) \
f(java_nio_Buffer) \
f(reflect_ConstantPool) \
f(reflect_UnsafeStaticFieldAccessorImpl) \
f(java_lang_reflect_Parameter) \
@@ -1587,16 +1586,6 @@ class java_lang_AssertionStatusDirectives: AllStatic {
};


class java_nio_Buffer: AllStatic {
private:
static int _limit_offset;

public:
static int limit_offset() { CHECK_INIT(_limit_offset); }
static void compute_offsets();
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
};

class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
private:
static int _owner_offset;
@@ -88,7 +88,8 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
case vmIntrinsics::_dlog10:
case vmIntrinsics::_dexp:
case vmIntrinsics::_dpow:
case vmIntrinsics::_checkIndex:
case vmIntrinsics::_Preconditions_checkIndex:
case vmIntrinsics::_Preconditions_checkLongIndex:
case vmIntrinsics::_Reference_get:
case vmIntrinsics::_updateCRC32:
case vmIntrinsics::_updateBytesCRC32:
@@ -467,11 +468,6 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_copyMemory:
if (!InlineArrayCopy || !InlineUnsafeOps) return true;
break;
#ifdef COMPILER1
case vmIntrinsics::_checkIndex:
if (!InlineNIOCheckIndex) return true;
break;
#endif // COMPILER1
#ifdef COMPILER2
case vmIntrinsics::_clone:
case vmIntrinsics::_copyOf:
@@ -341,10 +341,6 @@ class methodHandle;
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) \
do_name( checkIndex_name, "checkIndex") \
\
do_class(java_lang_StringCoding, "java/lang/StringCoding") \
do_intrinsic(_hasNegatives, java_lang_StringCoding, hasNegatives_name, hasNegatives_signature, F_S) \
do_name( hasNegatives_name, "hasNegatives") \
@@ -124,6 +124,7 @@
template(java_io_FileInputStream, "java/io/FileInputStream") \
template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \
template(java_io_Serializable, "java/io/Serializable") \
template(java_nio_Buffer, "java/nio/Buffer") \
template(java_util_Arrays, "java/util/Arrays") \
template(java_util_Objects, "java/util/Objects") \
template(java_util_Properties, "java/util/Properties") \
@@ -482,6 +483,7 @@
template(use_unaligned_access_name, "UNALIGNED_ACCESS") \
template(data_cache_line_flush_size_name, "DATA_CACHE_LINE_FLUSH_SIZE") \
template(during_unsafe_access_name, "during_unsafe_access") \
template(checkIndex_name, "checkIndex") \
\
/* name symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2021, 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
@@ -33,9 +33,9 @@
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM.BufferPool;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;

import java.io.FileDescriptor;
import java.util.Objects;
import java.util.Spliterator;

/**
@@ -736,11 +736,8 @@ final int nextPutIndex(int nb) { // package-private
* IndexOutOfBoundsException} if it is not smaller than the limit
* or is smaller than zero.
*/
@IntrinsicCandidate
final int checkIndex(int i) { // package-private
if ((i < 0) || (i >= limit))
throw new IndexOutOfBoundsException();
return i;
return Objects.checkIndex(i, limit);

This comment has been minimized.

Loading
@AlanBateman

AlanBateman Apr 26, 2021
Contributor

Changing Buffer.checkIndex to use Objects.checkIndex is okay.

}

final int checkIndex(int i, int nb) { // package-private
Loading