duke@435: /* mikael@6198: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_UTILITIES_GROWABLEARRAY_HPP stefank@2314: #define SHARE_VM_UTILITIES_GROWABLEARRAY_HPP stefank@2314: stefank@2314: #include "memory/allocation.hpp" stefank@2314: #include "memory/allocation.inline.hpp" stefank@2314: #include "utilities/debug.hpp" stefank@2314: #include "utilities/globalDefinitions.hpp" stefank@2314: #include "utilities/top.hpp" stefank@2314: duke@435: // A growable array. duke@435: duke@435: /*************************************************************************/ duke@435: /* */ duke@435: /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ duke@435: /* */ duke@435: /* Should you use GrowableArrays to contain handles you must be certain */ duke@435: /* the the GrowableArray does not outlive the HandleMark that contains */ duke@435: /* the handles. Since GrowableArrays are typically resource allocated */ duke@435: /* the following is an example of INCORRECT CODE, */ duke@435: /* */ duke@435: /* ResourceMark rm; */ duke@435: /* GrowableArray* arr = new GrowableArray(size); */ duke@435: /* if (blah) { */ duke@435: /* while (...) { */ duke@435: /* HandleMark hm; */ duke@435: /* ... */ duke@435: /* Handle h(THREAD, some_oop); */ duke@435: /* arr->append(h); */ duke@435: /* } */ duke@435: /* } */ duke@435: /* if (arr->length() != 0 ) { */ duke@435: /* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */ duke@435: /* ... */ duke@435: /* } */ duke@435: /* */ duke@435: /* If the GrowableArrays you are creating is C_Heap allocated then it */ duke@435: /* hould not old handles since the handles could trivially try and */ duke@435: /* outlive their HandleMark. In some situations you might need to do */ duke@435: /* this and it would be legal but be very careful and see if you can do */ duke@435: /* the code in some other manner. */ duke@435: /* */ duke@435: /*************************************************************************/ duke@435: duke@435: // To call default constructor the placement operator new() is used. duke@435: // It should be empty (it only returns the passed void* pointer). duke@435: // The definition of placement operator new(size_t, void*) in the . duke@435: duke@435: #include duke@435: duke@435: // Need the correct linkage to call qsort without warnings duke@435: extern "C" { duke@435: typedef int (*_sort_Fn)(const void *, const void *); duke@435: } duke@435: duke@435: class GenericGrowableArray : public ResourceObj { never@3138: friend class VMStructs; never@3138: duke@435: protected: duke@435: int _len; // current length duke@435: int _max; // maximum length duke@435: Arena* _arena; // Indicates where allocation occurs: duke@435: // 0 means default ResourceArea duke@435: // 1 means on C heap duke@435: // otherwise, allocate in _arena zgu@3900: zgu@3900: MEMFLAGS _memflags; // memory type if allocation in C heap zgu@3900: duke@435: #ifdef ASSERT duke@435: int _nesting; // resource area nesting at creation duke@435: void set_nesting(); duke@435: void check_nesting(); duke@435: #else duke@435: #define set_nesting(); duke@435: #define check_nesting(); duke@435: #endif duke@435: duke@435: // Where are we going to allocate memory? duke@435: bool on_C_heap() { return _arena == (Arena*)1; } duke@435: bool on_stack () { return _arena == NULL; } duke@435: bool on_arena () { return _arena > (Arena*)1; } duke@435: duke@435: // This GA will use the resource stack for storage if c_heap==false, duke@435: // Else it will use the C heap. Use clear_and_deallocate to avoid leaks. zgu@3900: GenericGrowableArray(int initial_size, int initial_len, bool c_heap, MEMFLAGS flags = mtNone) { duke@435: _len = initial_len; duke@435: _max = initial_size; zgu@3900: _memflags = flags; zgu@3900: zgu@3900: // memory type has to be specified for C heap allocation zgu@3900: assert(!(c_heap && flags == mtNone), "memory type not specified for C heap object"); zgu@3900: duke@435: assert(_len >= 0 && _len <= _max, "initial_len too big"); duke@435: _arena = (c_heap ? (Arena*)1 : NULL); duke@435: set_nesting(); kvn@2040: assert(!on_C_heap() || allocated_on_C_heap(), "growable array must be on C heap if elements are"); kvn@2040: assert(!on_stack() || kvn@2040: (allocated_on_res_area() || allocated_on_stack()), kvn@2040: "growable array must be on stack if elements are not on arena and not on C heap"); duke@435: } duke@435: duke@435: // This GA will use the given arena for storage. duke@435: // Consider using new(arena) GrowableArray to allocate the header. duke@435: GenericGrowableArray(Arena* arena, int initial_size, int initial_len) { duke@435: _len = initial_len; duke@435: _max = initial_size; duke@435: assert(_len >= 0 && _len <= _max, "initial_len too big"); duke@435: _arena = arena; zgu@3900: _memflags = mtNone; zgu@3900: duke@435: assert(on_arena(), "arena has taken on reserved value 0 or 1"); kvn@2040: // Relax next assert to allow object allocation on resource area, kvn@2040: // on stack or embedded into an other object. kvn@2040: assert(allocated_on_arena() || allocated_on_stack(), kvn@2040: "growable array must be on arena or on stack if elements are on arena"); duke@435: } duke@435: duke@435: void* raw_allocate(int elementSize); jrose@867: jrose@867: // some uses pass the Thread explicitly for speed (4990299 tuning) jrose@867: void* raw_allocate(Thread* thread, int elementSize) { jrose@867: assert(on_stack(), "fast ResourceObj path only"); jrose@867: return (void*)resource_allocate_bytes(thread, elementSize * _max); jrose@867: } duke@435: }; duke@435: anoll@7028: template class GrowableArrayIterator; anoll@7028: template class GrowableArrayFilterIterator; anoll@7028: duke@435: template class GrowableArray : public GenericGrowableArray { never@3138: friend class VMStructs; never@3138: duke@435: private: duke@435: E* _data; // data array duke@435: duke@435: void grow(int j); duke@435: void raw_at_put_grow(int i, const E& p, const E& fill); duke@435: void clear_and_deallocate(); duke@435: public: jrose@867: GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) { jrose@867: _data = (E*)raw_allocate(thread, sizeof(E)); jrose@867: for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); jrose@867: } jrose@867: zgu@3900: GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal) zgu@3900: : GenericGrowableArray(initial_size, 0, C_heap, F) { duke@435: _data = (E*)raw_allocate(sizeof(E)); duke@435: for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); duke@435: } duke@435: zgu@3900: GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false, MEMFLAGS memflags = mtInternal) zgu@3900: : GenericGrowableArray(initial_size, initial_len, C_heap, memflags) { duke@435: _data = (E*)raw_allocate(sizeof(E)); duke@435: int i = 0; duke@435: for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); duke@435: for (; i < _max; i++) ::new ((void*)&_data[i]) E(); duke@435: } duke@435: duke@435: GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) { duke@435: _data = (E*)raw_allocate(sizeof(E)); duke@435: int i = 0; duke@435: for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler); duke@435: for (; i < _max; i++) ::new ((void*)&_data[i]) E(); duke@435: } duke@435: duke@435: GrowableArray() : GenericGrowableArray(2, 0, false) { duke@435: _data = (E*)raw_allocate(sizeof(E)); duke@435: ::new ((void*)&_data[0]) E(); duke@435: ::new ((void*)&_data[1]) E(); duke@435: } duke@435: duke@435: // Does nothing for resource and arena objects duke@435: ~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); } duke@435: duke@435: void clear() { _len = 0; } duke@435: int length() const { return _len; } johnc@5548: int max_length() const { return _max; } duke@435: void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; } duke@435: bool is_empty() const { return _len == 0; } duke@435: bool is_nonempty() const { return _len != 0; } duke@435: bool is_full() const { return _len == _max; } duke@435: DEBUG_ONLY(E* data_addr() const { return _data; }) duke@435: duke@435: void print(); duke@435: jrose@867: int append(const E& elem) { duke@435: check_nesting(); duke@435: if (_len == _max) grow(_len); jrose@867: int idx = _len++; jrose@867: _data[idx] = elem; jrose@867: return idx; duke@435: } duke@435: kvn@3651: bool append_if_missing(const E& elem) { kvn@3651: // Returns TRUE if elem is added. kvn@3651: bool missed = !contains(elem); kvn@3651: if (missed) append(elem); kvn@3651: return missed; duke@435: } duke@435: kamg@4245: E& at(int i) { kamg@4245: assert(0 <= i && i < _len, "illegal index"); kamg@4245: return _data[i]; kamg@4245: } kamg@4245: kamg@4245: E const& at(int i) const { duke@435: assert(0 <= i && i < _len, "illegal index"); duke@435: return _data[i]; duke@435: } duke@435: duke@435: E* adr_at(int i) const { duke@435: assert(0 <= i && i < _len, "illegal index"); duke@435: return &_data[i]; duke@435: } duke@435: duke@435: E first() const { duke@435: assert(_len > 0, "empty list"); duke@435: return _data[0]; duke@435: } duke@435: duke@435: E top() const { duke@435: assert(_len > 0, "empty list"); duke@435: return _data[_len-1]; duke@435: } duke@435: anoll@7028: GrowableArrayIterator begin() const { anoll@7028: return GrowableArrayIterator(this, 0); anoll@7028: } anoll@7028: anoll@7028: GrowableArrayIterator end() const { anoll@7028: return GrowableArrayIterator(this, length()); anoll@7028: } anoll@7028: duke@435: void push(const E& elem) { append(elem); } duke@435: duke@435: E pop() { duke@435: assert(_len > 0, "empty list"); duke@435: return _data[--_len]; duke@435: } duke@435: duke@435: void at_put(int i, const E& elem) { duke@435: assert(0 <= i && i < _len, "illegal index"); duke@435: _data[i] = elem; duke@435: } duke@435: duke@435: E at_grow(int i, const E& fill = E()) { duke@435: assert(0 <= i, "negative index"); duke@435: check_nesting(); duke@435: if (i >= _len) { duke@435: if (i >= _max) grow(i); duke@435: for (int j = _len; j <= i; j++) duke@435: _data[j] = fill; duke@435: _len = i+1; duke@435: } duke@435: return _data[i]; duke@435: } duke@435: duke@435: void at_put_grow(int i, const E& elem, const E& fill = E()) { duke@435: assert(0 <= i, "negative index"); duke@435: check_nesting(); duke@435: raw_at_put_grow(i, elem, fill); duke@435: } duke@435: duke@435: bool contains(const E& elem) const { duke@435: for (int i = 0; i < _len; i++) { duke@435: if (_data[i] == elem) return true; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: int find(const E& elem) const { duke@435: for (int i = 0; i < _len; i++) { duke@435: if (_data[i] == elem) return i; duke@435: } duke@435: return -1; duke@435: } duke@435: coleenp@4037: int find_from_end(const E& elem) const { coleenp@4037: for (int i = _len-1; i >= 0; i--) { coleenp@4037: if (_data[i] == elem) return i; coleenp@4037: } coleenp@4037: return -1; coleenp@4037: } coleenp@4037: duke@435: int find(void* token, bool f(void*, E)) const { duke@435: for (int i = 0; i < _len; i++) { duke@435: if (f(token, _data[i])) return i; duke@435: } duke@435: return -1; duke@435: } duke@435: coleenp@4037: int find_from_end(void* token, bool f(void*, E)) const { duke@435: // start at the end of the array duke@435: for (int i = _len-1; i >= 0; i--) { duke@435: if (f(token, _data[i])) return i; duke@435: } duke@435: return -1; duke@435: } duke@435: duke@435: void remove(const E& elem) { duke@435: for (int i = 0; i < _len; i++) { duke@435: if (_data[i] == elem) { duke@435: for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j]; duke@435: _len--; duke@435: return; duke@435: } duke@435: } duke@435: ShouldNotReachHere(); duke@435: } duke@435: kvn@3651: // The order is preserved. duke@435: void remove_at(int index) { duke@435: assert(0 <= index && index < _len, "illegal index"); duke@435: for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j]; duke@435: _len--; duke@435: } duke@435: kvn@3651: // The order is changed. kvn@3651: void delete_at(int index) { kvn@3651: assert(0 <= index && index < _len, "illegal index"); kvn@3651: if (index < --_len) { kvn@3651: // Replace removed element with last one. kvn@3651: _data[index] = _data[_len]; kvn@3651: } kvn@3651: } kvn@3651: never@1515: // inserts the given element before the element at index i never@1515: void insert_before(const int idx, const E& elem) { roland@7041: assert(0 <= idx && idx <= _len, "illegal index"); never@1515: check_nesting(); never@1515: if (_len == _max) grow(_len); never@1515: for (int j = _len - 1; j >= idx; j--) { never@1515: _data[j + 1] = _data[j]; never@1515: } never@1515: _len++; never@1515: _data[idx] = elem; never@1515: } never@1515: duke@435: void appendAll(const GrowableArray* l) { duke@435: for (int i = 0; i < l->_len; i++) { roland@7041: raw_at_put_grow(_len, l->_data[i], E()); duke@435: } duke@435: } duke@435: duke@435: void sort(int f(E*,E*)) { duke@435: qsort(_data, length(), sizeof(E), (_sort_Fn)f); duke@435: } duke@435: // sort by fixed-stride sub arrays: duke@435: void sort(int f(E*,E*), int stride) { duke@435: qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); duke@435: } duke@435: }; duke@435: duke@435: // Global GrowableArray methods (one instance in the library per each 'E' type). duke@435: duke@435: template void GrowableArray::grow(int j) { duke@435: // grow the array by doubling its size (amortized growth) duke@435: int old_max = _max; duke@435: if (_max == 0) _max = 1; // prevent endless loop duke@435: while (j >= _max) _max = _max*2; duke@435: // j < _max duke@435: E* newData = (E*)raw_allocate(sizeof(E)); duke@435: int i = 0; duke@435: for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]); duke@435: for ( ; i < _max; i++) ::new ((void*)&newData[i]) E(); duke@435: for (i = 0; i < old_max; i++) _data[i].~E(); duke@435: if (on_C_heap() && _data != NULL) { duke@435: FreeHeap(_data); duke@435: } duke@435: _data = newData; duke@435: } duke@435: duke@435: template void GrowableArray::raw_at_put_grow(int i, const E& p, const E& fill) { duke@435: if (i >= _len) { duke@435: if (i >= _max) grow(i); duke@435: for (int j = _len; j < i; j++) duke@435: _data[j] = fill; duke@435: _len = i+1; duke@435: } duke@435: _data[i] = p; duke@435: } duke@435: duke@435: // This function clears and deallocate the data in the growable array that duke@435: // has been allocated on the C heap. It's not public - called by the duke@435: // destructor. duke@435: template void GrowableArray::clear_and_deallocate() { duke@435: assert(on_C_heap(), duke@435: "clear_and_deallocate should only be called when on C heap"); duke@435: clear(); duke@435: if (_data != NULL) { duke@435: for (int i = 0; i < _max; i++) _data[i].~E(); duke@435: FreeHeap(_data); duke@435: _data = NULL; duke@435: } duke@435: } duke@435: duke@435: template void GrowableArray::print() { duke@435: tty->print("Growable Array " INTPTR_FORMAT, this); duke@435: tty->print(": length %ld (_max %ld) { ", _len, _max); duke@435: for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i])); duke@435: tty->print("}\n"); duke@435: } stefank@2314: anoll@7028: // Custom STL-style iterator to iterate over GrowableArrays anoll@7028: // It is constructed by invoking GrowableArray::begin() and GrowableArray::end() anoll@7028: template class GrowableArrayIterator : public StackObj { anoll@7028: friend class GrowableArray; anoll@7028: template friend class GrowableArrayFilterIterator; anoll@7028: anoll@7028: private: anoll@7028: const GrowableArray* _array; // GrowableArray we iterate over anoll@7028: int _position; // The current position in the GrowableArray anoll@7028: anoll@7028: // Private constructor used in GrowableArray::begin() and GrowableArray::end() anoll@7028: GrowableArrayIterator(const GrowableArray* array, int position) : _array(array), _position(position) { anoll@7028: assert(0 <= position && position <= _array->length(), "illegal position"); anoll@7028: } anoll@7028: anoll@7028: public: anoll@7028: GrowableArrayIterator& operator++() { ++_position; return *this; } anoll@7028: E operator*() { return _array->at(_position); } anoll@7028: anoll@7028: bool operator==(const GrowableArrayIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position == rhs._position; anoll@7028: } anoll@7028: anoll@7028: bool operator!=(const GrowableArrayIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position != rhs._position; anoll@7028: } anoll@7028: }; anoll@7028: anoll@7028: // Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate anoll@7028: template class GrowableArrayFilterIterator : public StackObj { anoll@7028: friend class GrowableArray; anoll@7028: anoll@7028: private: anoll@7028: const GrowableArray* _array; // GrowableArray we iterate over anoll@7028: int _position; // Current position in the GrowableArray anoll@7028: UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy anoll@7028: anoll@7028: public: anoll@7028: GrowableArrayFilterIterator(const GrowableArrayIterator& begin, UnaryPredicate filter_predicate) anoll@7028: : _array(begin._array), _position(begin._position), _predicate(filter_predicate) { anoll@7028: // Advance to first element satisfying the predicate anoll@7028: while(_position != _array->length() && !_predicate(_array->at(_position))) { anoll@7028: ++_position; anoll@7028: } anoll@7028: } anoll@7028: anoll@7028: GrowableArrayFilterIterator& operator++() { anoll@7028: do { anoll@7028: // Advance to next element satisfying the predicate anoll@7028: ++_position; anoll@7028: } while(_position != _array->length() && !_predicate(_array->at(_position))); anoll@7028: return *this; anoll@7028: } anoll@7028: anoll@7028: E operator*() { return _array->at(_position); } anoll@7028: anoll@7028: bool operator==(const GrowableArrayIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position == rhs._position; anoll@7028: } anoll@7028: anoll@7028: bool operator!=(const GrowableArrayIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position != rhs._position; anoll@7028: } anoll@7028: anoll@7028: bool operator==(const GrowableArrayFilterIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position == rhs._position; anoll@7028: } anoll@7028: anoll@7028: bool operator!=(const GrowableArrayFilterIterator& rhs) { anoll@7028: assert(_array == rhs._array, "iterator belongs to different array"); anoll@7028: return _position != rhs._position; anoll@7028: } anoll@7028: }; anoll@7028: stefank@2314: #endif // SHARE_VM_UTILITIES_GROWABLEARRAY_HPP