зеркало из https://github.com/mozilla/gecko-dev.git
177 строки
5.6 KiB
C++
177 строки
5.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "MemoryBlobImpl.h"
|
|
#include "mozilla/IntegerPrintfMacros.h"
|
|
#include "mozilla/SHA1.h"
|
|
#include "nsPrintfCString.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
NS_IMPL_ADDREF(MemoryBlobImpl::DataOwnerAdapter)
|
|
NS_IMPL_RELEASE(MemoryBlobImpl::DataOwnerAdapter)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(MemoryBlobImpl::DataOwnerAdapter)
|
|
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
|
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
|
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
|
mSerializableInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
nsresult MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
|
uint32_t aStart,
|
|
uint32_t aLength,
|
|
nsIInputStream** _retval)
|
|
{
|
|
nsresult rv;
|
|
MOZ_ASSERT(aDataOwner, "Uh ...");
|
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
|
|
|
rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
|
static_cast<const char*>(aDataOwner->mData) +
|
|
aStart,
|
|
(int32_t)aLength,
|
|
NS_ASSIGNMENT_DEPEND);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ADDREF(*_retval =
|
|
new MemoryBlobImpl::DataOwnerAdapter(aDataOwner, stream));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED0(MemoryBlobImpl, BlobImpl)
|
|
|
|
already_AddRefed<BlobImpl>
|
|
MemoryBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
|
const nsAString& aContentType,
|
|
ErrorResult& aRv)
|
|
{
|
|
RefPtr<BlobImpl> impl =
|
|
new MemoryBlobImpl(this, aStart, aLength, aContentType);
|
|
return impl.forget();
|
|
}
|
|
|
|
void
|
|
MemoryBlobImpl::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv)
|
|
{
|
|
if (mLength > INT32_MAX) {
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
return;
|
|
}
|
|
|
|
aRv = MemoryBlobImpl::DataOwnerAdapter::Create(mDataOwner, mStart, mLength,
|
|
aStream);
|
|
}
|
|
|
|
/* static */ StaticMutex
|
|
MemoryBlobImpl::DataOwner::sDataOwnerMutex;
|
|
|
|
/* static */ StaticAutoPtr<LinkedList<MemoryBlobImpl::DataOwner>>
|
|
MemoryBlobImpl::DataOwner::sDataOwners;
|
|
|
|
/* static */ bool
|
|
MemoryBlobImpl::DataOwner::sMemoryReporterRegistered = false;
|
|
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf)
|
|
|
|
class MemoryBlobImplDataOwnerMemoryReporter final
|
|
: public nsIMemoryReporter
|
|
{
|
|
~MemoryBlobImplDataOwnerMemoryReporter() {}
|
|
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
|
nsISupports* aData, bool aAnonymize) override
|
|
{
|
|
typedef MemoryBlobImpl::DataOwner DataOwner;
|
|
|
|
StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
|
|
|
|
if (!DataOwner::sDataOwners) {
|
|
return NS_OK;
|
|
}
|
|
|
|
const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
|
|
size_t smallObjectsTotal = 0;
|
|
|
|
for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
|
|
owner; owner = owner->getNext()) {
|
|
|
|
size_t size = MemoryFileDataOwnerMallocSizeOf(owner->mData);
|
|
|
|
if (size < LARGE_OBJECT_MIN_SIZE) {
|
|
smallObjectsTotal += size;
|
|
} else {
|
|
SHA1Sum sha1;
|
|
sha1.update(owner->mData, owner->mLength);
|
|
uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
|
|
sha1.finish(digest);
|
|
|
|
nsAutoCString digestString;
|
|
for (size_t i = 0; i < sizeof(digest); i++) {
|
|
digestString.AppendPrintf("%02x", digest[i]);
|
|
}
|
|
|
|
aHandleReport->Callback(
|
|
/* process */ NS_LITERAL_CSTRING(""),
|
|
nsPrintfCString(
|
|
"explicit/dom/memory-file-data/large/file(length=%" PRIu64 ", sha1=%s)",
|
|
owner->mLength, aAnonymize ? "<anonymized>" : digestString.get()),
|
|
KIND_HEAP, UNITS_BYTES, size,
|
|
nsPrintfCString(
|
|
"Memory used to back a memory file of length %" PRIu64 " bytes. The file "
|
|
"has a sha1 of %s.\n\n"
|
|
"Note that the allocator may round up a memory file's length -- "
|
|
"that is, an N-byte memory file may take up more than N bytes of "
|
|
"memory.",
|
|
owner->mLength, digestString.get()),
|
|
aData);
|
|
}
|
|
}
|
|
|
|
if (smallObjectsTotal > 0) {
|
|
aHandleReport->Callback(
|
|
/* process */ NS_LITERAL_CSTRING(""),
|
|
NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
|
|
KIND_HEAP, UNITS_BYTES, smallObjectsTotal,
|
|
nsPrintfCString(
|
|
"Memory used to back small memory files (i.e. those taking up less "
|
|
"than %zu bytes of memory each).\n\n"
|
|
"Note that the allocator may round up a memory file's length -- "
|
|
"that is, an N-byte memory file may take up more than N bytes of "
|
|
"memory.", LARGE_OBJECT_MIN_SIZE),
|
|
aData);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(MemoryBlobImplDataOwnerMemoryReporter, nsIMemoryReporter)
|
|
|
|
/* static */ void
|
|
MemoryBlobImpl::DataOwner::EnsureMemoryReporterRegistered()
|
|
{
|
|
sDataOwnerMutex.AssertCurrentThreadOwns();
|
|
if (sMemoryReporterRegistered) {
|
|
return;
|
|
}
|
|
|
|
RegisterStrongMemoryReporter(new MemoryBlobImplDataOwnerMemoryReporter());
|
|
|
|
sMemoryReporterRegistered = true;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|