summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/src/d8.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/src/d8.cc')
-rw-r--r--src/3rdparty/v8/src/d8.cc710
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