1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MemoryBlobImpl.h"
8 #include "mozilla/ipc/InputStreamUtils.h"
9 #include "mozilla/IntegerPrintfMacros.h"
10 #include "mozilla/SHA1.h"
11 #include "nsIMemoryReporter.h"
12 #include "nsPrintfCString.h"
13 #include "nsRFPService.h"
14 #include "nsStringStream.h"
17 namespace mozilla::dom
{
20 already_AddRefed
<MemoryBlobImpl
> MemoryBlobImpl::CreateWithCustomLastModified(
21 void* aMemoryBuffer
, uint64_t aLength
, const nsAString
& aName
,
22 const nsAString
& aContentType
, int64_t aLastModifiedDate
) {
23 RefPtr
<MemoryBlobImpl
> blobImpl
= new MemoryBlobImpl(
24 aMemoryBuffer
, aLength
, aName
, aContentType
, aLastModifiedDate
);
25 return blobImpl
.forget();
29 already_AddRefed
<MemoryBlobImpl
> MemoryBlobImpl::CreateWithLastModifiedNow(
30 void* aMemoryBuffer
, uint64_t aLength
, const nsAString
& aName
,
31 const nsAString
& aContentType
, RTPCallerType aRTPCallerType
) {
32 int64_t lastModificationDate
=
33 nsRFPService::ReduceTimePrecisionAsUSecs(PR_Now(), 0, aRTPCallerType
);
34 return CreateWithCustomLastModified(aMemoryBuffer
, aLength
, aName
,
35 aContentType
, lastModificationDate
);
38 nsresult
MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner
* aDataOwner
,
39 size_t aStart
, size_t aLength
,
40 nsIInputStream
** _retval
) {
41 MOZ_ASSERT(aDataOwner
, "Uh ...");
42 Span data
{static_cast<const char*>(aDataOwner
->mData
) + aStart
, aLength
};
43 RefPtr adapter
= new MemoryBlobImpl::DataOwnerAdapter(aDataOwner
, data
);
44 return NS_NewByteInputStream(_retval
, adapter
);
47 already_AddRefed
<BlobImpl
> MemoryBlobImpl::CreateSlice(
48 uint64_t aStart
, uint64_t aLength
, const nsAString
& aContentType
,
49 ErrorResult
& aRv
) const {
50 RefPtr
<BlobImpl
> impl
=
51 new MemoryBlobImpl(this, aStart
, aLength
, aContentType
);
55 void MemoryBlobImpl::CreateInputStream(nsIInputStream
** aStream
,
56 ErrorResult
& aRv
) const {
57 if (mLength
>= INT32_MAX
) {
58 aRv
.Throw(NS_ERROR_FAILURE
);
62 aRv
= MemoryBlobImpl::DataOwnerAdapter::Create(mDataOwner
, mStart
, mLength
,
67 StaticMutex
MemoryBlobImpl::DataOwner::sDataOwnerMutex
;
69 /* static */ StaticAutoPtr
<LinkedList
<MemoryBlobImpl::DataOwner
>>
70 MemoryBlobImpl::DataOwner::sDataOwners
;
73 bool MemoryBlobImpl::DataOwner::sMemoryReporterRegistered
= false;
75 MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf
)
77 class MemoryBlobImplDataOwnerMemoryReporter final
: public nsIMemoryReporter
{
78 ~MemoryBlobImplDataOwnerMemoryReporter() = default;
81 NS_DECL_THREADSAFE_ISUPPORTS
83 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
84 nsISupports
* aData
, bool aAnonymize
) override
{
85 using DataOwner
= MemoryBlobImpl::DataOwner
;
87 StaticMutexAutoLock
lock(DataOwner::sDataOwnerMutex
);
89 if (!DataOwner::sDataOwners
) {
93 const size_t LARGE_OBJECT_MIN_SIZE
= 8 * 1024;
94 size_t smallObjectsTotal
= 0;
96 for (DataOwner
* owner
= DataOwner::sDataOwners
->getFirst(); owner
;
97 owner
= owner
->getNext()) {
98 size_t size
= MemoryFileDataOwnerMallocSizeOf(owner
->mData
);
100 if (size
< LARGE_OBJECT_MIN_SIZE
) {
101 smallObjectsTotal
+= size
;
104 sha1
.update(owner
->mData
, owner
->mLength
);
105 uint8_t digest
[SHA1Sum::kHashSize
]; // SHA1 digests are 20 bytes long.
108 nsAutoCString digestString
;
109 for (size_t i
= 0; i
< sizeof(digest
); i
++) {
110 digestString
.AppendPrintf("%02x", digest
[i
]);
113 aHandleReport
->Callback(
116 "explicit/dom/memory-file-data/large/file(length=%" PRIu64
119 aAnonymize
? "<anonymized>" : digestString
.get()),
120 KIND_HEAP
, UNITS_BYTES
, size
,
122 "Memory used to back a memory file of length %" PRIu64
124 "has a sha1 of %s.\n\n"
125 "Note that the allocator may round up a memory file's length "
127 "that is, an N-byte memory file may take up more than N bytes "
130 owner
->mLength
, digestString
.get()),
135 if (smallObjectsTotal
> 0) {
136 aHandleReport
->Callback(
137 /* process */ ""_ns
, "explicit/dom/memory-file-data/small"_ns
,
138 KIND_HEAP
, UNITS_BYTES
, smallObjectsTotal
,
140 "Memory used to back small memory files (i.e. those taking up "
142 "than %zu bytes of memory each).\n\n"
143 "Note that the allocator may round up a memory file's length -- "
144 "that is, an N-byte memory file may take up more than N bytes of "
146 LARGE_OBJECT_MIN_SIZE
),
154 NS_IMPL_ISUPPORTS(MemoryBlobImplDataOwnerMemoryReporter
, nsIMemoryReporter
)
157 void MemoryBlobImpl::DataOwner::EnsureMemoryReporterRegistered() {
158 sDataOwnerMutex
.AssertCurrentThreadOwns();
159 if (sMemoryReporterRegistered
) {
163 RegisterStrongMemoryReporter(new MemoryBlobImplDataOwnerMemoryReporter());
165 sMemoryReporterRegistered
= true;
168 } // namespace mozilla::dom