Skip to content

Commit cae577a

Browse files
committed
8295486: Inconsistent constant field values observed during compilation
Reviewed-by: chagedorn, kvn, jbhateja, vlivanov
1 parent 969f6a3 commit cae577a

File tree

11 files changed

+299
-64
lines changed

11 files changed

+299
-64
lines changed

src/hotspot/share/ci/ciArray.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ ciConstant ciArray::element_value_impl(BasicType elembt,
6363
assert(ary->is_objArray(), "");
6464
objArrayOop objary = (objArrayOop) ary;
6565
oop elem = objary->obj_at(index);
66-
ciEnv* env = CURRENT_ENV;
67-
ciObject* box = env->get_object(elem);
68-
return ciConstant(T_OBJECT, box);
66+
return ciConstant(elembt, CURRENT_ENV->get_object(elem));
6967
}
7068
default:
7169
break;
@@ -94,9 +92,15 @@ ciConstant ciArray::element_value_impl(BasicType elembt,
9492
// Returns T_ILLEGAL if there is no element at the given index.
9593
ciConstant ciArray::element_value(int index) {
9694
BasicType elembt = element_basic_type();
95+
ciConstant value = check_constant_value_cache(index, elembt);
96+
if (value.is_valid()) {
97+
return value;
98+
}
9799
GUARDED_VM_ENTRY(
98-
return element_value_impl(elembt, get_arrayOop(), index);
100+
value = element_value_impl(elembt, get_arrayOop(), index);
99101
)
102+
add_to_constant_value_cache(index, value);
103+
return value;
100104
}
101105

102106
// ------------------------------------------------------------------

src/hotspot/share/ci/ciConstant.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,35 @@
3232
//
3333
// This class represents a constant value.
3434

35+
// ------------------------------------------------------------------
36+
// ciConstant::is_null_or_zero
37+
bool ciConstant::is_null_or_zero() const {
38+
if (!is_java_primitive(basic_type())) {
39+
return as_object()->is_null_object();
40+
} else if (type2size[basic_type()] == 1) {
41+
// treat float bits as int, to avoid comparison with -0 and NaN
42+
return (_value._int == 0);
43+
} else if (type2size[basic_type()] == 2) {
44+
// treat double bits as long, to avoid comparison with -0 and NaN
45+
return (_value._long == 0);
46+
} else {
47+
return false;
48+
}
49+
}
50+
51+
// ------------------------------------------------------------------
52+
// ciConstant::is_loaded
53+
bool ciConstant::is_loaded() const {
54+
if (is_valid()) {
55+
if (is_reference_type(basic_type())) {
56+
return as_object()->is_loaded();
57+
} else {
58+
return true;
59+
}
60+
}
61+
return false;
62+
}
63+
3564
// ------------------------------------------------------------------
3665
// ciConstant::print
3766
void ciConstant::print() {

src/hotspot/share/ci/ciConstant.hpp

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
2626
#define SHARE_CI_CICONSTANT_HPP
2727

2828
#include "ci/ciClassList.hpp"
29-
#include "ci/ciNullObject.hpp"
29+
#include "utilities/globalDefinitions.hpp"
3030

3131
// ciConstant
3232
//
@@ -110,34 +110,14 @@ class ciConstant {
110110
return _value._object;
111111
}
112112

113-
bool is_null_or_zero() const {
114-
if (!is_java_primitive(basic_type())) {
115-
return as_object()->is_null_object();
116-
} else if (type2size[basic_type()] == 1) {
117-
// treat float bits as int, to avoid comparison with -0 and NaN
118-
return (_value._int == 0);
119-
} else if (type2size[basic_type()] == 2) {
120-
// treat double bits as long, to avoid comparison with -0 and NaN
121-
return (_value._long == 0);
122-
} else {
123-
return false;
124-
}
125-
}
113+
bool is_null_or_zero() const;
126114

127115
bool is_valid() const {
128116
return basic_type() != T_ILLEGAL;
129117
}
130118

131-
bool is_loaded() const {
132-
if (is_valid()) {
133-
if (is_reference_type(basic_type())) {
134-
return as_object()->is_loaded();
135-
} else {
136-
return true;
137-
}
138-
}
139-
return false;
140-
}
119+
bool is_loaded() const;
120+
141121
// Debugging output
142122
void print();
143123
};

src/hotspot/share/ci/ciField.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,7 @@ ciConstant ciField::constant_value() {
311311
}
312312
if (_constant_value.basic_type() == T_ILLEGAL) {
313313
// Static fields are placed in mirror objects.
314-
VM_ENTRY_MARK;
315-
ciInstance* mirror = CURRENT_ENV->get_instance(_holder->get_Klass()->java_mirror());
314+
ciInstance* mirror = _holder->java_mirror();
316315
_constant_value = mirror->field_value_impl(type()->basic_type(), offset());
317316
}
318317
if (FoldStableValues && is_stable() && _constant_value.is_null_or_zero()) {

src/hotspot/share/ci/ciInstance.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "ci/ciField.hpp"
2929
#include "ci/ciInstance.hpp"
3030
#include "ci/ciInstanceKlass.hpp"
31+
#include "ci/ciNullObject.hpp"
3132
#include "ci/ciUtilities.inline.hpp"
3233
#include "classfile/vmClasses.hpp"
3334
#include "oops/oop.inline.hpp"
@@ -59,17 +60,22 @@ ciType* ciInstance::java_mirror_type() {
5960
// ------------------------------------------------------------------
6061
// ciInstance::field_value_impl
6162
ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) {
63+
ciConstant value = check_constant_value_cache(offset, field_btype);
64+
if (value.is_valid()) {
65+
return value;
66+
}
67+
VM_ENTRY_MARK;
6268
oop obj = get_oop();
6369
assert(obj != nullptr, "bad oop");
6470
switch(field_btype) {
65-
case T_BYTE: return ciConstant(field_btype, obj->byte_field(offset));
66-
case T_CHAR: return ciConstant(field_btype, obj->char_field(offset));
67-
case T_SHORT: return ciConstant(field_btype, obj->short_field(offset));
68-
case T_BOOLEAN: return ciConstant(field_btype, obj->bool_field(offset));
69-
case T_INT: return ciConstant(field_btype, obj->int_field(offset));
70-
case T_FLOAT: return ciConstant(obj->float_field(offset));
71-
case T_DOUBLE: return ciConstant(obj->double_field(offset));
72-
case T_LONG: return ciConstant(obj->long_field(offset));
71+
case T_BYTE: value = ciConstant(field_btype, obj->byte_field(offset)); break;
72+
case T_CHAR: value = ciConstant(field_btype, obj->char_field(offset)); break;
73+
case T_SHORT: value = ciConstant(field_btype, obj->short_field(offset)); break;
74+
case T_BOOLEAN: value = ciConstant(field_btype, obj->bool_field(offset)); break;
75+
case T_INT: value = ciConstant(field_btype, obj->int_field(offset)); break;
76+
case T_FLOAT: value = ciConstant(obj->float_field(offset)); break;
77+
case T_DOUBLE: value = ciConstant(obj->double_field(offset)); break;
78+
case T_LONG: value = ciConstant(obj->long_field(offset)); break;
7379
case T_OBJECT: // fall through
7480
case T_ARRAY: {
7581
oop o = obj->obj_field(offset);
@@ -82,15 +88,17 @@ ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) {
8288
// information about the object's class (which is exact) or length.
8389

8490
if (o == nullptr) {
85-
return ciConstant(field_btype, ciNullObject::make());
91+
value = ciConstant(field_btype, ciNullObject::make());
8692
} else {
87-
return ciConstant(field_btype, CURRENT_ENV->get_object(o));
93+
value = ciConstant(field_btype, CURRENT_ENV->get_object(o));
8894
}
95+
break;
8996
}
9097
default:
9198
fatal("no field value: %s", type2name(field_btype));
92-
return ciConstant();
9399
}
100+
add_to_constant_value_cache(offset, value);
101+
return value;
94102
}
95103

96104
// ------------------------------------------------------------------
@@ -101,8 +109,7 @@ ciConstant ciInstance::field_value(ciField* field) {
101109
assert(is_loaded(), "invalid access - must be loaded");
102110
assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
103111
assert(field->is_static() || klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
104-
105-
GUARDED_VM_ENTRY(return field_value_impl(field->type()->basic_type(), field->offset());)
112+
return field_value_impl(field->type()->basic_type(), field->offset());
106113
}
107114

108115
// ------------------------------------------------------------------

src/hotspot/share/ci/ciObject.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,38 @@ jobject ciObject::constant_encoding() {
168168
return handle();
169169
}
170170

171+
// ------------------------------------------------------------------
172+
// ciObject::check_constant_value_cache()
173+
//
174+
// Cache constant value lookups to ensure that consistent values are observed
175+
// during compilation because fields may be (re-)initialized concurrently.
176+
ciConstant ciObject::check_constant_value_cache(int off, BasicType bt) {
177+
if (_constant_values != nullptr) {
178+
for (int i = 0; i < _constant_values->length(); ++i) {
179+
ConstantValue cached_val = _constant_values->at(i);
180+
if (cached_val.off() == off) {
181+
assert(cached_val.value().basic_type() == bt, "unexpected type");
182+
return cached_val.value();
183+
}
184+
}
185+
}
186+
return ciConstant();
187+
}
188+
189+
// ------------------------------------------------------------------
190+
// ciObject::add_to_constant_value_cache()
191+
//
192+
// Add a constant value to the cache.
193+
void ciObject::add_to_constant_value_cache(int off, ciConstant val) {
194+
assert(val.is_valid(), "value must be valid");
195+
assert(!check_constant_value_cache(off, val.basic_type()).is_valid(), "duplicate");
196+
if (_constant_values == nullptr) {
197+
Arena* arena = CURRENT_ENV->arena();
198+
_constant_values = new (arena) GrowableArray<ConstantValue>(arena, 1, 0, ConstantValue());
199+
}
200+
_constant_values->append(ConstantValue(off, val));
201+
}
202+
171203
// ------------------------------------------------------------------
172204
// ciObject::should_be_constant()
173205
bool ciObject::should_be_constant() {

src/hotspot/share/ci/ciObject.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727

2828
#include "ci/ciBaseObject.hpp"
2929
#include "ci/ciClassList.hpp"
30+
#include "ci/ciConstant.hpp"
3031
#include "runtime/handles.hpp"
32+
#include "utilities/growableArray.hpp"
3133

3234
// ciObject
3335
//
@@ -57,6 +59,22 @@ class ciObject : public ciBaseObject {
5759
jobject _handle;
5860
ciKlass* _klass;
5961

62+
// Cache constant value lookups to ensure that consistent values are observed during compilation.
63+
class ConstantValue {
64+
private:
65+
ciConstant _value;
66+
int _off;
67+
68+
public:
69+
ConstantValue() : _value(ciConstant()), _off(0) { }
70+
ConstantValue(int off, ciConstant value) : _value(value), _off(off) { }
71+
72+
int off() const { return _off; }
73+
ciConstant value() const { return _value; }
74+
};
75+
76+
GrowableArray<ConstantValue>* _constant_values = nullptr;
77+
6078
protected:
6179
ciObject();
6280
ciObject(oop o);
@@ -94,6 +112,10 @@ class ciObject : public ciBaseObject {
94112
// be registered with the oopRecorder.
95113
jobject constant_encoding();
96114

115+
// Access to the constant value cache
116+
ciConstant check_constant_value_cache(int off, BasicType bt);
117+
void add_to_constant_value_cache(int off, ciConstant val);
118+
97119
virtual bool is_object() const { return true; }
98120

99121
// What kind of ciObject is this?

src/hotspot/share/opto/phaseX.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1759,19 +1759,15 @@ PhaseCCP::~PhaseCCP() {
17591759

17601760

17611761
#ifdef ASSERT
1762-
static bool ccp_type_widens(const Type* t, const Type* t0) {
1763-
assert(t->meet(t0) == t->remove_speculative(), "Not monotonic");
1764-
switch (t->base() == t0->base() ? t->base() : Type::Top) {
1765-
case Type::Int:
1766-
assert(t0->isa_int()->_widen <= t->isa_int()->_widen, "widen increases");
1767-
break;
1768-
case Type::Long:
1769-
assert(t0->isa_long()->_widen <= t->isa_long()->_widen, "widen increases");
1770-
break;
1771-
default:
1772-
break;
1762+
void PhaseCCP::verify_type(Node* n, const Type* tnew, const Type* told) {
1763+
if (tnew->meet(told) != tnew->remove_speculative()) {
1764+
n->dump(1);
1765+
tty->print("told = "); told->dump(); tty->cr();
1766+
tty->print("tnew = "); tnew->dump(); tty->cr();
1767+
fatal("Not monotonic");
17731768
}
1774-
return true;
1769+
assert(!told->isa_int() || !tnew->isa_int() || told->is_int()->_widen <= tnew->is_int()->_widen, "widen increases");
1770+
assert(!told->isa_long() || !tnew->isa_long() || told->is_long()->_widen <= tnew->is_long()->_widen, "widen increases");
17751771
}
17761772
#endif //ASSERT
17771773

@@ -1806,7 +1802,7 @@ void PhaseCCP::analyze() {
18061802
}
18071803
const Type* new_type = n->Value(this);
18081804
if (new_type != type(n)) {
1809-
assert(ccp_type_widens(new_type, type(n)), "ccp type must widen");
1805+
DEBUG_ONLY(verify_type(n, new_type, type(n));)
18101806
dump_type_and_node(n, new_type);
18111807
set_type(n, new_type);
18121808
push_child_nodes_to_worklist(worklist, n);
@@ -1834,12 +1830,13 @@ void PhaseCCP::verify_analyze(Unique_Node_List& worklist_verify) {
18341830
continue; // ignore integer widen
18351831
}
18361832
}
1837-
if (n->is_Load()) {
1833+
if (n->is_Load() && !told->singleton()) {
18381834
// MemNode::can_see_stored_value looks up through many memory nodes,
18391835
// which means we would need to notify modifications from far up in
18401836
// the inputs all the way down to the LoadNode. We don't do that.
18411837
continue;
18421838
}
1839+
verify_type(n, tnew, told);
18431840
tty->cr();
18441841
tty->print_cr("Missed optimization (PhaseCCP):");
18451842
n->dump_bfs(1, 0, "");

src/hotspot/share/opto/phaseX.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -605,6 +605,7 @@ class PhaseCCP : public PhaseIterGVN {
605605
// Worklist algorithm identifies constants
606606
void analyze();
607607
#ifdef ASSERT
608+
void verify_type(Node* n, const Type* tnew, const Type* told);
608609
// For every node n on verify list, check if type(n) == n->Value()
609610
void verify_analyze(Unique_Node_List& worklist_verify);
610611
#endif

src/hotspot/share/opto/type.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -3370,7 +3370,6 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfa
33703370
_offset != arrayOopDesc::length_offset_in_bytes());
33713371
} else if (klass()->is_instance_klass()) {
33723372
ciInstanceKlass* ik = klass()->as_instance_klass();
3373-
ciField* field = NULL;
33743373
if (this->isa_klassptr()) {
33753374
// Perm objects don't use compressed references
33763375
} else if (_offset == OffsetBot || _offset == OffsetTop) {
@@ -3402,7 +3401,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfa
34023401
}
34033402
} else {
34043403
// Instance fields which contains a compressed oop references.
3405-
field = ik->get_field_by_offset(_offset, false);
3404+
ciField* field = ik->get_field_by_offset(_offset, false);
34063405
if (field != NULL) {
34073406
BasicType basic_elem_type = field->layout_type();
34083407
_is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);

0 commit comments

Comments
 (0)