src/share/vm/utilities/growableArray.hpp

Thu, 20 Nov 2008 16:56:09 -0800

author
ysr
date
Thu, 20 Nov 2008 16:56:09 -0800
changeset 888
c96030fff130
parent 867
275a3b7ff0d6
child 905
ad8c8ca4ab0f
permissions
-rw-r--r--

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 }

mercurial