mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 966911 Part 1: Improve DOMString and AString conversion code paths r=bholley
This commit is contained in:
parent
e3e24713ec
commit
dace60c6bb
@ -379,8 +379,6 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
{
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
||||
bool isDOMString = true;
|
||||
|
||||
AutoJSContext cx;
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
@ -473,81 +471,62 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
|
||||
case nsXPTType::T_ASTRING:
|
||||
{
|
||||
isDOMString = false;
|
||||
if (JSVAL_IS_VOID(s)) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &EmptyString();
|
||||
else
|
||||
(**((nsAString**)d)).SetIsVoid(true);
|
||||
return true;
|
||||
}
|
||||
// Fall through to T_DOMSTRING case.
|
||||
}
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
{
|
||||
static const char16_t EMPTY_STRING[] = { '\0' };
|
||||
static const char16_t VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
|
||||
|
||||
if (JSVAL_IS_NULL(s)) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &NullString();
|
||||
else
|
||||
(**((nsAString**)d)).SetIsVoid(true);
|
||||
return true;
|
||||
}
|
||||
size_t length = 0;
|
||||
const char16_t* chars = nullptr;
|
||||
JSString* str = nullptr;
|
||||
bool isNewString = false;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (JSVAL_IS_VOID(s)) {
|
||||
if (isDOMString) {
|
||||
chars = VOID_STRING;
|
||||
length = ArrayLength(VOID_STRING) - 1;
|
||||
} else {
|
||||
chars = EMPTY_STRING;
|
||||
length = 0;
|
||||
}
|
||||
} else if (!JSVAL_IS_NULL(s)) {
|
||||
if (!JSVAL_IS_VOID(s)) {
|
||||
str = ToString(cx, s);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
length = (uint32_t) JS_GetStringLength(str);
|
||||
if (length) {
|
||||
chars = JS_GetStringCharsZ(cx, str);
|
||||
if (!chars)
|
||||
return false;
|
||||
if (STRING_TO_JSVAL(str) != s)
|
||||
isNewString = true;
|
||||
} else {
|
||||
str = nullptr;
|
||||
chars = EMPTY_STRING;
|
||||
chars = useAllocator ? JS_GetStringCharsZAndLength(cx, str, &length)
|
||||
: JS_GetStringCharsAndLength(cx, str, &length);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
if (!length) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &EmptyString();
|
||||
else
|
||||
(**((nsAString**)d)).Truncate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nsString* ws;
|
||||
if (useAllocator) {
|
||||
// XXX extra string copy when isNewString
|
||||
if (str && !isNewString) {
|
||||
size_t strLength;
|
||||
const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
|
||||
if (!strChars)
|
||||
return false;
|
||||
|
||||
XPCReadableJSStringWrapper *wrapper =
|
||||
nsXPConnect::GetRuntimeInstance()->NewStringWrapper(strChars, strLength);
|
||||
if (!wrapper)
|
||||
return false;
|
||||
|
||||
*((const nsAString**)d) = wrapper;
|
||||
} else if (JSVAL_IS_NULL(s)) {
|
||||
XPCReadableJSStringWrapper *wrapper =
|
||||
new XPCReadableJSStringWrapper();
|
||||
if (!wrapper)
|
||||
return false;
|
||||
|
||||
*((const nsAString**)d) = wrapper;
|
||||
} else {
|
||||
// use nsString to encourage sharing
|
||||
const nsAString *rs = new nsString(chars, length);
|
||||
if (!rs)
|
||||
return false;
|
||||
*((const nsAString**)d) = rs;
|
||||
}
|
||||
ws = nsXPConnect::GetRuntimeInstance()->NewShortLivedString();
|
||||
*((const nsString**)d) = ws;
|
||||
} else {
|
||||
nsAString* ws = *((nsAString**)d);
|
||||
ws = *((nsString**)d);
|
||||
}
|
||||
|
||||
if (JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s))) {
|
||||
ws->Truncate();
|
||||
ws->SetIsVoid(true);
|
||||
} else
|
||||
ws->Assign(chars, length);
|
||||
if (!str) {
|
||||
ws->AssignLiteral(MOZ_UTF16("undefined"));
|
||||
} else if (useAllocator && STRING_TO_JSVAL(str) == s) {
|
||||
// The JS string will exist over the function call.
|
||||
// We don't need to copy the characters in this case.
|
||||
ws->Rebind(chars, length);
|
||||
} else {
|
||||
ws->Assign(chars, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -622,20 +601,14 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
{
|
||||
const jschar* chars;
|
||||
uint32_t length;
|
||||
size_t length;
|
||||
JSString* str;
|
||||
|
||||
if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
|
||||
if (useAllocator) {
|
||||
nsACString *rs = new nsCString();
|
||||
if (!rs)
|
||||
return false;
|
||||
|
||||
rs->SetIsVoid(true);
|
||||
*((nsACString**)d) = rs;
|
||||
*((const nsACString**)d) = &NullCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
rs->SetIsVoid(true);
|
||||
}
|
||||
return true;
|
||||
@ -644,11 +617,19 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
// The JS val is neither null nor void...
|
||||
|
||||
if (!(str = ToString(cx, s))||
|
||||
!(chars = JS_GetStringCharsZ(cx, str))) {
|
||||
!(chars = JS_GetStringCharsAndLength(cx, str, &length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
length = JS_GetStringLength(str);
|
||||
if (!length) {
|
||||
if (useAllocator) {
|
||||
*((const nsACString**)d) = &EmptyCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString *rs;
|
||||
if (useAllocator) {
|
||||
@ -661,9 +642,7 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
} else {
|
||||
rs = *((nsCString**)d);
|
||||
}
|
||||
const char16_t* start = (const char16_t*)chars;
|
||||
const char16_t* end = start + length;
|
||||
CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
|
||||
CopyUTF16toUTF8(Substring(chars, length), *rs);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -696,6 +675,16 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!length) {
|
||||
if (useAllocator) {
|
||||
*((const nsACString**)d) = &EmptyCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsACString *rs;
|
||||
if (useAllocator) {
|
||||
rs = new nsCString();
|
||||
|
@ -1415,38 +1415,32 @@ XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
||||
return n;
|
||||
}
|
||||
|
||||
XPCReadableJSStringWrapper *
|
||||
XPCJSRuntime::NewStringWrapper(const char16_t *str, uint32_t len)
|
||||
nsString*
|
||||
XPCJSRuntime::NewShortLivedString()
|
||||
{
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
StringWrapperEntry& ent = mScratchStrings[i];
|
||||
|
||||
if (!ent.mInUse) {
|
||||
ent.mInUse = true;
|
||||
|
||||
// Construct the string using placement new.
|
||||
|
||||
return new (ent.mString.addr()) XPCReadableJSStringWrapper(str, len);
|
||||
if (mScratchStrings[i].empty()) {
|
||||
mScratchStrings[i].construct();
|
||||
return mScratchStrings[i].addr();
|
||||
}
|
||||
}
|
||||
|
||||
// All our internal string wrappers are used, allocate a new string.
|
||||
|
||||
return new XPCReadableJSStringWrapper(str, len);
|
||||
return new nsString();
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::DeleteString(nsAString *string)
|
||||
XPCJSRuntime::DeleteShortLivedString(nsString *string)
|
||||
{
|
||||
if (string == &EmptyString() || string == &NullString())
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
StringWrapperEntry& ent = mScratchStrings[i];
|
||||
if (string == ent.mString.addr()) {
|
||||
if (!mScratchStrings[i].empty() &&
|
||||
mScratchStrings[i].addr() == string) {
|
||||
// One of our internal strings is no longer in use, mark
|
||||
// it as such and destroy the string.
|
||||
|
||||
ent.mInUse = false;
|
||||
ent.mString.addr()->~XPCReadableJSStringWrapper();
|
||||
|
||||
// it as such and free its data.
|
||||
mScratchStrings[i].destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1566,7 +1560,7 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
|
||||
#ifdef DEBUG
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
MOZ_ASSERT(!mScratchStrings[i].mInUse, "Uh, string wrapper still in use!");
|
||||
MOZ_ASSERT(mScratchStrings[i].empty(), "Short lived string still in use");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -2311,11 +2311,15 @@ CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
|
||||
break;
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
nsXPConnect::GetRuntimeInstance()->DeleteString((nsAString*)param.val.p);
|
||||
nsXPConnect::GetRuntimeInstance()->DeleteShortLivedString((nsString*)param.val.p);
|
||||
break;
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
case nsXPTType::T_CSTRING:
|
||||
delete (nsCString*) param.val.p;
|
||||
{
|
||||
nsCString* rs = (nsCString*)param.val.p;
|
||||
if (rs != &EmptyCString() && rs != &NullCString())
|
||||
delete rs;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(!type.IsArithmetic(), "Cleanup requested on unexpected type.");
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include <math.h>
|
||||
@ -393,33 +394,6 @@ private:
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// class to export a JSString as an const nsAString, no refcounting :(
|
||||
class XPCReadableJSStringWrapper : public nsDependentString
|
||||
{
|
||||
public:
|
||||
typedef nsDependentString::char_traits char_traits;
|
||||
|
||||
XPCReadableJSStringWrapper(const char16_t *chars, size_t length) :
|
||||
nsDependentString(chars, length)
|
||||
{ }
|
||||
|
||||
XPCReadableJSStringWrapper() :
|
||||
nsDependentString(char_traits::sEmptyBuffer, char_traits::sEmptyBuffer)
|
||||
{ SetIsVoid(true); }
|
||||
|
||||
bool init(JSContext* aContext, JSString* str)
|
||||
{
|
||||
size_t length;
|
||||
const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(IsEmpty(), "init() on initialized string");
|
||||
new(static_cast<nsDependentString *>(this)) nsDependentString(chars, length);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// In the current xpconnect system there can only be one XPCJSRuntime.
|
||||
// So, xpconnect can only be used on one JSRuntime within the process.
|
||||
|
||||
@ -580,8 +554,8 @@ public:
|
||||
|
||||
~XPCJSRuntime();
|
||||
|
||||
XPCReadableJSStringWrapper *NewStringWrapper(const char16_t *str, uint32_t len);
|
||||
void DeleteString(nsAString *string);
|
||||
nsString* NewShortLivedString();
|
||||
void DeleteShortLivedString(nsString *string);
|
||||
|
||||
void AddGCCallback(xpcGCCallback cb);
|
||||
void RemoveGCCallback(xpcGCCallback cb);
|
||||
@ -646,20 +620,7 @@ private:
|
||||
|
||||
#define XPCCCX_STRING_CACHE_SIZE 2
|
||||
|
||||
// String wrapper entry, holds a string, and a boolean that tells
|
||||
// whether the string is in use or not.
|
||||
//
|
||||
// NB: The string is not stored by value so that we avoid the cost of
|
||||
// construction/destruction.
|
||||
struct StringWrapperEntry
|
||||
{
|
||||
StringWrapperEntry() : mInUse(false) { }
|
||||
|
||||
mozilla::AlignedStorage2<XPCReadableJSStringWrapper> mString;
|
||||
bool mInUse;
|
||||
};
|
||||
|
||||
StringWrapperEntry mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
|
||||
mozilla::Maybe<nsString> mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
|
||||
|
||||
friend class Watchdog;
|
||||
friend class AutoLockWatchdog;
|
||||
|
@ -380,6 +380,11 @@ class nsTString_CharT : public nsTSubstring_CharT
|
||||
|
||||
#endif // !MOZ_STRING_WITH_OBSOLETE_API
|
||||
|
||||
/**
|
||||
* Allow this string to be bound to a character buffer
|
||||
* until the string is rebound or mutated; the caller
|
||||
* must ensure that the buffer outlives the string.
|
||||
*/
|
||||
void Rebind( const char_type* data, size_type length );
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user