Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index 1987adcbfef5710ff16c3c09ba7e275892a46e03..f40b5c27741787d5869fd3e0a61e92bb917d3bf1 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -300,6 +300,73 @@ static void FillWithHoles(FixedArray* dst, int from, int to) { |
} |
+static FixedArray* LeftTrimFixedArray(FixedArray* elms) { |
+ // For now this trick is only applied to fixed arrays in new space. |
+ // In large object space the object's start must coincide with chunk |
+ // and thus the trick is just not applicable. |
+ // In old space we do not use this trick to avoid dealing with |
+ // remembered sets. |
+ ASSERT(Heap::new_space()->Contains(elms)); |
+ |
+ STATIC_ASSERT(FixedArray::kMapOffset == 0); |
+ STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); |
+ STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); |
+ |
+ Object** former_start = HeapObject::RawField(elms, 0); |
+ |
+ const int len = elms->length(); |
+ |
+ // Technically in new space this write might be omitted (except for |
+ // debug mode which iterates through the heap), but to play safer |
+ // we still do it. |
+ former_start[0] = Heap::raw_unchecked_one_pointer_filler_map(); |
+ |
+ former_start[1] = Heap::fixed_array_map(); |
+ former_start[2] = reinterpret_cast<Object*>(len - 1); |
+ |
+ ASSERT_EQ(elms->address() + kPointerSize, (elms + kPointerSize)->address()); |
+ return elms + kPointerSize; |
+} |
+ |
+ |
+static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) { |
+ // For now this trick is only applied to fixed arrays in new space. |
+ // In large object space the object's start must coincide with chunk |
+ // and thus the trick is just not applicable. |
+ // In old space we do not use this trick to avoid dealing with |
+ // remembered sets. |
+ ASSERT(Heap::new_space()->Contains(elms)); |
+ |
+ STATIC_ASSERT(FixedArray::kMapOffset == 0); |
+ STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); |
+ STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); |
+ |
+ Object** former_start = HeapObject::RawField(elms, 0); |
+ |
+ const int len = elms->length(); |
+ |
+ // Technically in new space this write might be omitted (except for |
+ // debug mode which iterates through the heap), but to play safer |
+ // we still do it. |
+ if (to_trim == 1) { |
+ former_start[0] = Heap::raw_unchecked_one_pointer_filler_map(); |
+ } else if (to_trim == 2) { |
+ former_start[0] = Heap::raw_unchecked_two_pointer_filler_map(); |
+ } else { |
+ former_start[0] = Heap::raw_unchecked_byte_array_map(); |
+ ByteArray* as_byte_array = reinterpret_cast<ByteArray*>(elms); |
+ as_byte_array->set_length(ByteArray::LengthFor(to_trim * kPointerSize)); |
+ } |
+ |
+ former_start[to_trim] = Heap::fixed_array_map(); |
+ former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim); |
+ |
+ ASSERT_EQ(elms->address() + to_trim * kPointerSize, |
+ (elms + to_trim * kPointerSize)->address()); |
+ return elms + to_trim * kPointerSize; |
+} |
+ |
+ |
static bool ArrayPrototypeHasNoElements() { |
// This method depends on non writability of Object and Array prototype |
// fields. |
@@ -446,38 +513,6 @@ BUILTIN(ArrayPop) { |
} |
-static FixedArray* LeftTrimFixedArray(FixedArray* elms) { |
- // For now this trick is only applied to fixed arrays in new space. |
- // In large object space the object's start must coincide with chunk |
- // and thus the trick is just not applicable. |
- // In old space we do not use this trick to avoid dealing with |
- // remembered sets. |
- ASSERT(Heap::new_space()->Contains(elms)); |
- |
- Object** former_map = |
- HeapObject::RawField(elms, FixedArray::kMapOffset); |
- Object** former_length = |
- HeapObject::RawField(elms, FixedArray::kLengthOffset); |
- Object** former_first = |
- HeapObject::RawField(elms, FixedArray::kHeaderSize); |
- // Check that we don't forget to copy all the bits. |
- STATIC_ASSERT(FixedArray::kMapOffset + 2 * kPointerSize |
- == FixedArray::kHeaderSize); |
- |
- int len = elms->length(); |
- |
- *former_first = reinterpret_cast<Object*>(len - 1); |
- *former_length = Heap::fixed_array_map(); |
- // Technically in new space this write might be omitted (except for |
- // debug mode which iterates through the heap), but to play safer |
- // we still do it. |
- *former_map = Heap::raw_unchecked_one_pointer_filler_map(); |
- |
- ASSERT(elms->address() + kPointerSize == (elms + kPointerSize)->address()); |
- return elms + kPointerSize; |
-} |
- |
- |
BUILTIN(ArrayShift) { |
Object* receiver = *args.receiver(); |
FixedArray* elms = NULL; |
@@ -718,12 +753,27 @@ BUILTIN(ArraySplice) { |
if (item_count < actual_delete_count) { |
// Shrink the array. |
- AssertNoAllocation no_gc; |
- MoveElements(&no_gc, |
- elms, actual_start + item_count, |
- elms, actual_start + actual_delete_count, |
- (len - actual_delete_count - actual_start)); |
- FillWithHoles(elms, new_length, len); |
+ const bool trim_array = Heap::new_space()->Contains(elms) && |
+ ((actual_start + item_count) < |
+ (len - actual_delete_count - actual_start)); |
+ if (trim_array) { |
+ const int delta = actual_delete_count - item_count; |
+ |
+ if (actual_start > 0) { |
+ Object** start = elms->data_start(); |
+ memmove(start + delta, start, actual_start * kPointerSize); |
+ } |
+ |
+ elms = LeftTrimFixedArray(elms, delta); |
+ array->set_elements(elms, SKIP_WRITE_BARRIER); |
+ } else { |
+ AssertNoAllocation no_gc; |
+ MoveElements(&no_gc, |
+ elms, actual_start + item_count, |
+ elms, actual_start + actual_delete_count, |
+ (len - actual_delete_count - actual_start)); |
+ FillWithHoles(elms, new_length, len); |
+ } |
} else if (item_count > actual_delete_count) { |
// Currently fixed arrays cannot grow too big, so |
// we should never hit this case. |