Index: Source/bindings/core/v8/custom/V8MessagePortCustom.cpp |
diff --git a/Source/bindings/core/v8/custom/V8MessagePortCustom.cpp b/Source/bindings/core/v8/custom/V8MessagePortCustom.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..17d8c091acbec2a51a81bb6a6c9ac96cf56e41da |
--- /dev/null |
+++ b/Source/bindings/core/v8/custom/V8MessagePortCustom.cpp |
@@ -0,0 +1,110 @@ |
+#include "config.h" |
+#include "bindings/core/v8/SerializedScriptValueFactory.h" |
+#include "bindings/core/v8/V8MessagePort.h" |
+#include "core/dom/DOMArrayBuffer.h" |
+#include "core/dom/ExceptionCode.h" |
+ |
+namespace blink { |
+ |
+static void acculumateArrayBuffersForAllWorlds(v8::Isolate* isolate, DOMArrayBuffer* object, Vector<v8::Local<v8::ArrayBuffer>, 4>& buffers) |
+{ |
+ if (isMainThread()) { |
+ Vector<RefPtr<DOMWrapperWorld>> worlds; |
+ DOMWrapperWorld::allWorldsInMainThread(worlds); |
+ for (size_t i = 0; i < worlds.size(); i++) { |
+ v8::Local<v8::Object> wrapper = worlds[i]->domDataStore().get(object, isolate); |
+ if (!wrapper.IsEmpty()) |
+ buffers.append(v8::Local<v8::ArrayBuffer>::Cast(wrapper)); |
+ } |
+ } else { |
+ v8::Local<v8::Object> wrapper = DOMWrapperWorld::current(isolate).domDataStore().get(object, isolate); |
+ if (!wrapper.IsEmpty()) |
+ buffers.append(v8::Local<v8::ArrayBuffer>::Cast(wrapper)); |
+ } |
+} |
+ |
+typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray; |
+ |
+static PassOwnPtr<ArrayBufferContentsArray> neuterTransferableArrayBuffers(v8::Isolate* isolate, ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState) |
+{ |
+ OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size())); |
+ |
+ HashSet<DOMArrayBufferBase*> visited; |
+ for (size_t i = 0; i < arrayBuffers.size(); i++) { |
+ if (visited.contains(arrayBuffers[i].get())) |
+ continue; |
+ visited.add(arrayBuffers[i].get()); |
+ |
+ if (arrayBuffers[i]->isShared()) { |
+ // Don't have to neuter SharedArrayBuffer. |
+ continue; |
+ } |
+ |
+ Vector<v8::Local<v8::ArrayBuffer>, 4> bufferHandles; |
+ v8::HandleScope handleScope(isolate); |
+ acculumateArrayBuffersForAllWorlds(isolate, static_pointer_cast<DOMArrayBuffer>(arrayBuffers[i]).get(), bufferHandles); |
+ bool isNeuterable = true; |
+ for (size_t j = 0; j < bufferHandles.size(); j++) |
+ isNeuterable &= bufferHandles[j]->IsNeuterable(); |
+ |
+ RefPtr<DOMArrayBufferBase> toTransfer = arrayBuffers[i]; |
+ if (!isNeuterable) |
+ continue; |
+ |
+ bool result = toTransfer->transfer(contents->at(i)); |
+ if (!result) { |
+ exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " could not be transferred."); |
+ return nullptr; |
+ } |
+ |
+ for (size_t j = 0; j < bufferHandles.size(); j++) |
+ bufferHandles[j]->Neuter(); |
+ } |
+ |
+ return contents.release(); |
+} |
+ |
+void V8MessagePort::postMessageMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ ExceptionState exceptionState(ExceptionState::ExecutionContext, "postMessage", "MessagePort", info.Holder(), info.GetIsolate()); |
+ if (UNLIKELY(info.Length() < 1)) { |
+ setMinimumArityTypeError(exceptionState, 1, info.Length()); |
+ exceptionState.throwIfNeeded(); |
+ return; |
+ } |
+ MessagePort* messagePort = V8MessagePort::toImpl(info.Holder()); |
+ OwnPtrWillBeRawPtr<MessagePortArray> ports = adoptPtrWillBeNoop(new MessagePortArray); |
+ ArrayBufferArray arrayBuffers; |
+ if (info.Length() > 1) { |
+ const int transferablesArgIndex = 1; |
+ if (!SerializedScriptValue::extractTransferables(info.GetIsolate(), info[transferablesArgIndex], transferablesArgIndex, *ports, arrayBuffers, exceptionState)) { |
+ exceptionState.throwIfNeeded(); |
+ return; |
+ } |
+ } |
+ |
+ for (size_t i = 0; i < arrayBuffers.size(); i++) { |
+ if (arrayBuffers[i]->isNeutered()) { |
+ exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is already neutered."); |
+ return; |
+ } |
+ } |
+ |
+ // TODO(nhiroki) |
+ RefPtr<SerializedScriptValue> message = SerializedScriptValueFactory::instance().create(info.GetIsolate(), info[0], ports.get(), nullptr /* arrayBuffers */, exceptionState); |
+ if (exceptionState.throwIfNeeded()) |
+ return; |
+ |
+ if (!arrayBuffers.isEmpty()) { |
+ neuterTransferableArrayBuffers(info.GetIsolate(), arrayBuffers, exceptionState); |
+ if (exceptionState.throwIfNeeded()) |
+ return; |
+ } |
+ |
+ // FIXME: Only pass context/exceptionState if instance really requires it. |
+ ExecutionContext* context = currentExecutionContext(info.GetIsolate()); |
+ messagePort->postMessage(context, message.release(), ports.get(), exceptionState); |
+ exceptionState.throwIfNeeded(); |
+} |
+ |
+} // namespace blink |