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
duke@435 | 1 | /* |
duke@435 | 2 | * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. |
duke@435 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@435 | 4 | * |
duke@435 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@435 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@435 | 7 | * published by the Free Software Foundation. |
duke@435 | 8 | * |
duke@435 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@435 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@435 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@435 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@435 | 13 | * accompanied this code). |
duke@435 | 14 | * |
duke@435 | 15 | * You should have received a copy of the GNU General Public License version |
duke@435 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@435 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@435 | 18 | * |
duke@435 | 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
duke@435 | 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
duke@435 | 21 | * have any questions. |
duke@435 | 22 | * |
duke@435 | 23 | */ |
duke@435 | 24 | |
duke@435 | 25 | // A growable array. |
duke@435 | 26 | |
duke@435 | 27 | /*************************************************************************/ |
duke@435 | 28 | /* */ |
duke@435 | 29 | /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ |
duke@435 | 30 | /* */ |
duke@435 | 31 | /* Should you use GrowableArrays to contain handles you must be certain */ |
duke@435 | 32 | /* the the GrowableArray does not outlive the HandleMark that contains */ |
duke@435 | 33 | /* the handles. Since GrowableArrays are typically resource allocated */ |
duke@435 | 34 | /* the following is an example of INCORRECT CODE, */ |
duke@435 | 35 | /* */ |
duke@435 | 36 | /* ResourceMark rm; */ |
duke@435 | 37 | /* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */ |
duke@435 | 38 | /* if (blah) { */ |
duke@435 | 39 | /* while (...) { */ |
duke@435 | 40 | /* HandleMark hm; */ |
duke@435 | 41 | /* ... */ |
duke@435 | 42 | /* Handle h(THREAD, some_oop); */ |
duke@435 | 43 | /* arr->append(h); */ |
duke@435 | 44 | /* } */ |
duke@435 | 45 | /* } */ |
duke@435 | 46 | /* if (arr->length() != 0 ) { */ |
duke@435 | 47 | /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */ |
duke@435 | 48 | /* ... */ |
duke@435 | 49 | /* } */ |
duke@435 | 50 | /* */ |
duke@435 | 51 | /* If the GrowableArrays you are creating is C_Heap allocated then it */ |
duke@435 | 52 | /* hould not old handles since the handles could trivially try and */ |
duke@435 | 53 | /* outlive their HandleMark. In some situations you might need to do */ |
duke@435 | 54 | /* this and it would be legal but be very careful and see if you can do */ |
duke@435 | 55 | /* the code in some other manner. */ |
duke@435 | 56 | /* */ |
duke@435 | 57 | /*************************************************************************/ |
duke@435 | 58 | |
duke@435 | 59 | // To call default constructor the placement operator new() is used. |
duke@435 | 60 | // It should be empty (it only returns the passed void* pointer). |
duke@435 | 61 | // The definition of placement operator new(size_t, void*) in the <new>. |
duke@435 | 62 | |
duke@435 | 63 | #include <new> |
duke@435 | 64 | |
duke@435 | 65 | // Need the correct linkage to call qsort without warnings |
duke@435 | 66 | extern "C" { |
duke@435 | 67 | typedef int (*_sort_Fn)(const void *, const void *); |
duke@435 | 68 | } |
duke@435 | 69 | |
duke@435 | 70 | class GenericGrowableArray : public ResourceObj { |
duke@435 | 71 | protected: |
duke@435 | 72 | int _len; // current length |
duke@435 | 73 | int _max; // maximum length |
duke@435 | 74 | Arena* _arena; // Indicates where allocation occurs: |
duke@435 | 75 | // 0 means default ResourceArea |
duke@435 | 76 | // 1 means on C heap |
duke@435 | 77 | // otherwise, allocate in _arena |
duke@435 | 78 | #ifdef ASSERT |
duke@435 | 79 | int _nesting; // resource area nesting at creation |
duke@435 | 80 | void set_nesting(); |
duke@435 | 81 | void check_nesting(); |
duke@435 | 82 | #else |
duke@435 | 83 | #define set_nesting(); |
duke@435 | 84 | #define check_nesting(); |
duke@435 | 85 | #endif |
duke@435 | 86 | |
duke@435 | 87 | // Where are we going to allocate memory? |
duke@435 | 88 | bool on_C_heap() { return _arena == (Arena*)1; } |
duke@435 | 89 | bool on_stack () { return _arena == NULL; } |
duke@435 | 90 | bool on_arena () { return _arena > (Arena*)1; } |
duke@435 | 91 | |
duke@435 | 92 | // This GA will use the resource stack for storage if c_heap==false, |
duke@435 | 93 | // Else it will use the C heap. Use clear_and_deallocate to avoid leaks. |
duke@435 | 94 | GenericGrowableArray(int initial_size, int initial_len, bool c_heap) { |
duke@435 | 95 | _len = initial_len; |
duke@435 | 96 | _max = initial_size; |
duke@435 | 97 | assert(_len >= 0 && _len <= _max, "initial_len too big"); |
duke@435 | 98 | _arena = (c_heap ? (Arena*)1 : NULL); |
duke@435 | 99 | set_nesting(); |
duke@435 | 100 | assert(!c_heap || allocated_on_C_heap(), "growable array must be on C heap if elements are"); |
duke@435 | 101 | } |
duke@435 | 102 | |
duke@435 | 103 | // This GA will use the given arena for storage. |
duke@435 | 104 | // Consider using new(arena) GrowableArray<T> to allocate the header. |
duke@435 | 105 | GenericGrowableArray(Arena* arena, int initial_size, int initial_len) { |
duke@435 | 106 | _len = initial_len; |
duke@435 | 107 | _max = initial_size; |
duke@435 | 108 | assert(_len >= 0 && _len <= _max, "initial_len too big"); |
duke@435 | 109 | _arena = arena; |
duke@435 | 110 | assert(on_arena(), "arena has taken on reserved value 0 or 1"); |
duke@435 | 111 | } |
duke@435 | 112 | |
duke@435 | 113 | void* raw_allocate(int elementSize); |
jrose@867 | 114 | |
jrose@867 | 115 | // some uses pass the Thread explicitly for speed (4990299 tuning) |
jrose@867 | 116 | void* raw_allocate(Thread* thread, int elementSize) { |
jrose@867 | 117 | assert(on_stack(), "fast ResourceObj path only"); |
jrose@867 | 118 | return (void*)resource_allocate_bytes(thread, elementSize * _max); |
jrose@867 | 119 | } |
duke@435 | 120 | }; |
duke@435 | 121 | |
duke@435 | 122 | template<class E> class GrowableArray : public GenericGrowableArray { |
duke@435 | 123 | private: |
duke@435 | 124 | E* _data; // data array |
duke@435 | 125 | |
duke@435 | 126 | void grow(int j); |
duke@435 | 127 | void raw_at_put_grow(int i, const E& p, const E& fill); |
duke@435 | 128 | void clear_and_deallocate(); |
duke@435 | 129 | public: |
jrose@867 | 130 | GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) { |
jrose@867 | 131 | _data = (E*)raw_allocate(thread, sizeof(E)); |
jrose@867 | 132 | for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); |
jrose@867 | 133 | } |
jrose@867 | 134 | |
duke@435 | 135 | GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) { |
duke@435 | 136 | _data = (E*)raw_allocate(sizeof(E)); |
duke@435 | 137 | for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); |
duke@435 | 138 | } |
duke@435 | 139 | |
duke@435 | 140 | GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false) : GenericGrowableArray(initial_size, initial_len, C_heap) { |
duke@435 | 141 | _data = (E*)raw_allocate(sizeof(E)); |
duke@435 | 142 | int i = 0; |
duke@435 | 143 | for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); |
duke@435 | 144 | for (; i < _max; i++) ::new ((void*)&_data[i]) E(); |
duke@435 | 145 | } |
duke@435 | 146 | |
duke@435 | 147 | GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) { |
duke@435 | 148 | _data = (E*)raw_allocate(sizeof(E)); |
duke@435 | 149 | int i = 0; |
duke@435 | 150 | for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); |
duke@435 | 151 | for (; i < _max; i++) ::new ((void*)&_data[i]) E(); |
duke@435 | 152 | } |
duke@435 | 153 | |
duke@435 | 154 | GrowableArray() : GenericGrowableArray(2, 0, false) { |
duke@435 | 155 | _data = (E*)raw_allocate(sizeof(E)); |
duke@435 | 156 | ::new ((void*)&_data[0]) E(); |
duke@435 | 157 | ::new ((void*)&_data[1]) E(); |
duke@435 | 158 | } |
duke@435 | 159 | |
duke@435 | 160 | // Does nothing for resource and arena objects |
duke@435 | 161 | ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); } |
duke@435 | 162 | |
duke@435 | 163 | void clear() { _len = 0; } |
duke@435 | 164 | int length() const { return _len; } |
duke@435 | 165 | void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; } |
duke@435 | 166 | bool is_empty() const { return _len == 0; } |
duke@435 | 167 | bool is_nonempty() const { return _len != 0; } |
duke@435 | 168 | bool is_full() const { return _len == _max; } |
duke@435 | 169 | DEBUG_ONLY(E* data_addr() const { return _data; }) |
duke@435 | 170 | |
duke@435 | 171 | void print(); |
duke@435 | 172 | |
jrose@867 | 173 | int append(const E& elem) { |
duke@435 | 174 | check_nesting(); |
duke@435 | 175 | if (_len == _max) grow(_len); |
jrose@867 | 176 | int idx = _len++; |
jrose@867 | 177 | _data[idx] = elem; |
jrose@867 | 178 | return idx; |
duke@435 | 179 | } |
duke@435 | 180 | |
duke@435 | 181 | void append_if_missing(const E& elem) { |
duke@435 | 182 | if (!contains(elem)) append(elem); |
duke@435 | 183 | } |
duke@435 | 184 | |
duke@435 | 185 | E at(int i) const { |
duke@435 | 186 | assert(0 <= i && i < _len, "illegal index"); |
duke@435 | 187 | return _data[i]; |
duke@435 | 188 | } |
duke@435 | 189 | |
duke@435 | 190 | E* adr_at(int i) const { |
duke@435 | 191 | assert(0 <= i && i < _len, "illegal index"); |
duke@435 | 192 | return &_data[i]; |
duke@435 | 193 | } |
duke@435 | 194 | |
duke@435 | 195 | E first() const { |
duke@435 | 196 | assert(_len > 0, "empty list"); |
duke@435 | 197 | return _data[0]; |
duke@435 | 198 | } |
duke@435 | 199 | |
duke@435 | 200 | E top() const { |
duke@435 | 201 | assert(_len > 0, "empty list"); |
duke@435 | 202 | return _data[_len-1]; |
duke@435 | 203 | } |
duke@435 | 204 | |
duke@435 | 205 | void push(const E& elem) { append(elem); } |
duke@435 | 206 | |
duke@435 | 207 | E pop() { |
duke@435 | 208 | assert(_len > 0, "empty list"); |
duke@435 | 209 | return _data[--_len]; |
duke@435 | 210 | } |
duke@435 | 211 | |
duke@435 | 212 | void at_put(int i, const E& elem) { |
duke@435 | 213 | assert(0 <= i && i < _len, "illegal index"); |
duke@435 | 214 | _data[i] = elem; |
duke@435 | 215 | } |
duke@435 | 216 | |
duke@435 | 217 | E at_grow(int i, const E& fill = E()) { |
duke@435 | 218 | assert(0 <= i, "negative index"); |
duke@435 | 219 | check_nesting(); |
duke@435 | 220 | if (i >= _len) { |
duke@435 | 221 | if (i >= _max) grow(i); |
duke@435 | 222 | for (int j = _len; j <= i; j++) |
duke@435 | 223 | _data[j] = fill; |
duke@435 | 224 | _len = i+1; |
duke@435 | 225 | } |
duke@435 | 226 | return _data[i]; |
duke@435 | 227 | } |
duke@435 | 228 | |
duke@435 | 229 | void at_put_grow(int i, const E& elem, const E& fill = E()) { |
duke@435 | 230 | assert(0 <= i, "negative index"); |
duke@435 | 231 | check_nesting(); |
duke@435 | 232 | raw_at_put_grow(i, elem, fill); |
duke@435 | 233 | } |
duke@435 | 234 | |
duke@435 | 235 | bool contains(const E& elem) const { |
duke@435 | 236 | for (int i = 0; i < _len; i++) { |
duke@435 | 237 | if (_data[i] == elem) return true; |
duke@435 | 238 | } |
duke@435 | 239 | return false; |
duke@435 | 240 | } |
duke@435 | 241 | |
duke@435 | 242 | int find(const E& elem) const { |
duke@435 | 243 | for (int i = 0; i < _len; i++) { |
duke@435 | 244 | if (_data[i] == elem) return i; |
duke@435 | 245 | } |
duke@435 | 246 | return -1; |
duke@435 | 247 | } |
duke@435 | 248 | |
duke@435 | 249 | int find(void* token, bool f(void*, E)) const { |
duke@435 | 250 | for (int i = 0; i < _len; i++) { |
duke@435 | 251 | if (f(token, _data[i])) return i; |
duke@435 | 252 | } |
duke@435 | 253 | return -1; |
duke@435 | 254 | } |
duke@435 | 255 | |
duke@435 | 256 | int find_at_end(void* token, bool f(void*, E)) const { |
duke@435 | 257 | // start at the end of the array |
duke@435 | 258 | for (int i = _len-1; i >= 0; i--) { |
duke@435 | 259 | if (f(token, _data[i])) return i; |
duke@435 | 260 | } |
duke@435 | 261 | return -1; |
duke@435 | 262 | } |
duke@435 | 263 | |
duke@435 | 264 | void remove(const E& elem) { |
duke@435 | 265 | for (int i = 0; i < _len; i++) { |
duke@435 | 266 | if (_data[i] == elem) { |
duke@435 | 267 | for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j]; |
duke@435 | 268 | _len--; |
duke@435 | 269 | return; |
duke@435 | 270 | } |
duke@435 | 271 | } |
duke@435 | 272 | ShouldNotReachHere(); |
duke@435 | 273 | } |
duke@435 | 274 | |
duke@435 | 275 | void remove_at(int index) { |
duke@435 | 276 | assert(0 <= index && index < _len, "illegal index"); |
duke@435 | 277 | for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j]; |
duke@435 | 278 | _len--; |
duke@435 | 279 | } |
duke@435 | 280 | |
duke@435 | 281 | void appendAll(const GrowableArray<E>* l) { |
duke@435 | 282 | for (int i = 0; i < l->_len; i++) { |
duke@435 | 283 | raw_at_put_grow(_len, l->_data[i], 0); |
duke@435 | 284 | } |
duke@435 | 285 | } |
duke@435 | 286 | |
duke@435 | 287 | void sort(int f(E*,E*)) { |
duke@435 | 288 | qsort(_data, length(), sizeof(E), (_sort_Fn)f); |
duke@435 | 289 | } |
duke@435 | 290 | // sort by fixed-stride sub arrays: |
duke@435 | 291 | void sort(int f(E*,E*), int stride) { |
duke@435 | 292 | qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); |
duke@435 | 293 | } |
duke@435 | 294 | }; |
duke@435 | 295 | |
duke@435 | 296 | // Global GrowableArray methods (one instance in the library per each 'E' type). |
duke@435 | 297 | |
duke@435 | 298 | template<class E> void GrowableArray<E>::grow(int j) { |
duke@435 | 299 | // grow the array by doubling its size (amortized growth) |
duke@435 | 300 | int old_max = _max; |
duke@435 | 301 | if (_max == 0) _max = 1; // prevent endless loop |
duke@435 | 302 | while (j >= _max) _max = _max*2; |
duke@435 | 303 | // j < _max |
duke@435 | 304 | E* newData = (E*)raw_allocate(sizeof(E)); |
duke@435 | 305 | int i = 0; |
duke@435 | 306 | for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]); |
duke@435 | 307 | for ( ; i < _max; i++) ::new ((void*)&newData[i]) E(); |
duke@435 | 308 | for (i = 0; i < old_max; i++) _data[i].~E(); |
duke@435 | 309 | if (on_C_heap() && _data != NULL) { |
duke@435 | 310 | FreeHeap(_data); |
duke@435 | 311 | } |
duke@435 | 312 | _data = newData; |
duke@435 | 313 | } |
duke@435 | 314 | |
duke@435 | 315 | template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) { |
duke@435 | 316 | if (i >= _len) { |
duke@435 | 317 | if (i >= _max) grow(i); |
duke@435 | 318 | for (int j = _len; j < i; j++) |
duke@435 | 319 | _data[j] = fill; |
duke@435 | 320 | _len = i+1; |
duke@435 | 321 | } |
duke@435 | 322 | _data[i] = p; |
duke@435 | 323 | } |
duke@435 | 324 | |
duke@435 | 325 | // This function clears and deallocate the data in the growable array that |
duke@435 | 326 | // has been allocated on the C heap. It's not public - called by the |
duke@435 | 327 | // destructor. |
duke@435 | 328 | template<class E> void GrowableArray<E>::clear_and_deallocate() { |
duke@435 | 329 | assert(on_C_heap(), |
duke@435 | 330 | "clear_and_deallocate should only be called when on C heap"); |
duke@435 | 331 | clear(); |
duke@435 | 332 | if (_data != NULL) { |
duke@435 | 333 | for (int i = 0; i < _max; i++) _data[i].~E(); |
duke@435 | 334 | FreeHeap(_data); |
duke@435 | 335 | _data = NULL; |
duke@435 | 336 | } |
duke@435 | 337 | } |
duke@435 | 338 | |
duke@435 | 339 | template<class E> void GrowableArray<E>::print() { |
duke@435 | 340 | tty->print("Growable Array " INTPTR_FORMAT, this); |
duke@435 | 341 | tty->print(": length %ld (_max %ld) { ", _len, _max); |
duke@435 | 342 | for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i])); |
duke@435 | 343 | tty->print("}\n"); |
duke@435 | 344 | } |