Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/utilities/growableArray.hpp
32285 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_VM_UTILITIES_GROWABLEARRAY_HPP25#define SHARE_VM_UTILITIES_GROWABLEARRAY_HPP2627#include "memory/allocation.hpp"28#include "memory/allocation.inline.hpp"29#include "utilities/debug.hpp"30#include "utilities/globalDefinitions.hpp"31#include "utilities/top.hpp"3233// A growable array.3435/*************************************************************************/36/* */37/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */38/* */39/* Should you use GrowableArrays to contain handles you must be certain */40/* the the GrowableArray does not outlive the HandleMark that contains */41/* the handles. Since GrowableArrays are typically resource allocated */42/* the following is an example of INCORRECT CODE, */43/* */44/* ResourceMark rm; */45/* GrowableArray<Handle>* arr = new GrowableArray<Handle>(size); */46/* if (blah) { */47/* while (...) { */48/* HandleMark hm; */49/* ... */50/* Handle h(THREAD, some_oop); */51/* arr->append(h); */52/* } */53/* } */54/* if (arr->length() != 0 ) { */55/* oop bad_oop = arr->at(0)(); // Handle is BAD HERE. */56/* ... */57/* } */58/* */59/* If the GrowableArrays you are creating is C_Heap allocated then it */60/* hould not old handles since the handles could trivially try and */61/* outlive their HandleMark. In some situations you might need to do */62/* this and it would be legal but be very careful and see if you can do */63/* the code in some other manner. */64/* */65/*************************************************************************/6667// To call default constructor the placement operator new() is used.68// It should be empty (it only returns the passed void* pointer).69// The definition of placement operator new(size_t, void*) in the <new>.7071#include <new>7273// Need the correct linkage to call qsort without warnings74extern "C" {75typedef int (*_sort_Fn)(const void *, const void *);76}7778class GenericGrowableArray : public ResourceObj {79friend class VMStructs;8081protected:82int _len; // current length83int _max; // maximum length84Arena* _arena; // Indicates where allocation occurs:85// 0 means default ResourceArea86// 1 means on C heap87// otherwise, allocate in _arena8889MEMFLAGS _memflags; // memory type if allocation in C heap9091#ifdef ASSERT92int _nesting; // resource area nesting at creation93void set_nesting();94void check_nesting();95#else96#define set_nesting();97#define check_nesting();98#endif99100// Where are we going to allocate memory?101bool on_C_heap() { return _arena == (Arena*)1; }102bool on_stack () { return _arena == NULL; }103bool on_arena () { return _arena > (Arena*)1; }104105// This GA will use the resource stack for storage if c_heap==false,106// Else it will use the C heap. Use clear_and_deallocate to avoid leaks.107GenericGrowableArray(int initial_size, int initial_len, bool c_heap, MEMFLAGS flags = mtNone) {108_len = initial_len;109_max = initial_size;110_memflags = flags;111112// memory type has to be specified for C heap allocation113assert(!(c_heap && flags == mtNone), "memory type not specified for C heap object");114115assert(_len >= 0 && _len <= _max, "initial_len too big");116_arena = (c_heap ? (Arena*)1 : NULL);117set_nesting();118assert(!on_C_heap() || allocated_on_C_heap(), "growable array must be on C heap if elements are");119assert(!on_stack() ||120(allocated_on_res_area() || allocated_on_stack()),121"growable array must be on stack if elements are not on arena and not on C heap");122}123124// This GA will use the given arena for storage.125// Consider using new(arena) GrowableArray<T> to allocate the header.126GenericGrowableArray(Arena* arena, int initial_size, int initial_len) {127_len = initial_len;128_max = initial_size;129assert(_len >= 0 && _len <= _max, "initial_len too big");130_arena = arena;131_memflags = mtNone;132133assert(on_arena(), "arena has taken on reserved value 0 or 1");134// Relax next assert to allow object allocation on resource area,135// on stack or embedded into an other object.136assert(allocated_on_arena() || allocated_on_stack(),137"growable array must be on arena or on stack if elements are on arena");138}139140void* raw_allocate(int elementSize);141142// some uses pass the Thread explicitly for speed (4990299 tuning)143void* raw_allocate(Thread* thread, int elementSize) {144assert(on_stack(), "fast ResourceObj path only");145return (void*)resource_allocate_bytes(thread, elementSize * _max);146}147};148149template<class E> class GrowableArrayIterator;150template<class E, class UnaryPredicate> class GrowableArrayFilterIterator;151152template<class E> class GrowableArray : public GenericGrowableArray {153friend class VMStructs;154155private:156E* _data; // data array157158void grow(int j);159void raw_at_put_grow(int i, const E& p, const E& fill);160void clear_and_deallocate();161public:162GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) {163_data = (E*)raw_allocate(thread, sizeof(E));164for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();165}166167GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal)168: GenericGrowableArray(initial_size, 0, C_heap, F) {169_data = (E*)raw_allocate(sizeof(E));170// Needed for Visual Studio 2012 and older171#ifdef _MSC_VER172#pragma warning(suppress: 4345)173#endif174for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();175}176177GrowableArray(int initial_size, int initial_len, const E& filler, bool C_heap = false, MEMFLAGS memflags = mtInternal)178: GenericGrowableArray(initial_size, initial_len, C_heap, memflags) {179_data = (E*)raw_allocate(sizeof(E));180int i = 0;181for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);182for (; i < _max; i++) ::new ((void*)&_data[i]) E();183}184185GrowableArray(Arena* arena, int initial_size, int initial_len, const E& filler) : GenericGrowableArray(arena, initial_size, initial_len) {186_data = (E*)raw_allocate(sizeof(E));187int i = 0;188for (; i < _len; i++) ::new ((void*)&_data[i]) E(filler);189for (; i < _max; i++) ::new ((void*)&_data[i]) E();190}191192GrowableArray() : GenericGrowableArray(2, 0, false) {193_data = (E*)raw_allocate(sizeof(E));194::new ((void*)&_data[0]) E();195::new ((void*)&_data[1]) E();196}197198// Does nothing for resource and arena objects199~GrowableArray() { if (on_C_heap()) clear_and_deallocate(); }200201void clear() { _len = 0; }202int length() const { return _len; }203int max_length() const { return _max; }204void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; }205bool is_empty() const { return _len == 0; }206bool is_nonempty() const { return _len != 0; }207bool is_full() const { return _len == _max; }208DEBUG_ONLY(E* data_addr() const { return _data; })209210void print();211212int append(const E& elem) {213check_nesting();214if (_len == _max) grow(_len);215int idx = _len++;216_data[idx] = elem;217return idx;218}219220bool append_if_missing(const E& elem) {221// Returns TRUE if elem is added.222bool missed = !contains(elem);223if (missed) append(elem);224return missed;225}226227E& at(int i) {228assert(0 <= i && i < _len, "illegal index");229return _data[i];230}231232E const& at(int i) const {233assert(0 <= i && i < _len, "illegal index");234return _data[i];235}236237E* adr_at(int i) const {238assert(0 <= i && i < _len, "illegal index");239return &_data[i];240}241242E first() const {243assert(_len > 0, "empty list");244return _data[0];245}246247E top() const {248assert(_len > 0, "empty list");249return _data[_len-1];250}251252GrowableArrayIterator<E> begin() const {253return GrowableArrayIterator<E>(this, 0);254}255256GrowableArrayIterator<E> end() const {257return GrowableArrayIterator<E>(this, length());258}259260void push(const E& elem) { append(elem); }261262E pop() {263assert(_len > 0, "empty list");264return _data[--_len];265}266267void at_put(int i, const E& elem) {268assert(0 <= i && i < _len, "illegal index");269_data[i] = elem;270}271272E at_grow(int i, const E& fill = E()) {273assert(0 <= i, "negative index");274check_nesting();275if (i >= _len) {276if (i >= _max) grow(i);277for (int j = _len; j <= i; j++)278_data[j] = fill;279_len = i+1;280}281return _data[i];282}283284void at_put_grow(int i, const E& elem, const E& fill = E()) {285assert(0 <= i, "negative index");286check_nesting();287raw_at_put_grow(i, elem, fill);288}289290bool contains(const E& elem) const {291for (int i = 0; i < _len; i++) {292if (_data[i] == elem) return true;293}294return false;295}296297int find(const E& elem) const {298for (int i = 0; i < _len; i++) {299if (_data[i] == elem) return i;300}301return -1;302}303304int find_from_end(const E& elem) const {305for (int i = _len-1; i >= 0; i--) {306if (_data[i] == elem) return i;307}308return -1;309}310311int find(void* token, bool f(void*, E)) const {312for (int i = 0; i < _len; i++) {313if (f(token, _data[i])) return i;314}315return -1;316}317318int find_from_end(void* token, bool f(void*, E)) const {319// start at the end of the array320for (int i = _len-1; i >= 0; i--) {321if (f(token, _data[i])) return i;322}323return -1;324}325326void remove(const E& elem) {327for (int i = 0; i < _len; i++) {328if (_data[i] == elem) {329for (int j = i + 1; j < _len; j++) _data[j-1] = _data[j];330_len--;331return;332}333}334ShouldNotReachHere();335}336337// The order is preserved.338void remove_at(int index) {339assert(0 <= index && index < _len, "illegal index");340for (int j = index + 1; j < _len; j++) _data[j-1] = _data[j];341_len--;342}343344// The order is changed.345void delete_at(int index) {346assert(0 <= index && index < _len, "illegal index");347if (index < --_len) {348// Replace removed element with last one.349_data[index] = _data[_len];350}351}352353// inserts the given element before the element at index i354void insert_before(const int idx, const E& elem) {355assert(0 <= idx && idx <= _len, "illegal index");356check_nesting();357if (_len == _max) grow(_len);358for (int j = _len - 1; j >= idx; j--) {359_data[j + 1] = _data[j];360}361_len++;362_data[idx] = elem;363}364365void appendAll(const GrowableArray<E>* l) {366for (int i = 0; i < l->_len; i++) {367raw_at_put_grow(_len, l->_data[i], E());368}369}370371void sort(int f(E*,E*)) {372qsort(_data, length(), sizeof(E), (_sort_Fn)f);373}374// sort by fixed-stride sub arrays:375void sort(int f(E*,E*), int stride) {376qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f);377}378379// Binary search and insertion utility. Search array for element380// matching key according to the static compare function. Insert381// that element is not already in the list. Assumes the list is382// already sorted according to compare function.383template <int compare(const E&, const E&)> E insert_sorted(const E& key) {384bool found;385int location = find_sorted<E, compare>(key, found);386if (!found) {387insert_before(location, key);388}389return at(location);390}391392template <typename K, int compare(const K&, const E&)> int find_sorted(const K& key, bool& found) {393found = false;394int min = 0;395int max = length() - 1;396397while (max >= min) {398int mid = (int)(((uint)max + min) / 2);399E value = at(mid);400int diff = compare(key, value);401if (diff > 0) {402min = mid + 1;403} else if (diff < 0) {404max = mid - 1;405} else {406found = true;407return mid;408}409}410return min;411}412};413414// Global GrowableArray methods (one instance in the library per each 'E' type).415416template<class E> void GrowableArray<E>::grow(int j) {417// grow the array by doubling its size (amortized growth)418int old_max = _max;419if (_max == 0) _max = 1; // prevent endless loop420while (j >= _max) _max = _max*2;421// j < _max422E* newData = (E*)raw_allocate(sizeof(E));423int i = 0;424for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]);425// Needed for Visual Studio 2012 and older426#ifdef _MSC_VER427#pragma warning(suppress: 4345)428#endif429for ( ; i < _max; i++) ::new ((void*)&newData[i]) E();430for (i = 0; i < old_max; i++) _data[i].~E();431if (on_C_heap() && _data != NULL) {432FreeHeap(_data);433}434_data = newData;435}436437template<class E> void GrowableArray<E>::raw_at_put_grow(int i, const E& p, const E& fill) {438if (i >= _len) {439if (i >= _max) grow(i);440for (int j = _len; j < i; j++)441_data[j] = fill;442_len = i+1;443}444_data[i] = p;445}446447// This function clears and deallocate the data in the growable array that448// has been allocated on the C heap. It's not public - called by the449// destructor.450template<class E> void GrowableArray<E>::clear_and_deallocate() {451assert(on_C_heap(),452"clear_and_deallocate should only be called when on C heap");453clear();454if (_data != NULL) {455for (int i = 0; i < _max; i++) _data[i].~E();456FreeHeap(_data);457_data = NULL;458}459}460461template<class E> void GrowableArray<E>::print() {462tty->print("Growable Array " INTPTR_FORMAT, this);463tty->print(": length %ld (_max %ld) { ", _len, _max);464for (int i = 0; i < _len; i++) tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));465tty->print("}\n");466}467468// Custom STL-style iterator to iterate over GrowableArrays469// It is constructed by invoking GrowableArray::begin() and GrowableArray::end()470template<class E> class GrowableArrayIterator : public StackObj {471friend class GrowableArray<E>;472template<class F, class UnaryPredicate> friend class GrowableArrayFilterIterator;473474private:475const GrowableArray<E>* _array; // GrowableArray we iterate over476int _position; // The current position in the GrowableArray477478// Private constructor used in GrowableArray::begin() and GrowableArray::end()479GrowableArrayIterator(const GrowableArray<E>* array, int position) : _array(array), _position(position) {480assert(0 <= position && position <= _array->length(), "illegal position");481}482483public:484GrowableArrayIterator<E>& operator++() { ++_position; return *this; }485E operator*() { return _array->at(_position); }486487bool operator==(const GrowableArrayIterator<E>& rhs) {488assert(_array == rhs._array, "iterator belongs to different array");489return _position == rhs._position;490}491492bool operator!=(const GrowableArrayIterator<E>& rhs) {493assert(_array == rhs._array, "iterator belongs to different array");494return _position != rhs._position;495}496};497498// Custom STL-style iterator to iterate over elements of a GrowableArray that satisfy a given predicate499template<class E, class UnaryPredicate> class GrowableArrayFilterIterator : public StackObj {500friend class GrowableArray<E>;501502private:503const GrowableArray<E>* _array; // GrowableArray we iterate over504int _position; // Current position in the GrowableArray505UnaryPredicate _predicate; // Unary predicate the elements of the GrowableArray should satisfy506507public:508GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate)509: _array(begin._array), _position(begin._position), _predicate(filter_predicate) {510// Advance to first element satisfying the predicate511while(_position != _array->length() && !_predicate(_array->at(_position))) {512++_position;513}514}515516GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() {517do {518// Advance to next element satisfying the predicate519++_position;520} while(_position != _array->length() && !_predicate(_array->at(_position)));521return *this;522}523524E operator*() { return _array->at(_position); }525526bool operator==(const GrowableArrayIterator<E>& rhs) {527assert(_array == rhs._array, "iterator belongs to different array");528return _position == rhs._position;529}530531bool operator!=(const GrowableArrayIterator<E>& rhs) {532assert(_array == rhs._array, "iterator belongs to different array");533return _position != rhs._position;534}535536bool operator==(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {537assert(_array == rhs._array, "iterator belongs to different array");538return _position == rhs._position;539}540541bool operator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs) {542assert(_array == rhs._array, "iterator belongs to different array");543return _position != rhs._position;544}545};546547#endif // SHARE_VM_UTILITIES_GROWABLEARRAY_HPP548549550