diff options
Diffstat (limited to 'src/3rdparty/v8/src/d8.cc')
-rw-r--r-- | src/3rdparty/v8/src/d8.cc | 710 |
1 files changed, 510 insertions, 200 deletions
diff --git a/src/3rdparty/v8/src/d8.cc b/src/3rdparty/v8/src/d8.cc index ddd4100..b3b1bb8 100644 --- a/src/3rdparty/v8/src/d8.cc +++ b/src/3rdparty/v8/src/d8.cc @@ -200,7 +200,13 @@ Handle<Value> Shell::Write(const Arguments& args) { if (i != 0) { printf(" "); } - v8::String::Utf8Value str(args[i]); + + // Explicitly catch potential exceptions in toString(). + v8::TryCatch try_catch; + Handle<String> str_obj = args[i]->ToString(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + v8::String::Utf8Value str(str_obj); int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout)); if (n != str.length()) { printf("Error in fwrite\n"); @@ -284,9 +290,9 @@ Handle<Value> Shell::Load(const Arguments& args) { return Undefined(); } -static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { - if (value_in->IsUint32()) { - return value_in->Uint32Value(); +static int32_t convertToInt(Local<Value> value_in, TryCatch* try_catch) { + if (value_in->IsInt32()) { + return value_in->Int32Value(); } Local<Value> number = value_in->ToNumber(); @@ -296,7 +302,15 @@ static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { Local<Int32> int32 = number->ToInt32(); if (try_catch->HasCaught() || int32.IsEmpty()) return 0; - int32_t raw_value = int32->Int32Value(); + int32_t value = int32->Int32Value(); + if (try_catch->HasCaught()) return 0; + + return value; +} + + +static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { + int32_t raw_value = convertToInt(value_in, try_catch); if (try_catch->HasCaught()) return 0; if (raw_value < 0) { @@ -312,182 +326,463 @@ static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { ThrowException( String::New("Array length exceeds maximum length.")); } - return static_cast<size_t>(raw_value); + return raw_value; } -const char kArrayBufferMarkerPropName[] = "_is_array_buffer_"; -const char kArrayBufferReferencePropName[] = "_array_buffer_ref_"; +// TODO(rossberg): should replace these by proper uses of HasInstance, +// once we figure out a good way to make the templates global. +const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; +const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; -static const int kExternalArrayAllocationHeaderSize = 2; -Handle<Value> Shell::CreateExternalArray(const Arguments& args, - ExternalArrayType type, - size_t element_size) { - TryCatch try_catch; - bool is_array_buffer_construct = element_size == 0; - if (is_array_buffer_construct) { - type = v8::kExternalByteArray; - element_size = 1; +Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, + int32_t length) { + static const int32_t kMaxSize = 0x7fffffff; + // Make sure the total size fits into a (signed) int. + if (length < 0 || length > kMaxSize) { + return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); + } + uint8_t* data = new uint8_t[length]; + if (data == NULL) { + return ThrowException(String::New("Memory allocation failed")); } - ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || - element_size == 8); + memset(data, 0, length); + + buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); + Persistent<Object> persistent_array = Persistent<Object>::New(buffer); + persistent_array.MakeWeak(data, ExternalArrayWeakCallback); + persistent_array.MarkIndependent(); + V8::AdjustAmountOfExternalAllocatedMemory(length); + + buffer->SetIndexedPropertiesToExternalArrayData( + data, v8::kExternalByteArray, length); + buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); + + return buffer; +} + + +Handle<Value> Shell::ArrayBuffer(const Arguments& args) { + if (!args.IsConstructCall()) { + Handle<Value>* rec_args = new Handle<Value>[args.Length()]; + for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; + Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); + delete[] rec_args; + return result; + } + if (args.Length() == 0) { return ThrowException( - String::New("Array constructor must have at least one " - "parameter.")); - } - bool first_arg_is_array_buffer = - args[0]->IsObject() && - args[0]->ToObject()->Get( - String::New(kArrayBufferMarkerPropName))->IsTrue(); - // Currently, only the following constructors are supported: + String::New("ArrayBuffer constructor must have one argument")); + } + TryCatch try_catch; + int32_t length = convertToUint(args[0], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + return CreateExternalArrayBuffer(args.This(), length); +} + + +Handle<Object> Shell::CreateExternalArray(Handle<Object> array, + Handle<Object> buffer, + ExternalArrayType type, + int32_t length, + int32_t byteLength, + int32_t byteOffset, + int32_t element_size) { + ASSERT(element_size == 1 || element_size == 2 || + element_size == 4 || element_size == 8); + ASSERT(byteLength == length * element_size); + + void* data = buffer->GetIndexedPropertiesExternalArrayData(); + ASSERT(data != NULL); + + array->SetIndexedPropertiesToExternalArrayData( + static_cast<uint8_t*>(data) + byteOffset, type, length); + array->SetHiddenValue(String::New(kArrayMarkerPropName), Int32::New(type)); + array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly); + array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly); + array->Set(String::New("length"), Int32::New(length), ReadOnly); + array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size)); + array->Set(String::New("buffer"), buffer, ReadOnly); + + return array; +} + + +Handle<Value> Shell::CreateExternalArray(const Arguments& args, + ExternalArrayType type, + int32_t element_size) { + if (!args.IsConstructCall()) { + Handle<Value>* rec_args = new Handle<Value>[args.Length()]; + for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; + Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); + delete[] rec_args; + return result; + } + + TryCatch try_catch; + ASSERT(element_size == 1 || element_size == 2 || + element_size == 4 || element_size == 8); + + // All of the following constructors are supported: // TypedArray(unsigned long length) + // TypedArray(type[] array) + // TypedArray(TypedArray array) // TypedArray(ArrayBuffer buffer, // optional unsigned long byteOffset, // optional unsigned long length) - if (args.Length() > 3) { + Handle<Object> buffer; + int32_t length; + int32_t byteLength; + int32_t byteOffset; + bool init_from_array = false; + if (args.Length() == 0) { 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(); - - 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 (try_catch.HasCaught()) return try_catch.Exception(); - - if (data == NULL && array_buffer_length != 0) { - return ThrowException( - String::New("ArrayBuffer doesn't have data")); + String::New("Array constructor must have at least one argument")); + } + if (args[0]->IsObject() && + !args[0]->ToObject()->GetHiddenValue( + String::New(kArrayBufferMarkerPropName)).IsEmpty()) { + // Construct from ArrayBuffer. + buffer = args[0]->ToObject(); + int32_t bufferLength = + convertToUint(buffer->Get(String::New("byteLength")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + if (args.Length() < 2 || args[1]->IsUndefined()) { + byteOffset = 0; + } else { + byteOffset = convertToUint(args[1], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + if (byteOffset > bufferLength) { + return ThrowException(String::New("byteOffset out of bounds")); + } + if (byteOffset % element_size != 0) { + return ThrowException( + String::New("byteOffset must be multiple of element size")); + } } - if (args.Length() > 1) { - offset = 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 (args.Length() < 3 || args[2]->IsUndefined()) { + byteLength = bufferLength - byteOffset; + length = byteLength / element_size; + if (byteLength % element_size != 0) { return ThrowException( - String::New("offset must be multiple of element_size")); + String::New("buffer size must be multiple of element size")); + } + } else { + length = convertToUint(args[2], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + byteLength = length * element_size; + if (byteOffset + byteLength > bufferLength) { + return ThrowException(String::New("length out of bounds")); } } - - if (offset > array_buffer_length) { - return ThrowException( - String::New("byteOffset must be less than ArrayBuffer length.")); + } else { + if (args[0]->IsObject() && + args[0]->ToObject()->Has(String::New("length"))) { + // Construct from array. + length = convertToUint( + args[0]->ToObject()->Get(String::New("length")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + init_from_array = true; + } else { + // Construct from size. + length = convertToUint(args[0], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); } + byteLength = length * element_size; + byteOffset = 0; + + Handle<Object> global = Context::GetCurrent()->Global(); + Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); + ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); + Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; + Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( + 1, buffer_args); + if (try_catch.HasCaught()) return result; + buffer = result->ToObject(); + } - 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; - } + Handle<Object> array = CreateExternalArray( + args.This(), buffer, type, length, byteLength, byteOffset, element_size); - if (args.Length() != 3) { - if (length % element_size != 0) { - return ThrowException( - String::New("ArrayBuffer length minus the byteOffset must be a " - "multiple of the element size")); - } - length /= element_size; - } + if (init_from_array) { + Handle<Object> init = args[0]->ToObject(); + for (int i = 0; i < length; ++i) array->Set(i, init->Get(i)); + } + + return array; +} - // 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) { - return ThrowException( - String::New("length references an area beyond the end of the " - "ArrayBuffer")); - } - // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. - array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); +Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) { + TryCatch try_catch; + + if (!args.This()->IsObject()) { + return ThrowException( + String::New("'slice' invoked on non-object receiver")); } - if (is_array_buffer_construct) { - array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); + Local<Object> self = args.This(); + Local<Value> marker = + self->GetHiddenValue(String::New(kArrayBufferMarkerPropName)); + if (marker.IsEmpty()) { + return ThrowException( + String::New("'slice' invoked on wrong receiver type")); } - Persistent<Object> persistent_array = Persistent<Object>::New(array); - if (data == NULL && length != 0) { - // Make sure the total size fits into a (signed) int. - static const int kMaxSize = 0x7fffffff; - if (length > (kMaxSize - sizeof(size_t)) / element_size) { - 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); - V8::AdjustAmountOfExternalAllocatedMemory(total_size); + int32_t length = + convertToUint(self->Get(String::New("byteLength")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + if (args.Length() == 0) { + return ThrowException( + String::New("'slice' must have at least one argument")); + } + int32_t begin = convertToInt(args[0], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + if (begin < 0) begin += length; + if (begin < 0) begin = 0; + if (begin > length) begin = length; + + int32_t end; + if (args.Length() < 2 || args[1]->IsUndefined()) { + end = length; + } else { + end = convertToInt(args[1], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + if (end < 0) end += length; + if (end < 0) end = 0; + if (end > length) end = length; + if (end < begin) end = begin; } - persistent_array.MakeWeak(data, ExternalArrayWeakCallback); - persistent_array.MarkIndependent(); - array->SetIndexedPropertiesToExternalArrayData( - reinterpret_cast<uint8_t*>(data) + offset, 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("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. - if (first_arg_is_array_buffer) { - array->Set(String::New("buffer"), args[0], ReadOnly); - } + Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); + Handle<Value> new_args[] = { Uint32::New(end - begin) }; + Handle<Value> result = constructor->NewInstance(1, new_args); + if (try_catch.HasCaught()) return result; + Handle<Object> buffer = result->ToObject(); + uint8_t* dest = + static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData()); + uint8_t* src = begin + static_cast<uint8_t*>( + self->GetIndexedPropertiesExternalArrayData()); + memcpy(dest, src, end - begin); + + return buffer; +} + + +Handle<Value> Shell::ArraySubArray(const Arguments& args) { + TryCatch try_catch; + + if (!args.This()->IsObject()) { + return ThrowException( + String::New("'subarray' invoked on non-object receiver")); } - return array; + + Local<Object> self = args.This(); + Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); + if (marker.IsEmpty()) { + return ThrowException( + String::New("'subarray' invoked on wrong receiver type")); + } + + Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t length = + convertToUint(self->Get(String::New("length")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t byteOffset = + convertToUint(self->Get(String::New("byteOffset")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t element_size = + convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + if (args.Length() == 0) { + return ThrowException( + String::New("'subarray' must have at least one argument")); + } + int32_t begin = convertToInt(args[0], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + if (begin < 0) begin += length; + if (begin < 0) begin = 0; + if (begin > length) begin = length; + + int32_t end; + if (args.Length() < 2 || args[1]->IsUndefined()) { + end = length; + } else { + end = convertToInt(args[1], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + if (end < 0) end += length; + if (end < 0) end = 0; + if (end > length) end = length; + if (end < begin) end = begin; + } + + length = end - begin; + byteOffset += begin * element_size; + + Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); + Handle<Value> construct_args[] = { + buffer, Uint32::New(byteOffset), Uint32::New(length) + }; + return constructor->NewInstance(3, construct_args); } -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); - if (data != NULL && !prop_value->IsObject()) { - data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize; - V8::AdjustAmountOfExternalAllocatedMemory( - -static_cast<int>(*reinterpret_cast<size_t*>(data))); - free(data); +Handle<Value> Shell::ArraySet(const Arguments& args) { + TryCatch try_catch; + + if (!args.This()->IsObject()) { + return ThrowException( + String::New("'set' invoked on non-object receiver")); } - object.Dispose(); + + Local<Object> self = args.This(); + Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); + if (marker.IsEmpty()) { + return ThrowException( + String::New("'set' invoked on wrong receiver type")); + } + int32_t length = + convertToUint(self->Get(String::New("length")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t element_size = + convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + if (args.Length() == 0) { + return ThrowException( + String::New("'set' must have at least one argument")); + } + if (!args[0]->IsObject() || + !args[0]->ToObject()->Has(String::New("length"))) { + return ThrowException( + String::New("'set' invoked with non-array argument")); + } + Handle<Object> source = args[0]->ToObject(); + int32_t source_length = + convertToUint(source->Get(String::New("length")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + int32_t offset; + if (args.Length() < 2 || args[1]->IsUndefined()) { + offset = 0; + } else { + offset = convertToUint(args[1], &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + } + if (offset + source_length > length) { + return ThrowException(String::New("offset or source length out of bounds")); + } + + int32_t source_element_size; + if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty()) { + source_element_size = 0; + } else { + source_element_size = + convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + } + + if (element_size == source_element_size && + self->GetConstructor()->StrictEquals(source->GetConstructor())) { + // Use memmove on the array buffers. + Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + Handle<Object> source_buffer = + source->Get(String::New("buffer"))->ToObject(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t byteOffset = + convertToUint(self->Get(String::New("byteOffset")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t source_byteOffset = + convertToUint(source->Get(String::New("byteOffset")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>( + buffer->GetIndexedPropertiesExternalArrayData()); + uint8_t* src = source_byteOffset + static_cast<uint8_t*>( + source_buffer->GetIndexedPropertiesExternalArrayData()); + memmove(dest, src, source_length * element_size); + } else if (source_element_size == 0) { + // Source is not a typed array, copy element-wise sequentially. + for (int i = 0; i < source_length; ++i) { + self->Set(offset + i, source->Get(i)); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + } + } else { + // Need to copy element-wise to make the right conversions. + Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + Handle<Object> source_buffer = + source->Get(String::New("buffer"))->ToObject(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + if (buffer->StrictEquals(source_buffer)) { + // Same backing store, need to handle overlap correctly. + // This gets a bit tricky in the case of different element sizes + // (which, of course, is extremely unlikely to ever occur in practice). + int32_t byteOffset = + convertToUint(self->Get(String::New("byteOffset")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + int32_t source_byteOffset = + convertToUint(source->Get(String::New("byteOffset")), &try_catch); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + // Copy as much as we can from left to right. + int i = 0; + int32_t next_dest_offset = byteOffset + (offset + 1) * element_size; + int32_t next_src_offset = source_byteOffset + source_element_size; + while (i < length && next_dest_offset <= next_src_offset) { + self->Set(offset + i, source->Get(i)); + ++i; + next_dest_offset += element_size; + next_src_offset += source_element_size; + } + // Of what's left, copy as much as we can from right to left. + int j = length - 1; + int32_t dest_offset = byteOffset + (offset + j) * element_size; + int32_t src_offset = source_byteOffset + j * source_element_size; + while (j >= i && dest_offset >= src_offset) { + self->Set(offset + j, source->Get(j)); + --j; + dest_offset -= element_size; + src_offset -= source_element_size; + } + // There can be at most 8 entries left in the middle that need buffering + // (because the largest element_size is 8 times the smallest). + ASSERT(j+1 - i <= 8); + Handle<Value> temp[8]; + for (int k = i; k <= j; ++k) { + temp[k - i] = source->Get(k); + } + for (int k = i; k <= j; ++k) { + self->Set(offset + k, temp[k - i]); + } + } else { + // Different backing stores, safe to copy element-wise sequentially. + for (int i = 0; i < source_length; ++i) + self->Set(offset + i, source->Get(i)); + } + } + + return Undefined(); } -Handle<Value> Shell::ArrayBuffer(const Arguments& args) { - return CreateExternalArray(args, v8::kExternalByteArray, 0); +void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { + HandleScope scope; + int32_t length = + object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); + V8::AdjustAmountOfExternalAllocatedMemory(-length); + delete[] static_cast<uint8_t*>(data); + object.Dispose(); } @@ -507,8 +802,8 @@ Handle<Value> Shell::Int16Array(const Arguments& args) { Handle<Value> Shell::Uint16Array(const Arguments& args) { - return CreateExternalArray(args, kExternalUnsignedShortArray, - sizeof(uint16_t)); + return CreateExternalArray( + args, kExternalUnsignedShortArray, sizeof(uint16_t)); } @@ -523,18 +818,18 @@ Handle<Value> Shell::Uint32Array(const Arguments& args) { Handle<Value> Shell::Float32Array(const Arguments& args) { - return CreateExternalArray(args, kExternalFloatArray, - sizeof(float)); // NOLINT + return CreateExternalArray( + args, kExternalFloatArray, sizeof(float)); // NOLINT } Handle<Value> Shell::Float64Array(const Arguments& args) { - return CreateExternalArray(args, kExternalDoubleArray, - sizeof(double)); // NOLINT + return CreateExternalArray( + args, kExternalDoubleArray, sizeof(double)); // NOLINT } -Handle<Value> Shell::PixelArray(const Arguments& args) { +Handle<Value> Shell::Uint8ClampedArray(const Arguments& args) { return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t)); } @@ -764,7 +1059,7 @@ void Shell::InstallUtilityScript() { i::Debug* debug = i::Isolate::Current()->debug(); debug->Load(); i::Handle<i::JSObject> js_debug - = i::Handle<i::JSObject>(debug->debug_context()->global()); + = i::Handle<i::JSObject>(debug->debug_context()->global_object()); utility_context_->Global()->Set(String::New("$debug"), Utils::ToLocal(js_debug)); debug->debug_context()->set_security_token(HEAP->undefined_value()); @@ -829,13 +1124,32 @@ class BZip2Decompressor : public v8::StartupDataDecompressor { }; #endif + +Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate( + InvocationCallback fun) { + Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun); + Local<Template> proto_template = buffer_template->PrototypeTemplate(); + proto_template->Set(String::New("slice"), + FunctionTemplate::New(ArrayBufferSlice)); + return buffer_template; +} + + +Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { + Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); + Local<Template> proto_template = array_template->PrototypeTemplate(); + proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet)); + proto_template->Set(String::New("subarray"), + FunctionTemplate::New(ArraySubArray)); + return array_template; +} + + Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { Handle<ObjectTemplate> global_template = ObjectTemplate::New(); global_template->Set(String::New("print"), FunctionTemplate::New(Print)); global_template->Set(String::New("write"), FunctionTemplate::New(Write)); global_template->Set(String::New("read"), FunctionTemplate::New(Read)); - global_template->Set(String::New("readbinary"), - FunctionTemplate::New(ReadBinary)); global_template->Set(String::New("readbuffer"), FunctionTemplate::New(ReadBuffer)); global_template->Set(String::New("readline"), @@ -849,26 +1163,28 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { FunctionTemplate::New(DisableProfiler)); // Bind the handlers for external arrays. + PropertyAttribute attr = + static_cast<PropertyAttribute>(ReadOnly | DontDelete); global_template->Set(String::New("ArrayBuffer"), - FunctionTemplate::New(ArrayBuffer)); + CreateArrayBufferTemplate(ArrayBuffer), attr); global_template->Set(String::New("Int8Array"), - FunctionTemplate::New(Int8Array)); + CreateArrayTemplate(Int8Array), attr); global_template->Set(String::New("Uint8Array"), - FunctionTemplate::New(Uint8Array)); + CreateArrayTemplate(Uint8Array), attr); global_template->Set(String::New("Int16Array"), - FunctionTemplate::New(Int16Array)); + CreateArrayTemplate(Int16Array), attr); global_template->Set(String::New("Uint16Array"), - FunctionTemplate::New(Uint16Array)); + CreateArrayTemplate(Uint16Array), attr); global_template->Set(String::New("Int32Array"), - FunctionTemplate::New(Int32Array)); + CreateArrayTemplate(Int32Array), attr); global_template->Set(String::New("Uint32Array"), - FunctionTemplate::New(Uint32Array)); + CreateArrayTemplate(Uint32Array), attr); global_template->Set(String::New("Float32Array"), - FunctionTemplate::New(Float32Array)); + CreateArrayTemplate(Float32Array), attr); global_template->Set(String::New("Float64Array"), - FunctionTemplate::New(Float64Array)); - global_template->Set(String::New("PixelArray"), - FunctionTemplate::New(PixelArray)); + CreateArrayTemplate(Float64Array), attr); + global_template->Set(String::New("Uint8ClampedArray"), + CreateArrayTemplate(Uint8ClampedArray), attr); #ifdef LIVE_OBJECT_LIST global_template->Set(String::New("lol_is_enabled"), True()); @@ -901,7 +1217,7 @@ void Shell::Initialize() { // Set up counters if (i::StrLength(i::FLAG_map_counters) != 0) MapCounters(i::FLAG_map_counters); - if (i::FLAG_dump_counters) { + if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) { V8::SetCounterFunction(LookupCounter); V8::SetCreateHistogramFunction(CreateHistogram); V8::SetAddHistogramSampleFunction(AddHistogramSample); @@ -991,20 +1307,24 @@ void Shell::OnExit() { counters[j].key = i.CurrentKey(); } qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys); - printf("+--------------------------------------------+-------------+\n"); - printf("| Name | Value |\n"); - printf("+--------------------------------------------+-------------+\n"); + printf("+----------------------------------------------------------------+" + "-------------+\n"); + printf("| Name |" + " Value |\n"); + printf("+----------------------------------------------------------------+" + "-------------+\n"); for (j = 0; j < number_of_counters; j++) { Counter* counter = counters[j].counter; const char* key = counters[j].key; if (counter->is_histogram()) { - printf("| c:%-40s | %11i |\n", key, counter->count()); - printf("| t:%-40s | %11i |\n", key, counter->sample_total()); + printf("| c:%-60s | %11i |\n", key, counter->count()); + printf("| t:%-60s | %11i |\n", key, counter->sample_total()); } else { - printf("| %-42s | %11i |\n", key, counter->count()); + printf("| %-62s | %11i |\n", key, counter->count()); } } - printf("+--------------------------------------------+-------------+\n"); + printf("+----------------------------------------------------------------+" + "-------------+\n"); delete [] counters; } delete counters_file_; @@ -1056,45 +1376,29 @@ static char* ReadChars(const char* name, int* size_out) { } -Handle<Value> Shell::ReadBinary(const Arguments& args) { - String::Utf8Value filename(args[0]); - int size; - if (*filename == NULL) { - return ThrowException(String::New("Error loading file")); - } - char* chars = ReadChars(*filename, &size); - if (chars == NULL) { - return ThrowException(String::New("Error reading file")); - } - // We skip checking the string for UTF8 characters and use it raw as - // backing store for the external string with 8-bit characters. - BinaryResource* resource = new BinaryResource(chars, size); - return String::NewExternal(resource); -} - - Handle<Value> Shell::ReadBuffer(const Arguments& args) { + ASSERT(sizeof(char) == sizeof(uint8_t)); // NOLINT String::Utf8Value filename(args[0]); int length; if (*filename == NULL) { return ThrowException(String::New("Error loading file")); } - char* data = ReadChars(*filename, &length); + + uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length)); if (data == NULL) { return ThrowException(String::New("Error reading file")); } - 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); persistent_buffer.MarkIndependent(); + V8::AdjustAmountOfExternalAllocatedMemory(length); buffer->SetIndexedPropertiesToExternalArrayData( - reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); + data, kExternalUnsignedByteArray, length); buffer->Set(String::New("byteLength"), - Int32::New(static_cast<int32_t>(length)), ReadOnly); + Int32::New(static_cast<int32_t>(length)), ReadOnly); return buffer; } @@ -1259,7 +1563,7 @@ void SourceGroup::Execute() { Handle<String> SourceGroup::ReadFile(const char* name) { int size; - const char* chars = ReadChars(name, &size); + char* chars = ReadChars(name, &size); if (chars == NULL) return Handle<String>(); Handle<String> result = String::New(chars, size); delete[] chars; @@ -1291,6 +1595,11 @@ void SourceGroup::ExecuteInThread() { Execute(); } context.Dispose(); + if (Shell::options.send_idle_notification) { + const int kLongIdlePauseInMs = 1000; + V8::ContextDisposedNotification(); + V8::IdleNotification(kLongIdlePauseInMs); + } } if (done_semaphore_ != NULL) done_semaphore_->Signal(); } while (!Shell::options.last_run); @@ -1336,6 +1645,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { } else if (strcmp(argv[i], "--test") == 0) { options.test_shell = true; argv[i] = NULL; + } else if (strcmp(argv[i], "--send-idle-notification") == 0) { + options.send_idle_notification = true; + argv[i] = NULL; } else if (strcmp(argv[i], "--preemption") == 0) { #ifdef V8_SHARED printf("D8 with shared library does not support multi-threading\n"); @@ -1492,13 +1804,11 @@ int Shell::RunMain(int argc, char* argv[]) { } if (!options.last_run) { context.Dispose(); -#if !defined(V8_SHARED) - if (i::FLAG_send_idle_notification) { + if (options.send_idle_notification) { const int kLongIdlePauseInMs = 1000; V8::ContextDisposedNotification(); V8::IdleNotification(kLongIdlePauseInMs); } -#endif // !V8_SHARED } #ifndef V8_SHARED |