Somewhat reduce the amount of memory an nsPrincipal allocates in the common case. Bug 397733, r+sr+a=jst

This commit is contained in:
bzbarsky@mit.edu 2007-09-28 07:31:04 -07:00
parent d6e8ce696e
commit e252fc2b15
6 changed files with 80 additions and 37 deletions

View File

@ -41,11 +41,13 @@
#include "jsapi.h"
#include "nsIPrincipal.h"
class nsCString;
struct nsJSPrincipals : JSPrincipals
{
static nsresult Startup();
nsJSPrincipals();
nsresult Init(nsIPrincipal* aPrincipal, const char *aCodebase);
nsresult Init(nsIPrincipal* aPrincipal, const nsCString& aCodebase);
~nsJSPrincipals(void);
nsIPrincipal *nsIPrincipalPtr; // [WEAK] it owns us.

View File

@ -103,7 +103,7 @@ public:
protected:
nsJSPrincipals mJSPrincipals;
nsTArray< nsAutoPtr<nsHashtable> > mAnnotations;
nsHashtable mCapabilities;
nsHashtable* mCapabilities;
nsCString mPrefName;
static PRInt32 sCapabilitiesOrdinal;

View File

@ -47,6 +47,7 @@
#include "nsIJSRuntimeService.h"
#include "nsIServiceManager.h"
#include "nsMemory.h"
#include "nsStringBuffer.h"
JS_STATIC_DLL_CALLBACK(void *)
nsGetPrincipalArray(JSContext *cx, JSPrincipals *prin)
@ -198,7 +199,7 @@ nsJSPrincipals::nsJSPrincipals()
}
nsresult
nsJSPrincipals::Init(nsIPrincipal *aPrincipal, const char *aCodebase)
nsJSPrincipals::Init(nsIPrincipal *aPrincipal, const nsCString& aCodebase)
{
if (nsIPrincipalPtr) {
NS_ERROR("Init called twice!");
@ -206,15 +207,30 @@ nsJSPrincipals::Init(nsIPrincipal *aPrincipal, const char *aCodebase)
}
nsIPrincipalPtr = aPrincipal;
codebase = PL_strdup(aCodebase);
if (!codebase)
return NS_ERROR_OUT_OF_MEMORY;
nsStringBuffer* buf = nsStringBuffer::FromString(aCodebase);
char* data;
if (buf) {
buf->AddRef();
data = static_cast<char*>(buf->Data());
} else {
PRUint32 len = aCodebase.Length();
buf = nsStringBuffer::Alloc(len + 1); // addrefs
if (!buf) {
return NS_ERROR_OUT_OF_MEMORY;
}
data = static_cast<char*>(buf->Data());
memcpy(data, aCodebase.get(), len);
data[len] = '\0';
}
codebase = data;
return NS_OK;
}
nsJSPrincipals::~nsJSPrincipals()
{
if (codebase)
PL_strfree(codebase);
if (codebase) {
nsStringBuffer::FromData(codebase)->Release();
}
}

View File

@ -90,6 +90,8 @@ nsNullPrincipal::~nsNullPrincipal()
{
}
#define NS_NULLPRINCIPAL_PREFIX NS_NULLPRINCIPAL_SCHEME ":"
nsresult
nsNullPrincipal::Init()
{
@ -106,15 +108,21 @@ nsNullPrincipal::Init()
char* chars = id.ToString();
NS_ENSURE_TRUE(chars, NS_ERROR_OUT_OF_MEMORY);
nsCAutoString str(NS_NULLPRINCIPAL_SCHEME ":");
PRUint32 prefixLen = str.Length();
PRUint32 suffixLen = strlen(chars);
PRUint32 prefixLen = NS_ARRAY_LENGTH(NS_NULLPRINCIPAL_PREFIX) - 1;
// Use an nsCString so we only do the allocation once here and then share
// with nsJSPrincipals
nsCString str;
str.SetCapacity(prefixLen + suffixLen);
str.Append(NS_NULLPRINCIPAL_PREFIX);
str.Append(chars);
PR_Free(chars);
if (str.Length() != prefixLen + suffixLen) {
NS_WARNING("Out of memory allocating null-principal URI");
return NS_ERROR_OUT_OF_MEMORY;
}
@ -129,7 +137,7 @@ nsNullPrincipal::Init()
NS_TryToSetImmutable(mURI);
return mJSPrincipals.Init(this, str.get());
return mJSPrincipals.Init(this, str);
}
/**

View File

@ -103,7 +103,7 @@ nsPrincipal::Release()
}
nsPrincipal::nsPrincipal()
: mCapabilities(7),
: mCapabilities(nsnull),
mSecurityPolicy(nsnull),
mTrusted(PR_FALSE),
mInitialized(PR_FALSE),
@ -134,14 +134,14 @@ nsPrincipal::Init(const nsACString& aCertFingerprint,
if (!aCertFingerprint.IsEmpty()) {
rv = SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert);
if (NS_SUCCEEDED(rv)) {
rv = mJSPrincipals.Init(this, mCert->fingerprint.get());
rv = mJSPrincipals.Init(this, mCert->fingerprint);
}
}
else {
nsCAutoString spec;
rv = mCodebase->GetSpec(spec);
if (NS_SUCCEEDED(rv)) {
rv = mJSPrincipals.Init(this, spec.get());
rv = mJSPrincipals.Init(this, spec);
}
}
@ -153,6 +153,7 @@ nsPrincipal::Init(const nsACString& aCertFingerprint,
nsPrincipal::~nsPrincipal(void)
{
SetSecurityPolicy(nsnull);
delete mCapabilities;
}
NS_IMETHODIMP
@ -309,11 +310,13 @@ NS_IMETHODIMP
nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
{
// If this principal is marked invalid, can't enable any capabilities
nsCStringKey invalidKey(sInvalid);
if (mCapabilities.Exists(&invalidKey)) {
*result = nsIPrincipal::ENABLE_DENIED;
if (mCapabilities) {
nsCStringKey invalidKey(sInvalid);
if (mCapabilities->Exists(&invalidKey)) {
*result = nsIPrincipal::ENABLE_DENIED;
return NS_OK;
return NS_OK;
}
}
if (!mCert && !mTrusted) {
@ -353,7 +356,8 @@ nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
PRInt32 len = space ? space - start : strlen(start);
nsCAutoString capString(start, len);
nsCStringKey key(capString);
PRInt16 value = (PRInt16)NS_PTR_TO_INT32(mCapabilities.Get(&key));
PRInt16 value =
mCapabilities ? (PRInt16)NS_PTR_TO_INT32(mCapabilities->Get(&key)) : 0;
if (value == 0 || value == nsIPrincipal::ENABLE_UNKNOWN) {
// We don't know whether we can enable this capability,
// so we should ask the user.
@ -379,14 +383,18 @@ nsPrincipal::SetCanEnableCapability(const char *capability,
PRInt16 canEnable)
{
// If this principal is marked invalid, can't enable any capabilities
if (!mCapabilities) {
mCapabilities = new nsHashtable(7); // XXXbz gets bumped up to 16 anyway
NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
}
nsCStringKey invalidKey(sInvalid);
if (mCapabilities.Exists(&invalidKey)) {
if (mCapabilities->Exists(&invalidKey)) {
return NS_OK;
}
if (PL_strcmp(capability, sInvalid) == 0) {
mCapabilities.Reset();
mCapabilities->Reset();
}
const char *start = capability;
@ -395,7 +403,7 @@ nsPrincipal::SetCanEnableCapability(const char *capability,
int len = space ? space - start : strlen(start);
nsCAutoString capString(start, len);
nsCStringKey key(capString);
mCapabilities.Put(&key, NS_INT32_TO_PTR(canEnable));
mCapabilities->Put(&key, NS_INT32_TO_PTR(canEnable));
if (!space) {
break;
}
@ -667,7 +675,7 @@ nsPrincipal::InitFromPersistent(const char* aPrefName,
PRBool aIsCert,
PRBool aTrusted)
{
NS_PRECONDITION(mCapabilities.Count() == 0,
NS_PRECONDITION(!mCapabilities || mCapabilities->Count() == 0,
"mCapabilities was already initialized?");
NS_PRECONDITION(mAnnotations.Length() == 0,
"mAnnotations was already initialized?");
@ -699,7 +707,7 @@ nsPrincipal::InitFromPersistent(const char* aPrefName,
mOrigin = nsnull;
}
rv = mJSPrincipals.Init(this, aToken.get());
rv = mJSPrincipals.Init(this, aToken);
NS_ENSURE_SUCCESS(rv, rv);
//-- Save the preference name
@ -836,10 +844,12 @@ nsPrincipal::GetPreferences(char** aPrefName, char** aID,
//-- Capabilities
nsCAutoString grantedListStr, deniedListStr;
CapabilityList capList = CapabilityList();
capList.granted = &grantedListStr;
capList.denied = &deniedListStr;
mCapabilities.Enumerate(AppendCapability, (void*)&capList);
if (mCapabilities) {
CapabilityList capList = CapabilityList();
capList.granted = &grantedListStr;
capList.denied = &deniedListStr;
mCapabilities->Enumerate(AppendCapability, (void*)&capList);
}
if (!grantedListStr.IsEmpty()) {
grantedListStr.Truncate(grantedListStr.Length() - 1);
@ -910,12 +920,9 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
PRBool hasCapabilities;
nsresult rv = aStream->ReadBoolean(&hasCapabilities);
if (NS_SUCCEEDED(rv) && hasCapabilities) {
// We want to use one of the nsHashtable constructors, but don't want to
// generally have mCapabilities be a pointer... and nsHashtable has no
// reasonable copy-constructor. Placement-new to the rescue!
mCapabilities.~nsHashtable();
new (&mCapabilities) nsHashtable(aStream, ReadAnnotationEntry,
FreeAnnotationEntry, &rv);
mCapabilities = new nsHashtable(aStream, ReadAnnotationEntry,
FreeAnnotationEntry, &rv);
NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
}
if (NS_FAILED(rv)) {
@ -1008,10 +1015,10 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
// mAnnotations is transient data associated to specific JS stack frames. We
// don't want to serialize that.
PRBool hasCapabilities = (mCapabilities.Count() > 0);
PRBool hasCapabilities = (mCapabilities && mCapabilities->Count() > 0);
nsresult rv = aStream->WriteBoolean(hasCapabilities);
if (NS_SUCCEEDED(rv) && hasCapabilities) {
rv = mCapabilities.Write(aStream, WriteScalarValue);
rv = mCapabilities->Write(aStream, WriteScalarValue);
}
if (NS_FAILED(rv)) {

View File

@ -280,10 +280,20 @@ nsSystemPrincipal::nsSystemPrincipal()
{
}
#define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
nsresult
nsSystemPrincipal::Init()
{
return mJSPrincipals.Init(this, "[System Principal]");
// Use an nsCString so we only do the allocation once here and then
// share with nsJSPrincipals
nsCString str(SYSTEM_PRINCIPAL_SPEC);
if (!str.EqualsLiteral(SYSTEM_PRINCIPAL_SPEC)) {
NS_WARNING("Out of memory initializing system principal");
return NS_ERROR_OUT_OF_MEMORY;
}
return mJSPrincipals.Init(this, str);
}
nsSystemPrincipal::~nsSystemPrincipal(void)