Index: runtime/lib/growable_array.dart |
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart |
index 463214700e356ba0810b9d7ba4294226272cf31c..b004b062b4406b2f38c4ab47da9ee4cbf6f8fc42 100644 |
--- a/runtime/lib/growable_array.dart |
+++ b/runtime/lib/growable_array.dart |
@@ -87,8 +87,10 @@ class _GrowableList<T> extends ListBase<T> { |
return result; |
} |
+ static const int _kDefaultCapacity = 2; |
+ |
factory _GrowableList(int length) { |
- var data = _allocateData(length); |
+ var data = new _List((length == 0) ? _kDefaultCapacity : length); |
var result = new _GrowableList<T>.withData(data); |
if (length > 0) { |
result._setLength(length); |
@@ -97,7 +99,7 @@ class _GrowableList<T> extends ListBase<T> { |
} |
factory _GrowableList.withCapacity(int capacity) { |
- var data = _allocateData(capacity); |
+ var data = new _List((capacity == 0) ? _kDefaultCapacity : capacity); |
return new _GrowableList<T>.withData(data); |
} |
@@ -110,6 +112,16 @@ class _GrowableList<T> extends ListBase<T> { |
void set length(int new_length) { |
int old_capacity = _capacity; |
int new_capacity = new_length; |
+ if (new_length == 0) { |
+ // Ensure that we use _kDefaultCapacity only when the old_capacity |
+ // is greater than _kDefaultCapacity otherwise we end up growing the |
+ // the array. |
+ if (old_capacity < _kDefaultCapacity) { |
+ new_capacity = old_capacity; |
+ } else { |
+ new_capacity = _kDefaultCapacity; |
+ } |
+ } |
if (new_capacity > old_capacity) { |
_grow(new_capacity); |
_setLength(new_length); |
@@ -140,10 +152,14 @@ class _GrowableList<T> extends ListBase<T> { |
void operator []=(int index, T value) native "GrowableList_setIndexed"; |
+ // The length of this growable array. It is always less than or equal to the |
+ // length of the object array, which itself is always greater than 0, so that |
+ // grow() does not have to check for a zero length object array before |
+ // doubling its size. |
void add(T value) { |
var len = length; |
if (len == _capacity) { |
- _grow(_nextCapacity(len)); |
+ _grow(len * 2); |
} |
_setLength(len + 1); |
this[len] = value; |
@@ -162,7 +178,7 @@ class _GrowableList<T> extends ListBase<T> { |
var newLen = len + iterLen; |
if (newLen > cap) { |
do { |
- cap = _nextCapacity(cap); |
+ cap *= 2; |
} while (newLen > cap); |
_grow(cap); |
} |
@@ -188,7 +204,7 @@ class _GrowableList<T> extends ListBase<T> { |
if (this.length != newLen) throw new ConcurrentModificationError(this); |
len = newLen; |
} |
- _grow(_nextCapacity(_capacity)); |
+ _grow(_capacity * 2); |
} while (true); |
} |
@@ -216,36 +232,20 @@ class _GrowableList<T> extends ListBase<T> { |
; |
} |
- // Shared array used as backing for new empty growable arrays. |
- static final _List _emptyList = new _List(0); |
- |
- static _List _allocateData(int capacity) { |
- if (capacity == 0) { |
- // Use shared empty list as backing. |
- return _emptyList; |
- } |
- // Round up size to the next odd number, since this is free |
- // because of alignment requirements of the GC. |
- return new _List(capacity | 1); |
- } |
- |
- // Grow from 0 to 3, and then double + 1. |
- int _nextCapacity(int old_capacity) => (old_capacity * 2) | 3; |
- |
void _grow(int new_capacity) { |
- var newData = _allocateData(new_capacity); |
+ var new_data = new _List(new_capacity); |
for (int i = 0; i < length; i++) { |
- newData[i] = this[i]; |
+ new_data[i] = this[i]; |
} |
- _setData(newData); |
+ _setData(new_data); |
} |
void _shrink(int new_capacity, int new_length) { |
- var newData = _allocateData(new_capacity); |
+ var new_data = new _List(new_capacity); |
for (int i = 0; i < new_length; i++) { |
- newData[i] = this[i]; |
+ new_data[i] = this[i]; |
} |
- _setData(newData); |
+ _setData(new_data); |
} |
// Iterable interface. |