landing xpcom patch for bug 235499 "re-enable string buffer sharing between C++ and JS in xpconnect" r=dbaron sr=jst
git-svn-id: svn://10.0.0.236/trunk@168722 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "nsSubstring.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsDependentString.h"
|
||||
#include "nsMemory.h"
|
||||
#include "pratom.h"
|
||||
@@ -105,105 +106,6 @@ static nsStringStats gStringStats;
|
||||
#define STRING_STAT_INCREMENT(_s)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This structure precedes the string buffers "we" allocate. It may be the
|
||||
* case that nsTSubstring::mData does not point to one of these special
|
||||
* buffers. The mFlags member variable distinguishes the buffer type.
|
||||
*
|
||||
* When this header is in use, it enables reference counting, and capacity
|
||||
* tracking. NOTE: A string buffer can be modified only if its reference
|
||||
* count is 1.
|
||||
*/
|
||||
class nsStringHeader
|
||||
{
|
||||
private:
|
||||
|
||||
PRInt32 mRefCount;
|
||||
PRUint32 mStorageSize;
|
||||
|
||||
public:
|
||||
|
||||
void AddRef()
|
||||
{
|
||||
PR_AtomicIncrement(&mRefCount);
|
||||
STRING_STAT_INCREMENT(Share);
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if (PR_AtomicDecrement(&mRefCount) == 0)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Free);
|
||||
free(this); // we were allocated with |malloc|
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alloc returns a pointer to a new string header with set capacity.
|
||||
*/
|
||||
static nsStringHeader* Alloc(size_t size)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Alloc);
|
||||
|
||||
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
|
||||
|
||||
nsStringHeader *hdr =
|
||||
(nsStringHeader *) malloc(sizeof(nsStringHeader) + size);
|
||||
if (hdr)
|
||||
{
|
||||
hdr->mRefCount = 1;
|
||||
hdr->mStorageSize = size;
|
||||
}
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static nsStringHeader* Realloc(nsStringHeader* hdr, size_t size)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Realloc);
|
||||
|
||||
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
|
||||
|
||||
// no point in trying to save ourselves if we hit this assertion
|
||||
NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string");
|
||||
|
||||
hdr = (nsStringHeader*) realloc(hdr, sizeof(nsStringHeader) + size);
|
||||
if (hdr)
|
||||
hdr->mStorageSize = size;
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static nsStringHeader* FromData(void* data)
|
||||
{
|
||||
return (nsStringHeader*) ( ((char*) data) - sizeof(nsStringHeader) );
|
||||
}
|
||||
|
||||
void* Data() const
|
||||
{
|
||||
return (void*) ( ((char*) this) + sizeof(nsStringHeader) );
|
||||
}
|
||||
|
||||
PRUint32 StorageSize() const
|
||||
{
|
||||
return mStorageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because nsTSubstring allows only single threaded access, if this
|
||||
* method returns FALSE, then the caller can be sure that it has
|
||||
* exclusive access to the nsStringHeader and associated data.
|
||||
* However, if this function returns TRUE, then other strings may
|
||||
* rely on the data in this buffer being constant and other threads
|
||||
* may access this buffer simultaneously.
|
||||
*/
|
||||
PRBool IsReadonly() const
|
||||
{
|
||||
return mRefCount > 1;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
inline void
|
||||
@@ -211,7 +113,7 @@ ReleaseData( void* data, PRUint32 flags )
|
||||
{
|
||||
if (flags & nsSubstring::F_SHARED)
|
||||
{
|
||||
nsStringHeader::FromData(data)->Release();
|
||||
nsStringBuffer::FromData(data)->Release();
|
||||
}
|
||||
else if (flags & nsSubstring::F_OWNED)
|
||||
{
|
||||
@@ -221,6 +123,180 @@ ReleaseData( void* data, PRUint32 flags )
|
||||
// otherwise, nothing to do.
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// XXX or we could make nsStringBuffer be a friend of nsTAString
|
||||
|
||||
class nsAStringAccessor : public nsAString
|
||||
{
|
||||
private:
|
||||
nsAStringAccessor(); // NOT IMPLEMENTED
|
||||
|
||||
public:
|
||||
const void *vtable() const { return mVTable; }
|
||||
char_type *data() const { return mData; }
|
||||
size_type length() const { return mLength; }
|
||||
PRUint32 flags() const { return mFlags; }
|
||||
|
||||
void set(char_type *data, size_type len, PRUint32 flags)
|
||||
{
|
||||
ReleaseData(mData, mFlags);
|
||||
mData = data;
|
||||
mLength = len;
|
||||
mFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
class nsACStringAccessor : public nsACString
|
||||
{
|
||||
private:
|
||||
nsACStringAccessor(); // NOT IMPLEMENTED
|
||||
|
||||
public:
|
||||
const void *vtable() const { return mVTable; }
|
||||
char_type *data() const { return mData; }
|
||||
size_type length() const { return mLength; }
|
||||
PRUint32 flags() const { return mFlags; }
|
||||
|
||||
void set(char_type *data, size_type len, PRUint32 flags)
|
||||
{
|
||||
ReleaseData(mData, mFlags);
|
||||
mData = data;
|
||||
mLength = len;
|
||||
mFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsStringBuffer::AddRef()
|
||||
{
|
||||
PR_AtomicIncrement(&mRefCount);
|
||||
STRING_STAT_INCREMENT(Share);
|
||||
}
|
||||
|
||||
void
|
||||
nsStringBuffer::Release()
|
||||
{
|
||||
if (PR_AtomicDecrement(&mRefCount) == 0)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Free);
|
||||
free(this); // we were allocated with |malloc|
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alloc returns a pointer to a new string header with set capacity.
|
||||
*/
|
||||
nsStringBuffer*
|
||||
nsStringBuffer::Alloc(size_t size)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Alloc);
|
||||
|
||||
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
|
||||
|
||||
nsStringBuffer *hdr =
|
||||
(nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size);
|
||||
if (hdr)
|
||||
{
|
||||
hdr->mRefCount = 1;
|
||||
hdr->mStorageSize = size;
|
||||
}
|
||||
return hdr;
|
||||
}
|
||||
|
||||
nsStringBuffer*
|
||||
nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size)
|
||||
{
|
||||
STRING_STAT_INCREMENT(Realloc);
|
||||
|
||||
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
|
||||
|
||||
// no point in trying to save ourselves if we hit this assertion
|
||||
NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string");
|
||||
|
||||
hdr = (nsStringBuffer*) realloc(hdr, sizeof(nsStringBuffer) + size);
|
||||
if (hdr)
|
||||
hdr->mStorageSize = size;
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
nsStringBuffer*
|
||||
nsStringBuffer::FromString(const nsAString& str)
|
||||
{
|
||||
const nsAStringAccessor* accessor =
|
||||
NS_STATIC_CAST(const nsAStringAccessor*, &str);
|
||||
|
||||
if (accessor->vtable() != nsObsoleteAString::sCanonicalVTable ||
|
||||
!(accessor->flags() & nsSubstring::F_SHARED))
|
||||
return nsnull;
|
||||
|
||||
return FromData(accessor->data());
|
||||
}
|
||||
|
||||
nsStringBuffer*
|
||||
nsStringBuffer::FromString(const nsACString& str)
|
||||
{
|
||||
const nsACStringAccessor* accessor =
|
||||
NS_STATIC_CAST(const nsACStringAccessor*, &str);
|
||||
|
||||
if (accessor->vtable() != nsObsoleteACString::sCanonicalVTable ||
|
||||
!(accessor->flags() & nsCSubstring::F_SHARED))
|
||||
return nsnull;
|
||||
|
||||
return FromData(accessor->data());
|
||||
}
|
||||
|
||||
void
|
||||
nsStringBuffer::ToString(PRUint32 len, nsAString &str)
|
||||
{
|
||||
PRUnichar* data = NS_STATIC_CAST(PRUnichar*, Data());
|
||||
|
||||
nsAStringAccessor* accessor = NS_STATIC_CAST(nsAStringAccessor*, &str);
|
||||
if (accessor->vtable() != nsObsoleteAString::sCanonicalVTable)
|
||||
{
|
||||
str.Assign(data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(data[len] == PRUnichar(0), "data should be null terminated");
|
||||
|
||||
// preserve class flags
|
||||
PRUint32 flags = accessor->flags();
|
||||
flags = (flags & 0xFFFF0000) | nsSubstring::F_SHARED | nsSubstring::F_TERMINATED;
|
||||
|
||||
AddRef();
|
||||
accessor->set(data, len, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsStringBuffer::ToString(PRUint32 len, nsACString &str)
|
||||
{
|
||||
char* data = NS_STATIC_CAST(char*, Data());
|
||||
|
||||
nsACStringAccessor* accessor = NS_STATIC_CAST(nsACStringAccessor*, &str);
|
||||
if (accessor->vtable() != nsObsoleteACString::sCanonicalVTable)
|
||||
{
|
||||
str.Assign(data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(data[len] == char(0), "data should be null terminated");
|
||||
|
||||
// preserve class flags
|
||||
PRUint32 flags = accessor->flags();
|
||||
flags = (flags & 0xFFFF0000) | nsCSubstring::F_SHARED | nsCSubstring::F_TERMINATED;
|
||||
|
||||
AddRef();
|
||||
accessor->set(data, len, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
// define nsSubstring
|
||||
#include "string-template-def-unichar.h"
|
||||
|
||||
@@ -110,10 +110,10 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3
|
||||
// case #1
|
||||
if (mFlags & F_SHARED)
|
||||
{
|
||||
nsStringHeader* hdr = nsStringHeader::FromData(mData);
|
||||
nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
|
||||
if (!hdr->IsReadonly())
|
||||
{
|
||||
nsStringHeader *newHdr = nsStringHeader::Realloc(hdr, storageSize);
|
||||
nsStringBuffer *newHdr = nsStringBuffer::Realloc(hdr, storageSize);
|
||||
if (newHdr)
|
||||
{
|
||||
hdr = newHdr;
|
||||
@@ -145,7 +145,7 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3
|
||||
// make use of our F_OWNED or F_FIXED buffers because they are not
|
||||
// large enough.
|
||||
|
||||
nsStringHeader* newHdr = nsStringHeader::Alloc(storageSize);
|
||||
nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize);
|
||||
if (!newHdr)
|
||||
return PR_FALSE; // we are still in a consistent state
|
||||
|
||||
@@ -247,7 +247,7 @@ nsTSubstring_CharT::Capacity() const
|
||||
if (mFlags & F_SHARED)
|
||||
{
|
||||
// if the string is readonly, then we pretend that it has no capacity.
|
||||
nsStringHeader* hdr = nsStringHeader::FromData(mData);
|
||||
nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
|
||||
if (hdr->IsReadonly())
|
||||
capacity = size_type(-1);
|
||||
else
|
||||
@@ -278,7 +278,7 @@ nsTSubstring_CharT::EnsureMutable()
|
||||
{
|
||||
if (mFlags & (F_FIXED | F_OWNED))
|
||||
return;
|
||||
if ((mFlags & F_SHARED) && !nsStringHeader::FromData(mData)->IsReadonly())
|
||||
if ((mFlags & F_SHARED) && !nsStringBuffer::FromData(mData)->IsReadonly())
|
||||
return;
|
||||
|
||||
// promote to a shared string buffer
|
||||
@@ -358,7 +358,7 @@ nsTSubstring_CharT::Assign( const self_type& str )
|
||||
SetDataFlags(F_TERMINATED | F_SHARED);
|
||||
|
||||
// get an owning reference to the mData
|
||||
nsStringHeader::FromData(mData)->AddRef();
|
||||
nsStringBuffer::FromData(mData)->AddRef();
|
||||
}
|
||||
else if (str.mFlags & F_VOIDED)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user