From 2674733d0680dd0c1f0d68264fe634ee0e75f83c Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 24 Apr 2019 15:58:42 +0100 Subject: [PATCH] Bug 1536154 - Update JS_updateMallocCounter callers to use the new API r=bzbarsky This updates existing callers to use the new JS::AddAssociatedMemory API and adds calls to RemoveAssociatedMemory in finalizers. The associated memory doesn't need to be exact, so some simplifiations are made, e.g. in CanvasRenderingContext2D where we don't wait for memory to be allocated but update the number of bytes when the dimensions change, and for stream blobs where the value returned by SizeOfIncludingThis changes over the lifetime of the object. Differential Revision: https://phabricator.services.mozilla.com/D28692 --- dom/bindings/BindingUtils.h | 6 ++++-- dom/bindings/Codegen.py | 8 ++++++++ dom/canvas/CanvasRenderingContext2D.cpp | 14 ++++++++++++++ dom/file/Blob.cpp | 7 +++++++ .../components/osfile/NativeOSFileInternals.cpp | 5 +---- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 7c4f9075520d..d3cb04d184ba 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2591,7 +2591,8 @@ class MOZ_STACK_CLASS BindingJSObjectCreator { } if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) { - JS_updateMallocCounter(aCx, mallocBytes); + JS::AddAssociatedMemory(aReflector, mallocBytes, + JS::MemoryUse::DOMBinding); } } @@ -2607,7 +2608,8 @@ class MOZ_STACK_CLASS BindingJSObjectCreator { } if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) { - JS_updateMallocCounter(aCx, mallocBytes); + JS::AddAssociatedMemory(aReflector, mallocBytes, + JS::MemoryUse::DOMBinding); } } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index b3d770788a9a..d29fdc879f13 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1757,6 +1757,14 @@ def finalizeHook(descriptor, hookName, freeOp, obj): finalize += "ClearWrapper(self, self, %s);\n" % obj if descriptor.isGlobal(): finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), %s);\n" % (freeOp, obj) + finalize += fill( + """ + if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { + JS::RemoveAssociatedMemory(${obj}, mallocBytes, + JS::MemoryUse::DOMBinding); + } + """, + obj=obj) finalize += ("AddForDeferredFinalization<%s>(self);\n" % descriptor.nativeType) return CGIfWrapper(CGGeneric(finalize), "self") diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 3d1ad831e2d4..b30c6d14992d 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1486,8 +1486,22 @@ void CanvasRenderingContext2D::ClearTarget(int32_t aWidth, int32_t aHeight) { // Update dimensions only if new (strictly positive) values were passed. if (aWidth > 0 && aHeight > 0) { + // Update the memory size associated with the wrapper object when we change + // the dimensions. Note that we need to keep updating dying wrappers before + // they are finalized so that the memory accounting balances out. + JSObject* wrapper = GetWrapperMaybeDead(); + if (wrapper) { + JS::RemoveAssociatedMemory(wrapper, BindingJSObjectMallocBytes(this), + JS::MemoryUse::DOMBinding); + } + mWidth = aWidth; mHeight = aHeight; + + if (wrapper) { + JS::AddAssociatedMemory(wrapper, BindingJSObjectMallocBytes(this), + JS::MemoryUse::DOMBinding); + } } if (!mCanvasElement || !mCanvasElement->IsInComposedDoc()) { diff --git a/dom/file/Blob.cpp b/dom/file/Blob.cpp index b050d709e3a1..696fbd05c057 100644 --- a/dom/file/Blob.cpp +++ b/dom/file/Blob.cpp @@ -13,6 +13,7 @@ #include "nsPIDOMWindow.h" #include "StreamBlobImpl.h" #include "StringBlobImpl.h" +#include "js/GCAPI.h" namespace mozilla { namespace dom { @@ -229,6 +230,12 @@ void Blob::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) { size_t BindingJSObjectMallocBytes(Blob* aBlob) { MOZ_ASSERT(aBlob); + + // TODO: The hazard analysis currently can't see that none of the + // implementations of the GetAllocationSize virtual method call can GC (see + // bug 1531951). + JS::AutoSuppressGCAnalysis nogc; + return aBlob->GetAllocationSize(); } diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp index 9bc5530085a0..46324e4afc55 100644 --- a/toolkit/components/osfile/NativeOSFileInternals.cpp +++ b/toolkit/components/osfile/NativeOSFileInternals.cpp @@ -357,6 +357,7 @@ nsresult TypedArrayResult::GetCacheableResult( const ArrayBufferContents& contents = mContents.get(); MOZ_ASSERT(contents.data); + // This takes ownership of the buffer and notes the memory allocation. JS::Rooted arrayBuffer( cx, JS::NewArrayBufferWithContents(cx, contents.nbytes, contents.data)); if (!arrayBuffer) { @@ -368,10 +369,6 @@ nsresult TypedArrayResult::GetCacheableResult( if (!result) { return NS_ERROR_OUT_OF_MEMORY; } - // The memory of contents has been allocated on a thread that - // doesn't have a JSRuntime, hence without a context. Now that we - // have a context, attach the memory to where it belongs. - JS_updateMallocCounter(cx, contents.nbytes); mContents.forget(); aResult.setObject(*result);