Skip to content

Commit 7c97df2

Browse files
committed
8309862: Unsafe list operations in JfrStringPool
Reviewed-by: mgronlun Backport-of: 05f896a153ee950b21bae251d2870a8adfe4f04a
1 parent 19acd07 commit 7c97df2

File tree

5 files changed

+61
-30
lines changed

5 files changed

+61
-30
lines changed

src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -313,18 +313,20 @@ static size_t write_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) {
313313
return invoke(fs);
314314
}
315315

316-
typedef Content<JfrStringPool, &JfrStringPool::write> StringPool;
317-
typedef WriteCheckpointEvent<StringPool> WriteStringPool;
316+
typedef Content<JfrStringPool, &JfrStringPool::flush> FlushStringPoolFunctor;
317+
typedef Content<JfrStringPool, &JfrStringPool::write> WriteStringPoolFunctor;
318+
typedef WriteCheckpointEvent<FlushStringPoolFunctor> FlushStringPool;
319+
typedef WriteCheckpointEvent<WriteStringPoolFunctor> WriteStringPool;
318320

319321
static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
320-
StringPool sp(string_pool);
321-
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
322-
return invoke(wsp);
322+
FlushStringPoolFunctor fspf(string_pool);
323+
FlushStringPool fsp(chunkwriter, fspf, TYPE_STRING);
324+
return invoke(fsp);
323325
}
324326

325327
static u4 write_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
326-
StringPool sp(string_pool);
327-
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
328+
WriteStringPoolFunctor wspf(string_pool);
329+
WriteStringPool wsp(chunkwriter, wspf, TYPE_STRING);
328330
return invoke(wsp);
329331
}
330332

@@ -435,7 +437,6 @@ void JfrRecorderService::clear() {
435437
}
436438

437439
void JfrRecorderService::pre_safepoint_clear() {
438-
_string_pool.clear();
439440
_storage.clear();
440441
JfrStackTraceRepository::clear();
441442
}
@@ -449,14 +450,14 @@ void JfrRecorderService::invoke_safepoint_clear() {
449450
void JfrRecorderService::safepoint_clear() {
450451
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
451452
_checkpoint_manager.begin_epoch_shift();
452-
_string_pool.clear();
453453
_storage.clear();
454454
_chunkwriter.set_time_stamp();
455455
JfrStackTraceRepository::clear();
456456
_checkpoint_manager.end_epoch_shift();
457457
}
458458

459459
void JfrRecorderService::post_safepoint_clear() {
460+
_string_pool.clear();
460461
_checkpoint_manager.clear();
461462
}
462463

@@ -541,9 +542,6 @@ void JfrRecorderService::pre_safepoint_write() {
541542
// The sampler is released (unlocked) later in post_safepoint_write.
542543
ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire());
543544
}
544-
if (_string_pool.is_modified()) {
545-
write_stringpool(_string_pool, _chunkwriter);
546-
}
547545
write_storage(_storage, _chunkwriter);
548546
if (_stack_trace_repository.is_modified()) {
549547
write_stacktrace(_stack_trace_repository, _chunkwriter, false);
@@ -561,9 +559,6 @@ void JfrRecorderService::safepoint_write() {
561559
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
562560
_checkpoint_manager.begin_epoch_shift();
563561
JfrStackTraceRepository::clear_leak_profiler();
564-
if (_string_pool.is_modified()) {
565-
write_stringpool(_string_pool, _chunkwriter);
566-
}
567562
_checkpoint_manager.on_rotation();
568563
_storage.write_at_safepoint();
569564
_chunkwriter.set_time_stamp();
@@ -577,6 +572,7 @@ void JfrRecorderService::post_safepoint_write() {
577572
// Type tagging is epoch relative which entails we are able to write out the
578573
// already tagged artifacts for the previous epoch. We can accomplish this concurrently
579574
// with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
575+
write_stringpool(_string_pool, _chunkwriter);
580576
_checkpoint_manager.write_type_set();
581577
if (LeakProfiler::is_running()) {
582578
// The object sampler instance was exclusively acquired and locked in pre_safepoint_write.

src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,11 @@ class EpochDispatchOp {
214214
size_t elements() const { return _elements; }
215215
};
216216

217+
template <typename T>
218+
class ReinitializationOp {
219+
public:
220+
typedef T Type;
221+
bool process(Type* t);
222+
};
223+
217224
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP

src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,13 @@ size_t EpochDispatchOp<Operation>::dispatch(bool previous_epoch, const u1* eleme
168168
return elements;
169169
}
170170

171+
template <typename T>
172+
bool ReinitializationOp<T>::process(T* t) {
173+
assert(t != nullptr, "invariant");
174+
assert(t->identity() != nullptr, "invariant");
175+
t->reinitialize();
176+
t->release();
177+
return true;
178+
}
179+
171180
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP

src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,17 @@ static const size_t string_pool_buffer_size = 512 * K;
7777
bool JfrStringPool::initialize() {
7878
assert(_mspace == NULL, "invariant");
7979
_mspace = create_mspace<JfrStringPoolMspace>(string_pool_buffer_size,
80-
string_pool_cache_count, // cache limit
81-
string_pool_cache_count, // cache preallocate count
82-
false, // preallocate_to_free_list (== preallocate directly to live list)
80+
0,
81+
0, // cache preallocate count
82+
false,
8383
this);
84+
85+
// preallocate buffer count to each of the epoch live lists
86+
for (size_t i = 0; i < string_pool_cache_count * 2; ++i) {
87+
Buffer* const buffer = mspace_allocate(string_pool_buffer_size, _mspace);
88+
_mspace->add_to_live_list(buffer, i % 2 == 0);
89+
}
90+
assert(_mspace->free_list_is_empty(), "invariant");
8491
return _mspace != NULL;
8592
}
8693

@@ -95,11 +102,7 @@ static void release(BufferPtr buffer, Thread* thread) {
95102
assert(buffer->lease(), "invariant");
96103
assert(buffer->acquired_by_self(), "invariant");
97104
buffer->clear_lease();
98-
if (buffer->transient()) {
99-
buffer->set_retired();
100-
} else {
101-
buffer->release();
102-
}
105+
buffer->release();
103106
}
104107

105108
BufferPtr JfrStringPool::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
@@ -180,30 +183,44 @@ typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation;
180183
typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
181184
typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
182185
typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
186+
typedef ReinitializationOp<JfrStringPoolBuffer> ReinitializationOperation;
183187
typedef ReleaseWithExcisionOp<JfrStringPoolMspace, JfrStringPoolMspace::LiveList> ReleaseOperation;
184188
typedef CompositeOperation<ExclusiveWriteOperation, ReleaseOperation> WriteReleaseOperation;
189+
typedef CompositeOperation<ExclusiveWriteOperation, ReinitializationOperation> WriteReinitializeOperation;
185190
typedef CompositeOperation<ExclusiveDiscardOperation, ReleaseOperation> DiscardReleaseOperation;
186191

187192
size_t JfrStringPool::write() {
188193
Thread* const thread = Thread::current();
189194
WriteOperation wo(_chunkwriter, thread);
190195
ExclusiveWriteOperation ewo(wo);
191196
assert(_mspace->free_list_is_empty(), "invariant");
192-
ReleaseOperation ro(_mspace, _mspace->live_list());
197+
ReleaseOperation ro(_mspace, _mspace->live_list(true)); // previous epoch list
193198
WriteReleaseOperation wro(&ewo, &ro);
194199
assert(_mspace->live_list_is_nonempty(), "invariant");
195-
process_live_list(wro, _mspace);
200+
process_live_list(wro, _mspace, true); // previous epoch list
201+
return wo.processed();
202+
}
203+
204+
size_t JfrStringPool::flush() {
205+
Thread* const thread = Thread::current();
206+
WriteOperation wo(_chunkwriter, thread);
207+
ExclusiveWriteOperation ewo(wo);
208+
ReinitializationOperation rio;
209+
WriteReinitializeOperation wro(&ewo, &rio);
210+
assert(_mspace->free_list_is_empty(), "invariant");
211+
assert(_mspace->live_list_is_nonempty(), "invariant");
212+
process_live_list(wro, _mspace); // current epoch list
196213
return wo.processed();
197214
}
198215

199216
size_t JfrStringPool::clear() {
200217
DiscardOperation discard_operation;
201218
ExclusiveDiscardOperation edo(discard_operation);
202219
assert(_mspace->free_list_is_empty(), "invariant");
203-
ReleaseOperation ro(_mspace, _mspace->live_list());
220+
ReleaseOperation ro(_mspace, _mspace->live_list(true)); // previous epoch list
204221
DiscardReleaseOperation discard_op(&edo, &ro);
205222
assert(_mspace->live_list_is_nonempty(), "invariant");
206-
process_live_list(discard_op, _mspace);
223+
process_live_list(discard_op, _mspace, true); // previous epoch list
207224
return discard_operation.processed();
208225
}
209226

src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 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
@@ -35,7 +35,7 @@ class JavaThread;
3535
class JfrChunkWriter;
3636
class JfrStringPool;
3737

38-
typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStringPoolBuffer> > JfrStringPoolMspace;
38+
typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStringPoolBuffer>, JfrLinkedList<JfrStringPoolBuffer>, true > JfrStringPoolMspace;
3939

4040
//
4141
// Although called JfrStringPool, a more succinct description would be
@@ -45,8 +45,10 @@ typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStrin
4545
//
4646
class JfrStringPool : public JfrCHeapObj {
4747
public:
48-
size_t write();
4948
size_t clear();
49+
size_t flush();
50+
size_t write();
51+
5052
static jboolean add(jlong id, jstring string, JavaThread* jt);
5153

5254
typedef JfrStringPoolMspace::Node Buffer;

0 commit comments

Comments
 (0)