Commit 837d83eb authored by danno@chromium.org's avatar danno@chromium.org

Implement setting the length property for FixedDoubleArrays.

R=ager@chromium.org
BUG=none
TEST=none

Review URL: http://codereview.chromium.org/7400020

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8683 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 11c7b474
...@@ -4007,7 +4007,8 @@ bool JSObject::HasIndexedInterceptor() { ...@@ -4007,7 +4007,8 @@ bool JSObject::HasIndexedInterceptor() {
bool JSObject::AllowsSetElementsLength() { bool JSObject::AllowsSetElementsLength() {
bool result = elements()->IsFixedArray(); bool result = elements()->IsFixedArray() ||
elements()->IsFixedDoubleArray();
ASSERT(result == !HasExternalArrayElements()); ASSERT(result == !HasExternalArrayElements());
return result; return result;
} }
......
...@@ -3207,7 +3207,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { ...@@ -3207,7 +3207,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
case FAST_DOUBLE_ELEMENTS: { case FAST_DOUBLE_ELEMENTS: {
int length = IsJSArray() int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value() ? Smi::cast(JSArray::cast(this)->length())->value()
: FixedArray::cast(elements())->length(); : FixedDoubleArray::cast(elements())->length();
if (index < static_cast<uint32_t>(length)) { if (index < static_cast<uint32_t>(length)) {
FixedDoubleArray::cast(elements())->set_the_hole(index); FixedDoubleArray::cast(elements())->set_the_hole(index);
} }
...@@ -7628,31 +7628,54 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { ...@@ -7628,31 +7628,54 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
const int value = Smi::cast(smi_length)->value(); const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap()); if (value < 0) return ArrayLengthRangeError(GetHeap());
switch (GetElementsKind()) { switch (GetElementsKind()) {
case FAST_ELEMENTS: { case FAST_ELEMENTS:
int old_capacity = FixedArray::cast(elements())->length(); case FAST_DOUBLE_ELEMENTS: {
int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) { if (value <= old_capacity) {
if (IsJSArray()) { if (IsJSArray()) {
Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* fast_elements = FixedArray::cast(elements());
if (2 * value <= old_capacity) { if (2 * value <= old_capacity) {
// If more than half the elements won't be used, trim the array. // If more than half the elements won't be used, trim the array.
if (value == 0) { if (value == 0) {
initialize_elements(); initialize_elements();
} else { } else {
fast_elements->set_length(value); Address filler_start;
Address filler_start = fast_elements->address() + int filler_size;
FixedArray::OffsetOfElementAt(value); if (GetElementsKind() == FAST_ELEMENTS) {
int filler_size = (old_capacity - value) * kPointerSize; Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* fast_elements = FixedArray::cast(elements());
fast_elements->set_length(value);
filler_start = fast_elements->address() +
FixedArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kPointerSize;
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
fast_double_elements->set_length(value);
filler_start = fast_double_elements->address() +
FixedDoubleArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kDoubleSize;
}
GetHeap()->CreateFillerObjectAt(filler_start, filler_size); GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
} }
} else { } else {
// Otherwise, fill the unused tail with holes. // Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number()); int old_length = FastD2I(JSArray::cast(this)->length()->Number());
for (int i = value; i < old_length; i++) { if (GetElementsKind() == FAST_ELEMENTS) {
fast_elements->set_the_hole(i); FixedArray* fast_elements = FixedArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_elements->set_the_hole(i);
}
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_double_elements->set_the_hole(i);
}
} }
} }
JSArray::cast(this)->set_length(Smi::cast(smi_length)); JSArray::cast(this)->set_length(Smi::cast(smi_length));
...@@ -7663,8 +7686,18 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { ...@@ -7663,8 +7686,18 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
int new_capacity = value > min ? value : min; int new_capacity = value > min ? value : min;
if (new_capacity <= kMaxFastElementsLength || if (new_capacity <= kMaxFastElementsLength ||
!ShouldConvertToSlowElements(new_capacity)) { !ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result = MaybeObject* result;
SetFastElementsCapacityAndLength(new_capacity, value); if (GetElementsKind() == FAST_ELEMENTS) {
Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
result = SetFastElementsCapacityAndLength(new_capacity, value);
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
result = SetFastDoubleElementsCapacityAndLength(new_capacity,
value);
}
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
return this; return this;
} }
...@@ -7700,7 +7733,6 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { ...@@ -7700,7 +7733,6 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_PIXEL_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
UNREACHABLE(); UNREACHABLE();
break; break;
} }
......
...@@ -2169,6 +2169,9 @@ class FixedDoubleArray: public FixedArrayBase { ...@@ -2169,6 +2169,9 @@ class FixedDoubleArray: public FixedArrayBase {
return kHeaderSize + length * kDoubleSize; return kHeaderSize + length * kDoubleSize;
} }
// Code Generation support.
static int OffsetOfElementAt(int index) { return SizeFor(index); }
inline static bool is_the_hole_nan(double value); inline static bool is_the_hole_nan(double value);
inline static double hole_nan_as_double(); inline static double hole_nan_as_double();
inline static double canonical_not_the_hole_nan_as_double(); inline static double canonical_not_the_hole_nan_as_double();
......
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
// Test dictionary -> double elements -> dictionary elements round trip // Test dictionary -> double elements -> dictionary elements round trip
// Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc // Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc
var large_array_size = 500000; var large_array_size = 100000;
var approx_dict_to_elements_threshold = 69000; var approx_dict_to_elements_threshold = 75000;
var name = 0; var name = 0;
...@@ -42,14 +42,21 @@ function expected_array_value(i) { ...@@ -42,14 +42,21 @@ function expected_array_value(i) {
} }
function force_to_fast_double_array(a) { function force_to_fast_double_array(a) {
a[large_array_size - 2] = 1;
for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) { for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) {
a[i] = expected_array_value(i); a[i] = expected_array_value(i);
} }
assertTrue(%HasFastDoubleElements(a)); assertTrue(%HasFastDoubleElements(a));
} }
function make_object_like_array(size) {
obj = new Object();
obj.length = size;
return obj;
}
function testOneArrayType(allocator) { function testOneArrayType(allocator) {
var large_array = new allocator(500000); var large_array = new allocator(large_array_size);
force_to_fast_double_array(large_array); force_to_fast_double_array(large_array);
var six = 6; var six = 6;
...@@ -319,35 +326,94 @@ function testOneArrayType(allocator) { ...@@ -319,35 +326,94 @@ function testOneArrayType(allocator) {
// Make sure that we haven't converted from fast double. // Make sure that we haven't converted from fast double.
assertTrue(%HasFastDoubleElements(large_array)); assertTrue(%HasFastDoubleElements(large_array));
// Cause the array to grow beyond it's JSArray length. This will double the
// size of the capacity and force the array into "slow" dictionary case.
large_array[large_array_size+1] = 50;
assertTrue(%HasDictionaryElements(large_array));
assertEquals(50, large_array[large_array_size+1]);
assertEquals(large_array_size+2, large_array.length);
assertEquals(Infinity, large_array[5]);
assertEquals(undefined, large_array[large_array_size-1]);
assertEquals(undefined, large_array[-1]);
assertEquals(large_array_size+2, large_array.length);
// Test dictionary -> double elements -> fast elements.
var large_array2 = new allocator(large_array_size);
force_to_fast_double_array(large_array2);
delete large_array2[5];
// Convert back to fast elements and make sure the contents of the array are
// unchanged.
large_array2[25] = new Object();
assertTrue(%HasFastElements(large_array2));
for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
if (i != 25 && i != 5) {
assertEquals(expected_array_value(i), large_array2[i]);
}
}
assertEquals(undefined, large_array2[5])
assertEquals(undefined, large_array2[large_array_size-1])
assertEquals(undefined, large_array2[-1])
assertEquals(large_array_size, large_array2.length);
} }
testOneArrayType(make_object_like_array);
testOneArrayType(Array); testOneArrayType(Array);
var large_array = new Array(large_array_size);
force_to_fast_double_array(large_array);
assertTrue(%HasFastDoubleElements(large_array));
// Cause the array to grow beyond it's JSArray length. This will double the
// size of the capacity and force the array into "slow" dictionary case.
large_array[5] = Infinity;
large_array[large_array_size+10001] = 50;
assertTrue(%HasDictionaryElements(large_array));
assertEquals(50, large_array[large_array_size+10001]);
assertEquals(large_array_size+10002, large_array.length);
assertEquals(Infinity, large_array[5]);
assertEquals(undefined, large_array[large_array_size-1]);
assertEquals(undefined, large_array[-1]);
assertEquals(large_array_size+10002, large_array.length);
// Test dictionary -> double elements -> fast elements.
var large_array2 = new Array(large_array_size);
force_to_fast_double_array(large_array2);
delete large_array2[5];
// Convert back to fast elements and make sure the contents of the array are
// unchanged.
large_array2[25] = new Object();
assertTrue(%HasFastElements(large_array2));
for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
if (i != 25 && i != 5) {
assertEquals(expected_array_value(i), large_array2[i]);
}
}
assertEquals(undefined, large_array2[5]);
assertEquals(undefined, large_array2[large_array_size-1]);
assertEquals(undefined, large_array2[-1]);
assertEquals(large_array_size, large_array2.length);
// Make sure it's possible to change the array's length and that array is still
// intact after the resize.
var large_array3 = new Array(large_array_size);
force_to_fast_double_array(large_array3);
large_array3.length = 60000;
assertEquals(60000, large_array3.length);
assertEquals(undefined, large_array3[60000]);
assertTrue(%HasFastDoubleElements(large_array3));
assertEquals(expected_array_value(5), large_array3[5]);
assertEquals(expected_array_value(6), large_array3[6]);
assertEquals(expected_array_value(7), large_array3[7]);
assertEquals(expected_array_value(large_array3.length-1),
large_array3[large_array3.length-1]);
assertEquals(undefined, large_array3[large_array_size-1]);
assertEquals(undefined, large_array3[-1]);
gc();
for (var i= 0; i < large_array3.length; i += 501 ) {
assertEquals(expected_array_value(i), large_array3[i]);
}
large_array3.length = 25;
assertEquals(25, large_array3.length);
assertTrue(%HasFastDoubleElements(large_array3));
assertEquals(undefined, large_array3[25]);
assertEquals(expected_array_value(5), large_array3[5]);
assertEquals(expected_array_value(6), large_array3[6]);
assertEquals(expected_array_value(7), large_array3[7]);
assertEquals(expected_array_value(large_array3.length-1),
large_array3[large_array3.length-1]);
assertEquals(undefined, large_array3[large_array_size-1]);
assertEquals(undefined, large_array3[-1]);
gc();
for (var i= 0; i < large_array3.length; ++i) {
assertEquals(expected_array_value(i), large_array3[i]);
}
large_array3.length = 100;
assertEquals(100, large_array3.length);
large_array3[95] = 95;
assertTrue(%HasFastDoubleElements(large_array3));
assertEquals(undefined, large_array3[100]);
assertEquals(95, large_array3[95]);
assertEquals(expected_array_value(5), large_array3[5]);
assertEquals(expected_array_value(6), large_array3[6]);
assertEquals(expected_array_value(7), large_array3[7]);
assertEquals(undefined, large_array3[large_array3.length-1]);
assertEquals(undefined, large_array3[large_array_size-1]);
assertEquals(undefined, large_array3[-1]);
gc();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment