Some clean-up of typed array support in d8.
R=yangguo@chromium.org BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/10392130 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11679 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
ebe9a0e0b2
commit
716eac2801
134
src/d8.cc
134
src/d8.cc
@ -316,8 +316,8 @@ static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) {
|
||||
}
|
||||
|
||||
|
||||
const char kArrayBufferMarkerPropName[] = "_is_array_buffer_";
|
||||
const char kArrayBufferReferencePropName[] = "_array_buffer_ref_";
|
||||
const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
|
||||
const char kArrayBufferReferencePropName[] = "d8::_array_buffer_ref_";
|
||||
|
||||
static const int kExternalArrayAllocationHeaderSize = 2;
|
||||
|
||||
@ -334,132 +334,110 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
|
||||
element_size == 8);
|
||||
if (args.Length() == 0) {
|
||||
return ThrowException(
|
||||
String::New("Array constructor must have at least one "
|
||||
"parameter."));
|
||||
String::New("Array constructor must have at least one parameter."));
|
||||
}
|
||||
bool first_arg_is_array_buffer =
|
||||
args[0]->IsObject() &&
|
||||
args[0]->ToObject()->Get(
|
||||
args[0]->ToObject()->GetHiddenValue(
|
||||
String::New(kArrayBufferMarkerPropName))->IsTrue();
|
||||
// Currently, only the following constructors are supported:
|
||||
// ArrayBuffer(unsigned long length)
|
||||
// TypedArray(unsigned long length)
|
||||
// TypedArray(ArrayBuffer buffer,
|
||||
// optional unsigned long byteOffset,
|
||||
// optional unsigned long length)
|
||||
if (args.Length() > 3) {
|
||||
return ThrowException(
|
||||
String::New("Array constructor from ArrayBuffer must "
|
||||
"have 1-3 parameters."));
|
||||
}
|
||||
|
||||
Local<Value> length_value = (args.Length() < 3)
|
||||
? (first_arg_is_array_buffer
|
||||
? args[0]->ToObject()->Get(String::New("byteLength"))
|
||||
: args[0])
|
||||
: args[2];
|
||||
size_t byteLength = convertToUint(length_value, &try_catch);
|
||||
size_t length = byteLength;
|
||||
if (try_catch.HasCaught()) return try_catch.Exception();
|
||||
|
||||
size_t length;
|
||||
size_t byteLength;
|
||||
size_t byteOffset;
|
||||
void* data = NULL;
|
||||
size_t offset = 0;
|
||||
|
||||
Handle<Object> array = Object::New();
|
||||
if (first_arg_is_array_buffer) {
|
||||
Handle<Object> derived_from = args[0]->ToObject();
|
||||
data = derived_from->GetIndexedPropertiesExternalArrayData();
|
||||
|
||||
size_t array_buffer_length = convertToUint(
|
||||
derived_from->Get(String::New("byteLength")),
|
||||
&try_catch);
|
||||
if (is_array_buffer_construct) {
|
||||
byteLength = convertToUint(args[0], &try_catch);
|
||||
if (try_catch.HasCaught()) return try_catch.Exception();
|
||||
byteOffset = 0;
|
||||
length = byteLength;
|
||||
|
||||
if (data == NULL && array_buffer_length != 0) {
|
||||
return ThrowException(
|
||||
String::New("ArrayBuffer doesn't have data"));
|
||||
array->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
|
||||
} else if (first_arg_is_array_buffer) {
|
||||
Handle<Object> buffer = args[0]->ToObject();
|
||||
data = buffer->GetIndexedPropertiesExternalArrayData();
|
||||
byteLength =
|
||||
convertToUint(buffer->Get(String::New("byteLength")), &try_catch);
|
||||
if (try_catch.HasCaught()) return try_catch.Exception();
|
||||
if (data == NULL && byteLength != 0) {
|
||||
return ThrowException(String::New("ArrayBuffer does not have data"));
|
||||
}
|
||||
|
||||
if (args.Length() > 1) {
|
||||
offset = convertToUint(args[1], &try_catch);
|
||||
if (args.Length() < 2 || args[1]->IsUndefined()) {
|
||||
byteOffset = 0;
|
||||
} else {
|
||||
byteOffset = convertToUint(args[1], &try_catch);
|
||||
if (try_catch.HasCaught()) return try_catch.Exception();
|
||||
|
||||
// The given byteOffset must be a multiple of the element size of the
|
||||
// specific type, otherwise an exception is raised.
|
||||
if (offset % element_size != 0) {
|
||||
if (byteOffset % element_size != 0) {
|
||||
return ThrowException(
|
||||
String::New("offset must be multiple of element_size"));
|
||||
String::New("byteOffset must be multiple of element_size"));
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > array_buffer_length) {
|
||||
return ThrowException(
|
||||
String::New("byteOffset must be less than ArrayBuffer length."));
|
||||
}
|
||||
|
||||
if (args.Length() == 2) {
|
||||
// If length is not explicitly specified, the length of the ArrayBuffer
|
||||
// minus the byteOffset must be a multiple of the element size of the
|
||||
// specific type, or an exception is raised.
|
||||
length = array_buffer_length - offset;
|
||||
}
|
||||
|
||||
if (args.Length() != 3) {
|
||||
if (length % element_size != 0) {
|
||||
if (args.Length() < 3 || args[2]->IsUndefined()) {
|
||||
if (byteLength % element_size != 0) {
|
||||
return ThrowException(
|
||||
String::New("ArrayBuffer length minus the byteOffset must be a "
|
||||
"multiple of the element size"));
|
||||
String::New("buffer size must be multiple of element_size"));
|
||||
}
|
||||
length /= element_size;
|
||||
length = (byteLength - byteOffset) / element_size;
|
||||
} else {
|
||||
length = convertToUint(args[2], &try_catch);
|
||||
if (try_catch.HasCaught()) return try_catch.Exception();
|
||||
}
|
||||
|
||||
// If a given byteOffset and length references an area beyond the end of
|
||||
// the ArrayBuffer an exception is raised.
|
||||
if (offset + (length * element_size) > array_buffer_length) {
|
||||
if (byteOffset + length * element_size > byteLength) {
|
||||
return ThrowException(
|
||||
String::New("length references an area beyond the end of the "
|
||||
"ArrayBuffer"));
|
||||
String::New("byteOffset or length out of bounds"));
|
||||
}
|
||||
byteLength = byteOffset + length * element_size;
|
||||
|
||||
// Hold a reference to the ArrayBuffer so its buffer doesn't get collected.
|
||||
array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly);
|
||||
}
|
||||
|
||||
if (is_array_buffer_construct) {
|
||||
array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly);
|
||||
array->SetHiddenValue(
|
||||
String::New(kArrayBufferReferencePropName), args[0]);
|
||||
} else {
|
||||
length = convertToUint(args[0], &try_catch);
|
||||
byteLength = length * element_size;
|
||||
byteOffset = 0;
|
||||
}
|
||||
|
||||
Persistent<Object> persistent_array = Persistent<Object>::New(array);
|
||||
if (data == NULL && length != 0) {
|
||||
// Make sure the total size fits into a (signed) int.
|
||||
if (data == NULL && byteLength != 0) {
|
||||
ASSERT(byteOffset == 0);
|
||||
// Prepend the size of the allocated chunk to the data itself.
|
||||
int total_size =
|
||||
byteLength + kExternalArrayAllocationHeaderSize * sizeof(size_t);
|
||||
static const int kMaxSize = 0x7fffffff;
|
||||
if (length > (kMaxSize - sizeof(size_t)) / element_size) {
|
||||
// Make sure the total size fits into a (signed) int.
|
||||
if (total_size > kMaxSize) {
|
||||
return ThrowException(String::New("Array exceeds maximum size (2G)"));
|
||||
}
|
||||
// Prepend the size of the allocated chunk to the data itself.
|
||||
int total_size = length * element_size +
|
||||
kExternalArrayAllocationHeaderSize * sizeof(size_t);
|
||||
data = malloc(total_size);
|
||||
if (data == NULL) {
|
||||
return ThrowException(String::New("Memory allocation failed."));
|
||||
}
|
||||
*reinterpret_cast<size_t*>(data) = total_size;
|
||||
data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize;
|
||||
memset(data, 0, length * element_size);
|
||||
memset(data, 0, byteLength);
|
||||
V8::AdjustAmountOfExternalAllocatedMemory(total_size);
|
||||
}
|
||||
persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
|
||||
persistent_array.MarkIndependent();
|
||||
|
||||
array->SetIndexedPropertiesToExternalArrayData(
|
||||
reinterpret_cast<uint8_t*>(data) + offset, type,
|
||||
reinterpret_cast<uint8_t*>(data) + byteOffset, type,
|
||||
static_cast<int>(length));
|
||||
array->Set(String::New("byteLength"),
|
||||
Int32::New(static_cast<int32_t>(byteLength)), ReadOnly);
|
||||
if (!is_array_buffer_construct) {
|
||||
array->Set(String::New("byteOffset"),
|
||||
Int32::New(static_cast<int32_t>(byteOffset)), ReadOnly);
|
||||
array->Set(String::New("length"),
|
||||
Int32::New(static_cast<int32_t>(length)), ReadOnly);
|
||||
array->Set(String::New("byteOffset"),
|
||||
Int32::New(static_cast<int32_t>(offset)), ReadOnly);
|
||||
array->Set(String::New("BYTES_PER_ELEMENT"),
|
||||
Int32::New(static_cast<int32_t>(element_size)));
|
||||
// We currently support 'buffer' property only if constructed from a buffer.
|
||||
@ -475,7 +453,7 @@ void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
|
||||
HandleScope scope;
|
||||
Handle<String> prop_name = String::New(kArrayBufferReferencePropName);
|
||||
Handle<Object> converted_object = object->ToObject();
|
||||
Local<Value> prop_value = converted_object->Get(prop_name);
|
||||
Local<Value> prop_value = converted_object->GetHiddenValue(prop_name);
|
||||
if (data != NULL && !prop_value->IsObject()) {
|
||||
data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize;
|
||||
V8::AdjustAmountOfExternalAllocatedMemory(
|
||||
@ -1066,7 +1044,7 @@ Handle<Value> Shell::ReadBuffer(const Arguments& args) {
|
||||
}
|
||||
|
||||
Handle<Object> buffer = Object::New();
|
||||
buffer->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly);
|
||||
buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
|
||||
|
||||
Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
|
||||
persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
|
||||
|
Loading…
Reference in New Issue
Block a user