Chromium Code Reviews| Index: src/d8.cc |
| diff --git a/src/d8.cc b/src/d8.cc |
| index ad850f5ee780334d7cff606d6da2710005969b11..807124b083d48beffce335bd5c90d03f122a390c 100644 |
| --- a/src/d8.cc |
| +++ b/src/d8.cc |
| @@ -1,4 +1,4 @@ |
| -// Copyright 2011 the V8 project authors. All rights reserved. |
| +// Copyright 2012 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| @@ -281,63 +281,117 @@ Handle<Value> Shell::Load(const Arguments& args) { |
| return Undefined(); |
| } |
| +static int convertToInt(Local<Value> value_in, TryCatch* try_catch) { |
|
Jakob Kummerow
2012/01/11 10:17:53
Rename to convertToUint?
danno
2012/01/11 13:07:41
Done.
|
| + if (value_in->IsUint32()) { |
| + return value_in->Uint32Value(); |
| + } |
| -Handle<Value> Shell::CreateExternalArray(const Arguments& args, |
| - ExternalArrayType type, |
| - size_t element_size) { |
| - ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || |
| - element_size == 8); |
| - if (args.Length() != 1) { |
| - return ThrowException( |
| - String::New("Array constructor needs one parameter.")); |
| + Local<Value> number = value_in->ToNumber(); |
| + if (number.IsEmpty()) { |
| + ASSERT(try_catch->HasCaught()); |
| + return 0; |
| + } |
| + |
| + ASSERT(number->IsNumber()); |
| + Local<Int32> int32 = number->ToInt32(); |
| + if (int32.IsEmpty()) { |
| + ASSERT(try_catch->HasCaught()); |
| + return 0; |
| + } |
| + int32_t raw_value = int32->Int32Value(); |
| + if (try_catch->HasCaught()) { |
| + return 0; |
| + } |
| + if (raw_value < 0) { |
| + ThrowException(String::New("Array length must not be negative.")); |
| + return 0; |
| } |
| + |
| static const int kMaxLength = 0x3fffffff; |
| #ifndef V8_SHARED |
| ASSERT(kMaxLength == i::ExternalArray::kMaxLength); |
| #endif // V8_SHARED |
| - size_t length = 0; |
| + if (raw_value > static_cast<int32_t>(kMaxLength)) { |
| + ThrowException( |
| + String::New("Array length exceeds maximum length.")); |
| + } |
| + return static_cast<size_t>(raw_value); |
| +} |
| + |
| + |
| +const char kArrayBufferReferencePropName[] = "_array_buffer_ref"; |
| + |
| + |
| +Handle<Value> Shell::CreateExternalArray(const Arguments& args, |
| + ExternalArrayType type, |
| + size_t element_size) { |
| + ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || |
| + element_size == 8); |
| TryCatch try_catch; |
| - if (args[0]->IsUint32()) { |
| - length = args[0]->Uint32Value(); |
| - } else { |
| - Local<Number> number = args[0]->ToNumber(); |
| - if (number.IsEmpty()) { |
| - ASSERT(try_catch.HasCaught()); |
| - return try_catch.Exception(); |
| - } |
| - ASSERT(number->IsNumber()); |
| - Local<Int32> int32 = number->ToInt32(); |
| - if (int32.IsEmpty()) { |
| - if (try_catch.HasCaught()) { |
| - return try_catch.Exception(); |
| - } |
| - } |
| - int32_t raw_length = int32->Int32Value(); |
| - if (try_catch.HasCaught()) { |
| - return try_catch.Exception(); |
| - } |
| - if (raw_length < 0) { |
| - return ThrowException(String::New("Array length must not be negative.")); |
| + size_t derived_from_element_size = 1; |
| + if (args[0]->IsNumber()) { |
| + if (args.Length() != 1) { |
| + return ThrowException( |
| + String::New("Array constructor with length must have " |
| + "one parameter.")); |
| } |
| - if (raw_length > static_cast<int32_t>(kMaxLength)) { |
| + } else { |
| + if (args.Length() > 3 || args.Length() == 0) { |
|
Jakob Kummerow
2012/01/11 10:17:53
Arguments.operator[] is benign enough to simply re
danno
2012/01/11 13:07:41
Done.
|
| return ThrowException( |
| - String::New("Array length exceeds maximum length.")); |
| + String::New("Array constructor from ArrayBuffer must " |
| + "have 1-3 parameters.")); |
| } |
| - length = static_cast<size_t>(raw_length); |
| } |
| - if (length > static_cast<size_t>(kMaxLength)) { |
| - return ThrowException(String::New("Array length exceeds maximum length.")); |
| + |
| + Local<Value> length_value = (args.Length() == 1) |
| + ? (args[0]->IsNumber() |
| + ? args[0] |
| + : args[0]->ToObject()->Get(String::New("length"))) |
| + : args[2]; |
|
Jakob Kummerow
2012/01/11 10:17:53
args[2] is optional and could be undefined. As imp
danno
2012/01/11 13:07:41
Done.
|
| + int length = convertToInt(length_value, &try_catch); |
| + if (try_catch.HasCaught()) return try_catch.Exception(); |
| + |
| + void* data = NULL; |
| + if (!args[0]->IsNumber()) { |
| + Handle<Object> array = args[0]->ToObject(); |
| + data = array->GetIndexedPropertiesExternalArrayData(); |
| + if (data == NULL) { |
| + return ThrowException( |
| + String::New("ArrayBuffer doesn't have data")); |
| + } |
| + derived_from_element_size = |
| + array->Get(String::New("BYTES_PER_ELEMENT"))->ToInt32()->Int32Value(); |
|
Jakob Kummerow
2012/01/11 10:17:53
My reading of the spec at http://www.khronos.org/r
danno
2012/01/11 13:07:41
Done.
|
| + length *= derived_from_element_size; |
| + length /= element_size; |
| } |
| - void* data = calloc(length, element_size); |
| - if (data == NULL) { |
| - return ThrowException(String::New("Memory allocation failed.")); |
| + |
| + size_t offset = 0; |
| + if (args.Length() > 1) { |
| + offset = convertToInt(args[1], &try_catch); |
| + if (try_catch.HasCaught()) return try_catch.Exception(); |
| + |
| + if (offset % element_size != 0) { |
| + return ThrowException( |
| + String::New("offset must be multiple of element_size")); |
| + } |
| } |
| + |
| Handle<Object> array = Object::New(); |
| Persistent<Object> persistent_array = Persistent<Object>::New(array); |
| persistent_array.MakeWeak(data, ExternalArrayWeakCallback); |
| persistent_array.MarkIndependent(); |
| - array->SetIndexedPropertiesToExternalArrayData(data, type, |
| - static_cast<int>(length)); |
| + if (data == NULL) { |
| + data = calloc(length, element_size); |
| + if (data == NULL) { |
| + return ThrowException(String::New("Memory allocation failed.")); |
| + } |
| + } else { |
| + // Hold a reference to the ArrayBuffer so it's buffer doesn't get collected. |
|
Jakob Kummerow
2012/01/11 10:17:53
s/it's/its/
danno
2012/01/11 13:07:41
Done.
|
| + array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); |
| + } |
| + array->SetIndexedPropertiesToExternalArrayData( |
| + reinterpret_cast<uint8_t*>(data) + offset, type, |
|
Jakob Kummerow
2012/01/11 10:17:53
Whoa... please add checks that both |offset| and |
danno
2012/01/11 13:07:41
Done.
|
| + static_cast<int>(length)); |
| array->Set(String::New("length"), |
| Int32::New(static_cast<int32_t>(length)), ReadOnly); |
| array->Set(String::New("BYTES_PER_ELEMENT"), |
| @@ -347,8 +401,18 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, |
| void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { |
| - free(data); |
| - object.Dispose(); |
| + Handle<String> prop_name = String::New(kArrayBufferReferencePropName); |
| + Handle<Object> converted_object = object->ToObject(); |
| + Local<Value> prop_value = converted_object->Get(prop_name); |
| + if (!prop_value->IsObject()) { |
| + free(data); |
| + object.Dispose(); |
| + } |
| +} |
| + |
| + |
| +Handle<Value> Shell::ArrayBuffer(const Arguments& args) { |
| + return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); |
| } |
| @@ -693,6 +757,8 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { |
| FunctionTemplate::New(DisableProfiler)); |
| // Bind the handlers for external arrays. |
| + global_template->Set(String::New("ArrayBuffer"), |
| + FunctionTemplate::New(ArrayBuffer)); |
| global_template->Set(String::New("Int8Array"), |
| FunctionTemplate::New(Int8Array)); |
| global_template->Set(String::New("Uint8Array"), |