Skip to content

Commit 604225f

Browse files
committed
8354954: Typed static memory for late initialization of static class members in Hotspot
Reviewed-by: qamai, kbarrett, jvernee
1 parent 69d0f7a commit 604225f

File tree

5 files changed

+88
-10
lines changed

5 files changed

+88
-10
lines changed

src/hotspot/share/nmt/memTracker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "runtime/vmThread.hpp"
4242
#include "utilities/debug.hpp"
4343
#include "utilities/defaultStream.hpp"
44+
#include "utilities/deferred.hpp"
4445
#include "utilities/vmError.hpp"
4546

4647
#ifdef _WINDOWS
@@ -49,7 +50,7 @@
4950

5051
NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown;
5152

52-
MemBaseline MemTracker::_baseline;
53+
Deferred<MemBaseline> MemTracker::_baseline;
5354

5455
bool MemTracker::NmtVirtualMemoryLocker::_safe_to_use;
5556

@@ -67,6 +68,7 @@ void MemTracker::initialize() {
6768
STATIC_ASSERT(mt_number_of_tags <= max_jubyte);
6869

6970
if (level > NMT_off) {
71+
_baseline.initialize();
7072
if (!MallocTracker::initialize(level) ||
7173
!MemoryFileTracker::Instance::initialize(level) ||
7274
!VirtualMemoryTracker::initialize(level)) {

src/hotspot/share/nmt/memTracker.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,21 @@
2727

2828
#include "memory/reservedSpace.hpp"
2929
#include "nmt/mallocTracker.hpp"
30+
#include "nmt/memBaseline.hpp"
3031
#include "nmt/nmtCommon.hpp"
3132
#include "nmt/memoryFileTracker.hpp"
3233
#include "nmt/threadStackTracker.hpp"
3334
#include "nmt/virtualMemoryTracker.hpp"
3435
#include "runtime/mutexLocker.hpp"
3536
#include "utilities/debug.hpp"
3637
#include "utilities/nativeCallStack.hpp"
38+
#include "utilities/deferred.hpp"
3739

3840
#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail) ? \
3941
NativeCallStack(0) : FAKE_CALLSTACK)
4042
#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail) ? \
4143
NativeCallStack(1) : FAKE_CALLSTACK)
4244

43-
class MemBaseline;
44-
4545
class MemTracker : AllStatic {
4646
friend class VirtualMemoryTrackerTest;
4747

@@ -266,7 +266,7 @@ class MemTracker : AllStatic {
266266

267267
// Stored baseline
268268
static inline MemBaseline& get_baseline() {
269-
return _baseline;
269+
return *_baseline;
270270
}
271271

272272
static void tuning_statistics(outputStream* out);
@@ -319,7 +319,7 @@ class MemTracker : AllStatic {
319319
// Tracking level
320320
static NMT_TrackingLevel _tracking_level;
321321
// Stored baseline
322-
static MemBaseline _baseline;
322+
static Deferred<MemBaseline> _baseline;
323323
};
324324

325325
#endif // SHARE_NMT_MEMTRACKER_HPP

src/hotspot/share/nmt/memoryFileTracker.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include "utilities/nativeCallStack.hpp"
3333
#include "utilities/ostream.hpp"
3434

35-
MemoryFileTracker* MemoryFileTracker::Instance::_tracker = nullptr;
35+
Deferred<MemoryFileTracker> MemoryFileTracker::Instance::_tracker;
3636

3737
MemoryFileTracker::MemoryFileTracker(bool is_detailed_mode)
3838
: _stack_storage(is_detailed_mode), _files() {}
@@ -126,9 +126,8 @@ const GrowableArrayCHeap<MemoryFileTracker::MemoryFile*, mtNMT>& MemoryFileTrack
126126

127127
bool MemoryFileTracker::Instance::initialize(NMT_TrackingLevel tracking_level) {
128128
if (tracking_level == NMT_TrackingLevel::NMT_off) return true;
129-
_tracker = static_cast<MemoryFileTracker*>(os::malloc(sizeof(MemoryFileTracker), mtNMT));
130-
if (_tracker == nullptr) return false;
131-
new (_tracker) MemoryFileTracker(tracking_level == NMT_TrackingLevel::NMT_detail);
129+
bool is_detailed_mode = tracking_level == NMT_TrackingLevel::NMT_detail;
130+
_tracker.initialize(is_detailed_mode);
132131
return true;
133132
}
134133

src/hotspot/share/nmt/memoryFileTracker.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "utilities/growableArray.hpp"
3535
#include "utilities/nativeCallStack.hpp"
3636
#include "utilities/ostream.hpp"
37+
#include "utilities/deferred.hpp"
3738

3839
// The MemoryFileTracker tracks memory of 'memory files',
3940
// storage with its own memory space separate from the process.
@@ -91,7 +92,7 @@ class MemoryFileTracker {
9192
const GrowableArrayCHeap<MemoryFile*, mtNMT>& files();
9293

9394
class Instance : public AllStatic {
94-
static MemoryFileTracker* _tracker;
95+
static Deferred<MemoryFileTracker> _tracker;
9596

9697
public:
9798

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#ifndef SHARE_UTILITIES_STABLEVALUE_HPP
26+
#define SHARE_UTILITIES_STABLEVALUE_HPP
27+
28+
#include "globalDefinitions.hpp"
29+
#include <type_traits>
30+
31+
// The purpose of this class is to defer initialization of a T to a later point in time,
32+
// and then to never deallocate it. This is mainly useful for deferring the initialization of
33+
// static fields in classes, in order to avoid "Static Initialization Order Fiasco".
34+
template<typename T>
35+
class Deferred {
36+
union {
37+
T _t;
38+
};
39+
40+
DEBUG_ONLY(bool _initialized);
41+
42+
public:
43+
NONCOPYABLE(Deferred);
44+
45+
Deferred()
46+
DEBUG_ONLY(: _initialized(false)) {
47+
// Do not construct value, on purpose.
48+
}
49+
50+
~Deferred() {
51+
// Do not destruct value, on purpose.
52+
}
53+
54+
T* get() {
55+
assert(_initialized, "must be initialized before access");
56+
return &_t;
57+
}
58+
59+
T& operator*() {
60+
return *get();
61+
}
62+
63+
T* operator->() {
64+
return get();
65+
}
66+
67+
template<typename... Ts>
68+
void initialize(Ts&... args) {
69+
assert(!_initialized, "Double initialization forbidden");
70+
DEBUG_ONLY(_initialized = true);
71+
using NCVP = std::add_pointer_t<std::remove_cv_t<T>>;
72+
::new (const_cast<NCVP>(get())) T(args...);
73+
}
74+
};
75+
76+
#endif // SHARE_UTILITIES_STABLEVALUE_HPP

0 commit comments

Comments
 (0)