Commit 1a91b711 authored by binji@chromium.org's avatar binji@chromium.org

Add a ref-counted data holder to ArrayBufferContents

This is in preparation for adding the DOMSharedArrayBuffer object, which needs
to be able to share allocated array memory between multiple WTF::ArrayBuffers.

BUG=497295
R=jochen@chromium.org,haraken@chromium.org

Review URL: https://codereview.chromium.org/1186863005

git-svn-id: svn://svn.chromium.org/blink/trunk@198023 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 5f5d4a2e
......@@ -743,7 +743,7 @@ v8::Local<v8::Object> {{v8_class}}::findInstanceInPrototypeChain(v8::Local<v8::V
// Transfer the ownership of the allocated memory to an ArrayBuffer without
// copying.
v8::ArrayBuffer::Contents v8Contents = v8buffer->Externalize();
WTF::ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength());
WTF::ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength(), WTF::ArrayBufferContents::NotShared);
RefPtr<{{cpp_class}}> buffer = {{cpp_class}}::create(contents);
buffer->associateWithWrapper(v8::Isolate::GetCurrent(), buffer->wrapperTypeInfo(), object);
......
......@@ -55,7 +55,7 @@ TestArrayBuffer* V8ArrayBuffer::toImpl(v8::Local<v8::Object> object)
// Transfer the ownership of the allocated memory to an ArrayBuffer without
// copying.
v8::ArrayBuffer::Contents v8Contents = v8buffer->Externalize();
WTF::ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength());
WTF::ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength(), WTF::ArrayBufferContents::NotShared);
RefPtr<TestArrayBuffer> buffer = TestArrayBuffer::create(contents);
buffer->associateWithWrapper(v8::Isolate::GetCurrent(), buffer->wrapperTypeInfo(), object);
......
......@@ -277,7 +277,7 @@ bool ImageBuffer::getImageData(Multiply multiplied, const IntRect& rect, WTF::Ar
return false;
if (!isSurfaceValid()) {
WTF::ArrayBufferContents result(rect.width() * rect.height(), 4, WTF::ArrayBufferContents::ZeroInitialize);
WTF::ArrayBufferContents result(rect.width() * rect.height(), 4, WTF::ArrayBufferContents::NotShared, WTF::ArrayBufferContents::ZeroInitialize);
result.transfer(contents);
return true;
}
......@@ -289,6 +289,7 @@ bool ImageBuffer::getImageData(Multiply multiplied, const IntRect& rect, WTF::Ar
|| rect.maxY() > m_surface->size().height();
WTF::ArrayBufferContents result(
rect.width() * rect.height(), 4,
WTF::ArrayBufferContents::NotShared,
hasStrayArea
? WTF::ArrayBufferContents::ZeroInitialize
: WTF::ArrayBufferContents::DontInitialize);
......
......@@ -871,7 +871,7 @@ bool DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height, So
if (dataSize.hasOverflowed())
return false;
WTF::ArrayBufferContents pixels(width * height, 4, WTF::ArrayBufferContents::DontInitialize);
WTF::ArrayBufferContents pixels(width * height, 4, WTF::ArrayBufferContents::NotShared, WTF::ArrayBufferContents::DontInitialize);
GLint fbo = 0;
if (sourceBuffer == FrontBuffer && m_frontColorBuffer.texInfo.textureId) {
......
......@@ -33,10 +33,11 @@ namespace WTF {
bool ArrayBuffer::transfer(ArrayBufferContents& result)
{
ASSERT(!isShared());
RefPtr<ArrayBuffer> keepAlive(this);
if (!m_contents.data()) {
result.clear();
result.neuter();
return false;
}
......@@ -66,6 +67,20 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result)
return true;
}
bool ArrayBuffer::shareContentsWith(ArrayBufferContents& result)
{
ASSERT(isShared());
RefPtr<ArrayBuffer> keepAlive(this);
if (!m_contents.data()) {
result.neuter();
return false;
}
m_contents.shareWith(result);
return true;
}
void ArrayBuffer::addView(ArrayBufferView* view)
{
view->m_buffer = this;
......
......@@ -50,6 +50,9 @@ public:
// (through DOMArrayBuffer::createUninitialized).
static inline PassRefPtr<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
static inline PassRefPtr<ArrayBuffer> createShared(unsigned numElements, unsigned elementByteSize);
static inline PassRefPtr<ArrayBuffer> createShared(const void* source, unsigned byteLength);
inline void* data();
inline const void* data() const;
inline unsigned byteLength() const;
......@@ -63,7 +66,9 @@ public:
void removeView(ArrayBufferView*);
bool transfer(ArrayBufferContents&);
bool isNeutered() { return m_isNeutered; }
bool shareContentsWith(ArrayBufferContents&);
bool isNeutered() const { return m_isNeutered; }
bool isShared() const { return m_contents.isShared(); }
~ArrayBuffer() { }
......@@ -73,6 +78,7 @@ protected:
private:
static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
static inline PassRefPtr<ArrayBuffer> createOrNull(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
static inline PassRefPtr<ArrayBuffer> createShared(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
inline PassRefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
inline unsigned clampIndex(int index) const;
......@@ -100,12 +106,14 @@ PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned eleme
PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBuffer* other)
{
// TODO(binji): support creating a SharedArrayBuffer by copying another ArrayBuffer?
ASSERT(!other->isShared());
return ArrayBuffer::create(other->data(), other->byteLength());
}
PassRefPtr<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
{
ArrayBufferContents contents(byteLength, 1, ArrayBufferContents::ZeroInitialize);
ArrayBufferContents contents(byteLength, 1, ArrayBufferContents::NotShared, ArrayBufferContents::ZeroInitialize);
RELEASE_ASSERT(contents.data());
RefPtr<ArrayBuffer> buffer = adoptRef(new ArrayBuffer(contents));
memcpy(buffer->data(), source, byteLength);
......@@ -129,19 +137,40 @@ PassRefPtr<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, u
PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
{
ArrayBufferContents contents(numElements, elementByteSize, policy);
ArrayBufferContents contents(numElements, elementByteSize, ArrayBufferContents::NotShared, policy);
RELEASE_ASSERT(contents.data());
return adoptRef(new ArrayBuffer(contents));
}
PassRefPtr<ArrayBuffer> ArrayBuffer::createOrNull(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
{
ArrayBufferContents contents(numElements, elementByteSize, policy);
ArrayBufferContents contents(numElements, elementByteSize, ArrayBufferContents::NotShared, policy);
if (!contents.data())
return nullptr;
return adoptRef(new ArrayBuffer(contents));
}
PassRefPtr<ArrayBuffer> ArrayBuffer::createShared(unsigned numElements, unsigned elementByteSize)
{
return createShared(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize);
}
PassRefPtr<ArrayBuffer> ArrayBuffer::createShared(const void* source, unsigned byteLength)
{
ArrayBufferContents contents(byteLength, 1, ArrayBufferContents::Shared, ArrayBufferContents::ZeroInitialize);
RELEASE_ASSERT(contents.data());
RefPtr<ArrayBuffer> buffer = adoptRef(new ArrayBuffer(contents));
memcpy(buffer->data(), source, byteLength);
return buffer.release();
}
PassRefPtr<ArrayBuffer> ArrayBuffer::createShared(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
{
ArrayBufferContents contents(numElements, elementByteSize, ArrayBufferContents::Shared, policy);
RELEASE_ASSERT(contents.data());
return adoptRef(new ArrayBuffer(contents));
}
ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents)
: m_firstView(0), m_isNeutered(false)
{
......
......@@ -37,67 +37,65 @@ namespace WTF {
AdjustAmountOfExternalAllocatedMemoryFunction ArrayBufferContents::s_adjustAmountOfExternalAllocatedMemoryFunction;
ArrayBufferContents::ArrayBufferContents()
: m_data(0)
, m_sizeInBytes(0) { }
: m_holder(adoptRef(new DataHolder())) { }
ArrayBufferContents::ArrayBufferContents(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
: m_data(0)
, m_sizeInBytes(0)
ArrayBufferContents::ArrayBufferContents(unsigned numElements, unsigned elementByteSize, SharingType isShared, ArrayBufferContents::InitializationPolicy policy)
: m_holder(adoptRef(new DataHolder()))
{
// Do not allow 32-bit overflow of the total size.
unsigned totalSize = numElements * elementByteSize;
if (numElements) {
unsigned totalSize = numElements * elementByteSize;
if (totalSize / numElements != elementByteSize) {
m_data = 0;
return;
}
}
allocateMemory(numElements * elementByteSize, policy, m_data);
m_sizeInBytes = numElements * elementByteSize;
m_holder->allocateNew(totalSize, isShared, policy);
}
ArrayBufferContents::ArrayBufferContents(void* data, unsigned sizeInBytes)
: m_data(data)
, m_sizeInBytes(sizeInBytes)
ArrayBufferContents::ArrayBufferContents(
void* data, unsigned sizeInBytes, SharingType isShared)
: m_holder(adoptRef(new DataHolder()))
{
if (!m_data) {
ASSERT(!m_sizeInBytes);
m_sizeInBytes = 0;
// Allow null data if size is 0 bytes, make sure m_data is valid pointer.
// (partitionAllocGeneric guarantees valid pointer for size 0)
allocateMemory(0, ZeroInitialize, m_data);
if (data) {
m_holder->adopt(data, sizeInBytes, isShared);
} else {
ASSERT(!sizeInBytes);
sizeInBytes = 0;
// Allow null data if size is 0 bytes, make sure data is valid pointer.
// (PartitionAlloc guarantees valid pointer for size 0)
m_holder->allocateNew(sizeInBytes, isShared, ZeroInitialize);
}
}
ArrayBufferContents::~ArrayBufferContents()
{
freeMemory(m_data, m_sizeInBytes);
clear();
}
void ArrayBufferContents::clear()
void ArrayBufferContents::neuter()
{
m_data = 0;
m_sizeInBytes = 0;
m_holder.clear();
}
void ArrayBufferContents::transfer(ArrayBufferContents& other)
{
ASSERT(!other.m_data);
other.m_data = m_data;
other.m_sizeInBytes = m_sizeInBytes;
clear();
ASSERT(!isShared());
ASSERT(!other.m_holder->data());
other.m_holder = m_holder;
neuter();
}
void ArrayBufferContents::shareWith(ArrayBufferContents& other)
{
ASSERT(isShared());
ASSERT(!other.m_holder->data());
other.m_holder = m_holder;
}
void ArrayBufferContents::copyTo(ArrayBufferContents& other)
{
ASSERT(!other.m_sizeInBytes);
other.freeMemory(other.m_data, other.m_sizeInBytes);
allocateMemory(m_sizeInBytes, DontInitialize, other.m_data);
if (!other.m_data)
return;
memcpy(other.m_data, m_data, m_sizeInBytes);
other.m_sizeInBytes = m_sizeInBytes;
ASSERT(!m_holder->isShared() && !other.m_holder->isShared());
m_holder->copyMemoryTo(*other.m_holder);
}
void ArrayBufferContents::allocateMemory(size_t size, InitializationPolicy policy, void*& data)
......@@ -116,4 +114,47 @@ void ArrayBufferContents::freeMemory(void* data, size_t size)
s_adjustAmountOfExternalAllocatedMemoryFunction(-static_cast<int>(size));
}
ArrayBufferContents::DataHolder::DataHolder()
: m_data(nullptr)
, m_sizeInBytes(0)
, m_isShared(NotShared) { }
ArrayBufferContents::DataHolder::~DataHolder()
{
ArrayBufferContents::freeMemory(m_data, m_sizeInBytes);
m_data = nullptr;
m_sizeInBytes = 0;
m_isShared = NotShared;
}
void ArrayBufferContents::DataHolder::allocateNew(unsigned sizeInBytes, SharingType isShared, InitializationPolicy policy)
{
ASSERT(!m_data);
void* data = nullptr;
allocateMemory(sizeInBytes, policy, data);
m_data = data;
m_sizeInBytes = sizeInBytes;
m_isShared = isShared;
}
void ArrayBufferContents::DataHolder::adopt(void* data, unsigned sizeInBytes, SharingType isShared)
{
ASSERT(!m_data);
m_data = data;
m_sizeInBytes = sizeInBytes;
m_isShared = isShared;
}
void ArrayBufferContents::DataHolder::copyMemoryTo(DataHolder& other)
{
ASSERT(!other.m_sizeInBytes);
ArrayBufferContents::freeMemory(other.m_data, other.m_sizeInBytes);
ArrayBufferContents::allocateMemory(m_sizeInBytes, DontInitialize, other.m_data);
if (!other.m_data)
return;
memcpy(other.m_data, m_data, m_sizeInBytes);
other.m_sizeInBytes = m_sizeInBytes;
}
} // namespace WTF
......@@ -29,6 +29,8 @@
#include "wtf/Assertions.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#include "wtf/ThreadSafeRefCounted.h"
#include "wtf/WTF.h"
#include "wtf/WTFExport.h"
......@@ -42,24 +44,31 @@ public:
DontInitialize
};
enum SharingType {
NotShared,
Shared,
};
ArrayBufferContents();
ArrayBufferContents(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
ArrayBufferContents(unsigned numElements, unsigned elementByteSize, SharingType isShared, ArrayBufferContents::InitializationPolicy);
// Use with care. data must be allocated with allocateMemory.
// ArrayBufferContents will take ownership of the data and free it (using freeMemory)
// upon destruction.
// This constructor will not call observer->StartObserving(), so it is a responsibility
// of the caller to make sure JS knows about external memory.
ArrayBufferContents(void* data, unsigned sizeInBytes);
ArrayBufferContents(void* data, unsigned sizeInBytes, SharingType isShared);
~ArrayBufferContents();
void clear();
void neuter();
void* data() const { return m_data; }
unsigned sizeInBytes() const { return m_sizeInBytes; }
void* data() const { return m_holder ? m_holder->data() : nullptr; }
unsigned sizeInBytes() const { return m_holder ? m_holder->sizeInBytes() : 0; }
bool isShared() const { return m_holder ? m_holder->isShared() : false; }
void transfer(ArrayBufferContents& other);
void shareWith(ArrayBufferContents& other);
void copyTo(ArrayBufferContents& other);
static void allocateMemory(size_t, InitializationPolicy, void*&);
......@@ -71,8 +80,27 @@ public:
}
private:
void* m_data;
unsigned m_sizeInBytes;
class DataHolder : public ThreadSafeRefCounted<DataHolder> {
WTF_MAKE_NONCOPYABLE(DataHolder);
public:
DataHolder();
~DataHolder();
void allocateNew(unsigned sizeInBytes, SharingType isShared, InitializationPolicy);
void adopt(void* data, unsigned sizeInBytes, SharingType isShared);
void copyMemoryTo(DataHolder& other);
void* data() const { return m_data; }
unsigned sizeInBytes() const { return m_sizeInBytes; }
bool isShared() const { return m_isShared == Shared; }
private:
void* m_data;
unsigned m_sizeInBytes;
SharingType m_isShared;
};
RefPtr<DataHolder> m_holder;
static AdjustAmountOfExternalAllocatedMemoryFunction s_adjustAmountOfExternalAllocatedMemoryFunction;
};
......
......@@ -72,6 +72,7 @@ class WTF_EXPORT ArrayBufferView : public RefCounted<ArrayBufferView> {
void setNeuterable(bool flag) { m_isNeuterable = flag; }
bool isNeuterable() const { return m_isNeuterable; }
bool isShared() const { return m_buffer ? m_buffer->isShared() : false; }
virtual ~ArrayBufferView();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment