8309862: Unsafe list operations in JfrStringPool
Reviewed-by: egahlin
This commit is contained in:
parent
4f23fc1f27
commit
05f896a153
@ -338,18 +338,20 @@ static size_t write_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) {
|
|||||||
return invoke(fs);
|
return invoke(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Content<JfrStringPool, &JfrStringPool::write> StringPool;
|
typedef Content<JfrStringPool, &JfrStringPool::flush> FlushStringPoolFunctor;
|
||||||
typedef WriteCheckpointEvent<StringPool> WriteStringPool;
|
typedef Content<JfrStringPool, &JfrStringPool::write> WriteStringPoolFunctor;
|
||||||
|
typedef WriteCheckpointEvent<FlushStringPoolFunctor> FlushStringPool;
|
||||||
|
typedef WriteCheckpointEvent<WriteStringPoolFunctor> WriteStringPool;
|
||||||
|
|
||||||
static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
|
static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
|
||||||
StringPool sp(string_pool);
|
FlushStringPoolFunctor fspf(string_pool);
|
||||||
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
|
FlushStringPool fsp(chunkwriter, fspf, TYPE_STRING);
|
||||||
return invoke(wsp);
|
return invoke(fsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u4 write_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
|
static u4 write_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
|
||||||
StringPool sp(string_pool);
|
WriteStringPoolFunctor wspf(string_pool);
|
||||||
WriteStringPool wsp(chunkwriter, sp, TYPE_STRING);
|
WriteStringPool wsp(chunkwriter, wspf, TYPE_STRING);
|
||||||
return invoke(wsp);
|
return invoke(wsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +463,6 @@ void JfrRecorderService::clear() {
|
|||||||
|
|
||||||
void JfrRecorderService::pre_safepoint_clear() {
|
void JfrRecorderService::pre_safepoint_clear() {
|
||||||
clear_object_allocation_sampling();
|
clear_object_allocation_sampling();
|
||||||
_string_pool.clear();
|
|
||||||
_storage.clear();
|
_storage.clear();
|
||||||
JfrStackTraceRepository::clear();
|
JfrStackTraceRepository::clear();
|
||||||
}
|
}
|
||||||
@ -475,7 +476,6 @@ void JfrRecorderService::invoke_safepoint_clear() {
|
|||||||
void JfrRecorderService::safepoint_clear() {
|
void JfrRecorderService::safepoint_clear() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||||
_checkpoint_manager.begin_epoch_shift();
|
_checkpoint_manager.begin_epoch_shift();
|
||||||
_string_pool.clear();
|
|
||||||
_storage.clear();
|
_storage.clear();
|
||||||
_chunkwriter.set_time_stamp();
|
_chunkwriter.set_time_stamp();
|
||||||
JfrStackTraceRepository::clear();
|
JfrStackTraceRepository::clear();
|
||||||
@ -483,6 +483,7 @@ void JfrRecorderService::safepoint_clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JfrRecorderService::post_safepoint_clear() {
|
void JfrRecorderService::post_safepoint_clear() {
|
||||||
|
_string_pool.clear();
|
||||||
_checkpoint_manager.clear();
|
_checkpoint_manager.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,9 +568,6 @@ void JfrRecorderService::pre_safepoint_write() {
|
|||||||
// The sampler is released (unlocked) later in post_safepoint_write.
|
// The sampler is released (unlocked) later in post_safepoint_write.
|
||||||
ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire());
|
ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire());
|
||||||
}
|
}
|
||||||
if (_string_pool.is_modified()) {
|
|
||||||
write_stringpool(_string_pool, _chunkwriter);
|
|
||||||
}
|
|
||||||
write_storage(_storage, _chunkwriter);
|
write_storage(_storage, _chunkwriter);
|
||||||
if (_stack_trace_repository.is_modified()) {
|
if (_stack_trace_repository.is_modified()) {
|
||||||
write_stacktrace(_stack_trace_repository, _chunkwriter, false);
|
write_stacktrace(_stack_trace_repository, _chunkwriter, false);
|
||||||
@ -587,9 +585,6 @@ void JfrRecorderService::safepoint_write() {
|
|||||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||||
_checkpoint_manager.begin_epoch_shift();
|
_checkpoint_manager.begin_epoch_shift();
|
||||||
JfrStackTraceRepository::clear_leak_profiler();
|
JfrStackTraceRepository::clear_leak_profiler();
|
||||||
if (_string_pool.is_modified()) {
|
|
||||||
write_stringpool(_string_pool, _chunkwriter);
|
|
||||||
}
|
|
||||||
_checkpoint_manager.on_rotation();
|
_checkpoint_manager.on_rotation();
|
||||||
_storage.write_at_safepoint();
|
_storage.write_at_safepoint();
|
||||||
_chunkwriter.set_time_stamp();
|
_chunkwriter.set_time_stamp();
|
||||||
@ -603,6 +598,7 @@ void JfrRecorderService::post_safepoint_write() {
|
|||||||
// Type tagging is epoch relative which entails we are able to write out the
|
// Type tagging is epoch relative which entails we are able to write out the
|
||||||
// already tagged artifacts for the previous epoch. We can accomplish this concurrently
|
// already tagged artifacts for the previous epoch. We can accomplish this concurrently
|
||||||
// with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
|
// with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
|
||||||
|
write_stringpool(_string_pool, _chunkwriter);
|
||||||
_checkpoint_manager.write_type_set();
|
_checkpoint_manager.write_type_set();
|
||||||
if (LeakProfiler::is_running()) {
|
if (LeakProfiler::is_running()) {
|
||||||
// The object sampler instance was exclusively acquired and locked in pre_safepoint_write.
|
// The object sampler instance was exclusively acquired and locked in pre_safepoint_write.
|
||||||
|
@ -208,4 +208,11 @@ class EpochDispatchOp {
|
|||||||
size_t elements() const { return _elements; }
|
size_t elements() const { return _elements; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ReinitializationOp {
|
||||||
|
public:
|
||||||
|
typedef T Type;
|
||||||
|
bool process(Type* t);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
|
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
|
||||||
|
@ -175,4 +175,13 @@ size_t EpochDispatchOp<Operation>::dispatch(bool previous_epoch, const u1* eleme
|
|||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool ReinitializationOp<T>::process(T* t) {
|
||||||
|
assert(t != nullptr, "invariant");
|
||||||
|
assert(t->identity() != nullptr, "invariant");
|
||||||
|
t->reinitialize();
|
||||||
|
t->release();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
|
#endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
|
||||||
|
@ -77,10 +77,17 @@ static const size_t string_pool_buffer_size = 512 * K;
|
|||||||
bool JfrStringPool::initialize() {
|
bool JfrStringPool::initialize() {
|
||||||
assert(_mspace == nullptr, "invariant");
|
assert(_mspace == nullptr, "invariant");
|
||||||
_mspace = create_mspace<JfrStringPoolMspace>(string_pool_buffer_size,
|
_mspace = create_mspace<JfrStringPoolMspace>(string_pool_buffer_size,
|
||||||
string_pool_cache_count, // cache limit
|
0,
|
||||||
string_pool_cache_count, // cache preallocate count
|
0, // cache preallocate count
|
||||||
false, // preallocate_to_free_list (== preallocate directly to live list)
|
false,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
// preallocate buffer count to each of the epoch live lists
|
||||||
|
for (size_t i = 0; i < string_pool_cache_count * 2; ++i) {
|
||||||
|
Buffer* const buffer = mspace_allocate(string_pool_buffer_size, _mspace);
|
||||||
|
_mspace->add_to_live_list(buffer, i % 2 == 0);
|
||||||
|
}
|
||||||
|
assert(_mspace->free_list_is_empty(), "invariant");
|
||||||
return _mspace != nullptr;
|
return _mspace != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,12 +102,8 @@ static void release(BufferPtr buffer, Thread* thread) {
|
|||||||
assert(buffer->lease(), "invariant");
|
assert(buffer->lease(), "invariant");
|
||||||
assert(buffer->acquired_by_self(), "invariant");
|
assert(buffer->acquired_by_self(), "invariant");
|
||||||
buffer->clear_lease();
|
buffer->clear_lease();
|
||||||
if (buffer->transient()) {
|
|
||||||
buffer->set_retired();
|
|
||||||
} else {
|
|
||||||
buffer->release();
|
buffer->release();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BufferPtr JfrStringPool::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
|
BufferPtr JfrStringPool::flush(BufferPtr old, size_t used, size_t requested, Thread* thread) {
|
||||||
assert(old != nullptr, "invariant");
|
assert(old != nullptr, "invariant");
|
||||||
@ -180,8 +183,10 @@ typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation;
|
|||||||
typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
|
typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
|
||||||
typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
|
typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
|
||||||
typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
|
typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
|
||||||
|
typedef ReinitializationOp<JfrStringPoolBuffer> ReinitializationOperation;
|
||||||
typedef ReleaseWithExcisionOp<JfrStringPoolMspace, JfrStringPoolMspace::LiveList> ReleaseOperation;
|
typedef ReleaseWithExcisionOp<JfrStringPoolMspace, JfrStringPoolMspace::LiveList> ReleaseOperation;
|
||||||
typedef CompositeOperation<ExclusiveWriteOperation, ReleaseOperation> WriteReleaseOperation;
|
typedef CompositeOperation<ExclusiveWriteOperation, ReleaseOperation> WriteReleaseOperation;
|
||||||
|
typedef CompositeOperation<ExclusiveWriteOperation, ReinitializationOperation> WriteReinitializeOperation;
|
||||||
typedef CompositeOperation<ExclusiveDiscardOperation, ReleaseOperation> DiscardReleaseOperation;
|
typedef CompositeOperation<ExclusiveDiscardOperation, ReleaseOperation> DiscardReleaseOperation;
|
||||||
|
|
||||||
size_t JfrStringPool::write() {
|
size_t JfrStringPool::write() {
|
||||||
@ -189,10 +194,22 @@ size_t JfrStringPool::write() {
|
|||||||
WriteOperation wo(_chunkwriter, thread);
|
WriteOperation wo(_chunkwriter, thread);
|
||||||
ExclusiveWriteOperation ewo(wo);
|
ExclusiveWriteOperation ewo(wo);
|
||||||
assert(_mspace->free_list_is_empty(), "invariant");
|
assert(_mspace->free_list_is_empty(), "invariant");
|
||||||
ReleaseOperation ro(_mspace, _mspace->live_list());
|
ReleaseOperation ro(_mspace, _mspace->live_list(true)); // previous epoch list
|
||||||
WriteReleaseOperation wro(&ewo, &ro);
|
WriteReleaseOperation wro(&ewo, &ro);
|
||||||
assert(_mspace->live_list_is_nonempty(), "invariant");
|
assert(_mspace->live_list_is_nonempty(), "invariant");
|
||||||
process_live_list(wro, _mspace);
|
process_live_list(wro, _mspace, true); // previous epoch list
|
||||||
|
return wo.processed();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t JfrStringPool::flush() {
|
||||||
|
Thread* const thread = Thread::current();
|
||||||
|
WriteOperation wo(_chunkwriter, thread);
|
||||||
|
ExclusiveWriteOperation ewo(wo);
|
||||||
|
ReinitializationOperation rio;
|
||||||
|
WriteReinitializeOperation wro(&ewo, &rio);
|
||||||
|
assert(_mspace->free_list_is_empty(), "invariant");
|
||||||
|
assert(_mspace->live_list_is_nonempty(), "invariant");
|
||||||
|
process_live_list(wro, _mspace); // current epoch list
|
||||||
return wo.processed();
|
return wo.processed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,10 +217,10 @@ size_t JfrStringPool::clear() {
|
|||||||
DiscardOperation discard_operation;
|
DiscardOperation discard_operation;
|
||||||
ExclusiveDiscardOperation edo(discard_operation);
|
ExclusiveDiscardOperation edo(discard_operation);
|
||||||
assert(_mspace->free_list_is_empty(), "invariant");
|
assert(_mspace->free_list_is_empty(), "invariant");
|
||||||
ReleaseOperation ro(_mspace, _mspace->live_list());
|
ReleaseOperation ro(_mspace, _mspace->live_list(true)); // previous epoch list
|
||||||
DiscardReleaseOperation discard_op(&edo, &ro);
|
DiscardReleaseOperation discard_op(&edo, &ro);
|
||||||
assert(_mspace->live_list_is_nonempty(), "invariant");
|
assert(_mspace->live_list_is_nonempty(), "invariant");
|
||||||
process_live_list(discard_op, _mspace);
|
process_live_list(discard_op, _mspace, true); // previous epoch list
|
||||||
return discard_operation.processed();
|
return discard_operation.processed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -35,7 +35,7 @@ class JavaThread;
|
|||||||
class JfrChunkWriter;
|
class JfrChunkWriter;
|
||||||
class JfrStringPool;
|
class JfrStringPool;
|
||||||
|
|
||||||
typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStringPoolBuffer> > JfrStringPoolMspace;
|
typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStringPoolBuffer>, JfrLinkedList<JfrStringPoolBuffer>, true > JfrStringPoolMspace;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Although called JfrStringPool, a more succinct description would be
|
// Although called JfrStringPool, a more succinct description would be
|
||||||
@ -45,8 +45,10 @@ typedef JfrMemorySpace<JfrStringPool, JfrMspaceRetrieval, JfrLinkedList<JfrStrin
|
|||||||
//
|
//
|
||||||
class JfrStringPool : public JfrCHeapObj {
|
class JfrStringPool : public JfrCHeapObj {
|
||||||
public:
|
public:
|
||||||
size_t write();
|
|
||||||
size_t clear();
|
size_t clear();
|
||||||
|
size_t flush();
|
||||||
|
size_t write();
|
||||||
|
|
||||||
static jboolean add(jlong id, jstring string, JavaThread* jt);
|
static jboolean add(jlong id, jstring string, JavaThread* jt);
|
||||||
|
|
||||||
typedef JfrStringPoolMspace::Node Buffer;
|
typedef JfrStringPoolMspace::Node Buffer;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user