mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-06 14:10:36 +00:00
8152590: C2: @Stable support doesn't always work w/ incremental inlining
Reviewed-by: kvn
This commit is contained in:
parent
0c233de7ff
commit
7fc81004e3
@ -247,7 +247,7 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) {
|
||||
|
||||
} else if ((lf = x->array()->as_LoadField()) != NULL) {
|
||||
ciField* field = lf->field();
|
||||
if (field->is_constant() && field->is_static()) {
|
||||
if (field->is_static_constant()) {
|
||||
assert(PatchALot || ScavengeRootsInCode < 2, "Constant field loads are folded during parsing");
|
||||
ciObject* c = field->constant_value().as_object();
|
||||
if (!c->is_null_object()) {
|
||||
|
||||
@ -1520,6 +1520,8 @@ void GraphBuilder::method_return(Value x) {
|
||||
}
|
||||
|
||||
Value GraphBuilder::make_constant(ciConstant field_value, ciField* field) {
|
||||
if (!field_value.is_valid()) return NULL;
|
||||
|
||||
BasicType field_type = field_value.basic_type();
|
||||
ValueType* value = as_ValueType(field_value);
|
||||
|
||||
@ -1587,9 +1589,8 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
case Bytecodes::_getstatic: {
|
||||
// check for compile-time constants, i.e., initialized static final fields
|
||||
Value constant = NULL;
|
||||
if (field->is_constant() && !PatchALot) {
|
||||
if (field->is_static_constant() && !PatchALot) {
|
||||
ciConstant field_value = field->constant_value();
|
||||
// Stable static fields are checked for non-default values in ciField::initialize_from().
|
||||
assert(!field->is_stable() || !field_value.is_null_or_zero(),
|
||||
"stable static w/ default value shouldn't be a constant");
|
||||
constant = make_constant(field_value, field);
|
||||
@ -1618,31 +1619,18 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
Value constant = NULL;
|
||||
obj = apop();
|
||||
ObjectType* obj_type = obj->type()->as_ObjectType();
|
||||
if (obj_type->is_constant() && !PatchALot) {
|
||||
if (field->is_constant() && obj_type->is_constant() && !PatchALot) {
|
||||
ciObject* const_oop = obj_type->constant_value();
|
||||
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
|
||||
if (field->is_constant()) {
|
||||
ciConstant field_value = field->constant_value_of(const_oop);
|
||||
if (FoldStableValues && field->is_stable() && field_value.is_null_or_zero()) {
|
||||
// Stable field with default value can't be constant.
|
||||
constant = NULL;
|
||||
} else {
|
||||
constant = make_constant(field_value, field);
|
||||
}
|
||||
} else {
|
||||
// For CallSite objects treat the target field as a compile time constant.
|
||||
if (const_oop->is_call_site()) {
|
||||
ciConstant field_value = field->constant_value_of(const_oop);
|
||||
if (field_value.is_valid()) {
|
||||
constant = make_constant(field_value, field);
|
||||
// For CallSite objects add a dependency for invalidation of the optimization.
|
||||
if (field->is_call_site_target()) {
|
||||
ciCallSite* call_site = const_oop->as_call_site();
|
||||
if (field->is_call_site_target()) {
|
||||
ciMethodHandle* target = call_site->get_target();
|
||||
if (target != NULL) { // just in case
|
||||
ciConstant field_val(T_OBJECT, target);
|
||||
constant = new Constant(as_ValueType(field_val));
|
||||
// Add a dependence for invalidation of the optimization.
|
||||
if (!call_site->is_constant_call_site()) {
|
||||
dependency_recorder()->assert_call_site_target_value(call_site, target);
|
||||
}
|
||||
}
|
||||
if (!call_site->is_constant_call_site()) {
|
||||
ciMethodHandle* target = field_value.as_object()->as_method_handle();
|
||||
dependency_recorder()->assert_call_site_target_value(call_site, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +124,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return basic_type() != T_ILLEGAL;
|
||||
}
|
||||
// Debugging output
|
||||
void print();
|
||||
};
|
||||
|
||||
@ -235,96 +235,77 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||
_holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
|
||||
|
||||
// Check to see if the field is constant.
|
||||
bool is_final = this->is_final();
|
||||
bool is_stable = FoldStableValues && this->is_stable();
|
||||
if (_holder->is_initialized() && (is_final || is_stable)) {
|
||||
if (!this->is_static()) {
|
||||
// A field can be constant if it's a final static field or if
|
||||
// it's a final non-static field of a trusted class (classes in
|
||||
// java.lang.invoke and sun.invoke packages and subpackages).
|
||||
if (is_stable || trust_final_non_static_fields(_holder)) {
|
||||
_is_constant = true;
|
||||
return;
|
||||
}
|
||||
_is_constant = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// This field just may be constant. The only case where it will
|
||||
// not be constant is when the field is a *special* static&final field
|
||||
// whose value may change. The three examples are java.lang.System.in,
|
||||
// java.lang.System.out, and java.lang.System.err.
|
||||
|
||||
KlassHandle k = _holder->get_Klass();
|
||||
assert( SystemDictionary::System_klass() != NULL, "Check once per vm");
|
||||
if( k() == SystemDictionary::System_klass() ) {
|
||||
// Check offsets for case 2: System.in, System.out, or System.err
|
||||
if( _offset == java_lang_System::in_offset_in_bytes() ||
|
||||
_offset == java_lang_System::out_offset_in_bytes() ||
|
||||
_offset == java_lang_System::err_offset_in_bytes() ) {
|
||||
_is_constant = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Handle mirror = k->java_mirror();
|
||||
|
||||
switch(type()->basic_type()) {
|
||||
case T_BYTE:
|
||||
_constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
|
||||
break;
|
||||
case T_CHAR:
|
||||
_constant_value = ciConstant(type()->basic_type(), mirror->char_field(_offset));
|
||||
break;
|
||||
case T_SHORT:
|
||||
_constant_value = ciConstant(type()->basic_type(), mirror->short_field(_offset));
|
||||
break;
|
||||
case T_BOOLEAN:
|
||||
_constant_value = ciConstant(type()->basic_type(), mirror->bool_field(_offset));
|
||||
break;
|
||||
case T_INT:
|
||||
_constant_value = ciConstant(type()->basic_type(), mirror->int_field(_offset));
|
||||
break;
|
||||
case T_FLOAT:
|
||||
_constant_value = ciConstant(mirror->float_field(_offset));
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
_constant_value = ciConstant(mirror->double_field(_offset));
|
||||
break;
|
||||
case T_LONG:
|
||||
_constant_value = ciConstant(mirror->long_field(_offset));
|
||||
break;
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
{
|
||||
oop o = mirror->obj_field(_offset);
|
||||
|
||||
// A field will be "constant" if it is known always to be
|
||||
// a non-null reference to an instance of a particular class,
|
||||
// or to a particular array. This can happen even if the instance
|
||||
// or array is not perm. In such a case, an "unloaded" ciArray
|
||||
// or ciInstance is created. The compiler may be able to use
|
||||
// information about the object's class (which is exact) or length.
|
||||
|
||||
if (o == NULL) {
|
||||
_constant_value = ciConstant(type()->basic_type(), ciNullObject::make());
|
||||
} else {
|
||||
_constant_value = ciConstant(type()->basic_type(), CURRENT_ENV->get_object(o));
|
||||
assert(_constant_value.as_object() == CURRENT_ENV->get_object(o), "check interning");
|
||||
Klass* k = _holder->get_Klass();
|
||||
bool is_stable_field = FoldStableValues && is_stable();
|
||||
if (is_final() || is_stable_field) {
|
||||
if (is_static()) {
|
||||
// This field just may be constant. The only case where it will
|
||||
// not be constant is when the field is a *special* static & final field
|
||||
// whose value may change. The three examples are java.lang.System.in,
|
||||
// java.lang.System.out, and java.lang.System.err.
|
||||
assert(SystemDictionary::System_klass() != NULL, "Check once per vm");
|
||||
if (k == SystemDictionary::System_klass()) {
|
||||
// Check offsets for case 2: System.in, System.out, or System.err
|
||||
if( _offset == java_lang_System::in_offset_in_bytes() ||
|
||||
_offset == java_lang_System::out_offset_in_bytes() ||
|
||||
_offset == java_lang_System::err_offset_in_bytes() ) {
|
||||
_is_constant = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_stable && _constant_value.is_null_or_zero()) {
|
||||
// It is not a constant after all; treat it as uninitialized.
|
||||
_is_constant = false;
|
||||
} else {
|
||||
_is_constant = true;
|
||||
} else {
|
||||
// An instance field can be constant if it's a final static field or if
|
||||
// it's a final non-static field of a trusted class (classes in
|
||||
// java.lang.invoke and sun.invoke packages and subpackages).
|
||||
_is_constant = is_stable_field || trust_final_non_static_fields(_holder);
|
||||
}
|
||||
} else {
|
||||
_is_constant = false;
|
||||
// For CallSite objects treat the target field as a compile time constant.
|
||||
assert(SystemDictionary::CallSite_klass() != NULL, "should be already initialized");
|
||||
if (k == SystemDictionary::CallSite_klass() &&
|
||||
_offset == java_lang_invoke_CallSite::target_offset_in_bytes()) {
|
||||
_is_constant = true;
|
||||
} else {
|
||||
// Non-final & non-stable fields are not constants.
|
||||
_is_constant = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciField::constant_value
|
||||
// Get the constant value of a this static field.
|
||||
ciConstant ciField::constant_value() {
|
||||
assert(is_static() && is_constant(), "illegal call to constant_value()");
|
||||
if (!_holder->is_initialized()) {
|
||||
return ciConstant(); // Not initialized yet
|
||||
}
|
||||
if (_constant_value.basic_type() == T_ILLEGAL) {
|
||||
// Static fields are placed in mirror objects.
|
||||
VM_ENTRY_MARK;
|
||||
ciInstance* mirror = CURRENT_ENV->get_instance(_holder->get_Klass()->java_mirror());
|
||||
_constant_value = mirror->field_value_impl(type()->basic_type(), offset());
|
||||
}
|
||||
if (FoldStableValues && is_stable() && _constant_value.is_null_or_zero()) {
|
||||
return ciConstant();
|
||||
}
|
||||
return _constant_value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciField::constant_value_of
|
||||
// Get the constant value of non-static final field in the given object.
|
||||
ciConstant ciField::constant_value_of(ciObject* object) {
|
||||
assert(!is_static() && is_constant(), "only if field is non-static constant");
|
||||
assert(object->is_instance(), "must be instance");
|
||||
ciConstant field_value = object->as_instance()->field_value(this);
|
||||
if (FoldStableValues && is_stable() && field_value.is_null_or_zero()) {
|
||||
return ciConstant();
|
||||
}
|
||||
return field_value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciField::compute_type
|
||||
//
|
||||
|
||||
@ -62,7 +62,7 @@ private:
|
||||
void initialize_from(fieldDescriptor* fd);
|
||||
|
||||
public:
|
||||
ciFlags flags() { return _flags; }
|
||||
ciFlags flags() const { return _flags; }
|
||||
|
||||
// Of which klass is this field a member?
|
||||
//
|
||||
@ -89,13 +89,13 @@ public:
|
||||
//
|
||||
// In that case the declared holder of f would be B and
|
||||
// the canonical holder of f would be A.
|
||||
ciInstanceKlass* holder() { return _holder; }
|
||||
ciInstanceKlass* holder() const { return _holder; }
|
||||
|
||||
// Name of this field?
|
||||
ciSymbol* name() { return _name; }
|
||||
ciSymbol* name() const { return _name; }
|
||||
|
||||
// Signature of this field?
|
||||
ciSymbol* signature() { return _signature; }
|
||||
ciSymbol* signature() const { return _signature; }
|
||||
|
||||
// Of what type is this field?
|
||||
ciType* type() { return (_type == NULL) ? compute_type() : _type; }
|
||||
@ -107,13 +107,13 @@ public:
|
||||
int size_in_bytes() { return type2aelembytes(layout_type()); }
|
||||
|
||||
// What is the offset of this field?
|
||||
int offset() {
|
||||
int offset() const {
|
||||
assert(_offset >= 1, "illegal call to offset()");
|
||||
return _offset;
|
||||
}
|
||||
|
||||
// Same question, explicit units. (Fields are aligned to the byte level.)
|
||||
int offset_in_bytes() {
|
||||
int offset_in_bytes() const {
|
||||
return offset();
|
||||
}
|
||||
|
||||
@ -127,31 +127,27 @@ public:
|
||||
//
|
||||
// Clarification: A field is considered constant if:
|
||||
// 1. The field is both static and final
|
||||
// 2. The canonical holder of the field has undergone
|
||||
// static initialization.
|
||||
// 3. The field is not one of the special static/final
|
||||
// 2. The field is not one of the special static/final
|
||||
// non-constant fields. These are java.lang.System.in
|
||||
// and java.lang.System.out. Abomination.
|
||||
//
|
||||
// A field is also considered constant if it is marked @Stable
|
||||
// and is non-null (or non-zero, if a primitive).
|
||||
// For non-static fields, the null/zero check must be
|
||||
// arranged by the user, as constant_value().is_null_or_zero().
|
||||
bool is_constant() { return _is_constant; }
|
||||
//
|
||||
// A user should also check the field value (constant_value().is_valid()), since
|
||||
// constant fields of non-initialized classes don't have values yet.
|
||||
bool is_constant() const { return _is_constant; }
|
||||
|
||||
// Get the constant value of this field.
|
||||
ciConstant constant_value() {
|
||||
assert(is_static() && is_constant(), "illegal call to constant_value()");
|
||||
return _constant_value;
|
||||
// Get the constant value of the static field.
|
||||
ciConstant constant_value();
|
||||
|
||||
bool is_static_constant() {
|
||||
return is_static() && is_constant() && constant_value().is_valid();
|
||||
}
|
||||
|
||||
// Get the constant value of non-static final field in the given
|
||||
// object.
|
||||
ciConstant constant_value_of(ciObject* object) {
|
||||
assert(!is_static() && is_constant(), "only if field is non-static constant");
|
||||
assert(object->is_instance(), "must be instance");
|
||||
return object->as_instance()->field_value(this);
|
||||
}
|
||||
ciConstant constant_value_of(ciObject* object);
|
||||
|
||||
// Check for link time errors. Accessing a field from a
|
||||
// certain class via a certain bytecode may or may not be legal.
|
||||
@ -165,14 +161,14 @@ public:
|
||||
Bytecodes::Code bc);
|
||||
|
||||
// Java access flags
|
||||
bool is_public () { return flags().is_public(); }
|
||||
bool is_private () { return flags().is_private(); }
|
||||
bool is_protected () { return flags().is_protected(); }
|
||||
bool is_static () { return flags().is_static(); }
|
||||
bool is_final () { return flags().is_final(); }
|
||||
bool is_stable () { return flags().is_stable(); }
|
||||
bool is_volatile () { return flags().is_volatile(); }
|
||||
bool is_transient () { return flags().is_transient(); }
|
||||
bool is_public () const { return flags().is_public(); }
|
||||
bool is_private () const { return flags().is_private(); }
|
||||
bool is_protected () const { return flags().is_protected(); }
|
||||
bool is_static () const { return flags().is_static(); }
|
||||
bool is_final () const { return flags().is_final(); }
|
||||
bool is_stable () const { return flags().is_stable(); }
|
||||
bool is_volatile () const { return flags().is_volatile(); }
|
||||
bool is_transient () const { return flags().is_transient(); }
|
||||
|
||||
bool is_call_site_target() {
|
||||
ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
|
||||
|
||||
@ -56,49 +56,21 @@ ciType* ciInstance::java_mirror_type() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstance::field_value
|
||||
//
|
||||
// Constant value of a field.
|
||||
ciConstant ciInstance::field_value(ciField* field) {
|
||||
assert(is_loaded(), "invalid access - must be loaded");
|
||||
assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
|
||||
assert(klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
|
||||
|
||||
VM_ENTRY_MARK;
|
||||
ciConstant result;
|
||||
// ciInstance::field_value_impl
|
||||
ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) {
|
||||
Handle obj = get_oop();
|
||||
assert(!obj.is_null(), "bad oop");
|
||||
BasicType field_btype = field->type()->basic_type();
|
||||
int offset = field->offset();
|
||||
|
||||
switch(field_btype) {
|
||||
case T_BYTE:
|
||||
return ciConstant(field_btype, obj->byte_field(offset));
|
||||
break;
|
||||
case T_CHAR:
|
||||
return ciConstant(field_btype, obj->char_field(offset));
|
||||
break;
|
||||
case T_SHORT:
|
||||
return ciConstant(field_btype, obj->short_field(offset));
|
||||
break;
|
||||
case T_BOOLEAN:
|
||||
return ciConstant(field_btype, obj->bool_field(offset));
|
||||
break;
|
||||
case T_INT:
|
||||
return ciConstant(field_btype, obj->int_field(offset));
|
||||
break;
|
||||
case T_FLOAT:
|
||||
return ciConstant(obj->float_field(offset));
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
return ciConstant(obj->double_field(offset));
|
||||
break;
|
||||
case T_LONG:
|
||||
return ciConstant(obj->long_field(offset));
|
||||
break;
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
{
|
||||
case T_BYTE: return ciConstant(field_btype, obj->byte_field(offset));
|
||||
case T_CHAR: return ciConstant(field_btype, obj->char_field(offset));
|
||||
case T_SHORT: return ciConstant(field_btype, obj->short_field(offset));
|
||||
case T_BOOLEAN: return ciConstant(field_btype, obj->bool_field(offset));
|
||||
case T_INT: return ciConstant(field_btype, obj->int_field(offset));
|
||||
case T_FLOAT: return ciConstant(obj->float_field(offset));
|
||||
case T_DOUBLE: return ciConstant(obj->double_field(offset));
|
||||
case T_LONG: return ciConstant(obj->long_field(offset));
|
||||
case T_OBJECT: // fall through
|
||||
case T_ARRAY: {
|
||||
oop o = obj->obj_field(offset);
|
||||
|
||||
// A field will be "constant" if it is known always to be
|
||||
@ -115,11 +87,22 @@ ciConstant ciInstance::field_value(ciField* field) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
// to shut up the compiler
|
||||
fatal("no field value: %s", type2name(field_btype));
|
||||
return ciConstant();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstance::field_value
|
||||
//
|
||||
// Constant value of a field.
|
||||
ciConstant ciInstance::field_value(ciField* field) {
|
||||
assert(is_loaded(), "invalid access - must be loaded");
|
||||
assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
|
||||
assert(field->is_static() || klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
|
||||
|
||||
GUARDED_VM_ENTRY(return field_value_impl(field->type()->basic_type(), field->offset());)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstance::field_value_by_offset
|
||||
//
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
// instance of java.lang.Object.
|
||||
class ciInstance : public ciObject {
|
||||
CI_PACKAGE_ACCESS
|
||||
friend class ciField;
|
||||
|
||||
protected:
|
||||
ciInstance(instanceHandle h_i) : ciObject(h_i) {
|
||||
@ -50,6 +51,8 @@ protected:
|
||||
|
||||
void print_impl(outputStream* st);
|
||||
|
||||
ciConstant field_value_impl(BasicType field_btype, int offset);
|
||||
|
||||
public:
|
||||
// If this object is a java mirror, return the corresponding type.
|
||||
// Otherwise, return NULL.
|
||||
|
||||
@ -88,12 +88,7 @@ bool ciKlass::is_subclass_of(ciKlass* that) {
|
||||
assert(this->is_loaded(), "must be loaded: %s", this->name()->as_quoted_ascii());
|
||||
assert(that->is_loaded(), "must be loaded: %s", that->name()->as_quoted_ascii());
|
||||
|
||||
VM_ENTRY_MARK;
|
||||
Klass* this_klass = get_Klass();
|
||||
Klass* that_klass = that->get_Klass();
|
||||
bool result = this_klass->is_subclass_of(that_klass);
|
||||
|
||||
return result;
|
||||
GUARDED_VM_ENTRY(return get_Klass()->is_subclass_of(that->get_Klass());)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@ -58,9 +58,7 @@ ciSymbol::ciSymbol(Symbol* s)
|
||||
//
|
||||
// The text of the symbol as a null-terminated C string.
|
||||
const char* ciSymbol::as_utf8() {
|
||||
VM_QUICK_ENTRY_MARK;
|
||||
Symbol* s = get_symbol();
|
||||
return s->as_utf8();
|
||||
GUARDED_VM_QUICK_ENTRY(return get_symbol()->as_utf8();)
|
||||
}
|
||||
|
||||
// The text of the symbol as a null-terminated C string.
|
||||
|
||||
@ -4466,6 +4466,25 @@ void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* coun
|
||||
set_memory(st, TypeAryPtr::BYTES);
|
||||
}
|
||||
|
||||
Node* GraphKit::make_constant_from_field(ciField* field, Node* obj) {
|
||||
if (!field->is_constant()) {
|
||||
return NULL; // Field not marked as constant.
|
||||
}
|
||||
ciInstance* holder = NULL;
|
||||
if (!field->is_static()) {
|
||||
ciObject* const_oop = obj->bottom_type()->is_oopptr()->const_oop();
|
||||
if (const_oop != NULL && const_oop->is_instance()) {
|
||||
holder = const_oop->as_instance();
|
||||
}
|
||||
}
|
||||
const Type* con_type = Type::make_constant_from_field(field, holder, field->layout_type(),
|
||||
/*is_unsigned_load=*/false);
|
||||
if (con_type != NULL) {
|
||||
return makecon(con_type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
|
||||
// Reify the property as a CastPP node in Ideal graph to comply with monotonicity
|
||||
// assumption of CCP analysis.
|
||||
|
||||
@ -910,6 +910,8 @@ class GraphKit : public Phase {
|
||||
void add_predicate(int nargs = 0);
|
||||
void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs);
|
||||
|
||||
Node* make_constant_from_field(ciField* field, Node* obj);
|
||||
|
||||
// Produce new array node of stable type
|
||||
Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type);
|
||||
};
|
||||
|
||||
@ -2550,13 +2550,9 @@ bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_stor
|
||||
Node* p = NULL;
|
||||
// Try to constant fold a load from a constant field
|
||||
ciField* field = alias_type->field();
|
||||
if (heap_base_oop != top() &&
|
||||
field != NULL && field->is_constant() && !mismatched) {
|
||||
if (heap_base_oop != top() && field != NULL && field->is_constant() && !mismatched) {
|
||||
// final or stable field
|
||||
const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop);
|
||||
if (con_type != NULL) {
|
||||
p = makecon(con_type);
|
||||
}
|
||||
p = make_constant_from_field(field, heap_base_oop);
|
||||
}
|
||||
if (p == NULL) {
|
||||
// To be valid, unsafe loads may depend on other conditions than
|
||||
|
||||
@ -860,7 +860,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
|
||||
if (basic_elem_type == T_OBJECT || basic_elem_type == T_ARRAY) {
|
||||
if (!elem_type->is_loaded()) {
|
||||
field_type = TypeInstPtr::BOTTOM;
|
||||
} else if (field != NULL && field->is_constant() && field->is_static()) {
|
||||
} else if (field != NULL && field->is_static_constant()) {
|
||||
// This can happen if the constant oop is non-perm.
|
||||
ciObject* con = field->constant_value().as_object();
|
||||
// Do not "join" in the previous type; it doesn't add value,
|
||||
|
||||
@ -796,7 +796,7 @@ Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypeP
|
||||
#endif
|
||||
{
|
||||
assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop");
|
||||
load = new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency);
|
||||
load = new LoadPNode(ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1620,72 +1620,6 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ciConstant check_mismatched_access(ciConstant con, BasicType loadbt, bool is_unsigned) {
|
||||
BasicType conbt = con.basic_type();
|
||||
switch (conbt) {
|
||||
case T_BOOLEAN: conbt = T_BYTE; break;
|
||||
case T_ARRAY: conbt = T_OBJECT; break;
|
||||
}
|
||||
switch (loadbt) {
|
||||
case T_BOOLEAN: loadbt = T_BYTE; break;
|
||||
case T_NARROWOOP: loadbt = T_OBJECT; break;
|
||||
case T_ARRAY: loadbt = T_OBJECT; break;
|
||||
case T_ADDRESS: loadbt = T_OBJECT; break;
|
||||
}
|
||||
if (conbt == loadbt) {
|
||||
if (is_unsigned && conbt == T_BYTE) {
|
||||
// LoadB (T_BYTE) with a small mask (<=8-bit) is converted to LoadUB (T_BYTE).
|
||||
return ciConstant(T_INT, con.as_int() & 0xFF);
|
||||
} else {
|
||||
return con;
|
||||
}
|
||||
}
|
||||
if (conbt == T_SHORT && loadbt == T_CHAR) {
|
||||
// LoadS (T_SHORT) with a small mask (<=16-bit) is converted to LoadUS (T_CHAR).
|
||||
return ciConstant(T_INT, con.as_int() & 0xFFFF);
|
||||
}
|
||||
return ciConstant(); // T_ILLEGAL
|
||||
}
|
||||
|
||||
// Try to constant-fold a stable array element.
|
||||
static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, bool is_unsigned_load, BasicType loadbt) {
|
||||
assert(ary->const_oop(), "array should be constant");
|
||||
assert(ary->is_stable(), "array should be stable");
|
||||
|
||||
// Decode the results of GraphKit::array_element_address.
|
||||
ciArray* aobj = ary->const_oop()->as_array();
|
||||
ciConstant element_value = aobj->element_value_by_offset(off);
|
||||
if (element_value.basic_type() == T_ILLEGAL) {
|
||||
return NULL; // wrong offset
|
||||
}
|
||||
ciConstant con = check_mismatched_access(element_value, loadbt, is_unsigned_load);
|
||||
assert(con.basic_type() != T_ILLEGAL, "elembt=%s; loadbt=%s; unsigned=%d",
|
||||
type2name(element_value.basic_type()), type2name(loadbt), is_unsigned_load);
|
||||
|
||||
if (con.basic_type() != T_ILLEGAL && // not a mismatched access
|
||||
!con.is_null_or_zero()) { // not a default value
|
||||
const Type* con_type = Type::make_from_constant(con);
|
||||
if (con_type != NULL) {
|
||||
if (con_type->isa_aryptr()) {
|
||||
// Join with the array element type, in case it is also stable.
|
||||
int dim = ary->stable_dimension();
|
||||
con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
|
||||
}
|
||||
if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
|
||||
con_type = con_type->make_narrowoop();
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (TraceIterativeGVN) {
|
||||
tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
|
||||
con_type->dump(); tty->cr();
|
||||
}
|
||||
#endif //PRODUCT
|
||||
return con_type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------Value-----------------------------------------
|
||||
const Type* LoadNode::Value(PhaseGVN* phase) const {
|
||||
// Either input is TOP ==> the result is TOP
|
||||
@ -1714,10 +1648,14 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
|
||||
const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
|
||||
|
||||
// Try to constant-fold a stable array element.
|
||||
if (FoldStableValues && !is_mismatched_access() && ary->is_stable() && ary->const_oop() != NULL) {
|
||||
if (FoldStableValues && !is_mismatched_access() && ary->is_stable()) {
|
||||
// Make sure the reference is not into the header and the offset is constant
|
||||
if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) {
|
||||
const Type* con_type = fold_stable_ary_elem(ary, off, is_unsigned(), memory_type());
|
||||
ciObject* aobj = ary->const_oop();
|
||||
if (aobj != NULL && off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) {
|
||||
int stable_dimension = (ary->stable_dimension() > 0 ? ary->stable_dimension() - 1 : 0);
|
||||
const Type* con_type = Type::make_constant_from_array_element(aobj->as_array(), off,
|
||||
stable_dimension,
|
||||
memory_type(), is_unsigned());
|
||||
if (con_type != NULL) {
|
||||
return con_type;
|
||||
}
|
||||
@ -1784,28 +1722,10 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
|
||||
// For oop loads, we expect the _type to be precise.
|
||||
// Optimizations for constant objects
|
||||
ciObject* const_oop = tinst->const_oop();
|
||||
if (const_oop != NULL) {
|
||||
// For constant CallSites treat the target field as a compile time constant.
|
||||
if (const_oop->is_call_site()) {
|
||||
ciCallSite* call_site = const_oop->as_call_site();
|
||||
ciField* field = call_site->klass()->as_instance_klass()->get_field_by_offset(off, /*is_static=*/ false);
|
||||
if (field != NULL && field->is_call_site_target()) {
|
||||
ciMethodHandle* target = call_site->get_target();
|
||||
if (target != NULL) { // just in case
|
||||
ciConstant constant(T_OBJECT, target);
|
||||
const Type* t;
|
||||
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
|
||||
t = TypeNarrowOop::make_from_constant(constant.as_object(), true);
|
||||
} else {
|
||||
t = TypeOopPtr::make_from_constant(constant.as_object(), true);
|
||||
}
|
||||
// Add a dependence for invalidation of the optimization.
|
||||
if (!call_site->is_constant_call_site()) {
|
||||
C->dependencies()->assert_call_site_target_value(call_site, target);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (const_oop != NULL && const_oop->is_instance()) {
|
||||
const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), memory_type());
|
||||
if (con_type != NULL) {
|
||||
return con_type;
|
||||
}
|
||||
}
|
||||
} else if (tp->base() == Type::KlassPtr) {
|
||||
|
||||
@ -149,9 +149,9 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
|
||||
// Does this field have a constant value? If so, just push the value.
|
||||
if (field->is_constant()) {
|
||||
// final or stable field
|
||||
const Type* con_type = Type::make_constant(field, obj);
|
||||
if (con_type != NULL) {
|
||||
push_node(con_type->basic_type(), makecon(con_type));
|
||||
Node* con = make_constant_from_field(field, obj);
|
||||
if (con != NULL) {
|
||||
push_node(field->layout_type(), con);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -174,12 +174,16 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
|
||||
if (!field->type()->is_loaded()) {
|
||||
type = TypeInstPtr::BOTTOM;
|
||||
must_assert_null = true;
|
||||
} else if (field->is_constant() && field->is_static()) {
|
||||
} else if (field->is_static_constant()) {
|
||||
// This can happen if the constant oop is non-perm.
|
||||
ciObject* con = field->constant_value().as_object();
|
||||
// Do not "join" in the previous type; it doesn't add value,
|
||||
// and may yield a vacuous result if the field is of interface type.
|
||||
type = TypeOopPtr::make_from_constant(con)->isa_oopptr();
|
||||
if (con->is_null_object()) {
|
||||
type = TypePtr::NULL_PTR;
|
||||
} else {
|
||||
type = TypeOopPtr::make_from_constant(con)->isa_oopptr();
|
||||
}
|
||||
assert(type != NULL, "field singleton type must be consistent");
|
||||
} else {
|
||||
type = TypeOopPtr::make_from_klass(field_klass->as_klass());
|
||||
|
||||
@ -1112,7 +1112,7 @@ Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) {
|
||||
if( bt == T_OBJECT ) {
|
||||
if (!field->type()->is_loaded()) {
|
||||
type = TypeInstPtr::BOTTOM;
|
||||
} else if (field->is_constant()) {
|
||||
} else if (field->is_static_constant()) {
|
||||
// This can happen if the constant oop is non-perm.
|
||||
ciObject* con = field->constant_value().as_object();
|
||||
// Do not "join" in the previous type; it doesn't add value,
|
||||
|
||||
@ -225,74 +225,156 @@ const Type* Type::get_typeflow_type(ciType* type) {
|
||||
|
||||
|
||||
//-----------------------make_from_constant------------------------------------
|
||||
const Type* Type::make_from_constant(ciConstant constant, bool require_constant) {
|
||||
const Type* Type::make_from_constant(ciConstant constant, bool require_constant,
|
||||
int stable_dimension, bool is_narrow_oop,
|
||||
bool is_autobox_cache) {
|
||||
switch (constant.basic_type()) {
|
||||
case T_BOOLEAN: return TypeInt::make(constant.as_boolean());
|
||||
case T_CHAR: return TypeInt::make(constant.as_char());
|
||||
case T_BYTE: return TypeInt::make(constant.as_byte());
|
||||
case T_SHORT: return TypeInt::make(constant.as_short());
|
||||
case T_INT: return TypeInt::make(constant.as_int());
|
||||
case T_LONG: return TypeLong::make(constant.as_long());
|
||||
case T_FLOAT: return TypeF::make(constant.as_float());
|
||||
case T_DOUBLE: return TypeD::make(constant.as_double());
|
||||
case T_ARRAY:
|
||||
case T_OBJECT:
|
||||
{
|
||||
// cases:
|
||||
// can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
|
||||
// should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
|
||||
// An oop is not scavengable if it is in the perm gen.
|
||||
ciObject* oop_constant = constant.as_object();
|
||||
if (oop_constant->is_null_object()) {
|
||||
return Type::get_zero_type(T_OBJECT);
|
||||
} else if (require_constant || oop_constant->should_be_constant()) {
|
||||
return TypeOopPtr::make_from_constant(oop_constant, require_constant);
|
||||
case T_BOOLEAN: return TypeInt::make(constant.as_boolean());
|
||||
case T_CHAR: return TypeInt::make(constant.as_char());
|
||||
case T_BYTE: return TypeInt::make(constant.as_byte());
|
||||
case T_SHORT: return TypeInt::make(constant.as_short());
|
||||
case T_INT: return TypeInt::make(constant.as_int());
|
||||
case T_LONG: return TypeLong::make(constant.as_long());
|
||||
case T_FLOAT: return TypeF::make(constant.as_float());
|
||||
case T_DOUBLE: return TypeD::make(constant.as_double());
|
||||
case T_ARRAY:
|
||||
case T_OBJECT: {
|
||||
// cases:
|
||||
// can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
|
||||
// should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
|
||||
// An oop is not scavengable if it is in the perm gen.
|
||||
const Type* con_type = NULL;
|
||||
ciObject* oop_constant = constant.as_object();
|
||||
if (oop_constant->is_null_object()) {
|
||||
con_type = Type::get_zero_type(T_OBJECT);
|
||||
} else if (require_constant || oop_constant->should_be_constant()) {
|
||||
con_type = TypeOopPtr::make_from_constant(oop_constant, require_constant);
|
||||
if (con_type != NULL) {
|
||||
if (Compile::current()->eliminate_boxing() && is_autobox_cache) {
|
||||
con_type = con_type->is_aryptr()->cast_to_autobox_cache(true);
|
||||
}
|
||||
if (stable_dimension > 0) {
|
||||
assert(FoldStableValues, "sanity");
|
||||
assert(!con_type->is_zero_type(), "default value for stable field");
|
||||
con_type = con_type->is_aryptr()->cast_to_stable(true, stable_dimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_narrow_oop) {
|
||||
con_type = con_type->make_narrowoop();
|
||||
}
|
||||
return con_type;
|
||||
}
|
||||
}
|
||||
case T_ILLEGAL:
|
||||
// Invalid ciConstant returned due to OutOfMemoryError in the CI
|
||||
assert(Compile::current()->env()->failing(), "otherwise should not see this");
|
||||
return NULL;
|
||||
case T_ILLEGAL:
|
||||
// Invalid ciConstant returned due to OutOfMemoryError in the CI
|
||||
assert(Compile::current()->env()->failing(), "otherwise should not see this");
|
||||
return NULL;
|
||||
}
|
||||
// Fall through to failure
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ciConstant check_mismatched_access(ciConstant con, BasicType loadbt, bool is_unsigned) {
|
||||
BasicType conbt = con.basic_type();
|
||||
switch (conbt) {
|
||||
case T_BOOLEAN: conbt = T_BYTE; break;
|
||||
case T_ARRAY: conbt = T_OBJECT; break;
|
||||
}
|
||||
switch (loadbt) {
|
||||
case T_BOOLEAN: loadbt = T_BYTE; break;
|
||||
case T_NARROWOOP: loadbt = T_OBJECT; break;
|
||||
case T_ARRAY: loadbt = T_OBJECT; break;
|
||||
case T_ADDRESS: loadbt = T_OBJECT; break;
|
||||
}
|
||||
if (conbt == loadbt) {
|
||||
if (is_unsigned && conbt == T_BYTE) {
|
||||
// LoadB (T_BYTE) with a small mask (<=8-bit) is converted to LoadUB (T_BYTE).
|
||||
return ciConstant(T_INT, con.as_int() & 0xFF);
|
||||
} else {
|
||||
return con;
|
||||
}
|
||||
}
|
||||
if (conbt == T_SHORT && loadbt == T_CHAR) {
|
||||
// LoadS (T_SHORT) with a small mask (<=16-bit) is converted to LoadUS (T_CHAR).
|
||||
return ciConstant(T_INT, con.as_int() & 0xFFFF);
|
||||
}
|
||||
return ciConstant(); // T_ILLEGAL
|
||||
}
|
||||
|
||||
const Type* Type::make_constant(ciField* field, Node* obj) {
|
||||
if (!field->is_constant()) return NULL;
|
||||
// Try to constant-fold a stable array element.
|
||||
const Type* Type::make_constant_from_array_element(ciArray* array, int off, int stable_dimension,
|
||||
BasicType loadbt, bool is_unsigned_load) {
|
||||
// Decode the results of GraphKit::array_element_address.
|
||||
ciConstant element_value = array->element_value_by_offset(off);
|
||||
if (element_value.basic_type() == T_ILLEGAL) {
|
||||
return NULL; // wrong offset
|
||||
}
|
||||
ciConstant con = check_mismatched_access(element_value, loadbt, is_unsigned_load);
|
||||
|
||||
const Type* con_type = NULL;
|
||||
assert(con.basic_type() != T_ILLEGAL, "elembt=%s; loadbt=%s; unsigned=%d",
|
||||
type2name(element_value.basic_type()), type2name(loadbt), is_unsigned_load);
|
||||
|
||||
if (con.is_valid() && // not a mismatched access
|
||||
!con.is_null_or_zero()) { // not a default value
|
||||
bool is_narrow_oop = (loadbt == T_NARROWOOP);
|
||||
return Type::make_from_constant(con, /*require_constant=*/true, stable_dimension, is_narrow_oop, /*is_autobox_cache=*/false);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Type* Type::make_constant_from_field(ciInstance* holder, int off, bool is_unsigned_load, BasicType loadbt) {
|
||||
ciField* field;
|
||||
ciType* type = holder->java_mirror_type();
|
||||
if (type != NULL && type->is_instance_klass() && off >= InstanceMirrorKlass::offset_of_static_fields()) {
|
||||
// Static field
|
||||
field = type->as_instance_klass()->get_field_by_offset(off, /*is_static=*/true);
|
||||
} else {
|
||||
// Instance field
|
||||
field = holder->klass()->as_instance_klass()->get_field_by_offset(off, /*is_static=*/false);
|
||||
}
|
||||
if (field == NULL) {
|
||||
return NULL; // Wrong offset
|
||||
}
|
||||
return Type::make_constant_from_field(field, holder, loadbt, is_unsigned_load);
|
||||
}
|
||||
|
||||
const Type* Type::make_constant_from_field(ciField* field, ciInstance* holder,
|
||||
BasicType loadbt, bool is_unsigned_load) {
|
||||
if (!field->is_constant()) {
|
||||
return NULL; // Non-constant field
|
||||
}
|
||||
ciConstant field_value;
|
||||
if (field->is_static()) {
|
||||
// final static field
|
||||
con_type = Type::make_from_constant(field->constant_value(), /*require_const=*/true);
|
||||
if (Compile::current()->eliminate_boxing() && field->is_autobox_cache() && con_type != NULL) {
|
||||
con_type = con_type->is_aryptr()->cast_to_autobox_cache(true);
|
||||
}
|
||||
} else {
|
||||
field_value = field->constant_value();
|
||||
} else if (holder != NULL) {
|
||||
// final or stable non-static field
|
||||
// Treat final non-static fields of trusted classes (classes in
|
||||
// java.lang.invoke and sun.invoke packages and subpackages) as
|
||||
// compile time constants.
|
||||
if (obj->is_Con()) {
|
||||
const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
|
||||
ciObject* constant_oop = oop_ptr->const_oop();
|
||||
ciConstant constant = field->constant_value_of(constant_oop);
|
||||
con_type = Type::make_from_constant(constant, /*require_const=*/true);
|
||||
}
|
||||
field_value = field->constant_value_of(holder);
|
||||
}
|
||||
if (FoldStableValues && field->is_stable() && con_type != NULL) {
|
||||
if (con_type->is_zero_type()) {
|
||||
return NULL; // the field hasn't been initialized yet
|
||||
} else if (con_type->isa_oopptr()) {
|
||||
const Type* stable_type = Type::get_const_type(field->type());
|
||||
if (field->type()->is_array_klass()) {
|
||||
int stable_dimension = field->type()->as_array_klass()->dimension();
|
||||
stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
|
||||
}
|
||||
if (stable_type != NULL) {
|
||||
con_type = con_type->join_speculative(stable_type);
|
||||
}
|
||||
if (!field_value.is_valid()) {
|
||||
return NULL; // Not a constant
|
||||
}
|
||||
|
||||
ciConstant con = check_mismatched_access(field_value, loadbt, is_unsigned_load);
|
||||
|
||||
assert(con.is_valid(), "elembt=%s; loadbt=%s; unsigned=%d",
|
||||
type2name(field_value.basic_type()), type2name(loadbt), is_unsigned_load);
|
||||
|
||||
bool is_stable_array = FoldStableValues && field->is_stable() && field->type()->is_array_klass();
|
||||
int stable_dimension = (is_stable_array ? field->type()->as_array_klass()->dimension() : 0);
|
||||
bool is_narrow_oop = (loadbt == T_NARROWOOP);
|
||||
|
||||
const Type* con_type = make_from_constant(con, /*require_constant=*/ true,
|
||||
stable_dimension, is_narrow_oop,
|
||||
field->is_autobox_cache());
|
||||
if (con_type != NULL && field->is_call_site_target()) {
|
||||
ciCallSite* call_site = holder->as_call_site();
|
||||
if (!call_site->is_constant_call_site()) {
|
||||
ciMethodHandle* target = call_site->get_target();
|
||||
Compile::current()->dependencies()->assert_call_site_target_value(call_site, target);
|
||||
}
|
||||
}
|
||||
return con_type;
|
||||
|
||||
@ -417,9 +417,26 @@ public:
|
||||
static const Type* get_typeflow_type(ciType* type);
|
||||
|
||||
static const Type* make_from_constant(ciConstant constant,
|
||||
bool require_constant = false);
|
||||
bool require_constant = false,
|
||||
int stable_dimension = 0,
|
||||
bool is_narrow = false,
|
||||
bool is_autobox_cache = false);
|
||||
|
||||
static const Type* make_constant(ciField* field, Node* obj);
|
||||
static const Type* make_constant_from_field(ciInstance* holder,
|
||||
int off,
|
||||
bool is_unsigned_load,
|
||||
BasicType loadbt);
|
||||
|
||||
static const Type* make_constant_from_field(ciField* field,
|
||||
ciInstance* holder,
|
||||
BasicType loadbt,
|
||||
bool is_unsigned_load);
|
||||
|
||||
static const Type* make_constant_from_array_element(ciArray* array,
|
||||
int off,
|
||||
int stable_dimension,
|
||||
BasicType loadbt,
|
||||
bool is_unsigned_load);
|
||||
|
||||
// Speculative type helper methods. See TypePtr.
|
||||
virtual const TypePtr* speculative() const { return NULL; }
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.base/jdk.internal.vm.annotation
|
||||
* java.base/jdk.internal.misc
|
||||
*
|
||||
* @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
|
||||
* -Xbatch -XX:-TieredCompilation
|
||||
* -XX:+FoldStableValues
|
||||
@ -63,7 +64,6 @@ import jdk.test.lib.Platform;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@ -26,24 +26,28 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary tests on constant folding of unsafe get operations from stable arrays
|
||||
* @library /testlibrary /test/lib
|
||||
* @ignore 8151137
|
||||
* @library /testlibrary
|
||||
*
|
||||
* @requires vm.flavor != "client"
|
||||
*
|
||||
* @modules java.base/jdk.internal.vm.annotation
|
||||
* java.base/jdk.internal.misc
|
||||
|
||||
* @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
|
||||
* -Xbatch -XX:-TieredCompilation
|
||||
* -XX:+FoldStableValues
|
||||
* -XX:CompileCommand=dontinline,*Test::test*
|
||||
* UnsafeGetStableArrayElement
|
||||
* compiler.unsafe.UnsafeGetStableArrayElement
|
||||
*/
|
||||
package compiler.unsafe;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import java.util.concurrent.Callable;
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
import static jdk.internal.misc.Unsafe.*;
|
||||
import static jdk.test.lib.Asserts.*;
|
||||
import static jdk.test.lib.Platform;
|
||||
|
||||
public class UnsafeGetStableArrayElement {
|
||||
@Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16];
|
||||
@ -219,13 +223,7 @@ public class UnsafeGetStableArrayElement {
|
||||
Setter.reset();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (Platform.isServer()) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
static void test() throws Exception {
|
||||
static void testUnsafeAccess() throws Exception {
|
||||
// boolean[], aligned accesses
|
||||
testMatched( Test::testZ_Z, Test::changeZ);
|
||||
testMismatched(Test::testZ_B, Test::changeZ);
|
||||
@ -329,4 +327,11 @@ public class UnsafeGetStableArrayElement {
|
||||
run(Test::testL_I);
|
||||
run(Test::testL_F);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (Platform.isServer()) {
|
||||
testUnsafeAccess();
|
||||
}
|
||||
System.out.println("TEST PASSED");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user