| Index: Source/bindings/v8/SerializedScriptValue.cpp
|
| diff --git a/Source/bindings/v8/SerializedScriptValue.cpp b/Source/bindings/v8/SerializedScriptValue.cpp
|
| index 72f3560274859d1976525d08925f14eb1469278c..28bf94f5bb0b32d521a3956ab3c8ae928f114a89 100644
|
| --- a/Source/bindings/v8/SerializedScriptValue.cpp
|
| +++ b/Source/bindings/v8/SerializedScriptValue.cpp
|
| @@ -37,6 +37,7 @@
|
| #include "V8FileList.h"
|
| #include "V8ImageData.h"
|
| #include "V8MessagePort.h"
|
| +#include "bindings/v8/ExceptionState.h"
|
| #include "bindings/v8/ScriptScope.h"
|
| #include "bindings/v8/ScriptState.h"
|
| #include "bindings/v8/V8Binding.h"
|
| @@ -703,9 +704,7 @@ public:
|
| Success,
|
| InputError,
|
| DataCloneError,
|
| - InvalidStateError,
|
| - JSException,
|
| - JSFailure
|
| + JSException
|
| };
|
|
|
| Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, BlobDataHandleMap& blobDataHandles, v8::TryCatch& tryCatch, v8::Isolate* isolate)
|
| @@ -742,6 +741,8 @@ public:
|
| return m_status;
|
| }
|
|
|
| + String errorMessage() { return m_errorMessage; }
|
| +
|
| // Functions used by serialization states.
|
| StateBase* doSerialize(v8::Handle<v8::Value>, StateBase* next);
|
|
|
| @@ -752,12 +753,7 @@ public:
|
|
|
| StateBase* checkException(StateBase* state)
|
| {
|
| - return m_tryCatch.HasCaught() ? handleError(JSException, state) : 0;
|
| - }
|
| -
|
| - StateBase* reportFailure(StateBase* state)
|
| - {
|
| - return handleError(JSFailure, state);
|
| + return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0;
|
| }
|
|
|
| StateBase* writeObject(uint32_t numProperties, StateBase* state)
|
| @@ -860,7 +856,7 @@ private:
|
| if (StateBase* newState = serializer.checkException(this))
|
| return newState;
|
| if (propertyName.IsEmpty())
|
| - return serializer.reportFailure(this);
|
| + return serializer.handleError(InputError, "Empty property names cannot be cloned.", this);
|
| bool hasStringProperty = propertyName->IsString() && composite()->HasRealNamedProperty(propertyName.As<v8::String>());
|
| if (StateBase* newState = serializer.checkException(this))
|
| return newState;
|
| @@ -919,7 +915,7 @@ private:
|
| if (StateBase* newState = serializer.checkException(this))
|
| return newState;
|
| if (m_propertyNames.IsEmpty())
|
| - return serializer.reportFailure(this);
|
| + return serializer.handleError(InputError, "Empty property names cannot be cloned.", nextState());
|
| }
|
| return serializeProperties(false, serializer);
|
| }
|
| @@ -989,7 +985,7 @@ private:
|
| {
|
| ASSERT(state);
|
| ++m_depth;
|
| - return checkComposite(state) ? state : handleError(InputError, state);
|
| + return checkComposite(state) ? state : handleError(InputError, "Value being cloned is either cyclic or too deeply nested.", state);
|
| }
|
|
|
| StateBase* pop(StateBase* state)
|
| @@ -1001,10 +997,11 @@ private:
|
| return next;
|
| }
|
|
|
| - StateBase* handleError(Status errorStatus, StateBase* state)
|
| + StateBase* handleError(Status errorStatus, const String& message, StateBase* state)
|
| {
|
| ASSERT(errorStatus != Success);
|
| m_status = errorStatus;
|
| + m_errorMessage = message;
|
| while (state) {
|
| StateBase* tmp = state->nextState();
|
| delete state;
|
| @@ -1071,7 +1068,7 @@ private:
|
| if (!fs)
|
| return 0;
|
| if (!fs->clonable())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "A FileSystem object could not be cloned.", next);
|
| m_writer.writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().string());
|
| return 0;
|
| }
|
| @@ -1118,10 +1115,10 @@ private:
|
| if (!arrayBufferView)
|
| return 0;
|
| if (!arrayBufferView->buffer())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
|
| v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer(), v8::Handle<v8::Object>(), m_writer.getIsolate());
|
| if (underlyingBuffer.IsEmpty())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
|
| StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
|
| if (stateOut)
|
| return stateOut;
|
| @@ -1146,7 +1143,7 @@ private:
|
| if (!arrayBuffer)
|
| return 0;
|
| if (arrayBuffer->isNeutered())
|
| - return handleError(InvalidStateError, next);
|
| + return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
|
| ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>()));
|
| m_writer.writeArrayBuffer(*arrayBuffer);
|
| return 0;
|
| @@ -1158,7 +1155,7 @@ private:
|
| if (!arrayBuffer)
|
| return 0;
|
| if (arrayBuffer->isNeutered())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
|
| m_writer.writeTransferredArrayBuffer(index);
|
| return 0;
|
| }
|
| @@ -1208,6 +1205,7 @@ private:
|
| v8::TryCatch& m_tryCatch;
|
| int m_depth;
|
| Status m_status;
|
| + String m_errorMessage;
|
| typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool;
|
| ObjectPool m_objectPool;
|
| ObjectPool m_transferredMessagePorts;
|
| @@ -1229,9 +1227,9 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
|
| // that we grey and write below).
|
| ASSERT(!value->IsString());
|
| m_writer.writeObjectReference(objectReference);
|
| - } else if (value.IsEmpty())
|
| - return reportFailure(next);
|
| - else if (value->IsUndefined())
|
| + } else if (value.IsEmpty()) {
|
| + return handleError(InputError, "The empty property name cannot be cloned.", next);
|
| + } else if (value->IsUndefined())
|
| m_writer.writeUndefined();
|
| else if (value->IsNull())
|
| m_writer.writeNull();
|
| @@ -1254,13 +1252,13 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
|
| if (m_transferredMessagePorts.tryGet(value.As<v8::Object>(), &messagePortIndex))
|
| m_writer.writeTransferredMessagePort(messagePortIndex);
|
| else
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "A MessagePort could not be cloned.", next);
|
| } else if (V8ArrayBuffer::hasInstance(value, m_isolate, currentWorldType) && m_transferredArrayBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex))
|
| return writeTransferredArrayBuffer(value, arrayBufferIndex, next);
|
| else {
|
| v8::Handle<v8::Object> jsObject = value.As<v8::Object>();
|
| if (jsObject.IsEmpty())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "An object could not be cloned.", next);
|
| greyObject(jsObject);
|
| if (value->IsDate())
|
| m_writer.writeDate(value->NumberValue());
|
| @@ -1288,10 +1286,10 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
|
| return writeArrayBuffer(value, next);
|
| else if (value->IsObject()) {
|
| if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "An object could not be cloned.", next);
|
| return startObjectState(jsObject, next);
|
| } else
|
| - return handleError(DataCloneError, next);
|
| + return handleError(DataCloneError, "A value could not be cloned.", next);
|
| }
|
| return 0;
|
| }
|
| @@ -2253,21 +2251,21 @@ private:
|
|
|
| } // namespace
|
|
|
| -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, bool& didThrow, v8::Isolate* isolate)
|
| +PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
|
| {
|
| - return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, didThrow, isolate));
|
| + return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, exceptionState, isolate));
|
| }
|
|
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::createAndSwallowExceptions(v8::Handle<v8::Value> value, v8::Isolate* isolate)
|
| {
|
| - bool didThrow;
|
| - return adoptRef(new SerializedScriptValue(value, 0, 0, didThrow, isolate, DoNotThrowExceptions));
|
| + TrackExceptionState exceptionState;
|
| + return adoptRef(new SerializedScriptValue(value, 0, 0, exceptionState, isolate));
|
| }
|
|
|
| -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const ScriptValue& value, bool& didThrow, ScriptState* state)
|
| +PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const ScriptValue& value, ExceptionState& exceptionState, ScriptState* state)
|
| {
|
| ScriptScope scope(state);
|
| - return adoptRef(new SerializedScriptValue(value.v8Value(), 0, 0, didThrow, state->isolate()));
|
| + return adoptRef(new SerializedScriptValue(value.v8Value(), 0, 0, exceptionState, state->isolate()));
|
| }
|
|
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(const String& data)
|
| @@ -2368,14 +2366,13 @@ inline void neuterBinding(ArrayBufferView* object)
|
| }
|
| }
|
|
|
| -PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(ArrayBufferArray& arrayBuffers, bool& didThrow, v8::Isolate* isolate)
|
| +PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
|
| {
|
| ASSERT(arrayBuffers.size());
|
|
|
| for (size_t i = 0; i < arrayBuffers.size(); i++) {
|
| if (arrayBuffers[i]->isNeutered()) {
|
| - setDOMException(InvalidStateError, isolate);
|
| - didThrow = true;
|
| + exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is already neutered.");
|
| return nullptr;
|
| }
|
| }
|
| @@ -2392,8 +2389,7 @@ PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu
|
|
|
| bool result = arrayBuffers[i]->transfer(contents->at(i), neuteredViews);
|
| if (!result) {
|
| - setDOMException(InvalidStateError, isolate);
|
| - didThrow = true;
|
| + exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " could not be transferred.");
|
| return nullptr;
|
| }
|
|
|
| @@ -2404,52 +2400,36 @@ PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu
|
| return contents.release();
|
| }
|
|
|
| -SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, bool& didThrow, v8::Isolate* isolate, ExceptionPolicy policy)
|
| +SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
|
| : m_externallyAllocatedMemory(0)
|
| {
|
| - didThrow = false;
|
| Writer writer(isolate);
|
| Serializer::Status status;
|
| + String errorMessage;
|
| {
|
| v8::TryCatch tryCatch;
|
| Serializer serializer(writer, messagePorts, arrayBuffers, m_blobDataHandles, tryCatch, isolate);
|
| status = serializer.serialize(value);
|
| if (status == Serializer::JSException) {
|
| - didThrow = true;
|
| // If there was a JS exception thrown, re-throw it.
|
| - if (policy == ThrowExceptions)
|
| - tryCatch.ReThrow();
|
| + exceptionState.rethrowV8Exception(tryCatch.Exception());
|
| return;
|
| }
|
| + errorMessage = serializer.errorMessage();
|
| }
|
| switch (status) {
|
| case Serializer::InputError:
|
| case Serializer::DataCloneError:
|
| - // If there was an input error, throw a new exception outside
|
| - // of the TryCatch scope.
|
| - didThrow = true;
|
| - if (policy == ThrowExceptions)
|
| - setDOMException(DataCloneError, isolate);
|
| - return;
|
| - case Serializer::InvalidStateError:
|
| - didThrow = true;
|
| - if (policy == ThrowExceptions)
|
| - setDOMException(InvalidStateError, isolate);
|
| - return;
|
| - case Serializer::JSFailure:
|
| - // If there was a JS failure (but no exception), there's not
|
| - // much we can do except for unwinding the C++ stack by
|
| - // pretending there was a JS exception.
|
| - didThrow = true;
|
| + exceptionState.throwDOMException(DataCloneError, errorMessage);
|
| return;
|
| case Serializer::Success:
|
| m_data = writer.takeWireString();
|
| ASSERT(m_data.impl()->hasOneRef());
|
| if (arrayBuffers && arrayBuffers->size())
|
| - m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, didThrow, isolate);
|
| + m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, exceptionState, isolate);
|
| return;
|
| case Serializer::JSException:
|
| - // We should never get here because this case was handled above.
|
| + ASSERT_NOT_REACHED();
|
| break;
|
| }
|
| ASSERT_NOT_REACHED();
|
|
|