| Index: src/d8.cc
|
| diff --git a/src/d8.cc b/src/d8.cc
|
| index 13f0bc1ff05de8271ab8f1ccd9ed6df644108429..171c59b6f0464fb9dc314cb8a2d9246aa6574f70 100644
|
| --- a/src/d8.cc
|
| +++ b/src/d8.cc
|
| @@ -31,7 +31,6 @@
|
| #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"
|
| @@ -219,6 +218,16 @@
|
| }
|
|
|
|
|
| +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");
|
| @@ -401,10 +410,7 @@
|
| base::LazyMutex Shell::workers_mutex_;
|
| bool Shell::allow_new_workers_ = true;
|
| i::List<Worker*> Shell::workers_;
|
| -std::unordered_set<SharedArrayBuffer::Contents,
|
| - Shell::SharedArrayBufferContentsHash,
|
| - Shell::SharedArrayBufferContentsIsEqual>
|
| - Shell::externalized_shared_contents_;
|
| +i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
|
|
|
| Global<Context> Shell::evaluation_context_;
|
| ArrayBuffer::Allocator* Shell::array_buffer_allocator;
|
| @@ -1144,6 +1150,7 @@
|
| 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");
|
| @@ -1156,12 +1163,36 @@
|
| }
|
|
|
| Local<Value> message = args[0];
|
| - 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));
|
| + 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;
|
| }
|
| }
|
|
|
| @@ -1174,12 +1205,14 @@
|
| return;
|
| }
|
|
|
| - std::unique_ptr<SerializationData> data = worker->GetMessage();
|
| + SerializationData* data = worker->GetMessage();
|
| if (data) {
|
| - Local<Value> value;
|
| - if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
|
| - args.GetReturnValue().Set(value);
|
| - }
|
| + int offset = 0;
|
| + Local<Value> data_value;
|
| + if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
|
| + args.GetReturnValue().Set(data_value);
|
| + }
|
| + delete data;
|
| }
|
| }
|
|
|
| @@ -2115,12 +2148,14 @@
|
| thread_->Join();
|
| }
|
|
|
| +
|
| SerializationData::~SerializationData() {
|
| // Any ArrayBuffer::Contents are owned by this SerializationData object if
|
| - // ownership hasn't been transferred out.
|
| + // ownership hasn't been transferred out via ReadArrayBufferContents.
|
| // SharedArrayBuffer::Contents may be used by multiple threads, so must be
|
| // cleaned up by the main thread in Shell::CleanupWorkers().
|
| - for (const auto& contents : array_buffer_contents_) {
|
| + for (int i = 0; i < array_buffer_contents_.length(); ++i) {
|
| + ArrayBuffer::Contents& contents = array_buffer_contents_[i];
|
| if (contents.Data()) {
|
| Shell::array_buffer_allocator->Free(contents.Data(),
|
| contents.ByteLength());
|
| @@ -2128,35 +2163,96 @@
|
| }
|
| }
|
|
|
| -void SerializationData::ClearTransferredArrayBuffers() {
|
| - array_buffer_contents_.clear();
|
| -}
|
| -
|
| -void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
|
| +
|
| +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 SerializationDataQueue::Enqueue(SerializationData* data) {
|
| base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| - data_.push_back(std::move(data));
|
| -}
|
| -
|
| -bool SerializationDataQueue::Dequeue(
|
| - std::unique_ptr<SerializationData>* out_data) {
|
| - out_data->reset();
|
| + data_.Add(data);
|
| +}
|
| +
|
| +
|
| +bool SerializationDataQueue::Dequeue(SerializationData** data) {
|
| base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| - if (data_.empty()) return false;
|
| - *out_data = std::move(data_[0]);
|
| - data_.erase(data_.begin());
|
| + *data = NULL;
|
| + if (data_.is_empty()) return false;
|
| + *data = data_.Remove(0);
|
| return true;
|
| }
|
|
|
|
|
| bool SerializationDataQueue::IsEmpty() {
|
| base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| - return data_.empty();
|
| + return data_.is_empty();
|
| }
|
|
|
|
|
| void SerializationDataQueue::Clear() {
|
| base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| - data_.clear();
|
| + for (int i = 0; i < data_.length(); ++i) {
|
| + delete data_[i];
|
| + }
|
| + data_.Clear();
|
| }
|
|
|
|
|
| @@ -2185,20 +2281,22 @@
|
| thread_->Start();
|
| }
|
|
|
| -void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
|
| - in_queue_.Enqueue(std::move(data));
|
| +
|
| +void Worker::PostMessage(SerializationData* data) {
|
| + in_queue_.Enqueue(data);
|
| in_semaphore_.Signal();
|
| }
|
|
|
| -std::unique_ptr<SerializationData> Worker::GetMessage() {
|
| - std::unique_ptr<SerializationData> result;
|
| - while (!out_queue_.Dequeue(&result)) {
|
| +
|
| +SerializationData* Worker::GetMessage() {
|
| + SerializationData* data = NULL;
|
| + while (!out_queue_.Dequeue(&data)) {
|
| // 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 result;
|
| + return data;
|
| }
|
|
|
|
|
| @@ -2262,21 +2360,19 @@
|
| // Now wait for messages
|
| while (true) {
|
| in_semaphore_.Wait();
|
| - std::unique_ptr<SerializationData> data;
|
| + SerializationData* data;
|
| if (!in_queue_.Dequeue(&data)) continue;
|
| - if (!data) {
|
| + if (data == NULL) {
|
| break;
|
| }
|
| - v8::TryCatch try_catch(isolate);
|
| - Local<Value> value;
|
| - if (Shell::DeserializeValue(isolate, std::move(data))
|
| - .ToLocal(&value)) {
|
| - Local<Value> argv[] = {value};
|
| + int offset = 0;
|
| + Local<Value> data_value;
|
| + if (Shell::DeserializeValue(isolate, *data, &offset)
|
| + .ToLocal(&data_value)) {
|
| + Local<Value> argv[] = {data_value};
|
| (void)onmessage_fun->Call(context, global, 1, argv);
|
| }
|
| - if (try_catch.HasCaught()) {
|
| - Shell::ReportException(isolate, &try_catch);
|
| - }
|
| + delete data;
|
| }
|
| }
|
| }
|
| @@ -2303,15 +2399,21 @@
|
| }
|
|
|
| Local<Value> message = args[0];
|
| - Local<Value> transfer = Undefined(isolate);
|
| - std::unique_ptr<SerializationData> data =
|
| - Shell::SerializeValue(isolate, message, transfer);
|
| - if (data) {
|
| +
|
| + // 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)) {
|
| 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(std::move(data));
|
| + worker->out_queue_.Enqueue(data);
|
| worker->out_semaphore_.Signal();
|
| + } else {
|
| + delete data;
|
| }
|
| }
|
|
|
| @@ -2504,202 +2606,234 @@
|
| }
|
| }
|
|
|
| -class Serializer : public ValueSerializer::Delegate {
|
| - public:
|
| - explicit Serializer(Isolate* isolate)
|
| - : isolate_(isolate), serializer_(isolate, this) {}
|
| -
|
| - 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>();
|
| - }
|
| - serializer_.WriteHeader();
|
| -
|
| - if (!serializer_.WriteValue(context, value).To(&ok)) {
|
| - data_.reset();
|
| - return Nothing<bool>();
|
| - }
|
| -
|
| - if (!FinalizeTransfer().To(&ok)) {
|
| - return Nothing<bool>();
|
| - }
|
| -
|
| - std::pair<uint8_t*, size_t> pair = serializer_.Release();
|
| - data_->data_.reset(pair.first);
|
| - data_->size_ = pair.second;
|
| - return Just(true);
|
| - }
|
| -
|
| - 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));
|
| +
|
| +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;
|
| + }
|
| + 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;
|
| }
|
| }
|
| -
|
| - 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();
|
| + } 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;
|
| + }
|
| + 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;
|
| + }
|
| +
|
| + 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;
|
| + }
|
| +
|
| + SharedArrayBuffer::Contents contents;
|
| + if (sab->IsExternal()) {
|
| + contents = sab->GetContents();
|
| + } 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;
|
| + }
|
| + seen_objects->Add(object);
|
| + Local<Array> property_names;
|
| + if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
|
| + Throw(isolate, "Unable to get property names");
|
| + return false;
|
| + }
|
| +
|
| + 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;
|
| + }
|
| + }
|
| + } else {
|
| + Throw(isolate, "Don't know how to serialize object");
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +
|
| +MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
|
| + const SerializationData& data,
|
| + int* offset) {
|
| + DCHECK(offset);
|
| + EscapableHandleScope scope(isolate);
|
| + Local<Value> result;
|
| + SerializationTag tag = data.ReadTag(offset);
|
| +
|
| + 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;
|
| + }
|
| + 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;
|
| - 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>();
|
| - }
|
| + Local<Value> element_value;
|
| + CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
|
| + array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
|
| }
|
| - return Just(true);
|
| - } else if (transfer->IsUndefined()) {
|
| - return Just(true);
|
| - } else {
|
| - Throw(isolate_, "Transfer list must be an Array or undefined");
|
| - return Nothing<bool>();
|
| - }
|
| - }
|
| -
|
| - 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>();
|
| + 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();
|
| }
|
| -
|
| - if (!array_buffer->IsExternal()) {
|
| - array_buffer->Externalize();
|
| - }
|
| + result = object;
|
| + break;
|
| + }
|
| + 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();
|
| - array_buffer->Neuter();
|
| - data_->array_buffer_contents_.push_back(contents);
|
| - }
|
| -
|
| - 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());
|
| - }
|
| -
|
| - return Just(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);
|
| -};
|
| -
|
| -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);
|
| - }
|
| -
|
| - MaybeLocal<Value> ReadValue(Local<Context> context) {
|
| - bool read_header;
|
| - if (!deserializer_.ReadHeader(context).To(&read_header)) {
|
| - return MaybeLocal<Value>();
|
| - }
|
| -
|
| - 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);
|
| - }
|
| -
|
| - 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);
|
| - }
|
| -
|
| - MaybeLocal<Value> result = deserializer_.ReadValue(context);
|
| - if (!result.IsEmpty()) {
|
| - data_->ClearTransferredArrayBuffers();
|
| - }
|
| - 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);
|
| - }
|
| - return data;
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -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);
|
| + DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
|
| + data.ReadMemory(contents.Data(), byte_length, offset);
|
| + result = array_buffer;
|
| + break;
|
| + }
|
| + case kSerializationTagTransferredArrayBuffer: {
|
| + ArrayBuffer::Contents contents;
|
| + data.ReadArrayBufferContents(&contents, offset);
|
| + result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
|
| + ArrayBufferCreationMode::kInternalized);
|
| + break;
|
| + }
|
| + case kSerializationTagTransferredSharedArrayBuffer: {
|
| + SharedArrayBuffer::Contents contents;
|
| + data.ReadSharedArrayBufferContents(&contents, offset);
|
| + result = SharedArrayBuffer::New(isolate, contents.Data(),
|
| + contents.ByteLength());
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + return scope.Escape(result);
|
| }
|
|
|
|
|
| @@ -2725,10 +2859,12 @@
|
| base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
|
| allow_new_workers_ = true;
|
|
|
| - for (const auto& contents : externalized_shared_contents_) {
|
| + for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
|
| + const SharedArrayBuffer::Contents& contents =
|
| + externalized_shared_contents_[i];
|
| Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
|
| }
|
| - externalized_shared_contents_.clear();
|
| + externalized_shared_contents_.Clear();
|
| }
|
|
|
|
|
|
|