Bug 1690111 - Use new TypedArray APIs for creating a container with a copy of the data. r=necko-reviewers,farre,kershaw

Depends on D152496

Differential Revision: https://phabricator.services.mozilla.com/D152497
This commit is contained in:
Peter Van der Beken 2023-09-11 12:52:20 +00:00
parent 510b237b29
commit 176d24acb3
14 changed files with 111 additions and 91 deletions

View File

@ -21,18 +21,21 @@
namespace mozilla::dom {
static nsresult GetBufferDataAsStream(
const uint8_t* aData, uint32_t aDataLength, nsIInputStream** aResult,
uint64_t* aContentLength, nsACString& aContentType, nsACString& aCharset) {
static nsresult GetBufferDataAsStream(Vector<uint8_t>&& aData,
nsIInputStream** aResult,
uint64_t* aContentLength,
nsACString& aContentType,
nsACString& aCharset) {
aContentType.SetIsVoid(true);
aCharset.Truncate();
*aContentLength = aDataLength;
const char* data = reinterpret_cast<const char*>(aData);
*aContentLength = aData.length();
nsCOMPtr<nsIInputStream> stream;
nsresult rv = NS_NewByteInputStream(
getter_AddRefs(stream), Span(data, aDataLength), NS_ASSIGNMENT_COPY);
getter_AddRefs(stream),
AsChars(Span(aData.extractOrCopyRawBuffer(), *aContentLength)),
NS_ASSIGNMENT_ADOPT);
NS_ENSURE_SUCCESS(rv, rv);
stream.forget(aResult);
@ -44,20 +47,24 @@ template <>
nsresult BodyExtractor<const ArrayBuffer>::GetAsStream(
nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentTypeWithCharset, nsACString& aCharset) const {
mBody->ComputeState();
return GetBufferDataAsStream(mBody->Data(), mBody->Length(), aResult,
aContentLength, aContentTypeWithCharset,
aCharset);
Maybe<Vector<uint8_t>> body = mBody->CreateFromData<Vector<uint8_t>>();
if (body.isNothing()) {
return NS_ERROR_OUT_OF_MEMORY;
}
return GetBufferDataAsStream(body.extract(), aResult, aContentLength,
aContentTypeWithCharset, aCharset);
}
template <>
nsresult BodyExtractor<const ArrayBufferView>::GetAsStream(
nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentTypeWithCharset, nsACString& aCharset) const {
mBody->ComputeState();
return GetBufferDataAsStream(mBody->Data(), mBody->Length(), aResult,
aContentLength, aContentTypeWithCharset,
aCharset);
Maybe<Vector<uint8_t>> body = mBody->CreateFromData<Vector<uint8_t>>();
if (body.isNothing()) {
return NS_ERROR_OUT_OF_MEMORY;
}
return GetBufferDataAsStream(body.extract(), aResult, aContentLength,
aContentTypeWithCharset, aCharset);
}
template <>

View File

@ -30,6 +30,13 @@ nsresult BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength) {
return AppendBlobImpl(blobImpl);
}
nsresult BlobSet::AppendVector(Vector<uint8_t>&& aData) {
size_t length = aData.length();
RefPtr<BlobImpl> blobImpl =
new MemoryBlobImpl(aData.extractOrCopyRawBuffer(), length, u""_ns);
return AppendBlobImpl(blobImpl);
}
nsresult BlobSet::AppendUTF8String(const nsACString& aUTF8String,
bool nativeEOL) {
nsCString utf8Str;

View File

@ -20,6 +20,8 @@ class BlobSet final {
public:
[[nodiscard]] nsresult AppendVoidPtr(const void* aData, uint32_t aLength);
[[nodiscard]] nsresult AppendVector(Vector<uint8_t>&& aData);
[[nodiscard]] nsresult AppendUTF8String(const nsACString& aUTF8String,
bool nativeEOL);

View File

@ -210,26 +210,22 @@ void MultipartBlobImpl::InitializeBlob(const Sequence<Blob::BlobPart>& aData,
}
}
else if (data.IsArrayBuffer()) {
const ArrayBuffer& buffer = data.GetAsArrayBuffer();
buffer.ComputeState();
aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
if (aRv.Failed()) {
return;
}
}
else if (data.IsArrayBufferView()) {
const ArrayBufferView& buffer = data.GetAsArrayBufferView();
buffer.ComputeState();
aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
if (aRv.Failed()) {
return;
}
}
else {
MOZ_CRASH("Impossible blob data type.");
auto blobData = CreateFromTypedArrayData<Vector<uint8_t>>(data);
if (blobData.isNothing()) {
MOZ_CRASH("Impossible blob data type.");
}
if (!blobData.ref()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
aRv = blobSet.AppendVector(blobData.ref().extract());
if (aRv.Failed()) {
return;
}
}
}

View File

@ -841,23 +841,18 @@ RefPtr<Int64Promise> FileSystemWritableFileStream::Write(
// https://fs.spec.whatwg.org/#write-a-chunk
// Step 3.4.6 If data is a BufferSource, let dataBytes be a copy of data.
if (aData.IsArrayBuffer() || aData.IsArrayBufferView()) {
const auto dataSpan = [&aData]() -> mozilla::Span<uint8_t> {
if (aData.IsArrayBuffer()) {
const ArrayBuffer& buffer = aData.GetAsArrayBuffer();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}
const ArrayBufferView& buffer = aData.GetAsArrayBufferView();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}();
auto vectorFromTypedArray = CreateFromTypedArrayData<Vector<uint8_t>>(aData);
if (vectorFromTypedArray.isSome()) {
Maybe<Vector<uint8_t>>& maybeVector = vectorFromTypedArray.ref();
QM_TRY(MOZ_TO_RESULT(maybeVector.isSome()), CreateAndRejectInt64Promise);
// Here we copy
QM_TRY(MOZ_TO_RESULT(NS_NewByteInputStream(getter_AddRefs(inputStream),
AsChars(dataSpan),
NS_ASSIGNMENT_COPY)),
size_t length = maybeVector->length();
QM_TRY(MOZ_TO_RESULT(NS_NewByteInputStream(
getter_AddRefs(inputStream),
AsChars(Span(maybeVector->extractOrCopyRawBuffer(), length)),
NS_ASSIGNMENT_ADOPT)),
CreateAndRejectInt64Promise);
return WriteImpl(mTaskQueue, std::move(inputStream), mStreamOwner,

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/EncodedVideoChunk.h"
#include <utility>
#include "mozilla/dom/EncodedVideoChunkBinding.h"
#include "MediaData.h"

View File

@ -9,9 +9,9 @@
#include "js/TypeDecls.h"
#include "mozilla/Attributes.h"
#include "mozilla/Buffer.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"

View File

@ -828,13 +828,16 @@ bool TCPSocket::Send(const ArrayBuffer& aData, uint32_t aByteOffset,
mSocketBridgeChild->SendSend(std::move(arrayBuffer));
} else {
aData.ComputeState();
calculateOffsetAndCount(aData.Length());
JS::Rooted<JS::Value> value(RootingCx(), JS::ObjectValue(*aData.Obj()));
mozilla::Maybe<mozilla::UniquePtr<uint8_t[]>> arrayBuffer =
aData.CreateFromData<mozilla::UniquePtr<uint8_t[]>>(
calculateOffsetAndCount);
if (arrayBuffer.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return false;
}
stream = do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
nsresult rv = stream->SetData(value, aByteOffset, nbytes);
nsresult rv = stream->SetData(arrayBuffer.extract(), nbytes);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;

View File

@ -9,6 +9,7 @@
#include <cstdint>
#include "ErrorList.h"
#include "TypedArray.h"
#include "js/ArrayBuffer.h"
#include "js/ColumnNumber.h" // JS::ColumnNumberZeroOrigin
#include "js/JSON.h"
@ -526,9 +527,7 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
aData.ComputeState();
auto buf =
Buffer<uint8_t>::CopyFrom(Span(aData.Data(), aData.Length()));
Maybe<Buffer<uint8_t>> buf = aData.CreateFromData<Buffer<uint8_t>>();
if (buf.isNothing()) {
promise->MaybeRejectWithOperationError(
"Out of memory: Could not allocate buffer while writing to file");
@ -543,7 +542,7 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
DispatchAndResolve<uint32_t>(
state->mEventQueue, promise,
[file = std::move(file), buf = std::move(*buf),
[file = std::move(file), buf = buf.extract(),
opts = opts.unwrap()]() { return WriteSync(file, buf, opts); });
});
}

View File

@ -279,19 +279,8 @@ already_AddRefed<Promise> OutgoingDatagramStreamAlgorithms::WriteCallback(
// Step 3: Let datagrams be transport.[[Datagrams]].
// (mDatagrams is transport.[[Datagrams]])
// This is a duplicate of dom/encoding/TextDecoderStream.cpp#51-69
// PeterV will deal with that when he lands his patch for TypedArrays
auto data = [&arrayBuffer]() {
if (arrayBuffer.IsArrayBuffer()) {
const ArrayBuffer& buffer = arrayBuffer.GetAsArrayBuffer();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}
MOZ_ASSERT(arrayBuffer.IsArrayBufferView());
const ArrayBufferView& buffer = arrayBuffer.GetAsArrayBufferView();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}();
nsTArray<uint8_t> data;
Unused << AppendTypedArrayDataTo(arrayBuffer, data);
// Step 4: If datagrams.[[OutgoingMaxDatagramSize]] is less than datas
// [[ByteLength]], return a promise resolved with undefined.
@ -309,10 +298,9 @@ already_AddRefed<Promise> OutgoingDatagramStreamAlgorithms::WriteCallback(
// We pass along the datagram to the parent immediately.
// The OutgoingDatagramsQueue lives there, and steps 6-9 generally are
// implemented there
nsTArray<uint8_t> array(data);
LOG(("Sending Datagram, size = %zu", array.Length()));
LOG(("Sending Datagram, size = %zu", data.Length()));
mChild->SendOutgoingDatagram(
array, now,
std::move(data), now,
[promise](nsresult&&) {
// XXX result
LOG(("Datagram was sent"));
@ -331,7 +319,7 @@ already_AddRefed<Promise> OutgoingDatagramStreamAlgorithms::WriteCallback(
// We should be guaranteed that we don't get called again until the
// promise is resolved.
MOZ_ASSERT(mWaitConnect == nullptr);
mWaitConnect.reset(new DatagramEntry(data, now));
mWaitConnect.reset(new DatagramEntry(std::move(data), now));
mWaitConnectPromise = promise;
}

View File

@ -32,16 +32,16 @@ template <typename T>
static void GetDataFrom(const T& aObject, uint8_t*& aBuffer,
uint32_t& aLength) {
MOZ_ASSERT(!aBuffer);
aObject.ComputeState();
// We use malloc here rather than a FallibleTArray or fallible
// operator new[] since the gfxUserFontEntry will be calling free
// on it.
aBuffer = (uint8_t*)malloc(aObject.Length());
if (!aBuffer) {
// We need to use malloc here because the gfxUserFontEntry will be calling
// free on it, so the Vector's default AllocPolicy (MallocAllocPolicy) is
// fine.
Maybe<Vector<uint8_t>> buffer =
aObject.template CreateFromData<Vector<uint8_t>>();
if (buffer.isNothing()) {
return;
}
memcpy((void*)aBuffer, aObject.Data(), aObject.Length());
aLength = aObject.Length();
aLength = buffer->length();
aBuffer = buffer->extractOrCopyRawBuffer();
}
// -- FontFace ---------------------------------------------------------------

View File

@ -9,6 +9,7 @@
#include "js/ArrayBuffer.h" // JS::{GetArrayBuffer{ByteLength,Data},IsArrayBufferObject}
#include "js/RootingAPI.h" // JS::{Handle,Rooted}
#include "js/Value.h" // JS::Value
#include "mozilla/Span.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/dom/ScriptSettings.h"
@ -18,8 +19,8 @@ NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream,
nsIInputStream);
NS_IMETHODIMP
ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
uint64_t aByteOffset, uint64_t aLength) {
ArrayBufferInputStream::SetDataFromJS(JS::Handle<JS::Value> aBuffer,
uint64_t aByteOffset, uint64_t aLength) {
NS_ASSERT_OWNINGTHREAD(ArrayBufferInputStream);
if (!aBuffer.isObject()) {
@ -39,7 +40,7 @@ ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
return NS_ERROR_INVALID_ARG;
}
mArrayBuffer = mozilla::MakeUniqueFallible<char[]>(bufferLength);
mArrayBuffer = mozilla::MakeUniqueFallible<uint8_t[]>(bufferLength);
if (!mArrayBuffer) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -48,12 +49,18 @@ ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
JS::AutoCheckCannotGC nogc;
bool isShared;
char* src =
(char*)JS::GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
uint8_t* src = JS::GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
memcpy(&mArrayBuffer[0], src, mBufferLength);
return NS_OK;
}
nsresult ArrayBufferInputStream::SetData(mozilla::UniquePtr<uint8_t[]> aBytes,
uint64_t aByteLen) {
mArrayBuffer = std::move(aBytes);
mBufferLength = aByteLen;
return NS_OK;
}
NS_IMETHODIMP
ArrayBufferInputStream::Close() {
mClosed = true;
@ -108,8 +115,8 @@ ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void* closure,
}
uint32_t written;
nsresult rv = writer(this, closure, &mArrayBuffer[0] + mPos, *result, count,
&written);
nsresult rv = writer(this, closure, (char*)&mArrayBuffer[0] + mPos, *result,
count, &written);
if (NS_FAILED(rv)) {
// InputStreams do not propagate errors to caller.
return NS_OK;

View File

@ -31,7 +31,7 @@ class ArrayBufferInputStream : public nsIArrayBufferInputStream {
private:
virtual ~ArrayBufferInputStream() = default;
mozilla::UniquePtr<char[]> mArrayBuffer;
mozilla::UniquePtr<uint8_t[]> mArrayBuffer;
uint32_t mBufferLength{0};
uint32_t mPos{0};
bool mClosed{false};

View File

@ -5,6 +5,11 @@
#include "nsIInputStream.idl"
%{C++
#include "mozilla/UniquePtr.h"
%}
native Bytes(mozilla::UniquePtr<uint8_t[]>);
/**
* nsIArrayBufferInputStream
*
@ -21,5 +26,15 @@ interface nsIArrayBufferInputStream : nsIInputStream
* @param byteOffset - stream data offset
* @param byteLen - stream data length
*/
[binaryname(SetDataFromJS)]
void setData(in jsval buffer, in uint64_t byteOffset, in uint64_t byteLen);
/**
* SetData - assign data to the input stream.
*
* @param aBytes - stream data
* @param byteLen - stream data length
*/
[noscript, nostdcall, binaryname(SetData)]
void setDataNative(in Bytes bytes, in uint64_t byteLen);
};