Bug 1008126 - Part 1: Always transfer array buffers when cloning. r=bent

This commit is contained in:
Shian-Yow Wu 2014-06-06 13:34:29 +08:00
Родитель 22f18674b7
Коммит 262118dbcb
2 изменённых файлов: 64 добавлений и 23 удалений

Просмотреть файл

@ -118,6 +118,7 @@ public:
bool mUploadEventListenersAttached;
bool mMainThreadSeenLoadStart;
bool mInOpen;
bool mArrayBufferResponseWasTransferred;
public:
Proxy(XMLHttpRequest* aXHRPrivate, bool aMozAnon, bool aMozSystem)
@ -129,7 +130,7 @@ public:
mLastLengthComputable(false), mLastUploadLengthComputable(false),
mSeenLoadStart(false), mSeenUploadLoadStart(false),
mUploadEventListenersAttached(false), mMainThreadSeenLoadStart(false),
mInOpen(false)
mInOpen(false), mArrayBufferResponseWasTransferred(false)
{ }
NS_DECL_THREADSAFE_ISUPPORTS
@ -424,6 +425,7 @@ class EventRunnable MOZ_FINAL : public MainThreadProxyRunnable
bool mUploadEvent;
bool mProgressEvent;
bool mLengthComputable;
bool mUseCachedArrayBufferResponse;
nsresult mResponseTextResult;
nsresult mStatusResult;
nsresult mResponseResult;
@ -456,8 +458,8 @@ public:
mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal),
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
mUploadEvent(aUploadEvent), mProgressEvent(true),
mLengthComputable(aLengthComputable), mResponseTextResult(NS_OK),
mStatusResult(NS_OK), mResponseResult(NS_OK)
mLengthComputable(aLengthComputable), mUseCachedArrayBufferResponse(false),
mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
{ }
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
@ -465,7 +467,8 @@ public:
mResponse(JSVAL_VOID), mLoaded(0), mTotal(0),
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
mUseCachedArrayBufferResponse(false), mResponseTextResult(NS_OK),
mStatusResult(NS_OK), mResponseResult(NS_OK)
{ }
private:
@ -1177,22 +1180,48 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
if (NS_SUCCEEDED(mResponseResult)) {
if (!response.isGCThing()) {
mResponse = response;
}
else {
// Anything subject to GC must be cloned.
JSStructuredCloneCallbacks* callbacks =
aWorkerPrivate->IsChromeWorker() ?
ChromeWorkerStructuredCloneCallbacks(true) :
WorkerStructuredCloneCallbacks(true);
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) {
mClonedObjects.SwapElements(clonedObjects);
} else {
bool doClone = true;
JS::Rooted<JS::Value> transferable(aCx);
JS::Rooted<JSObject*> obj(aCx, response.isObjectOrNull() ?
response.toObjectOrNull() : nullptr);
if (obj && JS_IsArrayBufferObject(obj)) {
// Use cached response if the arraybuffer has been transfered.
if (mProxy->mArrayBufferResponseWasTransferred) {
MOZ_ASSERT(JS_IsNeuteredArrayBufferObject(obj));
mUseCachedArrayBufferResponse = true;
doClone = false;
} else {
JS::AutoValueArray<1> argv(aCx);
argv[0].set(response);
obj = JS_NewArrayObject(aCx, argv);
if (obj) {
transferable.setObject(*obj);
mProxy->mArrayBufferResponseWasTransferred = true;
} else {
mResponseResult = NS_ERROR_OUT_OF_MEMORY;
doClone = false;
}
}
}
else {
NS_WARNING("Failed to clone response!");
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
if (doClone) {
// Anything subject to GC must be cloned.
JSStructuredCloneCallbacks* callbacks =
aWorkerPrivate->IsChromeWorker() ?
ChromeWorkerStructuredCloneCallbacks(true) :
WorkerStructuredCloneCallbacks(true);
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
if (mResponseBuffer.write(aCx, response, transferable, callbacks,
&clonedObjects)) {
mClonedObjects.SwapElements(clonedObjects);
} else {
NS_WARNING("Failed to clone response!");
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
mProxy->mArrayBufferResponseWasTransferred = false;
}
}
}
}
@ -1317,7 +1346,7 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
state->mResponseURL = mResponseURL;
XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate;
xhr->UpdateState(*state);
xhr->UpdateState(*state, mUseCachedArrayBufferResponse);
if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) {
return true;
@ -1515,6 +1544,8 @@ SendRunnable::MainThreadRun()
}
}
mProxy->mArrayBufferResponseWasTransferred = false;
mProxy->mInnerChannelId++;
nsresult rv = mProxy->mXHR->Send(variant);
@ -2314,9 +2345,19 @@ XMLHttpRequest::GetResponseText(nsAString& aResponseText, ErrorResult& aRv)
}
void
XMLHttpRequest::UpdateState(const StateData& aStateData)
XMLHttpRequest::UpdateState(const StateData& aStateData,
bool aUseCachedArrayBufferResponse)
{
mStateData = aStateData;
if (aUseCachedArrayBufferResponse) {
MOZ_ASSERT(JS_IsArrayBufferObject(mStateData.mResponse.toObjectOrNull()));
JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
mStateData.mResponse);
mStateData = aStateData;
mStateData.mResponse = response;
}
else {
mStateData = aStateData;
}
if (mStateData.mResponse.isGCThing()) {
mozilla::HoldJSObjects(this);
}

Просмотреть файл

@ -245,7 +245,7 @@ public:
}
void
UpdateState(const StateData& aStateData);
UpdateState(const StateData& aStateData, bool aUseCachedArrayBufferResponse);
void
NullResponseText()