Index: src/d8.cc |
diff --git a/src/d8.cc b/src/d8.cc |
index f36e3a1739f0ca666baf2e9d3d442462d2032516..13d68999fb1a230bfa2e87348464c0c53d945fb1 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" |
@@ -58,8 +59,25 @@ |
#define CHECK(condition) assert(condition) |
#endif |
+namespace std { |
+ |
+template <> |
+struct hash<v8::SharedArrayBuffer::Contents> { |
jbroman
2017/01/24 18:53:43
(I'm not a V8 owner, but...)
1. The Chromium/Goog
binji
2017/01/25 00:31:35
Done.
|
+ size_t operator()(const v8::SharedArrayBuffer::Contents& contents) const { |
+ return std::hash<void*>()(contents.Data()) ^ |
+ std::hash<size_t>()(contents.ByteLength()); |
+ } |
+}; |
+ |
+} // namespace std |
+ |
namespace v8 { |
+bool operator==(const SharedArrayBuffer::Contents& a, |
+ const SharedArrayBuffer::Contents& b) { |
+ return a.Data() == b.Data() && a.ByteLength() == b.ByteLength(); |
+} |
+ |
namespace { |
const int MB = 1024 * 1024; |
@@ -218,16 +236,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 +418,8 @@ 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::externalized_shared_contents_; |
Global<Context> Shell::evaluation_context_; |
ArrayBuffer::Allocator* Shell::array_buffer_allocator; |
@@ -1163,36 +1172,11 @@ 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)) { |
+ Local<Value> transfer = |
+ args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate)); |
jbroman
2017/01/24 18:53:43
nit: is the Local<Value> cast necessary; I think i
binji
2017/01/25 00:31:36
The two arms of the conditional have different typ
jbroman
2017/01/25 16:34:54
OK, sorry.
Ordinarily the compiler would still ad
|
+ SerializationData* data; |
+ if (Shell::SerializeValue(isolate, message, transfer).To(&data)) { |
worker->PostMessage(data); |
- } else { |
- delete data; |
} |
} |
@@ -1207,12 +1191,10 @@ void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
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, data).ToLocal(&value)) { |
jbroman
2017/01/24 18:53:43
nit: Just checking, if this fails (i.e. an excepti
binji
2017/01/25 00:31:35
Yeah, it definitely will break the tests (or perha
|
+ args.GetReturnValue().Set(value); |
} |
- delete data; |
} |
} |
@@ -2148,14 +2130,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,66 +2143,8 @@ 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(); |
} |
@@ -2365,14 +2287,15 @@ void Worker::ExecuteInThread() { |
if (data == NULL) { |
break; |
} |
- int offset = 0; |
- Local<Value> data_value; |
- if (Shell::DeserializeValue(isolate, *data, &offset) |
- .ToLocal(&data_value)) { |
- Local<Value> argv[] = {data_value}; |
+ Local<Value> value; |
+ if (Shell::DeserializeValue(isolate, data).ToLocal(&value)) { |
jbroman
2017/01/24 18:53:43
If an exception is thrown from DeserializeValue, d
binji
2017/01/25 00:31:35
Done.
|
+ Local<Value> argv[] = {value}; |
+ v8::TryCatch try_catch(isolate); |
(void)onmessage_fun->Call(context, global, 1, argv); |
+ if (try_catch.HasCaught()) { |
+ Shell::ReportException(isolate, &try_catch); |
+ } |
} |
- delete data; |
} |
} |
} |
@@ -2398,22 +2321,15 @@ void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) { |
return; |
} |
+ SerializationData* data; |
jbroman
2017/01/24 18:53:43
Here and elsewhere: managing this memory by hand m
binji
2017/01/25 00:31:35
At the time when I originally wrote some of this,
|
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); |
+ if (Shell::SerializeValue(isolate, message, transfer).To(&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_semaphore_.Signal(); |
- } else { |
- delete data; |
} |
} |
@@ -2604,234 +2520,212 @@ void Shell::EmptyMessageQueues(Isolate* isolate) { |
} |
} |
+class Serializer : public ValueSerializer::Delegate { |
+ public: |
+ explicit Serializer(Isolate* isolate) |
+ : isolate_(isolate), serializer_(isolate, this), data_(nullptr) {} |
-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(); |
+ ~Serializer() { delete data_; } |
- 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_ == nullptr); |
+ data_ = 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; |
- } |
- } |
- } 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; |
- } |
+ serializer_.WriteHeader(); |
- 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; |
+ if (serializer_.WriteValue(context, value).To(&ok)) { |
+ if (!FinalizeTransfer().To(&ok)) { |
+ return Nothing<bool>(); |
} |
- 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; |
+ std::pair<uint8_t*, size_t> pair = serializer_.Release(); |
+ data_->data_ = pair.first; |
+ data_->size_ = pair.second; |
+ return Just(true); |
+ } else { |
+ delete data_; |
+ data_ = nullptr; |
} |
- seen_objects->Add(sab); |
- if (!FindInObjectList(sab, to_transfer)) { |
- Throw(isolate, "SharedArrayBuffer must be transferred"); |
- return false; |
+ return Nothing<bool>(); |
+ } |
+ |
+ SerializationData* Release() { |
+ SerializationData* result = data_; |
+ data_ = nullptr; |
+ return result; |
+ } |
+ |
+ 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 { |
+ *actual_size = size; |
+ return realloc(old_buffer, size); |
+ } |
+ |
+ 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)) { |
jbroman
2017/01/24 18:53:43
Not new, but this isn't very resilient against cod
binji
2017/01/25 00:31:35
Good point, added a TryCatch.
|
+ 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); |
+ } |
+ } |
+ 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_; |
+ 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, SerializationData* data) |
+ : isolate_(isolate), |
+ deserializer_(isolate, data->data(), data->size(), this), |
+ data_(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; |
- } |
- 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; |
+ ~Deserializer() { delete data_; } |
+ |
+ MaybeLocal<Value> ReadValue(Local<Context> context) { |
+ bool read_header; |
+ if (!deserializer_.ReadHeader(context).To(&read_header)) { |
+ return MaybeLocal<Value>(); |
} |
- 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_; |
+ SerializationData* data_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Deserializer); |
+}; |
+ |
+Maybe<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)) { |
+ 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 Just(data); |
} |
+ return Nothing<SerializationData*>(); |
+} |
- return scope.Escape(result); |
+MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate, |
+ SerializationData* data) { |
+ Local<Value> value; |
+ Local<Context> context = isolate->GetCurrentContext(); |
+ Deserializer deserializer(isolate, data); |
+ if (deserializer.ReadValue(context).ToLocal(&value)) { |
+ return MaybeLocal<Value>(value); |
+ } |
+ return MaybeLocal<Value>(); |
} |
@@ -2857,12 +2751,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(); |
} |