Line data Source code
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/. */
6 :
7 : #include "MemoryBlobImpl.h"
8 : #include "mozilla/IntegerPrintfMacros.h"
9 : #include "mozilla/SHA1.h"
10 : #include "nsPrintfCString.h"
11 :
12 : namespace mozilla {
13 : namespace dom {
14 :
15 0 : NS_IMPL_ADDREF(MemoryBlobImpl::DataOwnerAdapter)
16 0 : NS_IMPL_RELEASE(MemoryBlobImpl::DataOwnerAdapter)
17 :
18 0 : NS_INTERFACE_MAP_BEGIN(MemoryBlobImpl::DataOwnerAdapter)
19 0 : NS_INTERFACE_MAP_ENTRY(nsIInputStream)
20 0 : NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
21 0 : NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
22 0 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
23 : mSerializableInputStream)
24 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
25 0 : NS_INTERFACE_MAP_END
26 :
27 0 : nsresult MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner* aDataOwner,
28 : uint32_t aStart,
29 : uint32_t aLength,
30 : nsIInputStream** _retval)
31 : {
32 : nsresult rv;
33 0 : MOZ_ASSERT(aDataOwner, "Uh ...");
34 :
35 0 : nsCOMPtr<nsIInputStream> stream;
36 :
37 0 : rv = NS_NewByteInputStream(getter_AddRefs(stream),
38 0 : static_cast<const char*>(aDataOwner->mData) +
39 : aStart,
40 : (int32_t)aLength,
41 0 : NS_ASSIGNMENT_DEPEND);
42 0 : NS_ENSURE_SUCCESS(rv, rv);
43 :
44 0 : NS_ADDREF(*_retval =
45 0 : new MemoryBlobImpl::DataOwnerAdapter(aDataOwner, stream));
46 :
47 0 : return NS_OK;
48 : }
49 :
50 0 : NS_IMPL_ISUPPORTS_INHERITED0(MemoryBlobImpl, BlobImpl)
51 :
52 : already_AddRefed<BlobImpl>
53 0 : MemoryBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
54 : const nsAString& aContentType,
55 : ErrorResult& aRv)
56 : {
57 : RefPtr<BlobImpl> impl =
58 0 : new MemoryBlobImpl(this, aStart, aLength, aContentType);
59 0 : return impl.forget();
60 : }
61 :
62 : void
63 0 : MemoryBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
64 : {
65 0 : if (mLength > INT32_MAX) {
66 0 : aRv.Throw(NS_ERROR_FAILURE);
67 0 : return;
68 : }
69 :
70 0 : aRv = MemoryBlobImpl::DataOwnerAdapter::Create(mDataOwner, mStart, mLength,
71 0 : aStream);
72 : }
73 :
74 : /* static */ StaticMutex
75 3 : MemoryBlobImpl::DataOwner::sDataOwnerMutex;
76 :
77 : /* static */ StaticAutoPtr<LinkedList<MemoryBlobImpl::DataOwner>>
78 3 : MemoryBlobImpl::DataOwner::sDataOwners;
79 :
80 : /* static */ bool
81 : MemoryBlobImpl::DataOwner::sMemoryReporterRegistered = false;
82 :
83 0 : MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf)
84 :
85 0 : class MemoryBlobImplDataOwnerMemoryReporter final
86 : : public nsIMemoryReporter
87 : {
88 0 : ~MemoryBlobImplDataOwnerMemoryReporter() {}
89 :
90 : public:
91 : NS_DECL_THREADSAFE_ISUPPORTS
92 :
93 0 : NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
94 : nsISupports* aData, bool aAnonymize) override
95 : {
96 : typedef MemoryBlobImpl::DataOwner DataOwner;
97 :
98 0 : StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
99 :
100 0 : if (!DataOwner::sDataOwners) {
101 0 : return NS_OK;
102 : }
103 :
104 0 : const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
105 0 : size_t smallObjectsTotal = 0;
106 :
107 0 : for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
108 0 : owner; owner = owner->getNext()) {
109 :
110 0 : size_t size = MemoryFileDataOwnerMallocSizeOf(owner->mData);
111 :
112 0 : if (size < LARGE_OBJECT_MIN_SIZE) {
113 0 : smallObjectsTotal += size;
114 : } else {
115 0 : SHA1Sum sha1;
116 0 : sha1.update(owner->mData, owner->mLength);
117 : uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
118 0 : sha1.finish(digest);
119 :
120 0 : nsAutoCString digestString;
121 0 : for (size_t i = 0; i < sizeof(digest); i++) {
122 0 : digestString.AppendPrintf("%02x", digest[i]);
123 : }
124 :
125 0 : aHandleReport->Callback(
126 0 : /* process */ NS_LITERAL_CSTRING(""),
127 0 : nsPrintfCString(
128 : "explicit/dom/memory-file-data/large/file(length=%" PRIu64 ", sha1=%s)",
129 : owner->mLength, aAnonymize ? "<anonymized>" : digestString.get()),
130 : KIND_HEAP, UNITS_BYTES, size,
131 0 : nsPrintfCString(
132 : "Memory used to back a memory file of length %" PRIu64 " bytes. The file "
133 : "has a sha1 of %s.\n\n"
134 : "Note that the allocator may round up a memory file's length -- "
135 : "that is, an N-byte memory file may take up more than N bytes of "
136 : "memory.",
137 : owner->mLength, digestString.get()),
138 0 : aData);
139 : }
140 : }
141 :
142 0 : if (smallObjectsTotal > 0) {
143 0 : aHandleReport->Callback(
144 0 : /* process */ NS_LITERAL_CSTRING(""),
145 0 : NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
146 : KIND_HEAP, UNITS_BYTES, smallObjectsTotal,
147 0 : nsPrintfCString(
148 : "Memory used to back small memory files (i.e. those taking up less "
149 : "than %zu bytes of memory each).\n\n"
150 : "Note that the allocator may round up a memory file's length -- "
151 : "that is, an N-byte memory file may take up more than N bytes of "
152 : "memory.", LARGE_OBJECT_MIN_SIZE),
153 0 : aData);
154 : }
155 :
156 0 : return NS_OK;
157 : }
158 : };
159 :
160 0 : NS_IMPL_ISUPPORTS(MemoryBlobImplDataOwnerMemoryReporter, nsIMemoryReporter)
161 :
162 : /* static */ void
163 0 : MemoryBlobImpl::DataOwner::EnsureMemoryReporterRegistered()
164 : {
165 0 : sDataOwnerMutex.AssertCurrentThreadOwns();
166 0 : if (sMemoryReporterRegistered) {
167 0 : return;
168 : }
169 :
170 0 : RegisterStrongMemoryReporter(new MemoryBlobImplDataOwnerMemoryReporter());
171 :
172 0 : sMemoryReporterRegistered = true;
173 : }
174 :
175 : } // namespace dom
176 : } // namespace mozilla
|