зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1249739 - Improve performance in XHR in workers - part 3 - Implement XMLHttpRequestStringSnapshot, r=smaug
This commit is contained in:
Родитель
def1f6e7db
Коммит
284e7077e7
|
@ -567,9 +567,7 @@ NS_IMETHODIMP
|
|||
XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsString responseText;
|
||||
GetResponseText(responseText, rv);
|
||||
aResponseText = responseText;
|
||||
GetResponseText(aResponseText, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -577,7 +575,20 @@ void
|
|||
XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aResponseText.Truncate();
|
||||
XMLHttpRequestStringSnapshot snapshot;
|
||||
GetResponseText(snapshot, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot.GetAsString(aResponseText);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aSnapshot.Reset();
|
||||
|
||||
if (mResponseType != XMLHttpRequestResponseType::_empty &&
|
||||
mResponseType != XMLHttpRequestResponseType::Text &&
|
||||
|
@ -588,7 +599,7 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
|
||||
if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text &&
|
||||
!mInLoadProgressEvent) {
|
||||
aResponseText.SetIsVoid(true);
|
||||
aSnapshot.SetVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -601,7 +612,7 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
// more.
|
||||
if ((!mResponseXML && !mErrorParsingXML) ||
|
||||
mResponseBodyDecodedPos == mResponseBody.Length()) {
|
||||
mResponseText.GetAsString(aResponseText);
|
||||
mResponseText.CreateSnapshot(aSnapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -623,7 +634,7 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
mResponseBodyDecodedPos = 0;
|
||||
}
|
||||
|
||||
mResponseText.GetAsString(aResponseText);
|
||||
mResponseText.CreateSnapshot(aSnapshot);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -746,7 +757,7 @@ XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
|
|||
case XMLHttpRequestResponseType::Text:
|
||||
case XMLHttpRequestResponseType::Moz_chunked_text:
|
||||
{
|
||||
nsString str;
|
||||
nsAutoString str;
|
||||
aRv = GetResponseText(str);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
|
|
@ -470,6 +470,10 @@ public:
|
|||
virtual void
|
||||
GetResponseText(nsAString& aResponseText, ErrorResult& aRv) override;
|
||||
|
||||
void
|
||||
GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual nsIDocument*
|
||||
GetResponseXML(ErrorResult& aRv) override;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "XMLHttpRequestString.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -13,12 +14,26 @@ namespace dom {
|
|||
class XMLHttpRequestStringBuffer final
|
||||
{
|
||||
friend class XMLHttpRequestStringWriterHelper;
|
||||
friend class XMLHttpRequestStringSnapshotReaderHelper;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(XMLHttpRequestStringBuffer)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(XMLHttpRequestStringBuffer)
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
XMLHttpRequestStringBuffer()
|
||||
: mMutex("XMLHttpRequestStringBuffer::mMutex")
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Length()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mData.Length();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
UnsafeLength() const
|
||||
{
|
||||
return mData.Length();
|
||||
}
|
||||
|
@ -26,12 +41,16 @@ public:
|
|||
void
|
||||
Append(const nsAString& aString)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(XMLHttpRequestStringBuffer);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
mData.Append(aString);
|
||||
}
|
||||
|
||||
void
|
||||
GetAsString(nsAString& aString)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
aString = mData;
|
||||
}
|
||||
|
||||
|
@ -41,15 +60,33 @@ public:
|
|||
return mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
GetAsString(nsAString& aString, uint32_t aLength)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(aLength <= mData.Length());
|
||||
aString.Assign(mData.BeginReading(), aLength);
|
||||
}
|
||||
|
||||
void
|
||||
CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
aSnapshot.Set(this, mData.Length());
|
||||
}
|
||||
|
||||
private:
|
||||
~XMLHttpRequestStringBuffer()
|
||||
{}
|
||||
|
||||
nsString& Data()
|
||||
nsString& UnsafeData()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
Mutex mMutex;
|
||||
|
||||
// The following member variable is protected by mutex.
|
||||
nsString mData;
|
||||
};
|
||||
|
||||
|
@ -101,30 +138,116 @@ XMLHttpRequestString::IsEmpty() const
|
|||
return !mBuffer->Length();
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestString::CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot)
|
||||
{
|
||||
mBuffer->CreateSnapshot(aSnapshot);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// XMLHttpRequestStringSnapshot
|
||||
|
||||
XMLHttpRequestStringSnapshot::XMLHttpRequestStringSnapshot()
|
||||
: mLength(0)
|
||||
, mVoid(false)
|
||||
{
|
||||
}
|
||||
|
||||
XMLHttpRequestStringSnapshot::~XMLHttpRequestStringSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
XMLHttpRequestStringSnapshot&
|
||||
XMLHttpRequestStringSnapshot::operator=(const XMLHttpRequestStringSnapshot& aOther)
|
||||
{
|
||||
mBuffer = aOther.mBuffer;
|
||||
mLength = aOther.mLength;
|
||||
mVoid = aOther.mVoid;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestStringSnapshot::ResetInternal(bool aIsVoid)
|
||||
{
|
||||
mBuffer = nullptr;
|
||||
mLength = 0;
|
||||
mVoid = aIsVoid;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestStringSnapshot::Set(XMLHttpRequestStringBuffer* aBuffer,
|
||||
uint32_t aLength)
|
||||
{
|
||||
MOZ_ASSERT(aBuffer);
|
||||
MOZ_ASSERT(aLength <= aBuffer->UnsafeLength());
|
||||
|
||||
mBuffer = aBuffer;
|
||||
mLength = aLength;
|
||||
mVoid = false;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestStringSnapshot::GetAsString(nsAString& aString) const
|
||||
{
|
||||
if (mBuffer) {
|
||||
MOZ_ASSERT(!mVoid);
|
||||
mBuffer->GetAsString(aString, mLength);
|
||||
return;
|
||||
}
|
||||
|
||||
aString.Truncate();
|
||||
|
||||
if (mVoid) {
|
||||
aString.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// XMLHttpRequestStringWriterHelper
|
||||
|
||||
XMLHttpRequestStringWriterHelper::XMLHttpRequestStringWriterHelper(XMLHttpRequestString& aString)
|
||||
: mBuffer(aString.mBuffer)
|
||||
, mLock(aString.mBuffer->mMutex)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestStringWriterHelper::AddCapacity(int32_t aCapacity)
|
||||
{
|
||||
return mBuffer->Data().SetCapacity(mBuffer->Length() + aCapacity, fallible);
|
||||
return mBuffer->UnsafeData().SetCapacity(mBuffer->UnsafeLength() + aCapacity, fallible);
|
||||
}
|
||||
|
||||
char16_t*
|
||||
XMLHttpRequestStringWriterHelper::EndOfExistingData()
|
||||
{
|
||||
return mBuffer->Data().BeginWriting() + mBuffer->Length();
|
||||
return mBuffer->UnsafeData().BeginWriting() + mBuffer->UnsafeLength();
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestStringWriterHelper::AddLength(int32_t aLength)
|
||||
{
|
||||
mBuffer->Data().SetLength(mBuffer->Length() + aLength);
|
||||
mBuffer->UnsafeData().SetLength(mBuffer->UnsafeLength() + aLength);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// XMLHttpRequestStringReaderHelper
|
||||
|
||||
XMLHttpRequestStringSnapshotReaderHelper::XMLHttpRequestStringSnapshotReaderHelper(XMLHttpRequestStringSnapshot& aSnapshot)
|
||||
: mBuffer(aSnapshot.mBuffer)
|
||||
, mLock(aSnapshot.mBuffer->mMutex)
|
||||
{
|
||||
}
|
||||
|
||||
const char16_t*
|
||||
XMLHttpRequestStringSnapshotReaderHelper::Buffer() const
|
||||
{
|
||||
return mBuffer->UnsafeData().BeginReading();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
XMLHttpRequestStringSnapshotReaderHelper::Length() const
|
||||
{
|
||||
return mBuffer->UnsafeLength();
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
|
|
|
@ -10,11 +10,20 @@
|
|||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class Mutex;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class XMLHttpRequestStringBuffer;
|
||||
class XMLHttpRequestStringSnapshot;
|
||||
class XMLHttpRequestStringWriterHelper;
|
||||
class XMLHttpRequestStringSnapshotReaderHelper;
|
||||
|
||||
// We want to avoid the dup of strings when XHR in workers has access to
|
||||
// responseText for events dispatched during the loading state. For this reason
|
||||
// we use this class, able to create snapshots of the current size of itself
|
||||
// without making extra copies.
|
||||
class XMLHttpRequestString final
|
||||
{
|
||||
friend class XMLHttpRequestStringWriterHelper;
|
||||
|
@ -29,6 +38,9 @@ public:
|
|||
|
||||
void Append(const nsAString& aString);
|
||||
|
||||
// This method should be called only when the string is really needed because
|
||||
// it can cause the duplication of the strings in case the loading of the XHR
|
||||
// is not completed yet.
|
||||
void GetAsString(nsAString& aString) const;
|
||||
|
||||
size_t SizeOfThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
@ -37,11 +49,18 @@ public:
|
|||
|
||||
bool IsEmpty() const;
|
||||
|
||||
void CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot);
|
||||
|
||||
private:
|
||||
XMLHttpRequestString(const XMLHttpRequestString&) = delete;
|
||||
XMLHttpRequestString& operator=(const XMLHttpRequestString&) = delete;
|
||||
XMLHttpRequestString& operator=(const XMLHttpRequestString&&) = delete;
|
||||
|
||||
RefPtr<XMLHttpRequestStringBuffer> mBuffer;
|
||||
};
|
||||
|
||||
class XMLHttpRequestStringWriterHelper final
|
||||
// This class locks the buffer and allows the callee to write data into it.
|
||||
class MOZ_STACK_CLASS XMLHttpRequestStringWriterHelper final
|
||||
{
|
||||
public:
|
||||
explicit XMLHttpRequestStringWriterHelper(XMLHttpRequestString& aString);
|
||||
|
@ -56,7 +75,83 @@ public:
|
|||
AddLength(int32_t aLength);
|
||||
|
||||
private:
|
||||
XMLHttpRequestStringWriterHelper(const XMLHttpRequestStringWriterHelper&) = delete;
|
||||
XMLHttpRequestStringWriterHelper& operator=(const XMLHttpRequestStringWriterHelper&) = delete;
|
||||
XMLHttpRequestStringWriterHelper& operator=(const XMLHttpRequestStringWriterHelper&&) = delete;
|
||||
|
||||
RefPtr<XMLHttpRequestStringBuffer> mBuffer;
|
||||
MutexAutoLock mLock;
|
||||
};
|
||||
|
||||
// This class is the internal XMLHttpRequestStringBuffer of the
|
||||
// XMLHttpRequestString plus the current length. GetAsString will return the
|
||||
// string with that particular length also if the XMLHttpRequestStringBuffer is
|
||||
// grown in the meantime.
|
||||
class XMLHttpRequestStringSnapshot final
|
||||
{
|
||||
friend class XMLHttpRequestStringBuffer;
|
||||
friend class XMLHttpRequestStringSnapshotReaderHelper;
|
||||
|
||||
public:
|
||||
XMLHttpRequestStringSnapshot();
|
||||
~XMLHttpRequestStringSnapshot();
|
||||
|
||||
XMLHttpRequestStringSnapshot& operator=(const XMLHttpRequestStringSnapshot&);
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ResetInternal(false /* isVoid */);
|
||||
}
|
||||
|
||||
void SetVoid()
|
||||
{
|
||||
ResetInternal(true /* isVoid */);
|
||||
}
|
||||
|
||||
bool IsVoid() const
|
||||
{
|
||||
return mVoid;
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return !mLength;
|
||||
}
|
||||
|
||||
void GetAsString(nsAString& aString) const;
|
||||
|
||||
private:
|
||||
XMLHttpRequestStringSnapshot(const XMLHttpRequestStringSnapshot&) = delete;
|
||||
XMLHttpRequestStringSnapshot& operator=(const XMLHttpRequestStringSnapshot&&) = delete;
|
||||
|
||||
void Set(XMLHttpRequestStringBuffer* aBuffer, uint32_t aLength);
|
||||
|
||||
void ResetInternal(bool aIsVoid);
|
||||
|
||||
RefPtr<XMLHttpRequestStringBuffer> mBuffer;
|
||||
uint32_t mLength;
|
||||
bool mVoid;
|
||||
};
|
||||
|
||||
// This class locks the buffer and allows the callee to read data from it.
|
||||
class MOZ_STACK_CLASS XMLHttpRequestStringSnapshotReaderHelper final
|
||||
{
|
||||
public:
|
||||
explicit XMLHttpRequestStringSnapshotReaderHelper(XMLHttpRequestStringSnapshot& aSnapshot);
|
||||
|
||||
const char16_t*
|
||||
Buffer() const;
|
||||
|
||||
uint32_t
|
||||
Length() const;
|
||||
|
||||
private:
|
||||
XMLHttpRequestStringSnapshotReaderHelper(const XMLHttpRequestStringSnapshotReaderHelper&) = delete;
|
||||
XMLHttpRequestStringSnapshotReaderHelper& operator=(const XMLHttpRequestStringSnapshotReaderHelper&) = delete;
|
||||
XMLHttpRequestStringSnapshotReaderHelper& operator=(const XMLHttpRequestStringSnapshotReaderHelper&&) = delete;
|
||||
|
||||
RefPtr<XMLHttpRequestStringBuffer> mBuffer;
|
||||
MutexAutoLock mLock;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
|
|
|
@ -476,7 +476,7 @@ class EventRunnable final : public MainThreadProxyRunnable
|
|||
nsString mType;
|
||||
nsString mResponseType;
|
||||
JS::Heap<JS::Value> mResponse;
|
||||
nsString mResponseText;
|
||||
XMLHttpRequestStringSnapshot mResponseText;
|
||||
nsString mResponseURL;
|
||||
nsCString mStatusText;
|
||||
uint64_t mLoaded;
|
||||
|
@ -1129,7 +1129,10 @@ EventRunnable::PreDispatch(WorkerPrivate* /* unused */)
|
|||
MOZ_ASSERT(false, "This should never fail!");
|
||||
}
|
||||
|
||||
mResponseTextResult = xhr->GetResponseText(mResponseText);
|
||||
ErrorResult rv;
|
||||
xhr->GetResponseText(mResponseText, rv);
|
||||
mResponseTextResult = rv.StealNSResult();
|
||||
|
||||
if (NS_SUCCEEDED(mResponseTextResult)) {
|
||||
mResponseResult = mResponseTextResult;
|
||||
if (mResponseText.IsVoid()) {
|
||||
|
@ -1172,7 +1175,6 @@ EventRunnable::PreDispatch(WorkerPrivate* /* unused */)
|
|||
}
|
||||
|
||||
if (doClone) {
|
||||
ErrorResult rv;
|
||||
Write(cx, response, transferable, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
NS_WARNING("Failed to clone response!");
|
||||
|
@ -1186,7 +1188,6 @@ EventRunnable::PreDispatch(WorkerPrivate* /* unused */)
|
|||
|
||||
mStatusResult = xhr->GetStatus(&mStatus);
|
||||
|
||||
ErrorResult rv;
|
||||
xhr->GetStatusText(mStatusText, rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
|
@ -2391,10 +2392,11 @@ XMLHttpRequestWorker::GetResponse(JSContext* /* unused */,
|
|||
mStateData.mResponse =
|
||||
JS_GetEmptyStringValue(mWorkerPrivate->GetJSContext());
|
||||
} else {
|
||||
XMLHttpRequestStringSnapshotReaderHelper helper(mStateData.mResponseText);
|
||||
|
||||
JSString* str =
|
||||
JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
|
||||
mStateData.mResponseText.get(),
|
||||
mStateData.mResponseText.Length());
|
||||
helper.Buffer(), helper.Length());
|
||||
|
||||
if (!str) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -2414,7 +2416,13 @@ void
|
|||
XMLHttpRequestWorker::GetResponseText(nsAString& aResponseText, ErrorResult& aRv)
|
||||
{
|
||||
aRv = mStateData.mResponseTextResult;
|
||||
aResponseText = mStateData.mResponseText;
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString foo;
|
||||
mStateData.mResponseText.GetAsString(foo);
|
||||
aResponseText.Assign(foo.BeginReading(), foo.Length());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "WorkerHolder.h"
|
||||
#include "XMLHttpRequest.h"
|
||||
#include "XMLHttpRequestString.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -27,7 +28,7 @@ class XMLHttpRequestWorker final : public XMLHttpRequest,
|
|||
public:
|
||||
struct StateData
|
||||
{
|
||||
nsString mResponseText;
|
||||
XMLHttpRequestStringSnapshot mResponseText;
|
||||
nsString mResponseURL;
|
||||
uint32_t mStatus;
|
||||
nsCString mStatusText;
|
||||
|
@ -266,7 +267,7 @@ public:
|
|||
void
|
||||
NullResponseText()
|
||||
{
|
||||
mStateData.mResponseText.SetIsVoid(true);
|
||||
mStateData.mResponseText.SetVoid();
|
||||
mStateData.mResponse.setNull();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче