Skip to content
Permalink
Browse files
SVGImage should report its memory cost to JS garbage collector
https://bugs.webkit.org/show_bug.cgi?id=158139

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2016-06-01
Reviewed by Geoffrey Garen.

Like what we do in HTMLImageLoader::notifyFinished() by reporting the memory
cost of the BitmapImage, we need to do something similar for the SVGImage. In
SVGImage::dataChange() and when allDataReceived is true, we can calculate
the size of all DOM nodes and their renderers. The size of the encoded data
has to be added as well to the total memory cost. An approximation for the
memory cost has to be used since it is costly to get an accurate number.

* bindings/js/JSDocumentCustom.cpp:
(WebCore::reportMemoryForDocumentIfFrameless): Use Node::approximateMemoryCost()
instead of sizeof(Node). A Node's descendant can override this function and
return a more accurate memory cost.

* dom/Node.h:
(WebCore::Node::approximateMemoryCost): Define this new virtual function in the
Node class. Its default value is sizeof(Node) but any descendant can return a
more accurate number.

* platform/graphics/Image.h:
(WebCore::Image::data): Define a const version of data() so it can be called
the const function SVGImage::reportApproximateMemoryCost().

* svg/SVGGraphicsElement.h: Override approximateMemoryCost() to return
sizeof(SVGGraphicsElement).

* svg/SVGPathElement.cpp:
(WebCore::SVGPathElement::approximateMemoryCost): Override this function to return
the memory cost of the points and the m_path of the renderer.
* svg/SVGPathElement.h:

* svg/SVGPolyElement.cpp:
(WebCore::SVGPolyElement::approximateMemoryCost): Override this function to return
the memory cost of the points and the m_path of the renderer.
* svg/SVGPolyElement.h:

* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::reportApproximateMemoryCost): Calculate the memory cost of the
nodes in the SVGDocument of an SVGImage. Then report this number to the JS garbage
collector.

(WebCore::SVGImage::dataChanged): After loading all the SVG encoded data and building
its DOM tree and the render tree, report the total memory cost to the JS garbage collector.
* svg/graphics/SVGImage.h:

Canonical link: https://commits.webkit.org/176355@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201561 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Said Abou-Hallawa authored and webkit-commit-queue committed Jun 1, 2016
1 parent d103a58 commit 7d4682f481c7abf4baa42d1c7e651c081128c29e
@@ -1,3 +1,53 @@
2016-06-01 Said Abou-Hallawa <sabouhallawa@apple.com>

SVGImage should report its memory cost to JS garbage collector
https://bugs.webkit.org/show_bug.cgi?id=158139

Reviewed by Geoffrey Garen.

Like what we do in HTMLImageLoader::notifyFinished() by reporting the memory
cost of the BitmapImage, we need to do something similar for the SVGImage. In
SVGImage::dataChange() and when allDataReceived is true, we can calculate
the size of all DOM nodes and their renderers. The size of the encoded data
has to be added as well to the total memory cost. An approximation for the
memory cost has to be used since it is costly to get an accurate number.

* bindings/js/JSDocumentCustom.cpp:
(WebCore::reportMemoryForDocumentIfFrameless): Use Node::approximateMemoryCost()
instead of sizeof(Node). A Node's descendant can override this function and
return a more accurate memory cost.

* dom/Node.h:
(WebCore::Node::approximateMemoryCost): Define this new virtual function in the
Node class. Its default value is sizeof(Node) but any descendant can return a
more accurate number.

* platform/graphics/Image.h:
(WebCore::Image::data): Define a const version of data() so it can be called
the const function SVGImage::reportApproximateMemoryCost().

* svg/SVGGraphicsElement.h: Override approximateMemoryCost() to return
sizeof(SVGGraphicsElement).

* svg/SVGPathElement.cpp:
(WebCore::SVGPathElement::approximateMemoryCost): Override this function to return
the memory cost of the points and the m_path of the renderer.
* svg/SVGPathElement.h:

* svg/SVGPolyElement.cpp:
(WebCore::SVGPolyElement::approximateMemoryCost): Override this function to return
the memory cost of the points and the m_path of the renderer.
* svg/SVGPolyElement.h:

* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::reportApproximateMemoryCost): Calculate the memory cost of the
nodes in the SVGDocument of an SVGImage. Then report this number to the JS garbage
collector.

(WebCore::SVGImage::dataChanged): After loading all the SVG encoded data and building
its DOM tree and the render tree, report the total memory cost to the JS garbage collector.
* svg/graphics/SVGImage.h:

2016-06-01 Andreas Kling <akling@apple.com>

Use inline capacity for StylePropertyShorthand Vectors.
@@ -89,13 +89,13 @@ void reportMemoryForDocumentIfFrameless(ExecState& state, Document& document)
if (document.frame())
return;

size_t nodeCount = 0;
size_t memoryCost = 0;
for (Node* node = &document; node; node = NodeTraversal::next(*node))
++nodeCount;
memoryCost += node->approximateMemoryCost();

// FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
// https://bugs.webkit.org/show_bug.cgi?id=142595
state.heap()->deprecatedReportExtraMemory(nodeCount * sizeof(Node));
state.heap()->deprecatedReportExtraMemory(memoryCost);
}

JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<Document>&& document)
@@ -143,6 +143,7 @@ class Node : public EventTarget {
virtual String nodeValue() const;
virtual void setNodeValue(const String&, ExceptionCode&);
virtual NodeType nodeType() const = 0;
virtual size_t approximateMemoryCost() const { return sizeof(*this); }
ContainerNode* parentNode() const;
static ptrdiff_t parentNodeMemoryOffset() { return OBJECT_OFFSETOF(Node, m_parentNode); }
Element* parentElement() const;
@@ -122,6 +122,7 @@ class Image : public RefCounted<Image> {
virtual void destroyDecodedData(bool destroyAll = true) = 0;

SharedBuffer* data() { return m_encodedImageData.get(); }
const SharedBuffer* data() const { return m_encodedImageData.get(); }

// Animation begins whenever someone draws the image, so startAnimation() is not normally called.
// It will automatically pause once all observers no longer want to render the image anywhere.
@@ -53,6 +53,8 @@ class SVGGraphicsElement : public SVGElement, public SVGTransformable, public SV
virtual void toClipPath(Path&);
RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;

size_t approximateMemoryCost() const override { return sizeof(*this); }

protected:
SVGGraphicsElement(const QualifiedName&, Document&);

@@ -363,6 +363,14 @@ RefPtr<SVGPathSegListPropertyTearOff> SVGPathElement::animatedNormalizedPathSegL
return nullptr;
}

size_t SVGPathElement::approximateMemoryCost() const
{
// This is an approximation for path memory cost since the path is parsed on demand.
size_t pathMemoryCost = (m_pathByteStream.size() / 10) * sizeof(FloatPoint);
// We need to account for the memory which is allocated by the RenderSVGPath::m_path.
return sizeof(*this) + (renderer() ? pathMemoryCost * 2 + sizeof(RenderSVGPath) : pathMemoryCost);
}

void SVGPathElement::pathSegListChanged(SVGPathSegRole role, ListModification listModification)
{
switch (role) {
@@ -101,6 +101,8 @@ class SVGPathElement final : public SVGGraphicsElement,

void animatedPropertyWillBeDeleted();

size_t approximateMemoryCost() const override;

private:
SVGPathElement(const QualifiedName&, Document&);

@@ -130,4 +130,11 @@ RefPtr<SVGListPropertyTearOff<SVGPointList>> SVGPolyElement::animatedPoints()
return static_cast<SVGListPropertyTearOff<SVGPointList>*>(static_reference_cast<SVGAnimatedPointList>(lookupOrCreatePointsWrapper(this))->animVal().get());
}

size_t SVGPolyElement::approximateMemoryCost() const
{
size_t pointsCost = pointList().size() * sizeof(FloatPoint);
// We need to account for the memory which is allocated by the RenderSVGPath::m_path.
return sizeof(*this) + (renderer() ? pointsCost * 2 + sizeof(RenderSVGPath) : pointsCost);
}

}
@@ -38,6 +38,8 @@ class SVGPolyElement : public SVGGraphicsElement, public SVGExternalResourcesReq

static const SVGPropertyInfo* pointsPropertyInfo();

size_t approximateMemoryCost() const override;

protected:
SVGPolyElement(const QualifiedName&, Document&);

@@ -29,13 +29,15 @@
#include "SVGImage.h"

#include "Chrome.h"
#include "DOMWindow.h"
#include "DocumentLoader.h"
#include "ElementIterator.h"
#include "FrameLoader.h"
#include "FrameView.h"
#include "ImageBuffer.h"
#include "ImageObserver.h"
#include "IntRect.h"
#include "JSDOMWindowBase.h"
#include "MainFrame.h"
#include "PageConfiguration.h"
#include "RenderSVGRoot.h"
@@ -48,6 +50,8 @@
#include "SVGSVGElement.h"
#include "Settings.h"
#include "TextStream.h"
#include <runtime/JSCInlines.h>
#include <runtime/JSLock.h>

namespace WebCore {

@@ -353,6 +357,21 @@ void SVGImage::resetAnimation()
stopAnimation();
}

void SVGImage::reportApproximateMemoryCost() const
{
Document* document = m_page->mainFrame().document();
size_t decodedImageMemoryCost = 0;

for (Node* node = document; node; node = NodeTraversal::next(*node))
decodedImageMemoryCost += node->approximateMemoryCost();

JSC::VM& vm = JSDOMWindowBase::commonVM();
JSC::JSLockHolder lock(vm);
// FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
// https://bugs.webkit.org/show_bug.cgi?id=142595
vm.heap.deprecatedReportExtraMemory(decodedImageMemoryCost + data()->size());
}

bool SVGImage::dataChanged(bool allDataReceived)
{
// Don't do anything if is an empty image.
@@ -393,6 +412,7 @@ bool SVGImage::dataChanged(bool allDataReceived)

// Set the intrinsic size before a container size is available.
m_intrinsicSize = containerSize();
reportApproximateMemoryCost();
}

return m_page != nullptr;
@@ -82,6 +82,7 @@ class SVGImage final : public Image {
bool usesContainerSize() const override { return true; }
void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) override;

void reportApproximateMemoryCost() const;
bool dataChanged(bool allDataReceived) override;

// FIXME: SVGImages will be unable to prune because this function is not implemented yet.

0 comments on commit 7d4682f

Please sign in to comment.