forked from openjdk/jdk
/
stringDedup.hpp
221 lines (194 loc) · 8.89 KB
/
stringDedup.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
#define SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
// String Deduplication
//
// String deduplication aims to reduce the heap live-set by modifying equal
// instances of java.lang.String so they share the same backing byte array
// (the String's value).
//
// The deduplication process is divided in two main parts, 1) finding the
// objects to deduplicate, and 2) deduplicating those objects.
//
// The first part is done as part of a normal GC cycle when objects are
// marked or evacuated. At this time a check is applied on each object to
// determine whether it is a candidate for deduplication. Candidates are
// added to the set of deduplication requests for later processing.
//
// The second part, processing the deduplication requests, is a concurrent
// phase. This phase is executed by the deduplication thread, which takes
// candidates from the set of requests and tries to deduplicate them.
//
// A deduplication table is used to keep track of unique byte arrays used by
// String objects. When deduplicating, a lookup is made in this table to
// see if there is already an equivalent byte array that was used by some
// other String. If so, the String object is adjusted to point to that byte
// array, and the original array is released, allowing it to eventually be
// garbage collected. If the lookup fails the byte array is instead
// inserted into the table so it can potentially be shared with other
// Strings in the future.
//
// The set of requests uses entries from a pair of weak OopStorage objects.
// One is used for requests, the other is being processed. When processing
// completes, the roles of the storage objects are exchanged. The GC adds
// entries referring to discovered candidates, allocating new OopStorage
// entries for the requests. The deduplication processing thread does a
// concurrent iteration over the processing storage, deduplicating the
// Strings and releasing the OopStorage entries. Two storage objects are
// used so there isn't any conflict between adding and removing entries by
// different threads.
//
// The deduplication table uses entries from another weak OopStorage to hold
// the byte arrays. This permits reclamation of arrays that become unused.
// This is separate from the request storage objects because dead count
// tracking is used by the table implementation as part of resizing
// decisions and for deciding when to cleanup dead entries in the table.
// The usage pattern for the table is also very different from that of the
// request storages. The request/processing storages are used in a way that
// supports bulk allocation and release of entries.
//
// Candidate selection criteria is GC specific. This class provides some
// helper functions that may be of use when implementing candidate
// selection.
//
// Strings interned in the StringTable require special handling. Once a
// String has been added to the StringTable, its byte array must not change.
// Doing so would counteract C2 optimizations on string literals. But an
// interned string might later become a deduplication candidate through the
// normal GC discovery mechanism. To prevent such modifications, the
// deduplication_forbidden flag of a String is set before interning it. A
// String with that flag set may have its byte array added to the
// deduplication table, but will not have its byte array replaced by a
// different but equivalent array from the table.
//
// A GC must opt-in to support string deduplication. This primarily involves
// making deduplication requests. As the GC is processing objects it must
// determine which are candidates for deduplication, and add those objects
// to StringDedup::Requests objects. Typically, each GC marking/evacuation
// thread has its own Requests object. Once liveness analysis is complete,
// but before weak reference processing, the GC should flush or delete all
// of its Requests objects.
//
// For additional information on string deduplication, please see JEP 192,
// http://openjdk.java.net/jeps/192
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "oops/oopsHierarchy.hpp"
#include "utilities/globalDefinitions.hpp"
class Klass;
class ThreadClosure;
// The StringDedup class provides the API for the deduplication mechanism.
// StringDedup::Requests and the StringDedup functions for candidate testing
// are all that a GC needs to use to support the string deduplication
// feature. Other functions in the StringDedup class are called where
// needed, without requiring GC-specific code.
class StringDedup : public AllStatic {
class Config;
class Processor;
class Stat;
class StorageUse;
class Table;
static bool _initialized;
static bool _enabled;
static Processor* _processor;
static Stat _cur_stat;
static Stat _total_stat;
static const Klass* _string_klass_or_null;
static uint _enabled_age_threshold;
static uint _enabled_age_limit;
public:
class Requests;
// Initialize and check command line arguments.
// Returns true if configuration is valid, false otherwise.
static bool ergo_initialize();
// Initialize deduplication if enabled by command line arguments.
static void initialize();
// Returns true if string deduplication is enabled.
static bool is_enabled() { return _enabled; }
// Stop the deduplication processor thread.
// precondition: is_enabled()
static void stop();
// Visit the deduplication processor thread.
// precondition: is_enabled()
static void threads_do(ThreadClosure* tc);
// Marks the String as not being subject to deduplication. This can be
// used to prevent deduplication of Strings whose value array must remain
// stable and cannot be replaced by a shared duplicate. Must be called
// before obtaining the value array; this function provides an acquire
// barrier.
// precondition: is_enabled()
// precondition: java_string is a Java String object.
static void forbid_deduplication(oop java_string);
// Notify that a String is being added to the StringTable.
// Implicity forbids deduplication of the String.
// precondition: is_enabled()
// precondition: java_string is a Java String object.
static void notify_intern(oop java_string);
// precondition: at safepoint
static void verify();
// Some predicates for use in testing whether an object is a candidate for
// deduplication. These functions combine an implicit is_enabled check
// with another check in a single comparison.
// Return true if k is String klass and deduplication is enabled.
static bool is_enabled_string(const Klass* k) {
return k == _string_klass_or_null;
}
// Return true if age == StringDeduplicationAgeThreshold and
// deduplication is enabled.
static bool is_threshold_age(uint age) {
// Threshold is from option if enabled, or an impossible value (exceeds
// markWord::max_age) if disabled.
return age == _enabled_age_threshold;
}
// Return true if age < StringDeduplicationAgeThreshold and
// deduplication is enabled.
static bool is_below_threshold_age(uint age) {
// Limit is from option if enabled, or 0 if disabled.
return age < _enabled_age_limit;
}
};
// GC requests for String deduplication.
//
// Each marking thread should have it's own Requests object. When marking
// is completed the Requests object must be flushed (either explicitly or by
// the destructor).
class StringDedup::Requests : public CHeapObj<mtGC> {
StorageUse* _storage_for_requests;
oop** _buffer;
size_t _index;
bool _refill_failed;
bool refill_buffer();
public:
Requests();
~Requests(); // Calls flush().
// Request deduplication of java_string.
// prerequisite: StringDedup::is_enabled()
// prerequisite: java_string is a Java String
void add(oop java_string);
// Flush any buffered deduplication requests and release resources
// used by this object.
void flush();
};
#endif // SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP