Revision: 15998
Author: [email protected]
Date: Thu Aug 1 01:19:51 2013
Log: Speed-up 'new TypedArray(arrayLike)'.
Handle specially the cases when the argument is a typed array,
in particular of the same type as the one we create.
Allocate backing store uninitialized in cases when we can guarantee
complete initialization.
[email protected]
Review URL: https://codereview.chromium.org/21369002
http://code.google.com/p/v8/source/detail?r=15998
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/d8.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/typedarray.js
=======================================
--- /branches/bleeding_edge/include/v8.h Wed Jul 31 10:08:50 2013
+++ /branches/bleeding_edge/include/v8.h Thu Aug 1 01:19:51 2013
@@ -2410,8 +2410,20 @@
/**
* Allocate |length| bytes. Return NULL if allocation is not
successful.
+ * Memory should be initialized to zeroes.
*/
virtual void* Allocate(size_t length) = 0;
+
+ /**
+ * Allocate |length| bytes. Return NULL if allocation is not
successful.
+ * Memory does not have to be initialized.
+ */
+ virtual void* AllocateUninitialized(size_t length) {
+ // Override with call to |Allocate| for compatibility
+ // with legacy version.
+ return Allocate(length);
+ }
+
/**
* Free the memory pointed to |data|. That memory is guaranteed to be
* previously allocated by |Allocate|.
=======================================
--- /branches/bleeding_edge/src/d8.cc Wed Jul 31 00:51:46 2013
+++ /branches/bleeding_edge/src/d8.cc Thu Aug 1 01:19:51 2013
@@ -1562,7 +1562,14 @@
class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
- virtual void* Allocate(size_t length) { return malloc(length); }
+ virtual void* Allocate(size_t length) {
+ void* result = malloc(length);
+ memset(result, 0, length);
+ return result;
+ }
+ virtual void* AllocateUninitialized(size_t length) {
+ return malloc(length);
+ }
virtual void Free(void* data) { free(data); }
};
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Jul 31 05:10:49 2013
+++ /branches/bleeding_edge/src/runtime.cc Thu Aug 1 01:19:51 2013
@@ -712,13 +712,18 @@
bool Runtime::SetupArrayBufferAllocatingData(
Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
- size_t allocated_length) {
+ size_t allocated_length,
+ bool initialize) {
void* data;
CHECK(V8::ArrayBufferAllocator() != NULL);
if (allocated_length != 0) {
- data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
+ if (initialize) {
+ data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
+ } else {
+ data =
+
V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
+ }
if (data == NULL) return false;
- memset(data, 0, allocated_length);
} else {
data = NULL;
}
@@ -805,65 +810,69 @@
ARRAY_ID_UINT8C = 9
};
-
-RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 5);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
- CONVERT_SMI_ARG_CHECKED(arrayId, 1);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
-
- ASSERT(holder->GetInternalFieldCount() ==
- v8::ArrayBufferView::kInternalFieldCount);
- for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
- holder->SetInternalField(i, Smi::FromInt(0));
- }
-
- ExternalArrayType arrayType;
- size_t elementSize;
+static void ArrayIdToTypeAndSize(
+ int arrayId, ExternalArrayType* array_type, size_t* element_size) {
switch (arrayId) {
case ARRAY_ID_UINT8:
- arrayType = kExternalUnsignedByteArray;
- elementSize = 1;
+ *array_type = kExternalUnsignedByteArray;
+ *element_size = 1;
break;
case ARRAY_ID_INT8:
- arrayType = kExternalByteArray;
- elementSize = 1;
+ *array_type = kExternalByteArray;
+ *element_size = 1;
break;
case ARRAY_ID_UINT16:
- arrayType = kExternalUnsignedShortArray;
- elementSize = 2;
+ *array_type = kExternalUnsignedShortArray;
+ *element_size = 2;
break;
case ARRAY_ID_INT16:
- arrayType = kExternalShortArray;
- elementSize = 2;
+ *array_type = kExternalShortArray;
+ *element_size = 2;
break;
case ARRAY_ID_UINT32:
- arrayType = kExternalUnsignedIntArray;
- elementSize = 4;
+ *array_type = kExternalUnsignedIntArray;
+ *element_size = 4;
break;
case ARRAY_ID_INT32:
- arrayType = kExternalIntArray;
- elementSize = 4;
+ *array_type = kExternalIntArray;
+ *element_size = 4;
break;
case ARRAY_ID_FLOAT32:
- arrayType = kExternalFloatArray;
- elementSize = 4;
+ *array_type = kExternalFloatArray;
+ *element_size = 4;
break;
case ARRAY_ID_FLOAT64:
- arrayType = kExternalDoubleArray;
- elementSize = 8;
+ *array_type = kExternalDoubleArray;
+ *element_size = 8;
break;
case ARRAY_ID_UINT8C:
- arrayType = kExternalPixelArray;
- elementSize = 1;
+ *array_type = kExternalPixelArray;
+ *element_size = 1;
break;
default:
UNREACHABLE();
- return NULL;
}
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 5);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
+
+ ASSERT(holder->GetInternalFieldCount() ==
+ v8::ArrayBufferView::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+ holder->SetInternalField(i, Smi::FromInt(0));
+ }
+
+ ExternalArrayType array_type;
+ size_t element_size;
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
holder->set_buffer(*buffer);
holder->set_byte_offset(*byte_offset_object);
@@ -871,8 +880,8 @@
size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
size_t byte_length = NumberToSize(isolate, *byte_length_object);
- ASSERT(byte_length % elementSize == 0);
- size_t length = byte_length / elementSize;
+ ASSERT(byte_length % element_size == 0);
+ size_t length = byte_length / element_size;
Handle<Object> length_obj =
isolate->factory()->NewNumberFromSize(length);
holder->set_length(*length_obj);
@@ -881,11 +890,97 @@
Handle<ExternalArray> elements =
isolate->factory()->NewExternalArray(
- static_cast<int>(length), arrayType,
+ static_cast<int>(length), array_type,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
holder->set_elements(*elements);
return isolate->heap()->undefined_value();
}
+
+
+// Initializes a typed array from an array-like object.
+// If an array-like object happens to be a typed array of the same type,
+// initializes backing store using memove.
+//
+// Returns true if backing store was initialized or false otherwise.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
+
+ ASSERT(holder->GetInternalFieldCount() ==
+ v8::ArrayBufferView::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+ holder->SetInternalField(i, Smi::FromInt(0));
+ }
+
+ ExternalArrayType array_type;
+ size_t element_size;
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
+
+ Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
+ size_t length = NumberToSize(isolate, *length_obj);
+ size_t byte_length = length * element_size;
+ if (byte_length < length) { // Overflow
+ return isolate->Throw(*isolate->factory()->
+ NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ // We assume that the caller of this function will initialize holder
+ // with the loop
+ // for(i = 0; i < length; i++) { holder[i] = source[i]; }
+ // If source is a typed array, this loop will always run to completion,
+ // so we are sure that the backing store will be initialized.
+ // Otherwise, we do not know (the indexing operation might throw).
+ // Hence we require zero initialization unless our source is a typed
array.
+ bool should_zero_initialize = !source->IsJSTypedArray();
+
+ if (!Runtime::SetupArrayBufferAllocatingData(
+ isolate, buffer, byte_length, should_zero_initialize)) {
+ return isolate->Throw(*isolate->factory()->
+ NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ holder->set_buffer(*buffer);
+ holder->set_byte_offset(Smi::FromInt(0));
+ Handle<Object> byte_length_obj(
+ isolate->factory()->NewNumberFromSize(byte_length));
+ holder->set_byte_length(*byte_length_obj);
+ holder->set_length(*length_obj);
+ holder->set_weak_next(buffer->weak_first_view());
+ buffer->set_weak_first_view(*holder);
+
+ Handle<ExternalArray> elements =
+ isolate->factory()->NewExternalArray(
+ static_cast<int>(length), array_type,
+ static_cast<uint8_t*>(buffer->backing_store()));
+ holder->set_elements(*elements);
+
+ if (source->IsJSTypedArray()) {
+ Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
+
+ if (typed_array->type() == holder->type()) {
+ uint8_t* backing_store =
+ static_cast<uint8_t*>(
+ JSArrayBuffer::cast(typed_array->buffer())->backing_store());
+ size_t source_byte_offset =
+ NumberToSize(isolate, typed_array->byte_offset());
+ OS::MemCopy(
+ buffer->backing_store(),
+ backing_store + source_byte_offset,
+ byte_length);
+ return *isolate->factory()->true_value();
+ } else {
+ return *isolate->factory()->false_value();
+ }
+ }
+
+ return *isolate->factory()->false_value();
+}
#define TYPED_ARRAY_GETTER(getter, accessor) \
=======================================
--- /branches/bleeding_edge/src/runtime.h Mon Jul 29 02:12:16 2013
+++ /branches/bleeding_edge/src/runtime.h Thu Aug 1 01:19:51 2013
@@ -361,6 +361,7 @@
F(ArrayBufferSliceImpl, 3, 1) \
\
F(TypedArrayInitialize, 5, 1) \
+ F(TypedArrayInitializeFromArrayLike, 4, 1) \
F(TypedArrayGetBuffer, 1, 1) \
F(TypedArrayGetByteLength, 1, 1) \
F(TypedArrayGetByteOffset, 1, 1) \
@@ -784,7 +785,8 @@
static bool SetupArrayBufferAllocatingData(
Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
- size_t allocated_length);
+ size_t allocated_length,
+ bool initialize = true);
static void FreeArrayBuffer(
Isolate* isolate,
=======================================
--- /branches/bleeding_edge/src/typedarray.js Wed Jul 31 05:10:49 2013
+++ /branches/bleeding_edge/src/typedarray.js Thu Aug 1 01:19:51 2013
@@ -77,11 +77,10 @@
function ConstructByArrayLike(obj, arrayLike) {
var length = arrayLike.length;
var l = ToPositiveInteger(length, "invalid_typed_array_length");
- var byteLength = l * elementSize;
- var buffer = new $ArrayBuffer(byteLength);
- %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
- for (var i = 0; i < l; i++) {
- obj[i] = arrayLike[i];
+ if(!%TypedArrayInitializeFromArrayLike(obj, arrayId, arrayLike, l)) {
+ for (var i = 0; i < l; i++) {
+ obj[i] = arrayLike[i];
+ }
}
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.