Skip to content

Commit 0a255f7

Browse files
committed
Variant 3: Handle everything, including reads by compilers
1 parent 55c7969 commit 0a255f7

18 files changed

+1074
-42
lines changed

src/hotspot/share/c1/c1_GraphBuilder.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,7 @@ void GraphBuilder::method_return(Value x, bool ignore_return) {
15631563
// The conditions for a memory barrier are described in Parse::do_exits().
15641564
bool need_mem_bar = false;
15651565
if (method()->name() == ciSymbols::object_initializer_name() &&
1566-
(scope()->wrote_final() ||
1566+
(scope()->wrote_final() || scope()->wrote_stable() ||
15671567
(AlwaysSafeConstructors && scope()->wrote_fields()) ||
15681568
(support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) {
15691569
need_mem_bar = true;
@@ -1741,15 +1741,17 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
17411741
}
17421742
}
17431743

1744-
if (field->is_final() && (code == Bytecodes::_putfield)) {
1745-
scope()->set_wrote_final();
1746-
}
1747-
17481744
if (code == Bytecodes::_putfield) {
17491745
scope()->set_wrote_fields();
17501746
if (field->is_volatile()) {
17511747
scope()->set_wrote_volatile();
17521748
}
1749+
if (field->is_final()) {
1750+
scope()->set_wrote_final();
1751+
}
1752+
if (field->is_stable()) {
1753+
scope()->set_wrote_stable();
1754+
}
17531755
}
17541756

17551757
const int offset = !needs_patching ? field->offset_in_bytes() : -1;

src/hotspot/share/c1/c1_IR.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe
146146
_wrote_final = false;
147147
_wrote_fields = false;
148148
_wrote_volatile = false;
149+
_wrote_stable = false;
149150
_start = nullptr;
150151

151152
if (osr_bci != -1) {

src/hotspot/share/c1/c1_IR.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ class IRScope: public CompilationResourceObj {
149149
bool _wrote_final; // has written final field
150150
bool _wrote_fields; // has written fields
151151
bool _wrote_volatile; // has written volatile field
152+
bool _wrote_stable; // has written @Stable field
152153
BlockBegin* _start; // the start block, successsors are method entries
153154

154155
ResourceBitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable
@@ -187,6 +188,8 @@ class IRScope: public CompilationResourceObj {
187188
bool wrote_fields () const { return _wrote_fields; }
188189
void set_wrote_volatile() { _wrote_volatile = true; }
189190
bool wrote_volatile () const { return _wrote_volatile; }
191+
void set_wrote_stable() { _wrote_stable = true; }
192+
bool wrote_stable() const { return _wrote_stable; }
190193
};
191194

192195

src/hotspot/share/c1/c1_LIRGenerator.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,18 @@ void LIRGenerator::do_StoreField(StoreField* x) {
16771677

16781678
DecoratorSet decorators = IN_HEAP;
16791679
if (is_volatile) {
1680+
// Volatile access, full SC.
16801681
decorators |= MO_SEQ_CST;
1682+
} else if (x->field()->is_stable() && !x->field()->is_final() &&
1683+
is_reference_type(field_type)) {
1684+
// For reference @Stable fields, make sure we publish the contents
1685+
// safely. We need this to make sure compilers see a proper value when
1686+
// constant folding the access. Final @Stable fields are already
1687+
// handled in constructors.
1688+
decorators |= MO_RELEASE;
1689+
} else {
1690+
// Everything else is unordered.
1691+
decorators |= MO_UNORDERED;
16811692
}
16821693
if (needs_patching) {
16831694
decorators |= C1_NEEDS_PATCHING;

src/hotspot/share/ci/ciInstance.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) {
7878
case T_LONG: value = ciConstant(obj->long_field(offset)); break;
7979
case T_OBJECT: // fall through
8080
case T_ARRAY: {
81-
oop o = obj->obj_field(offset);
81+
// In case we are reading the constant off a reference @Stable field,
82+
// we need to match the releasing store with this acquire. There is no easy
83+
// way to know this from the offset, but it should not hurt to ask this for
84+
// all reference fields.
85+
oop o = obj->obj_field_acquire(offset);
8286

8387
// A field will be "constant" if it is known always to be
8488
// a non-null reference to an instance of a particular class,

src/hotspot/share/classfile/classFileParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1970,7 +1970,7 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
19701970
}
19711971
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Stable_signature): {
19721972
if (_location != _in_field) break; // only allow for fields
1973-
if (!privileged) break; // only allow in privileged code
1973+
if (RestrictStable && !privileged) break; // only allow in privileged code
19741974
return _field_Stable;
19751975
}
19761976
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): {

src/hotspot/share/opto/parse.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ class Parse : public GraphKit {
358358
bool _wrote_volatile; // Did we write a volatile field?
359359
bool _wrote_stable; // Did we write a @Stable field?
360360
bool _wrote_fields; // Did we write any field?
361-
Node* _alloc_with_final; // An allocation node with final field
361+
Node* _alloc_with_final_or_stable; // An allocation node with final or @Stable field
362362

363363
// Variables which track Java semantics during bytecode parsing:
364364

@@ -403,10 +403,10 @@ class Parse : public GraphKit {
403403
void set_wrote_stable(bool z) { _wrote_stable = z; }
404404
bool wrote_fields() const { return _wrote_fields; }
405405
void set_wrote_fields(bool z) { _wrote_fields = z; }
406-
Node* alloc_with_final() const { return _alloc_with_final; }
407-
void set_alloc_with_final(Node* n) {
408-
assert((_alloc_with_final == nullptr) || (_alloc_with_final == n), "different init objects?");
409-
_alloc_with_final = n;
406+
Node* alloc_with_final_or_stable() const { return _alloc_with_final_or_stable; }
407+
void set_alloc_with_final_or_stable(Node* n) {
408+
assert((_alloc_with_final_or_stable == nullptr) || (_alloc_with_final_or_stable == n), "different init objects?");
409+
_alloc_with_final_or_stable = n;
410410
}
411411

412412
Block* block() const { return _block; }

src/hotspot/share/opto/parse1.cpp

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
412412
_wrote_volatile = false;
413413
_wrote_stable = false;
414414
_wrote_fields = false;
415-
_alloc_with_final = nullptr;
415+
_alloc_with_final_or_stable = nullptr;
416416
_block = nullptr;
417417
_first_return = true;
418418
_replaced_nodes_for_exceptions = false;
@@ -984,8 +984,8 @@ void Parse::do_exits() {
984984
// Figure out if we need to emit the trailing barrier. The barrier is only
985985
// needed in the constructors, and only in three cases:
986986
//
987-
// 1. The constructor wrote a final. The effects of all initializations
988-
// must be committed to memory before any code after the constructor
987+
// 1. The constructor wrote a final or a @Stable field. All these
988+
// initializations must be ordered before any code after the constructor
989989
// publishes the reference to the newly constructed object. Rather
990990
// than wait for the publication, we simply block the writes here.
991991
// Rather than put a barrier on only those writes which are required
@@ -1010,34 +1010,23 @@ void Parse::do_exits() {
10101010
// exceptional returns, since they cannot publish normally.
10111011
//
10121012
if (method()->is_initializer() &&
1013-
(wrote_final() ||
1013+
(wrote_final() || wrote_stable() ||
10141014
(AlwaysSafeConstructors && wrote_fields()) ||
10151015
(support_IRIW_for_not_multiple_copy_atomic_cpu && wrote_volatile()))) {
1016+
Node* recorded_alloc = alloc_with_final_or_stable();
10161017
_exits.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease,
1017-
alloc_with_final());
1018+
recorded_alloc);
10181019

10191020
// If Memory barrier is created for final fields write
10201021
// and allocation node does not escape the initialize method,
10211022
// then barrier introduced by allocation node can be removed.
1022-
if (DoEscapeAnalysis && alloc_with_final()) {
1023-
AllocateNode* alloc = AllocateNode::Ideal_allocation(alloc_with_final());
1023+
if (DoEscapeAnalysis && (recorded_alloc != nullptr)) {
1024+
AllocateNode* alloc = AllocateNode::Ideal_allocation(recorded_alloc);
10241025
alloc->compute_MemBar_redundancy(method());
10251026
}
10261027
if (PrintOpto && (Verbose || WizardMode)) {
10271028
method()->print_name();
1028-
tty->print_cr(" writes finals and needs a memory barrier");
1029-
}
1030-
}
1031-
1032-
// Any method can write a @Stable field; insert memory barriers
1033-
// after those also. Can't bind predecessor allocation node (if any)
1034-
// with barrier because allocation doesn't always dominate
1035-
// MemBarRelease.
1036-
if (wrote_stable()) {
1037-
_exits.insert_mem_bar(Op_MemBarRelease);
1038-
if (PrintOpto && (Verbose || WizardMode)) {
1039-
method()->print_name();
1040-
tty->print_cr(" writes @Stable and needs a memory barrier");
1029+
tty->print_cr(" writes finals/@Stable and needs a memory barrier");
10411030
}
10421031
}
10431032

src/hotspot/share/opto/parse3.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,21 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
209209
Node* val = type2size[bt] == 1 ? pop() : pop_pair();
210210

211211
DecoratorSet decorators = IN_HEAP;
212-
decorators |= is_vol ? MO_SEQ_CST : MO_UNORDERED;
212+
213+
if (is_vol) {
214+
// Volatile access, full SC.
215+
decorators |= MO_SEQ_CST;
216+
} else if (field->is_stable() && !field->is_final() &&
217+
is_reference_type(field->layout_type())) {
218+
// For reference @Stable fields, make sure we publish the contents
219+
// safely. We need this to make sure compilers see a proper value when
220+
// constant folding the access. Final @Stable fields are already
221+
// handled in constructors.
222+
decorators |= MO_RELEASE;
223+
} else {
224+
// Everything else is unordered.
225+
decorators |= MO_UNORDERED;
226+
}
213227

214228
bool is_obj = is_reference_type(bt);
215229

@@ -236,22 +250,25 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
236250
set_wrote_fields(true);
237251

238252
// If the field is final, the rules of Java say we are in <init> or <clinit>.
239-
// Note the presence of writes to final non-static fields, so that we
253+
// If the field is @Stable, we can be in any method, but we only care about
254+
// constructors at this point.
255+
//
256+
// Note the presence of writes to final/@Stable non-static fields, so that we
240257
// can insert a memory barrier later on to keep the writes from floating
241258
// out of the constructor.
242-
// Any method can write a @Stable field; insert memory barriers after those also.
243-
if (field->is_final()) {
244-
set_wrote_final(true);
259+
if (field->is_final() || field->is_stable()) {
260+
if (field->is_final()) {
261+
set_wrote_final(true);
262+
}
263+
if (field->is_stable()) {
264+
set_wrote_stable(true);
265+
}
245266
if (AllocateNode::Ideal_allocation(obj) != nullptr) {
246267
// Preserve allocation ptr to create precedent edge to it in membar
247268
// generated on exit from constructor.
248-
// Can't bind stable with its allocation, only record allocation for final field.
249-
set_alloc_with_final(obj);
269+
set_alloc_with_final_or_stable(obj);
250270
}
251271
}
252-
if (field->is_stable()) {
253-
set_wrote_stable(true);
254-
}
255272
}
256273
}
257274

src/hotspot/share/runtime/globals.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,9 @@ const int ObjectAlignmentInBytes = 8;
19931993
\
19941994
product(bool, StressSecondarySupers, false, DIAGNOSTIC, \
19951995
"Use a terrible hash function in order to generate many collisions.") \
1996+
\
1997+
develop(bool, RestrictStable, true, \
1998+
"Restrict @Stable to trusted classes") \
19961999

19972000
// end of RUNTIME_FLAGS
19982001

0 commit comments

Comments
 (0)