Commit 17b7d33d authored by danno@chromium.org's avatar danno@chromium.org

Implement efficient element copying in ElementsAccessors.

Review URL: https://chromiumcodereview.appspot.com/9638014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10989 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e711ff38
......@@ -310,28 +310,6 @@ BUILTIN(ArrayCodeGeneric) {
}
static void CopyElements(Heap* heap,
AssertNoAllocation* no_gc,
FixedArray* dst,
int dst_index,
FixedArray* src,
int src_index,
int len) {
if (len == 0) return;
ASSERT(dst != src); // Use MoveElements instead.
ASSERT(dst->map() != HEAP->fixed_cow_array_map());
ASSERT(len > 0);
CopyWords(dst->data_start() + dst_index,
src->data_start() + src_index,
len);
WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
if (mode == UPDATE_WRITE_BARRIER) {
heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
}
heap->incremental_marking()->RecordWrites(dst);
}
static void MoveElements(Heap* heap,
AssertNoAllocation* no_gc,
FixedArray* dst,
......@@ -531,7 +509,8 @@ BUILTIN(ArrayPush) {
FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0,
new_elms, FAST_ELEMENTS, 0, len);
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
......@@ -667,7 +646,8 @@ BUILTIN(ArrayUnshift) {
}
FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0,
new_elms, FAST_ELEMENTS, to_add, len);
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
......@@ -778,8 +758,9 @@ BUILTIN(ArraySlice) {
if (!maybe_array->To(&result_array)) return maybe_array;
AssertNoAllocation no_gc;
CopyElements(heap, &no_gc, FixedArray::cast(result_array->elements()), 0,
elms, k, result_len);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, k,
FixedArray::cast(result_array->elements()),
FAST_ELEMENTS, 0, result_len);
return result_array;
}
......@@ -852,11 +833,9 @@ BUILTIN(ArraySplice) {
{
AssertNoAllocation no_gc;
// Fill newly created array.
CopyElements(heap,
&no_gc,
FixedArray::cast(result_array->elements()), 0,
elms, actual_start,
actual_delete_count);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, actual_start,
FixedArray::cast(result_array->elements()),
FAST_ELEMENTS, 0, actual_delete_count);
}
int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
......@@ -906,12 +885,13 @@ BUILTIN(ArraySplice) {
{
AssertNoAllocation no_gc;
// Copy the part before actual_start as is.
CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0,
new_elms, FAST_ELEMENTS, 0, actual_start);
const int to_copy = len - actual_delete_count - actual_start;
CopyElements(heap, &no_gc,
new_elms, actual_start + item_count,
elms, actual_start + actual_delete_count,
to_copy);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS,
actual_start + actual_delete_count,
new_elms, FAST_ELEMENTS,
actual_start + item_count, to_copy);
}
FillWithHoles(heap, new_elms, new_length, capacity);
......@@ -1000,7 +980,9 @@ BUILTIN(ArrayConcat) {
JSArray* array = JSArray::cast(args[i]);
int len = Smi::cast(array->length())->value();
FixedArray* elms = FixedArray::cast(array->elements());
CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0,
result_elms, FAST_ELEMENTS,
start_pos, len);
start_pos += len;
}
ASSERT(start_pos == result_len);
......
This diff is collapsed.
......@@ -29,6 +29,8 @@
#define V8_ELEMENTS_H_
#include "objects.h"
#include "heap.h"
#include "isolate.h"
namespace v8 {
namespace internal {
......@@ -40,7 +42,8 @@ class ElementsAccessor {
explicit ElementsAccessor(const char* name) : name_(name) { }
virtual ~ElementsAccessor() { }
virtual const char* name() const { return name_; }
virtual ElementsKind kind() const = 0;
const char* name() const { return name_; }
// Returns true if a holder contains an element with the specified key
// without iterating up the prototype chain. The caller can optionally pass
......@@ -85,6 +88,25 @@ class ElementsAccessor {
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
// Copy elements from one backing store to another. Typically, callers specify
// the source JSObject or JSArray in source_holder. If the holder's backing
// store is available, it can be passed in source and source_holder is
// ignored.
virtual MaybeObject* CopyElements(JSObject* source_holder,
uint32_t source_start,
FixedArrayBase* destination,
ElementsKind destination_kind,
uint32_t destination_start,
int copy_size,
FixedArrayBase* source = NULL) = 0;
MaybeObject* CopyElements(JSObject* from_holder,
FixedArrayBase* to,
ElementsKind to_kind,
FixedArrayBase* from = NULL) {
return CopyElements(from_holder, 0, to, to_kind, 0, -1, from);
}
virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
JSObject* holder,
FixedArray* to,
......@@ -123,6 +145,17 @@ class ElementsAccessor {
DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
};
void CopyObjectToObjectElements(AssertNoAllocation* no_gc,
FixedArray* from_obj,
ElementsKind from_kind,
uint32_t from_start,
FixedArray* to_obj,
ElementsKind to_kind,
uint32_t to_start,
int copy_size);
} } // namespace v8::internal
#endif // V8_ELEMENTS_H_
......@@ -8456,43 +8456,6 @@ void Code::Disassemble(const char* name, FILE* out) {
#endif // ENABLE_DISASSEMBLER
static void CopyFastElementsToFast(FixedArray* source,
FixedArray* destination,
WriteBarrierMode mode) {
int count = source->length();
int copy_size = Min(count, destination->length());
if (mode == SKIP_WRITE_BARRIER ||
!Page::FromAddress(destination->address())->IsFlagSet(
MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
Address to = destination->address() + FixedArray::kHeaderSize;
Address from = source->address() + FixedArray::kHeaderSize;
memcpy(reinterpret_cast<void*>(to),
reinterpret_cast<void*>(from),
kPointerSize * copy_size);
} else {
for (int i = 0; i < copy_size; ++i) {
destination->set(i, source->get(i), mode);
}
}
}
static void CopySlowElementsToFast(SeededNumberDictionary* source,
FixedArray* destination,
WriteBarrierMode mode) {
int destination_length = destination->length();
for (int i = 0; i < source->Capacity(); ++i) {
Object* key = source->KeyAt(i);
if (key->IsNumber()) {
uint32_t entry = static_cast<uint32_t>(key->Number());
if (entry < static_cast<uint32_t>(destination_length)) {
destination->set(entry, source->ValueAt(i), mode);
}
}
}
}
MaybeObject* JSObject::SetFastElementsCapacityAndLength(
int capacity,
int length,
......@@ -8526,79 +8489,17 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
FixedArrayBase* old_elements_raw = elements();
ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
new_elements, mode);
set_map_and_elements(new_map, new_elements);
break;
}
case DICTIONARY_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopySlowElementsToFast(SeededNumberDictionary::cast(old_elements_raw),
new_elements,
mode);
ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
? FAST_SMI_ONLY_ELEMENTS
: FAST_ELEMENTS;
// int copy_size = Min(old_elements_raw->length(), new_elements->length());
accessor->CopyElements(this, new_elements, to_kind);
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
set_map_and_elements(new_map, new_elements);
break;
}
case NON_STRICT_ARGUMENTS_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
// The object's map and the parameter map are unchanged, the unaliased
// arguments are copied to the new backing store.
FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
new_elements,
mode);
} else {
CopyFastElementsToFast(arguments, new_elements, mode);
}
FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
parameter_map->set(1, new_elements);
break;
}
case FAST_DOUBLE_ELEMENTS: {
FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
uint32_t old_length = static_cast<uint32_t>(old_elements->length());
// Fill out the new array with this content and array holes.
for (uint32_t i = 0; i < old_length; i++) {
if (!old_elements->is_the_hole(i)) {
Object* obj;
// Objects must be allocated in the old object space, since the
// overall number of HeapNumbers needed for the conversion might
// exceed the capacity of new space, and we would fail repeatedly
// trying to convert the FixedDoubleArray.
MaybeObject* maybe_value_object =
GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
TENURED);
if (!maybe_value_object->To(&obj)) return maybe_value_object;
// Force write barrier. It's not worth trying to exploit
// elems->GetWriteBarrierMode(), since it requires an
// AssertNoAllocation stack object that would have to be positioned
// after the HeapNumber allocation anyway.
new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
}
}
set_map(new_map);
set_elements(new_elements);
break;
}
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
UNREACHABLE();
break;
}
if (FLAG_trace_elements_transitions) {
......
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