Chromium Code Reviews| Index: src/d8.cc |
| diff --git a/src/d8.cc b/src/d8.cc |
| index f36e3a1739f0ca666baf2e9d3d442462d2032516..6f20ee3c8e501ae053b9fd9c9afdc5ead45a63c3 100644 |
| --- a/src/d8.cc |
| +++ b/src/d8.cc |
| @@ -31,6 +31,7 @@ |
| #include "src/base/sys-info.h" |
| #include "src/basic-block-profiler.h" |
| #include "src/interpreter/interpreter.h" |
| +#include "src/list-inl.h" |
| #include "src/msan.h" |
| #include "src/objects-inl.h" |
| #include "src/snapshot/natives.h" |
| @@ -218,16 +219,6 @@ static Local<Value> Throw(Isolate* isolate, const char* message) { |
| } |
| -bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) { |
| - for (int i = 0; i < list.length(); ++i) { |
| - if (list[i]->StrictEquals(object)) { |
| - return true; |
| - } |
| - } |
| - return false; |
| -} |
| - |
| - |
| Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) { |
| if (object->InternalFieldCount() != 1) { |
| Throw(isolate, "this is not a Worker"); |
| @@ -410,7 +401,10 @@ Global<Function> Shell::stringify_function_; |
| base::LazyMutex Shell::workers_mutex_; |
| bool Shell::allow_new_workers_ = true; |
| i::List<Worker*> Shell::workers_; |
| -i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; |
| +std::unordered_set<SharedArrayBuffer::Contents, |
| + Shell::SharedArrayBufferContentsHash, |
| + Shell::SharedArrayBufferContentsIsEqual> |
| + Shell::externalized_shared_contents_; |
| Global<Context> Shell::evaluation_context_; |
| ArrayBuffer::Allocator* Shell::array_buffer_allocator; |
| @@ -1150,7 +1144,6 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| Isolate* isolate = args.GetIsolate(); |
| HandleScope handle_scope(isolate); |
| - Local<Context> context = isolate->GetCurrentContext(); |
| if (args.Length() < 1) { |
| Throw(isolate, "Invalid argument"); |
| @@ -1163,36 +1156,12 @@ void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| } |
| Local<Value> message = args[0]; |
| - ObjectList to_transfer; |
| - if (args.Length() >= 2) { |
| - if (!args[1]->IsArray()) { |
| - Throw(isolate, "Transfer list must be an Array"); |
| - return; |
| - } |
| - |
| - Local<Array> transfer = Local<Array>::Cast(args[1]); |
| - uint32_t length = transfer->Length(); |
| - for (uint32_t i = 0; i < length; ++i) { |
| - Local<Value> element; |
| - if (transfer->Get(context, i).ToLocal(&element)) { |
| - if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) { |
| - Throw(isolate, |
| - "Transfer array elements must be an ArrayBuffer or " |
| - "SharedArrayBuffer."); |
| - break; |
| - } |
| - |
| - to_transfer.Add(Local<Object>::Cast(element)); |
| - } |
| - } |
| - } |
| - |
| - ObjectList seen_objects; |
| - SerializationData* data = new SerializationData; |
| - if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) { |
| - worker->PostMessage(data); |
| - } else { |
| - delete data; |
| + Local<Value> transfer = |
| + args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate)); |
| + std::unique_ptr<SerializationData> data = |
| + Shell::SerializeValue(isolate, message, transfer); |
| + if (data) { |
| + worker->PostMessage(std::move(data)); |
| } |
| } |
| @@ -1205,14 +1174,12 @@ void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| return; |
| } |
| - SerializationData* data = worker->GetMessage(); |
| + std::unique_ptr<SerializationData> data = worker->GetMessage(); |
| if (data) { |
| - int offset = 0; |
| - Local<Value> data_value; |
| - if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) { |
| - args.GetReturnValue().Set(data_value); |
| + Local<Value> value; |
| + if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) { |
| + args.GetReturnValue().Set(value); |
| } |
| - delete data; |
| } |
| } |
| @@ -2148,14 +2115,12 @@ void SourceGroup::JoinThread() { |
| thread_->Join(); |
| } |
| - |
| SerializationData::~SerializationData() { |
| // Any ArrayBuffer::Contents are owned by this SerializationData object if |
| - // ownership hasn't been transferred out via ReadArrayBufferContents. |
| + // ownership hasn't been transferred out. |
| // SharedArrayBuffer::Contents may be used by multiple threads, so must be |
| // cleaned up by the main thread in Shell::CleanupWorkers(). |
| - for (int i = 0; i < array_buffer_contents_.length(); ++i) { |
| - ArrayBuffer::Contents& contents = array_buffer_contents_[i]; |
| + for (const auto& contents : array_buffer_contents_) { |
| if (contents.Data()) { |
| Shell::array_buffer_allocator->Free(contents.Data(), |
| contents.ByteLength()); |
| @@ -2163,96 +2128,35 @@ SerializationData::~SerializationData() { |
| } |
| } |
| - |
| -void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); } |
| - |
| - |
| -void SerializationData::WriteMemory(const void* p, int length) { |
| - if (length > 0) { |
| - i::Vector<uint8_t> block = data_.AddBlock(0, length); |
| - memcpy(&block[0], p, length); |
| - } |
| -} |
| - |
| - |
| -void SerializationData::WriteArrayBufferContents( |
| - const ArrayBuffer::Contents& contents) { |
| - array_buffer_contents_.Add(contents); |
| - WriteTag(kSerializationTagTransferredArrayBuffer); |
| - int index = array_buffer_contents_.length() - 1; |
| - Write(index); |
| -} |
| - |
| - |
| -void SerializationData::WriteSharedArrayBufferContents( |
| - const SharedArrayBuffer::Contents& contents) { |
| - shared_array_buffer_contents_.Add(contents); |
| - WriteTag(kSerializationTagTransferredSharedArrayBuffer); |
| - int index = shared_array_buffer_contents_.length() - 1; |
| - Write(index); |
| -} |
| - |
| - |
| -SerializationTag SerializationData::ReadTag(int* offset) const { |
| - return static_cast<SerializationTag>(Read<uint8_t>(offset)); |
| -} |
| - |
| - |
| -void SerializationData::ReadMemory(void* p, int length, int* offset) const { |
| - if (length > 0) { |
| - memcpy(p, &data_[*offset], length); |
| - (*offset) += length; |
| - } |
| -} |
| - |
| - |
| -void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents, |
| - int* offset) const { |
| - int index = Read<int>(offset); |
| - DCHECK(index < array_buffer_contents_.length()); |
| - *contents = array_buffer_contents_[index]; |
| - // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter |
| - // our copy so it won't be double-free'd when this SerializationData is |
| - // destroyed. |
| - array_buffer_contents_[index] = ArrayBuffer::Contents(); |
| -} |
| - |
| - |
| -void SerializationData::ReadSharedArrayBufferContents( |
| - SharedArrayBuffer::Contents* contents, int* offset) const { |
| - int index = Read<int>(offset); |
| - DCHECK(index < shared_array_buffer_contents_.length()); |
| - *contents = shared_array_buffer_contents_[index]; |
| +void SerializationData::ClearTransferredArrayBuffers() { |
| + array_buffer_contents_.clear(); |
| } |
| - |
| -void SerializationDataQueue::Enqueue(SerializationData* data) { |
| +void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) { |
| base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| - data_.Add(data); |
| + data_.push_back(std::move(data)); |
| } |
| - |
| -bool SerializationDataQueue::Dequeue(SerializationData** data) { |
| +bool SerializationDataQueue::Dequeue( |
| + std::unique_ptr<SerializationData>* out_data) { |
| + out_data->reset(); |
| base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| - *data = NULL; |
| - if (data_.is_empty()) return false; |
| - *data = data_.Remove(0); |
| + if (data_.empty()) return false; |
| + *out_data = std::move(data_[0]); |
| + data_.erase(data_.begin()); |
| return true; |
| } |
| bool SerializationDataQueue::IsEmpty() { |
| base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| - return data_.is_empty(); |
| + return data_.empty(); |
| } |
| void SerializationDataQueue::Clear() { |
| base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| - for (int i = 0; i < data_.length(); ++i) { |
| - delete data_[i]; |
| - } |
| - data_.Clear(); |
| + data_.clear(); |
| } |
| @@ -2281,22 +2185,20 @@ void Worker::StartExecuteInThread(const char* script) { |
| thread_->Start(); |
| } |
| - |
| -void Worker::PostMessage(SerializationData* data) { |
| - in_queue_.Enqueue(data); |
| +void Worker::PostMessage(std::unique_ptr<SerializationData> data) { |
| + in_queue_.Enqueue(std::move(data)); |
| in_semaphore_.Signal(); |
| } |
| - |
| -SerializationData* Worker::GetMessage() { |
| - SerializationData* data = NULL; |
| - while (!out_queue_.Dequeue(&data)) { |
| +std::unique_ptr<SerializationData> Worker::GetMessage() { |
| + std::unique_ptr<SerializationData> result; |
| + while (!out_queue_.Dequeue(&result)) { |
| // If the worker is no longer running, and there are no messages in the |
| // queue, don't expect any more messages from it. |
| if (!base::NoBarrier_Load(&running_)) break; |
| out_semaphore_.Wait(); |
| } |
| - return data; |
| + return result; |
| } |
| @@ -2360,19 +2262,21 @@ void Worker::ExecuteInThread() { |
| // Now wait for messages |
| while (true) { |
| in_semaphore_.Wait(); |
| - SerializationData* data; |
| + std::unique_ptr<SerializationData> data; |
| if (!in_queue_.Dequeue(&data)) continue; |
| - if (data == NULL) { |
| + if (!data) { |
| break; |
| } |
| - int offset = 0; |
| - Local<Value> data_value; |
| - if (Shell::DeserializeValue(isolate, *data, &offset) |
| - .ToLocal(&data_value)) { |
| - Local<Value> argv[] = {data_value}; |
| + v8::TryCatch try_catch(isolate); |
| + Local<Value> value; |
| + if (Shell::DeserializeValue(isolate, std::move(data)) |
| + .ToLocal(&value)) { |
| + Local<Value> argv[] = {value}; |
| (void)onmessage_fun->Call(context, global, 1, argv); |
| } |
| - delete data; |
| + if (try_catch.HasCaught()) { |
| + Shell::ReportException(isolate, &try_catch); |
| + } |
| } |
| } |
| } |
| @@ -2399,21 +2303,15 @@ void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| } |
| Local<Value> message = args[0]; |
| - |
| - // TODO(binji): Allow transferring from worker to main thread? |
| - Shell::ObjectList to_transfer; |
| - |
| - Shell::ObjectList seen_objects; |
| - SerializationData* data = new SerializationData; |
| - if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects, |
| - data)) { |
| + Local<Value> transfer = Undefined(isolate); |
| + std::unique_ptr<SerializationData> data = |
| + Shell::SerializeValue(isolate, message, transfer); |
| + if (data) { |
| DCHECK(args.Data()->IsExternal()); |
| Local<External> this_value = Local<External>::Cast(args.Data()); |
| Worker* worker = static_cast<Worker*>(this_value->Value()); |
| - worker->out_queue_.Enqueue(data); |
| + worker->out_queue_.Enqueue(std::move(data)); |
| worker->out_semaphore_.Signal(); |
| - } else { |
| - delete data; |
| } |
| } |
| @@ -2604,234 +2502,202 @@ void Shell::EmptyMessageQueues(Isolate* isolate) { |
| } |
| } |
| +class Serializer : public ValueSerializer::Delegate { |
| + public: |
| + explicit Serializer(Isolate* isolate) |
| + : isolate_(isolate), serializer_(isolate, this) {} |
| -bool Shell::SerializeValue(Isolate* isolate, Local<Value> value, |
| - const ObjectList& to_transfer, |
| - ObjectList* seen_objects, |
| - SerializationData* out_data) { |
| - DCHECK(out_data); |
| - Local<Context> context = isolate->GetCurrentContext(); |
| - |
| - if (value->IsUndefined()) { |
| - out_data->WriteTag(kSerializationTagUndefined); |
| - } else if (value->IsNull()) { |
| - out_data->WriteTag(kSerializationTagNull); |
| - } else if (value->IsTrue()) { |
| - out_data->WriteTag(kSerializationTagTrue); |
| - } else if (value->IsFalse()) { |
| - out_data->WriteTag(kSerializationTagFalse); |
| - } else if (value->IsNumber()) { |
| - Local<Number> num = Local<Number>::Cast(value); |
| - double value = num->Value(); |
| - out_data->WriteTag(kSerializationTagNumber); |
| - out_data->Write(value); |
| - } else if (value->IsString()) { |
| - v8::String::Utf8Value str(value); |
| - out_data->WriteTag(kSerializationTagString); |
| - out_data->Write(str.length()); |
| - out_data->WriteMemory(*str, str.length()); |
| - } else if (value->IsArray()) { |
| - Local<Array> array = Local<Array>::Cast(value); |
| - if (FindInObjectList(array, *seen_objects)) { |
| - Throw(isolate, "Duplicated arrays not supported"); |
| - return false; |
| + Maybe<bool> WriteValue(Local<Context> context, Local<Value> value, |
| + Local<Value> transfer) { |
| + bool ok; |
| + DCHECK(!data_); |
| + data_.reset(new SerializationData); |
| + if (!PrepareTransfer(context, transfer).To(&ok)) { |
| + return Nothing<bool>(); |
| } |
| - seen_objects->Add(array); |
| - out_data->WriteTag(kSerializationTagArray); |
| - uint32_t length = array->Length(); |
| - out_data->Write(length); |
| - for (uint32_t i = 0; i < length; ++i) { |
| - Local<Value> element_value; |
| - if (array->Get(context, i).ToLocal(&element_value)) { |
| - if (!SerializeValue(isolate, element_value, to_transfer, seen_objects, |
| - out_data)) |
| - return false; |
| - } else { |
| - Throw(isolate, "Failed to serialize array element."); |
| - return false; |
| - } |
| + serializer_.WriteHeader(); |
| + |
| + if (!serializer_.WriteValue(context, value).To(&ok)) { |
| + data_.reset(); |
| + return Nothing<bool>(); |
| } |
| - } else if (value->IsArrayBuffer()) { |
| - Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value); |
| - if (FindInObjectList(array_buffer, *seen_objects)) { |
| - Throw(isolate, "Duplicated array buffers not supported"); |
| - return false; |
| + |
| + if (!FinalizeTransfer().To(&ok)) { |
| + return Nothing<bool>(); |
| } |
| - seen_objects->Add(array_buffer); |
| - if (FindInObjectList(array_buffer, to_transfer)) { |
| - // Transfer ArrayBuffer |
| - if (!array_buffer->IsNeuterable()) { |
| - Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer"); |
| - return false; |
| - } |
| - ArrayBuffer::Contents contents = array_buffer->IsExternal() |
| - ? array_buffer->GetContents() |
| - : array_buffer->Externalize(); |
| - array_buffer->Neuter(); |
| - out_data->WriteArrayBufferContents(contents); |
| - } else { |
| - ArrayBuffer::Contents contents = array_buffer->GetContents(); |
| - // Clone ArrayBuffer |
| - if (contents.ByteLength() > i::kMaxInt) { |
| - Throw(isolate, "ArrayBuffer is too big to clone"); |
| - return false; |
| - } |
| + std::pair<uint8_t*, size_t> pair = serializer_.Release(); |
| + data_->data_.reset(pair.first); |
| + data_->size_ = pair.second; |
| + return Just(true); |
| + } |
| - int32_t byte_length = static_cast<int32_t>(contents.ByteLength()); |
| - out_data->WriteTag(kSerializationTagArrayBuffer); |
| - out_data->Write(byte_length); |
| - out_data->WriteMemory(contents.Data(), byte_length); |
| - } |
| - } else if (value->IsSharedArrayBuffer()) { |
| - Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value); |
| - if (FindInObjectList(sab, *seen_objects)) { |
| - Throw(isolate, "Duplicated shared array buffers not supported"); |
| - return false; |
| - } |
| - seen_objects->Add(sab); |
| - if (!FindInObjectList(sab, to_transfer)) { |
| - Throw(isolate, "SharedArrayBuffer must be transferred"); |
| - return false; |
| + std::unique_ptr<SerializationData> Release() { return std::move(data_); } |
| + |
| + protected: |
| + // Implements ValueSerializer::Delegate. |
| + void ThrowDataCloneError(Local<String> message) override { |
| + isolate_->ThrowException(Exception::Error(message)); |
| + } |
| + |
| + Maybe<uint32_t> GetSharedArrayBufferId( |
| + Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override { |
| + DCHECK(data_ != nullptr); |
| + for (size_t index = 0; index < shared_array_buffers_.size(); ++index) { |
| + if (shared_array_buffers_[index] == shared_array_buffer) { |
| + return Just<uint32_t>(static_cast<uint32_t>(index)); |
| + } |
| } |
| - SharedArrayBuffer::Contents contents; |
| - if (sab->IsExternal()) { |
| - contents = sab->GetContents(); |
| + size_t index = shared_array_buffers_.size(); |
| + shared_array_buffers_.emplace_back(isolate_, shared_array_buffer); |
| + return Just<uint32_t>(static_cast<uint32_t>(index)); |
| + } |
| + |
| + void* ReallocateBufferMemory(void* old_buffer, size_t size, |
| + size_t* actual_size) override { |
| + void* result = realloc(old_buffer, size); |
| + *actual_size = result ? size : 0; |
| + return result; |
| + } |
| + |
| + void FreeBufferMemory(void* buffer) override { free(buffer); } |
| + |
| + private: |
| + Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) { |
| + if (transfer->IsArray()) { |
| + Local<Array> transfer_array = Local<Array>::Cast(transfer); |
| + uint32_t length = transfer_array->Length(); |
| + for (uint32_t i = 0; i < length; ++i) { |
| + Local<Value> element; |
| + if (transfer_array->Get(context, i).ToLocal(&element)) { |
| + if (!element->IsArrayBuffer()) { |
| + Throw(isolate_, "Transfer array elements must be an ArrayBuffer"); |
| + break; |
| + } |
| + |
| + Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element); |
| + serializer_.TransferArrayBuffer( |
| + static_cast<uint32_t>(array_buffers_.size()), array_buffer); |
| + array_buffers_.emplace_back(isolate_, array_buffer); |
| + } else { |
| + return Nothing<bool>(); |
| + } |
| + } |
| + return Just(true); |
| + } else if (transfer->IsUndefined()) { |
| + return Just(true); |
| } else { |
| - contents = sab->Externalize(); |
| - base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); |
| - externalized_shared_contents_.Add(contents); |
| - } |
| - out_data->WriteSharedArrayBufferContents(contents); |
| - } else if (value->IsObject()) { |
| - Local<Object> object = Local<Object>::Cast(value); |
| - if (FindInObjectList(object, *seen_objects)) { |
| - Throw(isolate, "Duplicated objects not supported"); |
| - return false; |
| + Throw(isolate_, "Transfer list must be an Array or undefined"); |
| + return Nothing<bool>(); |
| } |
| - seen_objects->Add(object); |
| - Local<Array> property_names; |
| - if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) { |
| - Throw(isolate, "Unable to get property names"); |
| - return false; |
| + } |
| + |
| + Maybe<bool> FinalizeTransfer() { |
| + for (const auto& global_array_buffer : array_buffers_) { |
| + Local<ArrayBuffer> array_buffer = |
| + Local<ArrayBuffer>::New(isolate_, global_array_buffer); |
| + if (!array_buffer->IsNeuterable()) { |
| + Throw(isolate_, "ArrayBuffer could not be transferred"); |
| + return Nothing<bool>(); |
| + } |
| + |
| + if (!array_buffer->IsExternal()) { |
| + array_buffer->Externalize(); |
| + } |
| + ArrayBuffer::Contents contents = array_buffer->GetContents(); |
| + array_buffer->Neuter(); |
| + data_->array_buffer_contents_.push_back(contents); |
| } |
| - uint32_t length = property_names->Length(); |
| - out_data->WriteTag(kSerializationTagObject); |
| - out_data->Write(length); |
| - for (uint32_t i = 0; i < length; ++i) { |
| - Local<Value> name; |
| - Local<Value> property_value; |
| - if (property_names->Get(context, i).ToLocal(&name) && |
| - object->Get(context, name).ToLocal(&property_value)) { |
| - if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data)) |
| - return false; |
| - if (!SerializeValue(isolate, property_value, to_transfer, seen_objects, |
| - out_data)) |
| - return false; |
| - } else { |
| - Throw(isolate, "Failed to serialize property."); |
| - return false; |
| + for (const auto& global_shared_array_buffer : shared_array_buffers_) { |
| + Local<SharedArrayBuffer> shared_array_buffer = |
| + Local<SharedArrayBuffer>::New(isolate_, global_shared_array_buffer); |
| + if (!shared_array_buffer->IsExternal()) { |
| + shared_array_buffer->Externalize(); |
| } |
| + data_->shared_array_buffer_contents_.push_back( |
| + shared_array_buffer->GetContents()); |
| } |
| - } else { |
| - Throw(isolate, "Don't know how to serialize object"); |
| - return false; |
| + |
| + return Just(true); |
| } |
| - return true; |
| -} |
| + Isolate* isolate_; |
| + ValueSerializer serializer_; |
| + std::unique_ptr<SerializationData> data_; |
| + std::vector<Global<ArrayBuffer>> array_buffers_; |
| + std::vector<Global<SharedArrayBuffer>> shared_array_buffers_; |
| + DISALLOW_COPY_AND_ASSIGN(Serializer); |
| +}; |
| -MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate, |
| - const SerializationData& data, |
| - int* offset) { |
| - DCHECK(offset); |
| - EscapableHandleScope scope(isolate); |
| - Local<Value> result; |
| - SerializationTag tag = data.ReadTag(offset); |
| +class Deserializer : public ValueDeserializer::Delegate { |
| + public: |
| + Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data) |
| + : isolate_(isolate), |
| + deserializer_(isolate, data->data(), data->size(), this), |
| + data_(std::move(data)) { |
| + deserializer_.SetSupportsLegacyWireFormat(true); |
| + } |
| - switch (tag) { |
| - case kSerializationTagUndefined: |
| - result = Undefined(isolate); |
| - break; |
| - case kSerializationTagNull: |
| - result = Null(isolate); |
| - break; |
| - case kSerializationTagTrue: |
| - result = True(isolate); |
| - break; |
| - case kSerializationTagFalse: |
| - result = False(isolate); |
| - break; |
| - case kSerializationTagNumber: |
| - result = Number::New(isolate, data.Read<double>(offset)); |
| - break; |
| - case kSerializationTagString: { |
| - int length = data.Read<int>(offset); |
| - CHECK(length >= 0); |
| - std::vector<char> buffer(length + 1); // + 1 so it is never empty. |
| - data.ReadMemory(&buffer[0], length, offset); |
| - MaybeLocal<String> str = |
| - String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal, |
| - length).ToLocalChecked(); |
| - if (!str.IsEmpty()) result = str.ToLocalChecked(); |
| - break; |
| + MaybeLocal<Value> ReadValue(Local<Context> context) { |
| + bool read_header; |
| + if (!deserializer_.ReadHeader(context).To(&read_header)) { |
| + return MaybeLocal<Value>(); |
| } |
| - case kSerializationTagArray: { |
| - uint32_t length = data.Read<uint32_t>(offset); |
| - Local<Array> array = Array::New(isolate, length); |
| - for (uint32_t i = 0; i < length; ++i) { |
| - Local<Value> element_value; |
| - CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value)); |
| - array->Set(isolate->GetCurrentContext(), i, element_value).FromJust(); |
| - } |
| - result = array; |
| - break; |
| - } |
| - case kSerializationTagObject: { |
| - int length = data.Read<int>(offset); |
| - Local<Object> object = Object::New(isolate); |
| - for (int i = 0; i < length; ++i) { |
| - Local<Value> property_name; |
| - CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name)); |
| - Local<Value> property_value; |
| - CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value)); |
| - object->Set(isolate->GetCurrentContext(), property_name, property_value) |
| - .FromJust(); |
| - } |
| - result = object; |
| - break; |
| + |
| + uint32_t index = 0; |
| + for (const auto& contents : data_->array_buffer_contents()) { |
| + Local<ArrayBuffer> array_buffer = |
| + ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength()); |
| + deserializer_.TransferArrayBuffer(index++, array_buffer); |
| } |
| - case kSerializationTagArrayBuffer: { |
| - int32_t byte_length = data.Read<int32_t>(offset); |
| - Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length); |
| - ArrayBuffer::Contents contents = array_buffer->GetContents(); |
| - DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength()); |
| - data.ReadMemory(contents.Data(), byte_length, offset); |
| - result = array_buffer; |
| - break; |
| + |
| + index = 0; |
| + for (const auto& contents : data_->shared_array_buffer_contents()) { |
| + Local<SharedArrayBuffer> shared_array_buffer = SharedArrayBuffer::New( |
| + isolate_, contents.Data(), contents.ByteLength()); |
| + deserializer_.TransferSharedArrayBuffer(index++, shared_array_buffer); |
| } |
| - case kSerializationTagTransferredArrayBuffer: { |
| - ArrayBuffer::Contents contents; |
| - data.ReadArrayBufferContents(&contents, offset); |
| - result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(), |
| - ArrayBufferCreationMode::kInternalized); |
| - break; |
| + |
| + MaybeLocal<Value> result = deserializer_.ReadValue(context); |
| + if (!result.IsEmpty()) { |
| + data_->ClearTransferredArrayBuffers(); |
| } |
| - case kSerializationTagTransferredSharedArrayBuffer: { |
| - SharedArrayBuffer::Contents contents; |
| - data.ReadSharedArrayBufferContents(&contents, offset); |
| - result = SharedArrayBuffer::New(isolate, contents.Data(), |
| - contents.ByteLength()); |
| - break; |
| + return result; |
| + } |
| + |
| + private: |
| + Isolate* isolate_; |
| + ValueDeserializer deserializer_; |
| + std::unique_ptr<SerializationData> data_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Deserializer); |
| +}; |
| + |
| +std::unique_ptr<SerializationData> Shell::SerializeValue( |
| + Isolate* isolate, Local<Value> value, Local<Value> transfer) { |
| + bool ok; |
| + Local<Context> context = isolate->GetCurrentContext(); |
| + Serializer serializer(isolate); |
| + if (serializer.WriteValue(context, value, transfer).To(&ok)) { |
| + std::unique_ptr<SerializationData> data = serializer.Release(); |
| + base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); |
| + for (const auto& contents : data->shared_array_buffer_contents()) { |
| + externalized_shared_contents_.insert(contents); |
| } |
| - default: |
| - UNREACHABLE(); |
| + return data; |
| } |
| + return std::unique_ptr<SerializationData>(); |
|
jbroman
2017/01/26 21:53:03
nit: Dunno about v8, but in Chromium/Blink I'd pre
binji
2017/01/27 19:33:21
Done.
|
| +} |
| - return scope.Escape(result); |
| +MaybeLocal<Value> Shell::DeserializeValue( |
| + Isolate* isolate, std::unique_ptr<SerializationData> data) { |
| + Local<Value> value; |
| + Local<Context> context = isolate->GetCurrentContext(); |
| + Deserializer deserializer(isolate, std::move(data)); |
| + return deserializer.ReadValue(context); |
| } |
| @@ -2857,12 +2723,10 @@ void Shell::CleanupWorkers() { |
| base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); |
| allow_new_workers_ = true; |
| - for (int i = 0; i < externalized_shared_contents_.length(); ++i) { |
| - const SharedArrayBuffer::Contents& contents = |
| - externalized_shared_contents_[i]; |
| + for (const auto& contents : externalized_shared_contents_) { |
| Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); |
| } |
| - externalized_shared_contents_.Clear(); |
| + externalized_shared_contents_.clear(); |
| } |