Skip to content

Commit 05f896a

Browse files
author
Markus Grönlund
committed
8309862: Unsafe list operations in JfrStringPool
Reviewed-by: egahlin
1 parent 4f23fc1 commit 05f896a

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
@@ -338,18 +338,20 @@ static size_t write_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) {
338338
return invoke(fs);
339339
}
340340

341-
typedef Content<JfrStringPool, &JfrStringPool::write> StringPool;
342-
typedef WriteCheckpointEvent<StringPool> WriteStringPool;
341+
typedef Content<JfrStringPool, &JfrStringPool::flush> FlushStringPoolFunctor;
342+
typedef Content<JfrStringPool, &JfrStringPool::write> WriteStringPoolFunctor;
343+
typedef WriteCheckpointEvent<FlushStringPoolFunctor> FlushStringPool;
344+
typedef WriteCheckpointEvent<WriteStringPoolFunctor> WriteStringPool;
343345

344346
static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
345-
StringPool sp(string_pool);
346-
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
347-
return invoke(wsp);
347+
FlushStringPoolFunctor fspf(string_pool);
348+
FlushStringPool fsp(chunkwriter, fspf, TYPE_STRING);
349+
return invoke(fsp);
348350
}
349351

350352
static u4 write_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
351-
StringPool sp(string_pool);
352-
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
353+
WriteStringPoolFunctor wspf(string_pool);
354+
WriteStringPool wsp(chunkwriter, wspf, TYPE_STRING);
353355
return invoke(wsp);
354356
}
355357

@@ -461,7 +463,6 @@ void JfrRecorderService::clear() {
461463

462464
void JfrRecorderService::pre_safepoint_clear() {
463465
clear_object_allocation_sampling();
464-
_string_pool.clear();
465466
_storage.clear();
466467
JfrStackTraceRepository::clear();
467468
}
@@ -475,14 +476,14 @@ void JfrRecorderService::invoke_safepoint_clear() {
475476
void JfrRecorderService::safepoint_clear() {
476477
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
477478
_checkpoint_manager.begin_epoch_shift();
478-
_string_pool.clear();
479479
_storage.clear();
480480
_chunkwriter.set_time_stamp();
481481
JfrStackTraceRepository::clear();
482482
_checkpoint_manager.end_epoch_shift();
483483
}
484484

485485
void JfrRecorderService::post_safepoint_clear() {
486+
_string_pool.clear();
486487
_checkpoint_manager.clear();
487488
}
488489

@@ -567,9 +568,6 @@ void JfrRecorderService::pre_safepoint_write() {
567568
// The sampler is released (unlocked) later in post_safepoint_write.
568569
ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire());
569570
}
570-
if (_string_pool.is_modified()) {
571-
write_stringpool(_string_pool, _chunkwriter);
572-
}
573571
write_storage(_storage, _chunkwriter);
574572
if (_stack_trace_repository.is_modified()) {
575573
write_stacktrace(_stack_trace_repository, _chunkwriter, false);
@@ -587,9 +585,6 @@ void JfrRecorderService::safepoint_write() {
587585
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
588586
_checkpoint_manager.begin_epoch_shift();
589587
JfrStackTraceRepository::clear_leak_profiler();
590-
if (_string_pool.is_modified()) {
591-
write_stringpool(_string_pool, _chunkwriter);
592-
}
593588
_checkpoint_manager.on_rotation();
594589
_storage.write_at_safepoint();
595590
_chunkwriter.set_time_stamp();
@@ -603,6 +598,7 @@ void JfrRecorderService::post_safepoint_write() {
603598
// Type tagging is epoch relative which entails we are able to write out the
604599
// already tagged artifacts for the previous epoch. We can accomplish this concurrently
605600
// with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
601+
write_stringpool(_string_pool, _chunkwriter);
606602
_checkpoint_manager.write_type_set();
607603
if (LeakProfiler::is_running()) {
608604
// 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
@@ -208,4 +208,11 @@ class EpochDispatchOp {
208208
size_t elements() const { return _elements; }
209209
};
210210

211+
template <typename T>
212+
class ReinitializationOp {
213+
public:
214+
typedef T Type;
215+
bool process(Type* t);
216+
};
217+
211218
#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
@@ -175,4 +175,13 @@ size_t EpochDispatchOp<Operation>::dispatch(bool previous_epoch, const u1* eleme
175175
return elements;
176176
}
177177

178+
template <typename T>
179+
bool ReinitializationOp<T>::process(T* t) {
180+
assert(t != nullptr, "invariant");
181+
assert(t->identity() != nullptr, "invariant");
182+
t->reinitialize();
183+
t->release();
184+
return true;
185+
}
186+
178187
#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 == nullptr, "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 != nullptr;
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)