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"
13 #include "nsPrintfCString.h"
14 #include "nsRFPService.h"
15 #include "nsStringStream.h"
18 namespace mozilla::dom
{
21 already_AddRefed
<MemoryBlobImpl
> MemoryBlobImpl::CreateWithCustomLastModified(
22 void* aMemoryBuffer
, uint64_t aLength
, const nsAString
& aName
,
23 const nsAString
& aContentType
, int64_t aLastModifiedDate
) {
24 RefPtr
<MemoryBlobImpl
> blobImpl
= new MemoryBlobImpl(
25 aMemoryBuffer
, aLength
, aName
, aContentType
, aLastModifiedDate
);
26 return blobImpl
.forget();
30 already_AddRefed
<MemoryBlobImpl
> MemoryBlobImpl::CreateWithLastModifiedNow(
31 void* aMemoryBuffer
, uint64_t aLength
, const nsAString
& aName
,
32 const nsAString
& aContentType
, bool aCrossOriginIsolated
) {
33 int64_t lastModificationDate
= nsRFPService::ReduceTimePrecisionAsUSecs(
35 /* aIsSystemPrincipal */ false, aCrossOriginIsolated
);
36 return CreateWithCustomLastModified(aMemoryBuffer
, aLength
, aName
,
37 aContentType
, lastModificationDate
);
40 nsresult
MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner
* aDataOwner
,
41 size_t aStart
, size_t aLength
,
42 nsIInputStream
** _retval
) {
43 MOZ_ASSERT(aDataOwner
, "Uh ...");
44 Span data
{static_cast<const char*>(aDataOwner
->mData
) + aStart
, aLength
};
45 RefPtr adapter
= new MemoryBlobImpl::DataOwnerAdapter(aDataOwner
, data
);
46 return NS_NewByteInputStream(_retval
, adapter
);
49 already_AddRefed
<BlobImpl
> MemoryBlobImpl::CreateSlice(
50 uint64_t aStart
, uint64_t aLength
, const nsAString
& aContentType
,
52 RefPtr
<BlobImpl
> impl
=
53 new MemoryBlobImpl(this, aStart
, aLength
, aContentType
);
57 void MemoryBlobImpl::CreateInputStream(nsIInputStream
** aStream
,
59 if (mLength
>= INT32_MAX
) {
60 aRv
.Throw(NS_ERROR_FAILURE
);
64 aRv
= MemoryBlobImpl::DataOwnerAdapter::Create(mDataOwner
, mStart
, mLength
,
69 StaticMutex
MemoryBlobImpl::DataOwner::sDataOwnerMutex
;
71 /* static */ StaticAutoPtr
<LinkedList
<MemoryBlobImpl::DataOwner
>>
72 MemoryBlobImpl::DataOwner::sDataOwners
;
75 bool MemoryBlobImpl::DataOwner::sMemoryReporterRegistered
= false;
77 MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf
)
79 class MemoryBlobImplDataOwnerMemoryReporter final
: public nsIMemoryReporter
{
80 ~MemoryBlobImplDataOwnerMemoryReporter() = default;
83 NS_DECL_THREADSAFE_ISUPPORTS
85 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
86 nsISupports
* aData
, bool aAnonymize
) override
{
87 using DataOwner
= MemoryBlobImpl::DataOwner
;
89 StaticMutexAutoLock
lock(DataOwner::sDataOwnerMutex
);
91 if (!DataOwner::sDataOwners
) {
95 const size_t LARGE_OBJECT_MIN_SIZE
= 8 * 1024;
96 size_t smallObjectsTotal
= 0;
98 for (DataOwner
* owner
= DataOwner::sDataOwners
->getFirst(); owner
;
99 owner
= owner
->getNext()) {
100 size_t size
= MemoryFileDataOwnerMallocSizeOf(owner
->mData
);
102 if (size
< LARGE_OBJECT_MIN_SIZE
) {
103 smallObjectsTotal
+= size
;
106 sha1
.update(owner
->mData
, owner
->mLength
);
107 uint8_t digest
[SHA1Sum::kHashSize
]; // SHA1 digests are 20 bytes long.
110 nsAutoCString digestString
;
111 for (size_t i
= 0; i
< sizeof(digest
); i
++) {
112 digestString
.AppendPrintf("%02x", digest
[i
]);
115 aHandleReport
->Callback(
118 "explicit/dom/memory-file-data/large/file(length=%" PRIu64
121 aAnonymize
? "<anonymized>" : digestString
.get()),
122 KIND_HEAP
, UNITS_BYTES
, size
,
124 "Memory used to back a memory file of length %" PRIu64
126 "has a sha1 of %s.\n\n"
127 "Note that the allocator may round up a memory file's length "
129 "that is, an N-byte memory file may take up more than N bytes "
132 owner
->mLength
, digestString
.get()),
137 if (smallObjectsTotal
> 0) {
138 aHandleReport
->Callback(
139 /* process */ ""_ns
, "explicit/dom/memory-file-data/small"_ns
,
140 KIND_HEAP
, UNITS_BYTES
, smallObjectsTotal
,
142 "Memory used to back small memory files (i.e. those taking up "
144 "than %zu bytes of memory each).\n\n"
145 "Note that the allocator may round up a memory file's length -- "
146 "that is, an N-byte memory file may take up more than N bytes of "
148 LARGE_OBJECT_MIN_SIZE
),
156 NS_IMPL_ISUPPORTS(MemoryBlobImplDataOwnerMemoryReporter
, nsIMemoryReporter
)
159 void MemoryBlobImpl::DataOwner::EnsureMemoryReporterRegistered() {
160 sDataOwnerMutex
.AssertCurrentThreadOwns();
161 if (sMemoryReporterRegistered
) {
165 RegisterStrongMemoryReporter(new MemoryBlobImplDataOwnerMemoryReporter());
167 sMemoryReporterRegistered
= true;
170 } // namespace mozilla::dom