mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8295808: GrowableArray should support capacity management
Reviewed-by: aboldtch, tschatzl, sspitsyn
This commit is contained in:
parent
6289600fe8
commit
3a873d3c5b
8 changed files with 176 additions and 105 deletions
|
@ -1902,7 +1902,7 @@ void GraphBuilder::check_args_for_profiling(Values* obj_args, int expected) {
|
||||||
bool ignored_will_link;
|
bool ignored_will_link;
|
||||||
ciSignature* declared_signature = NULL;
|
ciSignature* declared_signature = NULL;
|
||||||
ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
|
ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
|
||||||
assert(expected == obj_args->max_length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
|
assert(expected == obj_args->capacity() || real_target->is_method_handle_intrinsic(), "missed on arg?");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1913,7 +1913,7 @@ Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target,
|
||||||
if (obj_args == NULL) {
|
if (obj_args == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int s = obj_args->max_length();
|
int s = obj_args->capacity();
|
||||||
// if called through method handle invoke, some arguments may have been popped
|
// if called through method handle invoke, some arguments may have been popped
|
||||||
for (int i = start, j = 0; j < s && i < args->length(); i++) {
|
for (int i = start, j = 0; j < s && i < args->length(); i++) {
|
||||||
if (args->at(i)->type()->is_object_kind()) {
|
if (args->at(i)->type()->is_object_kind()) {
|
||||||
|
@ -3968,9 +3968,9 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, bool ign
|
||||||
int start = 0;
|
int start = 0;
|
||||||
Values* obj_args = args_list_for_profiling(callee, start, has_receiver);
|
Values* obj_args = args_list_for_profiling(callee, start, has_receiver);
|
||||||
if (obj_args != NULL) {
|
if (obj_args != NULL) {
|
||||||
int s = obj_args->max_length();
|
int s = obj_args->capacity();
|
||||||
// if called through method handle invoke, some arguments may have been popped
|
// if called through method handle invoke, some arguments may have been popped
|
||||||
for (int i = args_base+start, j = 0; j < obj_args->max_length() && i < state()->stack_size(); ) {
|
for (int i = args_base+start, j = 0; j < obj_args->capacity() && i < state()->stack_size(); ) {
|
||||||
Value v = state()->stack_at_inc(i);
|
Value v = state()->stack_at_inc(i);
|
||||||
if (v->type()->is_object_kind()) {
|
if (v->type()->is_object_kind()) {
|
||||||
obj_args->push(v);
|
obj_args->push(v);
|
||||||
|
|
|
@ -56,10 +56,11 @@
|
||||||
// the vectors. The size of the table is the size of either vector.
|
// the vectors. The size of the table is the size of either vector.
|
||||||
//
|
//
|
||||||
// The capacity of the vectors is explicitly controlled, based on the size.
|
// The capacity of the vectors is explicitly controlled, based on the size.
|
||||||
// Given N > 0 and 2^N <= size < 2^(N+1), then capacity = 2^N + k * 2^(N-1)
|
// Given N > 0 and 2^N <= size < 2^(N+1), then capacity <= 2^N + k * 2^(N-1)
|
||||||
// for the smallest integer k in [0,2] such that size <= capacity. That is,
|
// for the smallest integer k in [0,2] such that size <= capacity. That is,
|
||||||
// use a power of 2 or the midpoint between consecutive powers of 2 that is
|
// use a power of 2 or the midpoint between consecutive powers of 2 that is
|
||||||
// minimally at least size.
|
// minimally at least size. When adding an entry and the capacity has been
|
||||||
|
// reached, capacity is increased to the next of those values.
|
||||||
//
|
//
|
||||||
// The main benefit of this representation is that it uses less space than a
|
// The main benefit of this representation is that it uses less space than a
|
||||||
// more traditional linked-list of entry nodes representation. Such a
|
// more traditional linked-list of entry nodes representation. Such a
|
||||||
|
@ -89,12 +90,11 @@ class StringDedup::Table::Bucket {
|
||||||
GrowableArrayCHeap<uint, mtStringDedup> _hashes;
|
GrowableArrayCHeap<uint, mtStringDedup> _hashes;
|
||||||
GrowableArrayCHeap<TableValue, mtStringDedup> _values;
|
GrowableArrayCHeap<TableValue, mtStringDedup> _values;
|
||||||
|
|
||||||
void adjust_capacity(int new_capacity);
|
|
||||||
void expand_if_full();
|
void expand_if_full();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// precondition: reserve == 0 or is the result of needed_capacity.
|
// precondition: reserve == 0 or is the result of needed_capacity.
|
||||||
Bucket(int reserve = 0);
|
explicit Bucket(int reserve = 0);
|
||||||
|
|
||||||
~Bucket() {
|
~Bucket() {
|
||||||
while (!_values.is_empty()) {
|
while (!_values.is_empty()) {
|
||||||
|
@ -107,7 +107,7 @@ public:
|
||||||
const GrowableArrayView<uint>& hashes() const { return _hashes; }
|
const GrowableArrayView<uint>& hashes() const { return _hashes; }
|
||||||
const GrowableArrayView<TableValue>& values() const { return _values; }
|
const GrowableArrayView<TableValue>& values() const { return _values; }
|
||||||
|
|
||||||
bool is_empty() const { return _hashes.length() == 0; }
|
bool is_empty() const { return _hashes.is_empty(); }
|
||||||
int length() const { return _hashes.length(); }
|
int length() const { return _hashes.length(); }
|
||||||
|
|
||||||
void add(uint hash_code, TableValue value) {
|
void add(uint hash_code, TableValue value) {
|
||||||
|
@ -150,33 +150,17 @@ int StringDedup::Table::Bucket::needed_capacity(int needed) {
|
||||||
return (needed <= low) ? low : high;
|
return (needed <= low) ? low : high;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringDedup::Table::Bucket::adjust_capacity(int new_capacity) {
|
|
||||||
GrowableArrayCHeap<uint, mtStringDedup> new_hashes{new_capacity};
|
|
||||||
GrowableArrayCHeap<TableValue, mtStringDedup> new_values{new_capacity};
|
|
||||||
while (!_hashes.is_empty()) {
|
|
||||||
new_hashes.push(_hashes.pop());
|
|
||||||
new_values.push(_values.pop());
|
|
||||||
}
|
|
||||||
_hashes.swap(&new_hashes);
|
|
||||||
_values.swap(&new_values);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringDedup::Table::Bucket::expand_if_full() {
|
void StringDedup::Table::Bucket::expand_if_full() {
|
||||||
if (_hashes.length() == _hashes.max_length()) {
|
if (_hashes.is_full()) {
|
||||||
adjust_capacity(needed_capacity(_hashes.max_length() + 1));
|
int needed = needed_capacity(_hashes.capacity() + 1);
|
||||||
|
_hashes.reserve(needed);
|
||||||
|
_values.reserve(needed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringDedup::Table::Bucket::shrink() {
|
void StringDedup::Table::Bucket::shrink() {
|
||||||
if (_hashes.is_empty()) {
|
_hashes.shrink_to_fit();
|
||||||
_hashes.clear_and_deallocate();
|
_values.shrink_to_fit();
|
||||||
_values.clear_and_deallocate();
|
|
||||||
} else {
|
|
||||||
int target = needed_capacity(_hashes.length());
|
|
||||||
if (target < _hashes.max_length()) {
|
|
||||||
adjust_capacity(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringDedup::Table::TableValue
|
StringDedup::Table::TableValue
|
||||||
|
|
|
@ -256,7 +256,7 @@ static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array
|
||||||
false,
|
false,
|
||||||
true, // a DcmdFramework "option"
|
true, // a DcmdFramework "option"
|
||||||
false);
|
false);
|
||||||
for (int i = 0; i < array->max_length(); ++i) {
|
for (int i = 0; i < array->capacity(); ++i) {
|
||||||
array->append(dummy);
|
array->append(dummy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,7 +487,7 @@
|
||||||
/*******************/ \
|
/*******************/ \
|
||||||
\
|
\
|
||||||
nonstatic_field(GrowableArrayBase, _len, int) \
|
nonstatic_field(GrowableArrayBase, _len, int) \
|
||||||
nonstatic_field(GrowableArrayBase, _max, int) \
|
nonstatic_field(GrowableArrayBase, _capacity, int) \
|
||||||
nonstatic_field(GrowableArray<int>, _data, int*) \
|
nonstatic_field(GrowableArray<int>, _data, int*) \
|
||||||
\
|
\
|
||||||
/********************************/ \
|
/********************************/ \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -76,23 +76,23 @@ protected:
|
||||||
// Current number of accessible elements
|
// Current number of accessible elements
|
||||||
int _len;
|
int _len;
|
||||||
// Current number of allocated elements
|
// Current number of allocated elements
|
||||||
int _max;
|
int _capacity;
|
||||||
|
|
||||||
GrowableArrayBase(int initial_max, int initial_len) :
|
GrowableArrayBase(int capacity, int initial_len) :
|
||||||
_len(initial_len),
|
_len(initial_len),
|
||||||
_max(initial_max) {
|
_capacity(capacity) {
|
||||||
assert(_len >= 0 && _len <= _max, "initial_len too big");
|
assert(_len >= 0 && _len <= _capacity, "initial_len too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
~GrowableArrayBase() {}
|
~GrowableArrayBase() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int length() const { return _len; }
|
int length() const { return _len; }
|
||||||
int max_length() const { return _max; }
|
int capacity() const { return _capacity; }
|
||||||
|
|
||||||
bool is_empty() const { return _len == 0; }
|
bool is_empty() const { return _len == 0; }
|
||||||
bool is_nonempty() const { return _len != 0; }
|
bool is_nonempty() const { return _len != 0; }
|
||||||
bool is_full() const { return _len == _max; }
|
bool is_full() const { return _len == _capacity; }
|
||||||
|
|
||||||
void clear() { _len = 0; }
|
void clear() { _len = 0; }
|
||||||
void trunc_to(int length) {
|
void trunc_to(int length) {
|
||||||
|
@ -118,8 +118,8 @@ class GrowableArrayView : public GrowableArrayBase {
|
||||||
protected:
|
protected:
|
||||||
E* _data; // data array
|
E* _data; // data array
|
||||||
|
|
||||||
GrowableArrayView<E>(E* data, int initial_max, int initial_len) :
|
GrowableArrayView<E>(E* data, int capacity, int initial_len) :
|
||||||
GrowableArrayBase(initial_max, initial_len), _data(data) {}
|
GrowableArrayBase(capacity, initial_len), _data(data) {}
|
||||||
|
|
||||||
~GrowableArrayView() {}
|
~GrowableArrayView() {}
|
||||||
|
|
||||||
|
@ -157,12 +157,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
E first() const {
|
E first() const {
|
||||||
assert(_len > 0, "empty list");
|
assert(_len > 0, "empty");
|
||||||
return _data[0];
|
return _data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
E top() const {
|
E top() const {
|
||||||
assert(_len > 0, "empty list");
|
assert(_len > 0, "empty");
|
||||||
return _data[_len-1];
|
return _data[_len-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ public:
|
||||||
|
|
||||||
void print() const {
|
void print() const {
|
||||||
tty->print("Growable Array " PTR_FORMAT, p2i(this));
|
tty->print("Growable Array " PTR_FORMAT, p2i(this));
|
||||||
tty->print(": length %d (_max %d) { ", _len, _max);
|
tty->print(": length %d (capacity %d) { ", _len, _capacity);
|
||||||
for (int i = 0; i < _len; i++) {
|
for (int i = 0; i < _len; i++) {
|
||||||
tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
|
tty->print(INTPTR_FORMAT " ", *(intptr_t*)&(_data[i]));
|
||||||
}
|
}
|
||||||
|
@ -360,23 +360,24 @@ template <typename E, typename Derived>
|
||||||
class GrowableArrayWithAllocator : public GrowableArrayView<E> {
|
class GrowableArrayWithAllocator : public GrowableArrayView<E> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
|
|
||||||
|
void expand_to(int j);
|
||||||
void grow(int j);
|
void grow(int j);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GrowableArrayWithAllocator(E* data, int initial_max) :
|
GrowableArrayWithAllocator(E* data, int capacity) :
|
||||||
GrowableArrayView<E>(data, initial_max, 0) {
|
GrowableArrayView<E>(data, capacity, 0) {
|
||||||
for (int i = 0; i < initial_max; i++) {
|
for (int i = 0; i < capacity; i++) {
|
||||||
::new ((void*)&data[i]) E();
|
::new ((void*)&data[i]) E();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GrowableArrayWithAllocator(E* data, int initial_max, int initial_len, const E& filler) :
|
GrowableArrayWithAllocator(E* data, int capacity, int initial_len, const E& filler) :
|
||||||
GrowableArrayView<E>(data, initial_max, initial_len) {
|
GrowableArrayView<E>(data, capacity, initial_len) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < initial_len; i++) {
|
for (; i < initial_len; i++) {
|
||||||
::new ((void*)&data[i]) E(filler);
|
::new ((void*)&data[i]) E(filler);
|
||||||
}
|
}
|
||||||
for (; i < initial_max; i++) {
|
for (; i < capacity; i++) {
|
||||||
::new ((void*)&data[i]) E();
|
::new ((void*)&data[i]) E();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +386,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int append(const E& elem) {
|
int append(const E& elem) {
|
||||||
if (this->_len == this->_max) grow(this->_len);
|
if (this->_len == this->_capacity) grow(this->_len);
|
||||||
int idx = this->_len++;
|
int idx = this->_len++;
|
||||||
this->_data[idx] = elem;
|
this->_data[idx] = elem;
|
||||||
return idx;
|
return idx;
|
||||||
|
@ -403,7 +404,7 @@ public:
|
||||||
E at_grow(int i, const E& fill = E()) {
|
E at_grow(int i, const E& fill = E()) {
|
||||||
assert(0 <= i, "negative index");
|
assert(0 <= i, "negative index");
|
||||||
if (i >= this->_len) {
|
if (i >= this->_len) {
|
||||||
if (i >= this->_max) grow(i);
|
if (i >= this->_capacity) grow(i);
|
||||||
for (int j = this->_len; j <= i; j++)
|
for (int j = this->_len; j <= i; j++)
|
||||||
this->_data[j] = fill;
|
this->_data[j] = fill;
|
||||||
this->_len = i+1;
|
this->_len = i+1;
|
||||||
|
@ -414,7 +415,7 @@ public:
|
||||||
void at_put_grow(int i, const E& elem, const E& fill = E()) {
|
void at_put_grow(int i, const E& elem, const E& fill = E()) {
|
||||||
assert(0 <= i, "negative index");
|
assert(0 <= i, "negative index");
|
||||||
if (i >= this->_len) {
|
if (i >= this->_len) {
|
||||||
if (i >= this->_max) grow(i);
|
if (i >= this->_capacity) grow(i);
|
||||||
for (int j = this->_len; j < i; j++)
|
for (int j = this->_len; j < i; j++)
|
||||||
this->_data[j] = fill;
|
this->_data[j] = fill;
|
||||||
this->_len = i+1;
|
this->_len = i+1;
|
||||||
|
@ -425,7 +426,7 @@ public:
|
||||||
// inserts the given element before the element at index i
|
// inserts the given element before the element at index i
|
||||||
void insert_before(const int idx, const E& elem) {
|
void insert_before(const int idx, const E& elem) {
|
||||||
assert(0 <= idx && idx <= this->_len, "illegal index");
|
assert(0 <= idx && idx <= this->_len, "illegal index");
|
||||||
if (this->_len == this->_max) grow(this->_len);
|
if (this->_len == this->_capacity) grow(this->_len);
|
||||||
for (int j = this->_len - 1; j >= idx; j--) {
|
for (int j = this->_len - 1; j >= idx; j--) {
|
||||||
this->_data[j + 1] = this->_data[j];
|
this->_data[j + 1] = this->_data[j];
|
||||||
}
|
}
|
||||||
|
@ -437,7 +438,7 @@ public:
|
||||||
assert(0 <= idx && idx <= this->_len, "illegal index");
|
assert(0 <= idx && idx <= this->_len, "illegal index");
|
||||||
int array_len = array->length();
|
int array_len = array->length();
|
||||||
int new_len = this->_len + array_len;
|
int new_len = this->_len + array_len;
|
||||||
if (new_len >= this->_max) grow(new_len);
|
if (new_len >= this->_capacity) grow(new_len);
|
||||||
|
|
||||||
for (int j = this->_len - 1; j >= idx; j--) {
|
for (int j = this->_len - 1; j >= idx; j--) {
|
||||||
this->_data[j + array_len] = this->_data[j];
|
this->_data[j + array_len] = this->_data[j];
|
||||||
|
@ -481,40 +482,80 @@ public:
|
||||||
void swap(GrowableArrayWithAllocator<E, Derived>* other) {
|
void swap(GrowableArrayWithAllocator<E, Derived>* other) {
|
||||||
::swap(this->_data, other->_data);
|
::swap(this->_data, other->_data);
|
||||||
::swap(this->_len, other->_len);
|
::swap(this->_len, other->_len);
|
||||||
::swap(this->_max, other->_max);
|
::swap(this->_capacity, other->_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure capacity is at least new_capacity.
|
||||||
|
void reserve(int new_capacity);
|
||||||
|
|
||||||
|
// Reduce capacity to length.
|
||||||
|
void shrink_to_fit();
|
||||||
|
|
||||||
void clear_and_deallocate();
|
void clear_and_deallocate();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename E, typename Derived>
|
template <typename E, typename Derived>
|
||||||
void GrowableArrayWithAllocator<E, Derived>::grow(int j) {
|
void GrowableArrayWithAllocator<E, Derived>::expand_to(int new_capacity) {
|
||||||
int old_max = this->_max;
|
int old_capacity = this->_capacity;
|
||||||
// grow the array by increasing _max to the first power of two larger than the size we need
|
assert(new_capacity > old_capacity,
|
||||||
this->_max = next_power_of_2((uint32_t)j);
|
"expected growth but %d <= %d", new_capacity, old_capacity);
|
||||||
// j < _max
|
this->_capacity = new_capacity;
|
||||||
E* newData = static_cast<Derived*>(this)->allocate();
|
E* newData = static_cast<Derived*>(this)->allocate();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for ( ; i < this->_len; i++) ::new ((void*)&newData[i]) E(this->_data[i]);
|
for ( ; i < this->_len; i++) ::new ((void*)&newData[i]) E(this->_data[i]);
|
||||||
for ( ; i < this->_max; i++) ::new ((void*)&newData[i]) E();
|
for ( ; i < this->_capacity; i++) ::new ((void*)&newData[i]) E();
|
||||||
for (i = 0; i < old_max; i++) this->_data[i].~E();
|
for (i = 0; i < old_capacity; i++) this->_data[i].~E();
|
||||||
if (this->_data != NULL) {
|
if (this->_data != NULL) {
|
||||||
static_cast<Derived*>(this)->deallocate(this->_data);
|
static_cast<Derived*>(this)->deallocate(this->_data);
|
||||||
}
|
}
|
||||||
this->_data = newData;
|
this->_data = newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename E, typename Derived>
|
||||||
|
void GrowableArrayWithAllocator<E, Derived>::grow(int j) {
|
||||||
|
// grow the array by increasing _capacity to the first power of two larger than the size we need
|
||||||
|
expand_to(next_power_of_2((uint32_t)j));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, typename Derived>
|
||||||
|
void GrowableArrayWithAllocator<E, Derived>::reserve(int new_capacity) {
|
||||||
|
if (new_capacity > this->_capacity) {
|
||||||
|
expand_to(new_capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, typename Derived>
|
||||||
|
void GrowableArrayWithAllocator<E, Derived>::shrink_to_fit() {
|
||||||
|
int old_capacity = this->_capacity;
|
||||||
|
int len = this->_len;
|
||||||
|
assert(len <= old_capacity, "invariant");
|
||||||
|
|
||||||
|
// If already at full capacity, nothing to do.
|
||||||
|
if (len == old_capacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not empty, allocate new, smaller, data, and copy old data to it.
|
||||||
|
E* old_data = this->_data;
|
||||||
|
E* new_data = nullptr;
|
||||||
|
this->_capacity = len; // Must preceed allocate().
|
||||||
|
if (len > 0) {
|
||||||
|
new_data = static_cast<Derived*>(this)->allocate();
|
||||||
|
for (int i = 0; i < len; ++i) ::new (&new_data[i]) E(old_data[i]);
|
||||||
|
}
|
||||||
|
// Destroy contents of old data, and deallocate it.
|
||||||
|
for (int i = 0; i < old_capacity; ++i) old_data[i].~E();
|
||||||
|
if (old_data != nullptr) {
|
||||||
|
static_cast<Derived*>(this)->deallocate(old_data);
|
||||||
|
}
|
||||||
|
// Install new data, which might be nullptr.
|
||||||
|
this->_data = new_data;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename E, typename Derived>
|
template <typename E, typename Derived>
|
||||||
void GrowableArrayWithAllocator<E, Derived>::clear_and_deallocate() {
|
void GrowableArrayWithAllocator<E, Derived>::clear_and_deallocate() {
|
||||||
if (this->_data != NULL) {
|
this->clear();
|
||||||
for (int i = 0; i < this->_max; i++) {
|
this->shrink_to_fit();
|
||||||
this->_data[i].~E();
|
|
||||||
}
|
|
||||||
static_cast<Derived*>(this)->deallocate(this->_data);
|
|
||||||
this->_data = NULL;
|
|
||||||
}
|
|
||||||
this->_len = 0;
|
|
||||||
this->_max = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GrowableArrayResourceAllocator {
|
class GrowableArrayResourceAllocator {
|
||||||
|
@ -661,15 +702,15 @@ class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
|
||||||
E* allocate() {
|
E* allocate() {
|
||||||
if (on_stack()) {
|
if (on_stack()) {
|
||||||
debug_only(_metadata.on_stack_alloc_check());
|
debug_only(_metadata.on_stack_alloc_check());
|
||||||
return allocate(this->_max);
|
return allocate(this->_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (on_C_heap()) {
|
if (on_C_heap()) {
|
||||||
return allocate(this->_max, _metadata.memflags());
|
return allocate(this->_capacity, _metadata.memflags());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(on_arena(), "Sanity");
|
assert(on_arena(), "Sanity");
|
||||||
return allocate(this->_max, _metadata.arena());
|
return allocate(this->_capacity, _metadata.arena());
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(E* mem) {
|
void deallocate(E* mem) {
|
||||||
|
@ -679,26 +720,26 @@ class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GrowableArray(int initial_max = 2, MEMFLAGS memflags = mtNone) :
|
GrowableArray(int initial_capacity = 2, MEMFLAGS memflags = mtNone) :
|
||||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||||
allocate(initial_max, memflags),
|
allocate(initial_capacity, memflags),
|
||||||
initial_max),
|
initial_capacity),
|
||||||
_metadata(memflags) {
|
_metadata(memflags) {
|
||||||
init_checks();
|
init_checks();
|
||||||
}
|
}
|
||||||
|
|
||||||
GrowableArray(int initial_max, int initial_len, const E& filler, MEMFLAGS memflags = mtNone) :
|
GrowableArray(int initial_capacity, int initial_len, const E& filler, MEMFLAGS memflags = mtNone) :
|
||||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||||
allocate(initial_max, memflags),
|
allocate(initial_capacity, memflags),
|
||||||
initial_max, initial_len, filler),
|
initial_capacity, initial_len, filler),
|
||||||
_metadata(memflags) {
|
_metadata(memflags) {
|
||||||
init_checks();
|
init_checks();
|
||||||
}
|
}
|
||||||
|
|
||||||
GrowableArray(Arena* arena, int initial_max, int initial_len, const E& filler) :
|
GrowableArray(Arena* arena, int initial_capacity, int initial_len, const E& filler) :
|
||||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||||
allocate(initial_max, arena),
|
allocate(initial_capacity, arena),
|
||||||
initial_max, initial_len, filler),
|
initial_capacity, initial_len, filler),
|
||||||
_metadata(arena) {
|
_metadata(arena) {
|
||||||
init_checks();
|
init_checks();
|
||||||
}
|
}
|
||||||
|
@ -728,7 +769,7 @@ class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHe
|
||||||
NONCOPYABLE(GrowableArrayCHeap);
|
NONCOPYABLE(GrowableArrayCHeap);
|
||||||
|
|
||||||
E* allocate() {
|
E* allocate() {
|
||||||
return allocate(this->_max, F);
|
return allocate(this->_capacity, F);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(E* mem) {
|
void deallocate(E* mem) {
|
||||||
|
@ -736,15 +777,15 @@ class GrowableArrayCHeap : public GrowableArrayWithAllocator<E, GrowableArrayCHe
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GrowableArrayCHeap(int initial_max = 0) :
|
GrowableArrayCHeap(int initial_capacity = 0) :
|
||||||
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
||||||
allocate(initial_max, F),
|
allocate(initial_capacity, F),
|
||||||
initial_max) {}
|
initial_capacity) {}
|
||||||
|
|
||||||
GrowableArrayCHeap(int initial_max, int initial_len, const E& filler) :
|
GrowableArrayCHeap(int initial_capacity, int initial_len, const E& filler) :
|
||||||
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
GrowableArrayWithAllocator<E, GrowableArrayCHeap<E, F> >(
|
||||||
allocate(initial_max, F),
|
allocate(initial_capacity, F),
|
||||||
initial_max, initial_len, filler) {}
|
initial_capacity, initial_len, filler) {}
|
||||||
|
|
||||||
~GrowableArrayCHeap() {
|
~GrowableArrayCHeap() {
|
||||||
this->clear_and_deallocate();
|
this->clear_and_deallocate();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -43,15 +43,15 @@ public class GenericGrowableArray extends VMObject {
|
||||||
|
|
||||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||||
Type type = db.lookupType("GrowableArrayBase");
|
Type type = db.lookupType("GrowableArrayBase");
|
||||||
_max_field = new CIntField(type.getCIntegerField("_max"), 0);
|
_capacity_field = new CIntField(type.getCIntegerField("_capacity"), 0);
|
||||||
_len_field = new CIntField(type.getCIntegerField("_len"), 0);
|
_len_field = new CIntField(type.getCIntegerField("_len"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CIntField _max_field;
|
private static CIntField _capacity_field;
|
||||||
private static CIntField _len_field;
|
private static CIntField _len_field;
|
||||||
|
|
||||||
public int max() {
|
public int capacity() {
|
||||||
return (int)_max_field.getValue(getAddress());
|
return (int)_capacity_field.getValue(getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int length() {
|
public int length() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -39,11 +39,11 @@ TEST(ZArray, sanity) {
|
||||||
|
|
||||||
// Check size
|
// Check size
|
||||||
ASSERT_EQ(a.length(), 0);
|
ASSERT_EQ(a.length(), 0);
|
||||||
ASSERT_EQ(a.max_length(), 0);
|
ASSERT_EQ(a.capacity(), 0);
|
||||||
ASSERT_EQ(a.is_empty(), true);
|
ASSERT_EQ(a.is_empty(), true);
|
||||||
|
|
||||||
ASSERT_EQ(b.length(), 10);
|
ASSERT_EQ(b.length(), 10);
|
||||||
ASSERT_GE(b.max_length(), 10);
|
ASSERT_GE(b.capacity(), 10);
|
||||||
ASSERT_EQ(b.is_empty(), false);
|
ASSERT_EQ(b.is_empty(), false);
|
||||||
|
|
||||||
// Clear elements
|
// Clear elements
|
||||||
|
@ -51,14 +51,14 @@ TEST(ZArray, sanity) {
|
||||||
|
|
||||||
// Check that b is unaffected
|
// Check that b is unaffected
|
||||||
ASSERT_EQ(b.length(), 10);
|
ASSERT_EQ(b.length(), 10);
|
||||||
ASSERT_GE(b.max_length(), 10);
|
ASSERT_GE(b.capacity(), 10);
|
||||||
ASSERT_EQ(b.is_empty(), false);
|
ASSERT_EQ(b.is_empty(), false);
|
||||||
|
|
||||||
a.append(1);
|
a.append(1);
|
||||||
|
|
||||||
// Check that b is unaffected
|
// Check that b is unaffected
|
||||||
ASSERT_EQ(b.length(), 10);
|
ASSERT_EQ(b.length(), 10);
|
||||||
ASSERT_GE(b.max_length(), 10);
|
ASSERT_GE(b.capacity(), 10);
|
||||||
ASSERT_EQ(b.is_empty(), false);
|
ASSERT_EQ(b.is_empty(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -124,6 +124,43 @@ protected:
|
||||||
ASSERT_EQ(counter, 10);
|
ASSERT_EQ(counter, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ArrayClass>
|
||||||
|
static void test_capacity(ArrayClass* a) {
|
||||||
|
ASSERT_EQ(a->length(), 0);
|
||||||
|
a->reserve(50);
|
||||||
|
ASSERT_EQ(a->length(), 0);
|
||||||
|
ASSERT_EQ(a->capacity(), 50);
|
||||||
|
for (int i = 0; i < 50; ++i) {
|
||||||
|
a->append(i);
|
||||||
|
}
|
||||||
|
ASSERT_EQ(a->length(), 50);
|
||||||
|
ASSERT_EQ(a->capacity(), 50);
|
||||||
|
a->append(50);
|
||||||
|
ASSERT_EQ(a->length(), 51);
|
||||||
|
int capacity = a->capacity();
|
||||||
|
ASSERT_GE(capacity, 51);
|
||||||
|
for (int i = 0; i < 30; ++i) {
|
||||||
|
a->pop();
|
||||||
|
}
|
||||||
|
ASSERT_EQ(a->length(), 21);
|
||||||
|
ASSERT_EQ(a->capacity(), capacity);
|
||||||
|
a->shrink_to_fit();
|
||||||
|
ASSERT_EQ(a->length(), 21);
|
||||||
|
ASSERT_EQ(a->capacity(), 21);
|
||||||
|
|
||||||
|
a->reserve(50);
|
||||||
|
ASSERT_EQ(a->length(), 21);
|
||||||
|
ASSERT_EQ(a->capacity(), 50);
|
||||||
|
|
||||||
|
a->clear();
|
||||||
|
ASSERT_EQ(a->length(), 0);
|
||||||
|
ASSERT_EQ(a->capacity(), 50);
|
||||||
|
|
||||||
|
a->shrink_to_fit();
|
||||||
|
ASSERT_EQ(a->length(), 0);
|
||||||
|
ASSERT_EQ(a->capacity(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ArrayClass>
|
template <typename ArrayClass>
|
||||||
static void test_copy1(ArrayClass* a) {
|
static void test_copy1(ArrayClass* a) {
|
||||||
ASSERT_EQ(a->length(), 1);
|
ASSERT_EQ(a->length(), 1);
|
||||||
|
@ -200,7 +237,8 @@ protected:
|
||||||
enum TestEnum {
|
enum TestEnum {
|
||||||
Append,
|
Append,
|
||||||
Clear,
|
Clear,
|
||||||
Iterator,
|
Capacity,
|
||||||
|
Iterator
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ArrayClass>
|
template <typename ArrayClass>
|
||||||
|
@ -214,6 +252,10 @@ protected:
|
||||||
test_clear(a);
|
test_clear(a);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Capacity:
|
||||||
|
test_capacity(a);
|
||||||
|
break;
|
||||||
|
|
||||||
case Iterator:
|
case Iterator:
|
||||||
test_iterator(a);
|
test_iterator(a);
|
||||||
break;
|
break;
|
||||||
|
@ -402,6 +444,10 @@ TEST_VM_F(GrowableArrayTest, clear) {
|
||||||
with_all_types_all_0(Clear);
|
with_all_types_all_0(Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_VM_F(GrowableArrayTest, capacity) {
|
||||||
|
with_all_types_all_0(Capacity);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_VM_F(GrowableArrayTest, iterator) {
|
TEST_VM_F(GrowableArrayTest, iterator) {
|
||||||
with_all_types_all_0(Iterator);
|
with_all_types_all_0(Iterator);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue