+2012-08-21 Ulan Degenbaev <ulan@chromium.org>
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer constructed and destructed
+ https://bugs.webkit.org/show_bug.cgi?id=92993
+
+ Reviewed by Kenneth Russell.
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer
+ is constructed and destructed so that V8's garbage collection
+ heuristics can account for the memory held by these objects.
+
+ * ManualTests/typed-array-memory.html: Added.
+
2012-08-21 Martin Robinson <mrobinson@igalia.com>
[GTK] Using a native window for the WebView breaks GtkOverlay
--- /dev/null
+<html>
+<head>
+<title>ArrayBuffer External Memory test</title>
+<script>
+
+var log;
+function print(message, color)
+{
+ var paragraph = document.createElement("div");
+ paragraph.appendChild(document.createTextNode(message));
+ paragraph.style.fontFamily = "monospace";
+ if (color)
+ paragraph.style.color = color;
+ log.appendChild(paragraph);
+}
+
+function pass(msg)
+{
+ print("PASS: " + msg, "green");
+}
+
+function fail(msg)
+{
+ print("FAIL: " + msg, "red");
+}
+
+var KB = 1024;
+var MB = KB * KB;
+var noise = KB;
+
+function externalMemory() {
+ return getV8Statistics().amount_of_external_allocated_memory;
+}
+
+function collectGarbage() {
+ for (var i = 0; i < 10; i++) gc();
+}
+
+function allocationsThatIncreaseExternalMemory() {
+ function test(expression) {
+ var before = externalMemory();
+ (function () { eval(expression); }) ();
+ var now = externalMemory();
+ if (now < before + MB - noise) {
+ fail(expression + " did not increase the amount of external memory (" +
+ before + ", " + now + ").");
+ } else {
+ pass(expression + " increased the amount of external memory.");
+ }
+ collectGarbage();
+ var after = externalMemory();
+ if (after > now + noise) {
+ fail("Garbage collection after " + expression +
+ " did not return the amount of external memory to the initial value (" +
+ now + ", " + after + ").");
+ } else {
+ pass("Garbage collection after " + expression +
+ " returned the amount of external memory to the initial value.");
+ }
+ }
+
+ test("(new ArrayBuffer(MB))");
+ test("(new Float32Array(MB))");
+ test("(new Float64Array(MB))");
+ test("(new Int8Array(MB))");
+ test("(new Int16Array(MB))");
+ test("(new Int32Array(MB))");
+ test("(new Uint8Array(MB))");
+ test("(new Uint16Array(MB))");
+ test("(new Uint32Array(MB))");
+ var largeJSArray = [];
+ for (var i = 0; i < MB; i++) largeJSArray.push(i);
+ test("(new Float32Array(largeJSArray))");
+ test("(new Float64Array(largeJSArray))");
+ test("(new Int8Array(largeJSArray))");
+ test("(new Int16Array(largeJSArray))");
+ test("(new Int32Array(largeJSArray))");
+ test("(new Uint8Array(largeJSArray))");
+ test("(new Uint16Array(largeJSArray))");
+ test("(new Uint32Array(largeJSArray))");
+ var int8Array = new Int8Array(MB);
+ test("(new Float32Array(int8Array))");
+ test("(new Float64Array(int8Array))");
+ test("(new Int8Array(int8Array))");
+ test("(new Int16Array(int8Array))");
+ test("(new Int32Array(int8Array))");
+ test("(new Uint8Array(int8Array))");
+ test("(new Uint16Array(int8Array))");
+ test("(new Uint32Array(int8Array))");
+}
+
+
+function allocationsThatDoNotChangeExternalMemory() {
+ function test(expression) {
+ var before = externalMemory();
+ (function () { eval(expression); }) ();
+ var now = externalMemory();
+ if (now > before + noise) {
+ fail(expression + " increased the amount of external memory (" + before + ", " + now + ").");
+ } else {
+ pass(expression + " did not increase the amount of external memory.");
+ }
+ collectGarbage();
+ var after = externalMemory();
+ if (after < now - noise) {
+ fail("Garbage collection after " + expression + " decreased the amount of external memory (" +
+ now + ", " + after + ").");
+ } else {
+ pass("Garbage collection after " + expression +
+ " did not decrease the amount of external memory.");
+ }
+ }
+ var arrayBuffer = new ArrayBuffer(MB);
+ test("(new Float32Array(arrayBuffer))");
+ test("(new Float64Array(arrayBuffer))");
+ test("(new Int8Array(arrayBuffer))");
+ test("(new Int16Array(arrayBuffer))");
+ test("(new Int32Array(arrayBuffer))");
+ test("(new Uint8Array(arrayBuffer))");
+ test("(new Uint16Array(arrayBuffer))");
+ test("(new Uint32Array(arrayBuffer))");
+ var int8Array = new Int8Array(MB);
+ test("(new Float32Array(int8Array.buffer))");
+ test("(new Float64Array(int8Array.buffer))");
+ test("(new Int8Array(int8Array.buffer))");
+ test("(new Int16Array(int8Array.buffer))");
+ test("(new Int32Array(int8Array.buffer))");
+ test("(new Uint8Array(int8Array.buffer))");
+ test("(new Uint16Array(int8Array.buffer))");
+ test("(new Uint32Array(int8Array.buffer))");
+}
+
+
+function transfersThatDecreaseExternalMemory() {
+ var workerSource =
+"function externalMemory() {\n" +
+" return getV8Statistics().amount_of_external_allocated_memory;\n" +
+"}\n" +
+"function collectGarbage() {\n" +
+" for (var i = 0; i < 10; i++) gc();\n" +
+"}\n" +
+"var before = externalMemory();\n" +
+"self.onmessage = function(e) {\n" +
+" var now = externalMemory();\n" +
+" e.data = null;\n" +
+" collectGarbage();\n" +
+" var after = externalMemory();\n" +
+" self.postMessage(before + ' ' + now + ' ' + after);\n" +
+"}\n";
+
+ var blob = new Blob([workerSource]);
+ var worker = new Worker(window.webkitURL.createObjectURL(blob));
+ worker.onmessage = function (e) {
+ print("message from worker: " + e.data, "blue");
+ }
+ function test(expression)
+ {
+ var buffer = eval(expression);
+ try {
+ var before = externalMemory();
+ worker.webkitPostMessage(buffer, [buffer]);
+ var now = externalMemory();
+ if (now > before - MB + noise) {
+ fail("Transfer of " + expression + " did not decrease the amount of external memory (" +
+ before + ", " + now + ").");
+ } else {
+ pass("Transfer of " + expression + " decreased the amount of external memory.");
+ }
+ collectGarbage();
+ var after = externalMemory();
+ if (after < now - noise) {
+ fail("Garbage collection after transfer of " + expression +
+ " decreased the amount of external memory (" + now + ", " + after + ").");
+ } else {
+ pass("Garbage collection after transfer of " + expression +
+ " did not decrease the amount of external memory.");
+ }
+ } catch (e) {
+ fail("Transfer of " + name + ": could not webkitPostMessage: " + e);
+ return false;
+ }
+ return true;
+ }
+ test("(new ArrayBuffer(MB))");
+ test("(new Float32Array(MB)).buffer");
+ test("(new Float64Array(MB)).buffer");
+ test("(new Int8Array(MB)).buffer");
+ test("(new Int16Array(MB)).buffer");
+ test("(new Int32Array(MB)).buffer");
+ test("(new Uint8Array(MB)).buffer");
+ test("(new Uint16Array(MB)).buffer");
+ test("(new Uint32Array(MB)).buffer");
+}
+
+
+function runAll() {
+ log = document.getElementById("log1");
+ if (typeof gc == "undefined" || typeof getV8Statistics == "undefined") {
+ print("Run chrome browser with --js-flags='--expose_gc --track_gc_object_stats'", "red");
+ } else {
+ allocationsThatIncreaseExternalMemory();
+ collectGarbage();
+ allocationsThatDoNotChangeExternalMemory();
+ collectGarbage();
+ log = document.getElementById("log2");
+ transfersThatDecreaseExternalMemory();
+ collectGarbage();
+ }
+}
+
+</script>
+</head>
+<body onload="runAll()">
+<p>This test checks that allocation and deallocation of typed arrays correctly
+adjusts the amount of external memory in V8.</p>
+<div id='log1'></div>
+<p>This test checks that transfer of an array buffer to worker decreases amount of
+external memory in the main V8 isolate.</p>
+<div id='log2'></div>
+</body>
+</html>
+2012-08-21 Ulan Degenbaev <ulan@chromium.org>
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer constructed and destructed
+ https://bugs.webkit.org/show_bug.cgi?id=92993
+
+ Reviewed by Kenneth Russell.
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer
+ is constructed and destructed so that V8's garbage collection
+ heuristics can account for the memory held by these objects.
+
+ * wtf/ArrayBuffer.h:
+ (WTF):
+ (ArrayBufferDeallocationObserver):
+ (WTF::ArrayBufferContents::ArrayBufferContents):
+ (WTF::ArrayBufferContents::transfer):
+ (ArrayBufferContents):
+ (ArrayBuffer):
+ (WTF::ArrayBuffer::setDeallocationObserver):
+ (WTF::ArrayBufferContents::~ArrayBufferContents):
+
2012-08-21 Benjamin Poulain <bpoulain@apple.com>
Store CString data in the CStringBuffer to avoid the double indirection
class ArrayBuffer;
class ArrayBufferView;
+#if defined(WTF_USE_V8)
+// The current implementation assumes that the instance of this class is a
+// singleton living for the entire process's lifetime.
+class ArrayBufferDeallocationObserver {
+public:
+ virtual void ArrayBufferDeallocated(unsigned sizeInBytes) = 0;
+};
+#endif
+
+
class ArrayBufferContents {
WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
public:
ArrayBufferContents()
: m_data(0)
, m_sizeInBytes(0)
+#if defined(WTF_USE_V8)
+ , m_deallocationObserver(0)
+#endif
{ }
inline ~ArrayBufferContents();
ArrayBufferContents(void* data, unsigned sizeInBytes)
: m_data(data)
, m_sizeInBytes(sizeInBytes)
+#if defined(WTF_USE_V8)
+ , m_deallocationObserver(0)
+#endif
{ }
friend class ArrayBuffer;
other.m_sizeInBytes = m_sizeInBytes;
m_data = 0;
m_sizeInBytes = 0;
+#if defined(WTF_USE_V8)
+ // Notify the current V8 isolate that the buffer is gone.
+ if (m_deallocationObserver)
+ m_deallocationObserver->ArrayBufferDeallocated(other.m_sizeInBytes);
+ ASSERT(!other.m_deallocationObserver);
+ m_deallocationObserver = 0;
+#endif
}
void* m_data;
unsigned m_sizeInBytes;
+
+#if defined(WTF_USE_V8)
+ ArrayBufferDeallocationObserver* m_deallocationObserver;
+#endif
};
class ArrayBuffer : public RefCounted<ArrayBuffer> {
WTF_EXPORT_PRIVATE bool transfer(ArrayBufferContents&, Vector<RefPtr<ArrayBufferView> >& neuteredViews);
bool isNeutered() { return !m_contents.m_data; }
+#if defined(WTF_USE_V8)
+ void setDeallocationObserver(ArrayBufferDeallocationObserver* deallocationObserver)
+ {
+ m_contents.m_deallocationObserver = deallocationObserver;
+ }
+#endif
+
~ArrayBuffer() { }
private:
ArrayBufferContents::~ArrayBufferContents()
{
+#if defined (WTF_USE_V8)
+ if (m_deallocationObserver)
+ m_deallocationObserver->ArrayBufferDeallocated(m_sizeInBytes);
+#endif
WTF::fastFree(m_data);
}
+2012-08-21 Ulan Degenbaev <ulan@chromium.org>
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer constructed and destructed
+ https://bugs.webkit.org/show_bug.cgi?id=92993
+
+ Reviewed by Kenneth Russell.
+
+ Call AdjustAmountOfExternalAllocatedMemory when V8ArrayBuffer
+ is constructed and destructed so that V8's garbage collection
+ heuristics can account for the memory held by these objects.
+
+ * WebCore.gypi:
+ * bindings/v8/SerializedScriptValue.cpp:
+ * bindings/v8/custom/V8ArrayBufferCustom.cpp:
+ (WebCore::V8ArrayBufferDeallocationObserver::instance):
+ (WebCore):
+ (WebCore::V8ArrayBuffer::constructorCallback):
+ * bindings/v8/custom/V8ArrayBufferCustom.h: Added.
+ (WebCore):
+ * bindings/v8/custom/V8ArrayBufferViewCustom.cpp:
+ * bindings/v8/custom/V8ArrayBufferViewCustom.h:
+ (WebCore::constructWebGLArray):
+ * dom/MessageEvent.cpp:
+ (WebCore::MessageEvent::MessageEvent):
+ (WebCore::MessageEvent::initMessageEvent):
+
2012-08-21 Taiju Tsuiki <tzik@chromium.org>
Web Inspector: Completion events of InspectorFileSystemAgent should be fired asynchronously.
'bindings/v8/WorldContextHandle.h',
'bindings/v8/WrapperTypeInfo.h',
'bindings/v8/custom/V8ArrayBufferCustom.cpp',
+ 'bindings/v8/custom/V8ArrayBufferCustom.h',
'bindings/v8/custom/V8ArrayBufferViewCustom.cpp',
'bindings/v8/custom/V8ArrayBufferViewCustom.h',
'bindings/v8/custom/V8AudioBufferSourceNodeCustom.cpp',
*/
#include "config.h"
+#include "V8ArrayBufferCustom.h"
+
#include <wtf/ArrayBuffer.h>
+#include <wtf/StdLibExtras.h>
#include "ExceptionCode.h"
-#include "V8Binding.h"
#include "V8ArrayBuffer.h"
+#include "V8Binding.h"
#include "V8Proxy.h"
namespace WebCore {
+V8ArrayBufferDeallocationObserver* V8ArrayBufferDeallocationObserver::instance()
+{
+ DEFINE_STATIC_LOCAL(V8ArrayBufferDeallocationObserver, deallocationObserver, ());
+ return &deallocationObserver;
+}
+
+
v8::Handle<v8::Value> V8ArrayBuffer::constructorCallback(const v8::Arguments& args)
{
INC_STATS("DOM.ArrayBuffer.Constructor");
buffer = ArrayBuffer::create(static_cast<unsigned>(length), 1);
if (!buffer.get())
return throwError(RangeError, "ArrayBuffer size is not a small enough positive integer.", args.GetIsolate());
+ buffer->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance());
+ v8::V8::AdjustAmountOfExternalAllocatedMemory(buffer->byteLength());
// Transform the holder into a wrapper object for the array.
v8::Handle<v8::Object> wrapper = args.Holder();
V8DOMWrapper::setDOMWrapper(wrapper, &info, buffer.get());
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef V8ArrayBufferCustom_h
+#define V8ArrayBufferCustom_h
+
+#include <v8.h>
+#include <wtf/ArrayBuffer.h>
+
+namespace WebCore {
+
+class V8ArrayBufferDeallocationObserver: public WTF::ArrayBufferDeallocationObserver {
+public:
+ virtual void ArrayBufferDeallocated(unsigned sizeInBytes)
+ {
+ v8::V8::AdjustAmountOfExternalAllocatedMemory(-static_cast<int>(sizeInBytes));
+ }
+ static V8ArrayBufferDeallocationObserver* instance();
+};
+
+}
+
+#endif // V8ArrayBufferCustom_h
-
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
#include "ExceptionCode.h"
#include "V8ArrayBuffer.h"
+#include "V8ArrayBufferCustom.h"
#include "V8Binding.h"
#include "V8Proxy.h"
if (!array.get())
return throwError(RangeError, tooLargeSize, args.GetIsolate());
+ array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance());
+ v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength());
+
memcpy(array->baseAddress(), source->baseAddress(), length * sizeof(ElementType));
return wrapArrayBufferView(args, type, array, arrayType, true);
if (!array.get())
return throwError(RangeError, tooLargeSize, args.GetIsolate());
+ if (doInstantiation) {
+ array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance());
+ v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength());
+ }
+
// Transform the holder into a wrapper object for the array.
V8DOMWrapper::setDOMWrapper(args.Holder(), type, array.get());