Thu, 20 Nov 2008 16:56:09 -0800
6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa
1 /*
2 * Copyright 1997-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 // A growable array.
27 /*************************************************************************/
28 /* */
29 /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
30 /* */
31 /* Should you use GrowableArrays to contain handles you must be certain */
32 /* the the GrowableArray does not outlive the HandleMark that contains */
33 /* the handles. Since GrowableArrays are typically resource allocated */
34 /* the following is an example of INCORRECT CODE, */
35 /* */
36 /* ResourceMark rm; */
37 /* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */
38 /* if (blah) { */
39 /* while (...) { */
40 /* HandleMark hm; */
41 /* ... */
42 /* Handle h(THREAD, some_oop); */
43 /* arr->append(h); */
44 /* } */
45 /* } */
46 /* if (arr->length() != 0 ) { */
47 /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */
48 /* ... */
49 /* } */
50 /* */
51 /* If the GrowableArrays you are creating is C_Heap allocated then it */
52 /* hould not old handles since the handles could trivially try and */
53 /* outlive their HandleMark. In some situations you might need to do */
54 /* this and it would be legal but be very careful and see if you can do */
55 /* the code in some other manner. */
56 /* */
57 /*************************************************************************/
59 // To call default constructor the placement operator new() is used.
60 // It should be empty (it only returns the passed void* pointer).
61 // The definition of placement operator new(size_t, void*) in the <new>.
63 #include <new>
65 // Need the correct linkage to call qsort without warnings
66 extern "C" {
67 typedef int (*_sort_Fn)(const void *, const void *);
68 }
70 class GenericGrowableArray : public ResourceObj {
71 protected:
72 int _len; // current length
73 int _max; // maximum length
74 Arena* _arena; // Indicates where allocation occurs:
75 // 0 means default ResourceArea
76 // 1 means on C heap
77 // otherwise, allocate in _arena
78 #ifdef ASSERT
79 int _nesting; // resource area nesting at creation
80 void set_nesting();
81 void check_nesting();
82 #else
83 #define set_nesting();
84 #define check_nesting();
85 #endif
87 // Where are we going to allocate memory?
88 bool on_C_heap() { return _arena == (Arena*)1; }
89 bool on_stack () { return _arena == NULL; }
90 bool on_arena () { return _arena > (Arena*)1; }
92 // This GA will use the resource stack for storage if c_heap==false,
93 // Else it will use the C heap. Use clear_and_deallocate to avoid leaks.
94 GenericGrowableArray(int initial_size, int initial_len, bool c_heap) {
95 _len = initial_len;
96 _max = initial_size;
97 assert(_len >= 0 && _len <= _max, "initial_len too big");
98 _arena = (c_heap ? (Arena*)1 : NULL);
99 set_nesting();
100 assert(!c_heap || allocated_on_C_heap(), "growable array must be on C heap if elements are");
101 }
103 // This GA will use the given arena for storage.
104 // Consider using new(arena) GrowableArray<T> to allocate the header.
105 GenericGrowableArray(Arena* arena, int initial_size, int initial_len) {
106 _len = initial_len;
107 _max = initial_size;
108 assert(_len >= 0 && _len <= _max, "initial_len too big");
109 _arena = arena;
110 assert(on_arena(), "arena has taken on reserved value 0 or 1");
111 }
113 void* raw_allocate(int elementSize);
115 // some uses pass the Thread explicitly for speed (4990299 tuning)
116 void* raw_allocate(Thread* thread, int elementSize) {
117 assert(on_stack(), "fast ResourceObj path only");
118 return (void*)resource_allocate_bytes(thread, elementSize * _max);
119 }
120 };
122 template<class E> class GrowableArray : public GenericGrowableArray {
123 private:
124 E* _data; // data array
126 void grow(int j);
127 void raw_at_put_grow(int i, const E& p, const E& fill);
128 void clear_and_deallocate();
129 public:
130 GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) {
131 _data = (E*)raw_allocate(thread, sizeof(E));
132 for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
133 }
135 GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) {
136 _data = (E*)raw_allocate(sizeof(E));
137 for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
138 }
140 GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false) : GenericGrowableArray(initial_size, initial_len, C_heap) {
141 _data = (E*)raw_allocate(sizeof(E));
142 int i = 0;
143 for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);
144 for (; i < _max; i++) ::new ((void*)&_data[i]) E();
145 }
147 GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) {
148 _data = (E*)raw_allocate(sizeof(E));
149 int i = 0;
150 for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);
151 for (; i < _max; i++) ::new ((void*)&_data[i]) E();
152 }
154 GrowableArray() : GenericGrowableArray(2, 0, false) {
155 _data = (E*)raw_allocate(sizeof(E));
156 ::new ((void*)&_data[0]) E();
157 ::new ((void*)&_data[1]) E();
158 }
160 // Does nothing for resource and arena objects
161 ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); }
163 void clear() { _len = 0; }
164 int length() const { return _len; }
165 void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; }
166 bool is_empty() const { return _len == 0; }
167 bool is_nonempty() const { return _len != 0; }
168 bool is_full() const { return _len == _max; }
169 DEBUG_ONLY(E* data_addr() const { return _data; })
171 void print();
173 int append(const E& elem) {
174 check_nesting();
175 if (_len == _max) grow(_len);
176 int idx = _len++;
177 _data[idx] = elem;
178 return idx;
179 }
181 void append_if_missing(const E& elem) {
182 if (!contains(elem)) append(elem);
183 }
185 E at(int i) const {
186 assert(0 <= i && i < _len, "illegal index");
187 return _data[i];
188 }
190 E* adr_at(int i) const {
191 assert(0 <= i && i < _len, "illegal index");
192 return &_data[i];
193 }
195 E first() const {
196 assert(_len > 0, "empty list");
197 return _data[0];
198 }
200 E top() const {
201 assert(_len > 0, "empty list");
202 return _data[_len-1];
203 }
205 void push(const E& elem) { append(elem); }
207 E pop() {
208 assert(_len > 0, "empty list");
209 return _data[--_len];
210 }
212 void at_put(int i, const E& elem) {
213 assert(0 <= i && i < _len, "illegal index");
214 _data[i] = elem;
215 }
217 E at_grow(int i, const E& fill = E()) {
218 assert(0 <= i, "negative index");
219 check_nesting();
220 if (i >= _len) {
221 if (i >= _max) grow(i);
222 for (int j = _len; j <= i; j++)
223 _data[j] = fill;
224 _len = i+1;
225 }
226 return _data[i];
227 }
229 void at_put_grow(int i, const E& elem, const E& fill = E()) {
230 assert(0 <= i, "negative index");
231 check_nesting();
232 raw_at_put_grow(i, elem, fill);
233 }
235 bool contains(const E& elem) const {
236 for (int i = 0; i < _len; i++) {
237 if (_data[i] == elem) return true;
238 }
239 return false;
240 }
242 int find(const E& elem) const {
243 for (int i = 0; i < _len; i++) {
244 if (_data[i] == elem) return i;
245 }
246 return -1;
247 }
249 int find(void* token, bool f(void*, E)) const {
250 for (int i = 0; i < _len; i++) {
251 if (f(token, _data[i])) return i;
252 }
253 return -1;
254 }
256 int find_at_end(void* token, bool f(void*, E)) const {
257 // start at the end of the array
258 for (int i = _len-1; i >= 0; i--) {
259 if (f(token, _data[i])) return i;
260 }
261 return -1;
262 }
264 void remove(const E& elem) {
265 for (int i = 0; i < _len; i++) {
266 if (_data[i] == elem) {
267 for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j];
268 _len--;
269 return;
270 }
271 }
272 ShouldNotReachHere();
273 }
275 void remove_at(int index) {
276 assert(0 <= index && index < _len, "illegal index");
277 for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j];
278 _len--;
279 }
281 void appendAll(const GrowableArray<E>* l) {
282 for (int i = 0; i < l->_len; i++) {
283 raw_at_put_grow(_len, l->_data[i], 0);
284 }
285 }
287 void sort(int f(E*,E*)) {
288 qsort(_data, length(), sizeof(E), (_sort_Fn)f);
289 }
290 // sort by fixed-stride sub arrays:
291 void sort(int f(E*,E*), int stride) {
292 qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f);
293 }
294 };
296 // Global GrowableArray methods (one instance in the library per each 'E' type).
298 template<class E> void GrowableArray<E>::grow(int j) {
299 // grow the array by doubling its size (amortized growth)
300 int old_max = _max;
301 if (_max == 0) _max = 1; // prevent endless loop
302 while (j >= _max) _max = _max*2;
303 // j < _max
304 E* newData = (E*)raw_allocate(sizeof(E));
305 int i = 0;
306 for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]);
307 for ( ; i < _max; i++) ::new ((void*)&newData[i]) E();
308 for (i = 0; i < old_max; i++) _data[i].~E();
309 if (on_C_heap() && _data != NULL) {
310 FreeHeap(_data);
311 }
312 _data = newData;
313 }
315 template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) {
316 if (i >= _len) {
317 if (i >= _max) grow(i);
318 for (int j = _len; j < i; j++)
319 _data[j] = fill;
320 _len = i+1;
321 }
322 _data[i] = p;
323 }
325 // This function clears and deallocate the data in the growable array that
326 // has been allocated on the C heap. It's not public - called by the
327 // destructor.
328 template<class E> void GrowableArray<E>::clear_and_deallocate() {
329 assert(on_C_heap(),
330 "clear_and_deallocate should only be called when on C heap");
331 clear();
332 if (_data != NULL) {
333 for (int i = 0; i < _max; i++) _data[i].~E();
334 FreeHeap(_data);
335 _data = NULL;
336 }
337 }
339 template<class E> void GrowableArray<E>::print() {
340 tty->print("Growable Array " INTPTR_FORMAT, this);
341 tty->print(": length %ld (_max %ld) { ", _len, _max);
342 for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
343 tty->print("}\n");
344 }