From 0b4c7c8de9bd6fe5191b06e975df093e98f53b51 Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Thu, 16 May 2013 11:48:03 +0000 Subject: [PATCH] Remove d8 implementation of ArrayBuffer and typed arrays. R=rossberg@chromium.org Review URL: https://codereview.chromium.org/14654011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14706 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/d8.cc | 660 +-------------------------------------------------------- src/runtime.cc | 2 +- 2 files changed, 4 insertions(+), 658 deletions(-) diff --git a/src/d8.cc b/src/d8.cc index 7ac78cc..b95432e 100644 --- a/src/d8.cc +++ b/src/d8.cc @@ -89,38 +89,15 @@ static Handle Throw(const char* message) { } -// 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_"; - - -#define FOR_EACH_STRING(V) \ - V(ArrayBuffer, "ArrayBuffer") \ - V(ArrayBufferMarkerPropName, kArrayBufferMarkerPropName) \ - V(ArrayMarkerPropName, kArrayMarkerPropName) \ - V(buffer, "buffer") \ - V(byteLength, "byteLength") \ - V(byteOffset, "byteOffset") \ - V(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \ - V(length, "length") - class PerIsolateData { public: explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) { HandleScope scope(isolate); -#define INIT_STRING(name, value) \ - name##_string_ = Persistent::New(isolate, String::NewSymbol(value)); - FOR_EACH_STRING(INIT_STRING) -#undef INIT_STRING isolate->SetData(this); } ~PerIsolateData() { -#define DISPOSE_STRING(name, value) name##_string_.Dispose(isolate_); - FOR_EACH_STRING(DISPOSE_STRING) -#undef DISPOSE_STRING isolate_->SetData(NULL); // Not really needed, just to be sure... } @@ -128,13 +105,6 @@ class PerIsolateData { return reinterpret_cast(isolate->GetData()); } -#define DEFINE_STRING_GETTER(name, value) \ - static Handle name##_string(Isolate* isolate) { \ - return Handle(*Get(isolate)->name##_string_); \ - } - FOR_EACH_STRING(DEFINE_STRING_GETTER) -#undef DEFINE_STRING_GETTER - class RealmScope { public: explicit RealmScope(PerIsolateData* data); @@ -153,10 +123,6 @@ class PerIsolateData { Persistent* realms_; Persistent realm_shared_; -#define DEFINE_MEMBER(name, value) Persistent name##_string_; - FOR_EACH_STRING(DEFINE_MEMBER) -#undef DEFINE_MEMBER - int RealmFind(Handle context); }; @@ -561,565 +527,6 @@ Handle Shell::Load(const Arguments& args) { return Undefined(args.GetIsolate()); } -static int32_t convertToInt(Local value_in, TryCatch* try_catch) { - if (value_in->IsInt32()) { - return value_in->Int32Value(); - } - - Local number = value_in->ToNumber(); - if (try_catch->HasCaught()) return 0; - - ASSERT(number->IsNumber()); - Local int32 = number->ToInt32(); - if (try_catch->HasCaught() || int32.IsEmpty()) return 0; - - int32_t value = int32->Int32Value(); - if (try_catch->HasCaught()) return 0; - - return value; -} - - -static int32_t convertToUint(Local value_in, TryCatch* try_catch) { - int32_t raw_value = convertToInt(value_in, try_catch); - if (try_catch->HasCaught()) return 0; - - if (raw_value < 0) { - Throw("Array length must not be negative."); - return 0; - } - - static const int kMaxLength = 0x3fffffff; -#ifndef V8_SHARED - ASSERT(kMaxLength == i::ExternalArray::kMaxLength); -#endif // V8_SHARED - if (raw_value > static_cast(kMaxLength)) { - Throw("Array length exceeds maximum length."); - } - return raw_value; -} - - -Handle Shell::CreateExternalArrayBuffer(Isolate* isolate, - Handle 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 Throw("ArrayBuffer exceeds maximum size (2G)"); - } - uint8_t* data = new uint8_t[length]; - if (data == NULL) { - return Throw("Memory allocation failed"); - } - memset(data, 0, length); - - buffer->SetHiddenValue( - PerIsolateData::ArrayBufferMarkerPropName_string(isolate), True()); - Persistent persistent_array = - Persistent::New(isolate, buffer); - persistent_array.MakeWeak(isolate, data, ExternalArrayWeakCallback); - persistent_array.MarkIndependent(isolate); - isolate->AdjustAmountOfExternalAllocatedMemory(length); - - buffer->SetIndexedPropertiesToExternalArrayData( - data, v8::kExternalByteArray, length); - buffer->Set(PerIsolateData::byteLength_string(isolate), - Int32::New(length, isolate), - ReadOnly); - - return buffer; -} - - -Handle Shell::ArrayBuffer(const Arguments& args) { - if (!args.IsConstructCall()) { - Handle* rec_args = new Handle[args.Length()]; - for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; - Handle result = args.Callee()->NewInstance(args.Length(), rec_args); - delete[] rec_args; - return result; - } - - if (args.Length() == 0) { - return Throw("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.GetIsolate(), args.This(), length); -} - - -Handle Shell::CreateExternalArray(Isolate* isolate, - Handle array, - Handle 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(data) + byteOffset, type, length); - array->SetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate), - Int32::New(type, isolate)); - array->Set(PerIsolateData::byteLength_string(isolate), - Int32::New(byteLength, isolate), - ReadOnly); - array->Set(PerIsolateData::byteOffset_string(isolate), - Int32::New(byteOffset, isolate), - ReadOnly); - array->Set(PerIsolateData::length_string(isolate), - Int32::New(length, isolate), - ReadOnly); - array->Set(PerIsolateData::BYTES_PER_ELEMENT_string(isolate), - Int32::New(element_size, isolate)); - array->Set(PerIsolateData::buffer_string(isolate), - buffer, - ReadOnly); - - return array; -} - - -Handle Shell::CreateExternalArray(const Arguments& args, - ExternalArrayType type, - int32_t element_size) { - Isolate* isolate = args.GetIsolate(); - if (!args.IsConstructCall()) { - Handle* rec_args = new Handle[args.Length()]; - for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; - Handle 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) - Handle buffer; - int32_t length; - int32_t byteLength; - int32_t byteOffset; - bool init_from_array = false; - if (args.Length() == 0) { - return Throw("Array constructor must have at least one argument"); - } - if (args[0]->IsObject() && - !args[0]->ToObject()->GetHiddenValue( - PerIsolateData::ArrayBufferMarkerPropName_string(isolate)).IsEmpty()) { - // Construct from ArrayBuffer. - buffer = args[0]->ToObject(); - int32_t bufferLength = convertToUint( - buffer->Get(PerIsolateData::byteLength_string(isolate)), &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 Throw("byteOffset out of bounds"); - } - if (byteOffset % element_size != 0) { - return Throw("byteOffset must be multiple of element size"); - } - } - - if (args.Length() < 3 || args[2]->IsUndefined()) { - byteLength = bufferLength - byteOffset; - length = byteLength / element_size; - if (byteLength % element_size != 0) { - return Throw("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 Throw("length out of bounds"); - } - } - } else { - if (args[0]->IsObject() && - args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) { - // Construct from array. - Local value = - args[0]->ToObject()->Get(PerIsolateData::length_string(isolate)); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - length = convertToUint(value, &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 global = Context::GetCurrent()->Global(); - Handle array_buffer = - global->Get(PerIsolateData::ArrayBuffer_string(isolate)); - ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); - Handle buffer_args[] = { Uint32::New(byteLength, isolate) }; - Handle result = Handle::Cast(array_buffer)->NewInstance( - 1, buffer_args); - if (try_catch.HasCaught()) return result; - buffer = result->ToObject(); - } - - Handle array = - CreateExternalArray(isolate, args.This(), buffer, type, length, - byteLength, byteOffset, element_size); - - if (init_from_array) { - Handle init = args[0]->ToObject(); - for (int i = 0; i < length; ++i) { - Local value = init->Get(i); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - array->Set(i, value); - } - } - - return array; -} - - -Handle Shell::ArrayBufferSlice(const Arguments& args) { - TryCatch try_catch; - - if (!args.This()->IsObject()) { - return Throw("'slice' invoked on non-object receiver"); - } - - Isolate* isolate = args.GetIsolate(); - Local self = args.This(); - Local marker = self->GetHiddenValue( - PerIsolateData::ArrayBufferMarkerPropName_string(isolate)); - if (marker.IsEmpty()) { - return Throw("'slice' invoked on wrong receiver type"); - } - - int32_t length = convertToUint( - self->Get(PerIsolateData::byteLength_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - - if (args.Length() == 0) { - return Throw("'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; - } - - Local constructor = Local::Cast(self->GetConstructor()); - Handle new_args[] = { Uint32::New(end - begin, isolate) }; - Handle result = constructor->NewInstance(1, new_args); - if (try_catch.HasCaught()) return result; - Handle buffer = result->ToObject(); - uint8_t* dest = - static_cast(buffer->GetIndexedPropertiesExternalArrayData()); - uint8_t* src = begin + static_cast( - self->GetIndexedPropertiesExternalArrayData()); - memcpy(dest, src, end - begin); - - return buffer; -} - - -Handle Shell::ArraySubArray(const Arguments& args) { - TryCatch try_catch; - - if (!args.This()->IsObject()) { - return Throw("'subarray' invoked on non-object receiver"); - } - - Isolate* isolate = args.GetIsolate(); - Local self = args.This(); - Local marker = - self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate)); - if (marker.IsEmpty()) { - return Throw("'subarray' invoked on wrong receiver type"); - } - - Handle buffer = - self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t length = convertToUint( - self->Get(PerIsolateData::length_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t byteOffset = convertToUint( - self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t element_size = convertToUint( - self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - - if (args.Length() == 0) { - return Throw("'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 constructor = Local::Cast(self->GetConstructor()); - Handle construct_args[] = { - buffer, Uint32::New(byteOffset, isolate), Uint32::New(length, isolate) - }; - return constructor->NewInstance(3, construct_args); -} - - -Handle Shell::ArraySet(const Arguments& args) { - TryCatch try_catch; - - if (!args.This()->IsObject()) { - return Throw("'set' invoked on non-object receiver"); - } - - Isolate* isolate = args.GetIsolate(); - Local self = args.This(); - Local marker = - self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate)); - if (marker.IsEmpty()) { - return Throw("'set' invoked on wrong receiver type"); - } - int32_t length = convertToUint( - self->Get(PerIsolateData::length_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t element_size = convertToUint( - self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - - if (args.Length() == 0) { - return Throw("'set' must have at least one argument"); - } - if (!args[0]->IsObject() || - !args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) { - return Throw("'set' invoked with non-array argument"); - } - Handle source = args[0]->ToObject(); - int32_t source_length = convertToUint( - source->Get(PerIsolateData::length_string(isolate)), &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 Throw("offset or source length out of bounds"); - } - - int32_t source_element_size; - if (source->GetHiddenValue( - PerIsolateData::ArrayMarkerPropName_string(isolate)).IsEmpty()) { - source_element_size = 0; - } else { - source_element_size = convertToUint( - source->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), - &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 buffer = - self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - Handle source_buffer = - source->Get(PerIsolateData::buffer_string(isolate))->ToObject(); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t byteOffset = convertToUint( - self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t source_byteOffset = convertToUint( - source->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - - uint8_t* dest = byteOffset + offset * element_size + static_cast( - buffer->GetIndexedPropertiesExternalArrayData()); - uint8_t* src = source_byteOffset + static_cast( - 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 buffer = - self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - Handle source_buffer = - source->Get(PerIsolateData::buffer_string(isolate))->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(PerIsolateData::byteOffset_string(isolate)), &try_catch); - if (try_catch.HasCaught()) return try_catch.ReThrow(); - int32_t source_byteOffset = convertToUint( - source->Get(PerIsolateData::byteOffset_string(isolate)), &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 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(args.GetIsolate()); -} - - -void Shell::ExternalArrayWeakCallback(v8::Isolate* isolate, - Persistent* object, - uint8_t* data) { - HandleScope scope(isolate); - int32_t length = (*object)->Get( - PerIsolateData::byteLength_string(isolate))->Uint32Value(); - isolate->AdjustAmountOfExternalAllocatedMemory(-length); - delete[] data; - object->Dispose(isolate); -} - - -Handle Shell::Int8Array(const Arguments& args) { - return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); -} - - -Handle Shell::Uint8Array(const Arguments& args) { - return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); -} - - -Handle Shell::Int16Array(const Arguments& args) { - return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t)); -} - - -Handle Shell::Uint16Array(const Arguments& args) { - return CreateExternalArray( - args, kExternalUnsignedShortArray, sizeof(uint16_t)); -} - - -Handle Shell::Int32Array(const Arguments& args) { - return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t)); -} - - -Handle Shell::Uint32Array(const Arguments& args) { - return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t)); -} - - -Handle Shell::Float32Array(const Arguments& args) { - return CreateExternalArray( - args, kExternalFloatArray, sizeof(float)); // NOLINT -} - - -Handle Shell::Float64Array(const Arguments& args) { - return CreateExternalArray( - args, kExternalDoubleArray, sizeof(double)); // NOLINT -} - - -Handle Shell::Uint8ClampedArray(const Arguments& args) { - return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t)); -} - Handle Shell::Quit(const Arguments& args) { int exit_code = args[0]->Int32Value(); @@ -1412,26 +819,6 @@ class BZip2Decompressor : public v8::StartupDataDecompressor { #endif -Handle Shell::CreateArrayBufferTemplate( - InvocationCallback fun) { - Handle buffer_template = FunctionTemplate::New(fun); - Local