Fix bug 114115. Reduce long lived allocations by refactoring to hold main interface info structs in arena and buil refcounted info objects on demand (though cached for reuse) r=dbradley sr=jst

This commit is contained in:
jband%netscape.com 2002-01-10 23:49:47 +00:00
parent c96b2c0c8d
commit 02b0142c2d
12 changed files with 1069 additions and 730 deletions

View File

@ -55,6 +55,8 @@ interface nsIInterfaceInfoManager : nsISupports
nsIEnumerator enumerateInterfaces();
void autoRegisterInterfaces();
nsIEnumerator enumerateInterfacesWhoseNamesStartWith(in string prefix);
};
%{C++

View File

@ -11,19 +11,10 @@
- verify that interface names are always one-to-one with iids
- check for truncated xpt files and version problems
- http://bugzilla.mozilla.org/show_bug.cgi?id=33193
- support xpt files in more than just the components dir; e.g. plugins?
- probably just another field in the manifest containing a number
i.e. '0' means components dir, '1' means plugins dir, etc.
- TESTS!
- e.g. verify the merge stuff really works for various inputs.
- we really need a set of .xpt and .zip files and code that does an array
of autoreg and interfaceinof use activitities to test various corners
of the system.
- support #ifdef'ing out the zip #includes and uses
- this is needed if we want to remove the #include dependency on libjar
- most zip code is already in separate file. Only the places where it
finds and reads zips need #ifdefing - minimize the changes.
- switch to MoveTo for .dat file
- depends on bug 33098 (stupidly marked [feature]!)
- better autoreg logging
- use only 32 bits for file size?

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -42,7 +44,11 @@
MOZ_DECL_CTOR_COUNTER(xptiFile)
xptiFile::xptiFile()
: mSize(),
:
#ifdef DEBUG
mDEBUG_WorkingSet(nsnull),
#endif
mSize(),
mDate(),
mName(nsnull),
mGuts(nsnull),
@ -56,10 +62,12 @@ xptiFile::xptiFile(const nsInt64& aSize,
const nsInt64& aDate,
PRUint32 aDirectory,
const char* aName,
xptiWorkingSet* aWorkingSet,
XPTHeader* aHeader /*= nsnull */)
: mSize(aSize),
xptiWorkingSet* aWorkingSet)
:
#ifdef DEBUG
mDEBUG_WorkingSet(aWorkingSet),
#endif
mSize(aSize),
mDate(aDate),
mName(aName),
mGuts(nsnull),
@ -68,15 +76,15 @@ xptiFile::xptiFile(const nsInt64& aSize,
NS_ASSERTION(aWorkingSet,"bad param");
mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName);
if(aHeader)
SetHeader(aHeader);
MOZ_COUNT_CTOR(xptiFile);
}
xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet,
PRBool cloneGuts)
: mSize(r.mSize),
xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet)
:
#ifdef DEBUG
mDEBUG_WorkingSet(aWorkingSet),
#endif
mSize(r.mSize),
mDate(r.mDate),
mName(nsnull),
mGuts(nsnull),
@ -85,31 +93,21 @@ xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet,
NS_ASSERTION(aWorkingSet,"bad param");
mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName);
if(cloneGuts && r.mGuts)
mGuts = r.mGuts->Clone();
MOZ_COUNT_CTOR(xptiFile);
}
xptiFile::~xptiFile()
{
if(mGuts)
delete mGuts;
MOZ_COUNT_DTOR(xptiFile);
}
PRBool
xptiFile::SetHeader(XPTHeader* aHeader)
xptiFile::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet)
{
NS_ASSERTION(!mGuts,"bad state");
NS_ASSERTION(aHeader,"bad param");
NS_ASSERTION(aWorkingSet,"bad param");
mGuts = new xptiTypelibGuts(aHeader);
if(mGuts && !mGuts->IsValid())
{
delete mGuts;
mGuts = nsnull;
}
mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet);
return mGuts != nsnull;
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,91 +37,116 @@
*
* ***** END LICENSE BLOCK ***** */
/* Implementation of xptiInterfaceInfo. */
/* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */
#include "xptiprivate.h"
NS_IMPL_THREADSAFE_ISUPPORTS1(xptiInterfaceInfo, nsIInterfaceInfo)
/***************************************************************************/
// Debug Instrumentation...
void
xptiInterfaceInfo::CopyName(const char* name,
xptiWorkingSet* aWorkingSet)
#ifdef SHOW_INFO_COUNT_STATS
static int DEBUG_TotalInfos = 0;
static int DEBUG_CurrentInfos = 0;
static int DEBUG_MaxInfos = 0;
static int DEBUG_MonitorEntryCount = 0;
#define LOG_INFO_CREATE(t) \
DEBUG_TotalInfos++; \
DEBUG_CurrentInfos++; \
if(DEBUG_MaxInfos < DEBUG_CurrentInfos) \
DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */
#define LOG_INFO_DESTROY(t) \
DEBUG_CurrentInfos-- /* no ';' */
#define LOG_INFO_MONITOR_ENTRY \
DEBUG_MonitorEntryCount++ /* no ';' */
#else /* SHOW_INFO_COUNT_STATS */
#define LOG_INFO_CREATE(t) ((void)0)
#define LOG_INFO_DESTROY(t) ((void)0)
#define LOG_INFO_MONITOR_ENTRY ((void)0)
#endif /* SHOW_INFO_COUNT_STATS */
#ifdef DEBUG
// static
void xptiInterfaceInfo::DEBUG_ShutdownNotification()
{
NS_ASSERTION(name, "bad param!");
NS_ASSERTION(aWorkingSet, "bad param!");
NS_ASSERTION(!mName, "bad caller!");
#ifdef SHOW_INFO_COUNT_STATS
printf("iiii %d total xptiInterfaceInfos created\n", DEBUG_TotalInfos);
printf("iiii %d max xptiInterfaceInfos alive at one time\n", DEBUG_MaxInfos);
printf("iiii %d xptiInterfaceInfos still alive\n", DEBUG_CurrentInfos);
printf("iiii %d times locked\n", DEBUG_MonitorEntryCount);
#endif
}
#endif /* DEBUG */
int len = PL_strlen(name);
char* ptr = (char*) XPT_MALLOC(aWorkingSet->GetStringArena(), len+2);
if(ptr)
{
mName = &ptr[1];
memcpy(mName, name, len);
// XXX These are redundant as long as the underlying arena continues
// to zero out all mallocs. But...
mName[-1] = mName[len] = 0;
}
/***************************************************************************/
}
// static
xptiInterfaceEntry*
xptiInterfaceEntry::NewEntry(const char* name,
const nsID& iid,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet)
{
size_t nameLength = PL_strlen(name);
void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
sizeof(xptiInterfaceEntry) + nameLength);
if(!place)
return nsnull;
return new(place) xptiInterfaceEntry(name, nameLength, iid, typelib);
}
// static
xptiInterfaceEntry*
xptiInterfaceEntry::NewEntry(const xptiInterfaceEntry& r,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet)
{
size_t nameLength = PL_strlen(r.mName);
void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
sizeof(xptiInterfaceEntry) + nameLength);
if(!place)
return nsnull;
return new(place) xptiInterfaceEntry(r, nameLength, typelib);
}
xptiInterfaceInfo::xptiInterfaceInfo(const char* name,
const nsID& iid,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet)
xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
size_t nameLength,
const nsID& iid,
const xptiTypelib& typelib)
: mIID(iid),
mName(nsnull),
mTypelib(typelib)
mTypelib(typelib),
mInfo(nsnull),
mFlags(uint8(0))
{
NS_INIT_REFCNT();
CopyName(name, aWorkingSet);
memcpy(mName, name, nameLength);
}
xptiInterfaceInfo::xptiInterfaceInfo(const xptiInterfaceInfo& r,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet)
xptiInterfaceEntry::xptiInterfaceEntry(const xptiInterfaceEntry& r,
size_t nameLength,
const xptiTypelib& typelib)
: mIID(r.mIID),
mName(nsnull),
mTypelib(typelib)
mTypelib(typelib),
mInfo(nsnull),
mFlags(r.mFlags)
{
NS_INIT_REFCNT();
CopyName(r.mName, aWorkingSet);
if(IsValid() && r.IsValid())
{
mName[-1] = r.mName[-1]; // copy any flags
SetResolvedState(NOT_RESOLVED);
}
}
xptiInterfaceInfo::~xptiInterfaceInfo()
{
if(HasInterfaceRecord())
delete mInterface;
}
void
xptiInterfaceInfo::Invalidate()
{
if(IsValid())
{
// The order of operations here is important!
xptiTypelib typelib = GetTypelibRecord();
if(HasInterfaceRecord())
delete mInterface;
mTypelib = typelib;
mName = nsnull;
}
SetResolvedState(NOT_RESOLVED);
memcpy(mName, r.mName, nameLength);
}
PRBool
xptiInterfaceInfo::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */)
xptiInterfaceEntry::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */)
{
nsAutoLock lock(xptiInterfaceInfoManager::GetResolveLock());
return ResolveLocked(aWorkingSet);
}
PRBool
xptiInterfaceInfo::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */)
xptiInterfaceEntry::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */)
{
int resolvedState = GetResolveState();
@ -165,20 +192,20 @@ xptiInterfaceInfo::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */)
if(parent_index)
{
xptiInterfaceInfo* parent =
xptiInterfaceEntry* parent =
aWorkingSet->GetTypelibGuts(mInterface->mTypelib)->
GetInfoAtNoAddRef(parent_index - 1);
GetEntryAt(parent_index - 1);
if(!parent || !parent->EnsureResolvedLocked())
{
xptiTypelib aTypelib = mInterface->mTypelib;
delete mInterface;
mInterface = nsnull;
mTypelib = aTypelib;
SetResolvedState(RESOLVE_FAILED);
return PR_FALSE;
}
NS_ADDREF(mInterface->mParent = parent);
mInterface->mParent = parent;
mInterface->mMethodBaseIndex =
parent->mInterface->mMethodBaseIndex +
@ -197,107 +224,85 @@ xptiInterfaceInfo::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */)
// This *only* gets called by xptiInterfaceInfoManager::LoadFile (while locked).
PRBool
xptiInterfaceInfo::PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor,
xptiWorkingSet* aWorkingSet)
xptiInterfaceEntry::PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor,
xptiWorkingSet* aWorkingSet)
{
NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state");
LOG_RESOLVE(("~ partial resolve of %s\n", mName));
xptiInterfaceGuts* iface =
new xptiInterfaceGuts(aDescriptor, mTypelib, aWorkingSet);
xptiInterfaceGuts::NewGuts(aDescriptor, mTypelib, aWorkingSet);
if(!iface)
return PR_FALSE;
mInterface = iface;
if(!ScriptableFlagIsValid())
#ifdef DEBUG
if(!DEBUG_ScriptableFlagIsValid())
{
NS_ERROR("unexpected scriptable flag!");
SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags));
}
#endif
SetResolvedState(PARTIALLY_RESOLVED);
return PR_TRUE;
}
}
/***************************************************************************/
/**************************************************/
// These non-virtual methods handle the delegated nsIInterfaceInfo methods.
NS_IMETHODIMP
xptiInterfaceInfo::GetName(char **name)
nsresult
xptiInterfaceEntry::GetName(char **name)
{
NS_PRECONDITION(name, "bad param");
if(!mName)
return NS_ERROR_UNEXPECTED;
char* ptr = *name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1);
return ptr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetIID(nsIID **iid)
{
NS_PRECONDITION(iid, "bad param");
nsIID* ptr = *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
return ptr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP
xptiInterfaceInfo::IsScriptable(PRBool* result)
{
NS_ASSERTION(result, "bad bad caller!");
// It is not necessary to Resolve because this info is read from manifest.
*name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1);
return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_ASSERTION(ScriptableFlagIsValid(), "scriptable flag out of sync!");
nsresult
xptiInterfaceEntry::GetIID(nsIID **iid)
{
// It is not necessary to Resolve because this info is read from manifest.
*iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult
xptiInterfaceEntry::IsScriptable(PRBool* result)
{
// It is not necessary to Resolve because this info is read from manifest.
NS_ASSERTION(DEBUG_ScriptableFlagIsValid(), "scriptable flag out of sync!");
*result = GetScriptableFlag();
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::IsFunction(PRBool* result)
nsresult
xptiInterfaceEntry::IsFunction(PRBool* result)
{
NS_ASSERTION(result, "bad bad caller!");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
*result = XPT_ID_IS_FUNCTION(mInterface->mDescriptor->flags);
*result = XPT_ID_IS_FUNCTION(GetInterfaceGuts()->mDescriptor->flags);
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetParent(nsIInterfaceInfo** parent)
nsresult
xptiInterfaceEntry::GetMethodCount(uint16* count)
{
NS_PRECONDITION(parent, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
NS_IF_ADDREF(*parent = mInterface->mParent);
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetMethodCount(uint16* count)
{
NS_PRECONDITION(count, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
*count = mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods;
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetConstantCount(uint16* count)
nsresult
xptiInterfaceEntry::GetConstantCount(uint16* count)
{
NS_PRECONDITION(count, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
@ -306,11 +311,9 @@ xptiInterfaceInfo::GetConstantCount(uint16* count)
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info)
nsresult
xptiInterfaceEntry::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info)
{
NS_PRECONDITION(info, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
@ -333,21 +336,15 @@ xptiInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info)
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetMethodInfoForName(const char* methodName, uint16 *index,
const nsXPTMethodInfo** result)
nsresult
xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16 *index,
const nsXPTMethodInfo** result)
{
NS_PRECONDITION(methodName, "bad param");
NS_PRECONDITION(index, "bad param");
NS_PRECONDITION(result, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
// This is a slow algorithm, but this is not expected to be called much.
for(uint16 i = 0;
i < mInterface->mDescriptor->num_methods;
++i)
for(uint16 i = 0; i < mInterface->mDescriptor->num_methods; ++i)
{
const nsXPTMethodInfo* info;
info = NS_REINTERPRET_CAST(nsXPTMethodInfo*,
@ -359,9 +356,9 @@ xptiInterfaceInfo::GetMethodInfoForName(const char* methodName, uint16 *index,
return NS_OK;
}
}
if(mInterface->mParent)
return mInterface->mParent->GetMethodInfoForName(methodName,
index, result);
return mInterface->mParent->GetMethodInfoForName(methodName, index, result);
else
{
*index = 0;
@ -370,11 +367,9 @@ xptiInterfaceInfo::GetMethodInfoForName(const char* methodName, uint16 *index,
}
}
NS_IMETHODIMP
xptiInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant)
nsresult
xptiInterfaceEntry::GetConstant(uint16 index, const nsXPTConstant** constant)
{
NS_PRECONDITION(constant, "bad param");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
@ -398,33 +393,30 @@ xptiInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant)
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetInfoForParam(uint16 methodIndex,
const nsXPTParamInfo *param,
nsIInterfaceInfo** info)
{
NS_PRECONDITION(param, "bad pointer");
NS_PRECONDITION(info, "bad pointer");
// this is a private helper
nsresult
xptiInterfaceEntry::GetEntryForParam(PRUint16 methodIndex,
const nsXPTParamInfo * param,
xptiInterfaceEntry** entry)
{
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
if(methodIndex < mInterface->mMethodBaseIndex)
return mInterface->mParent->GetInfoForParam(methodIndex, param, info);
return mInterface->mParent->GetEntryForParam(methodIndex, param, entry);
if(methodIndex >= mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods)
{
NS_PRECONDITION(0, "bad param");
*info = NULL;
NS_ERROR("bad param");
return NS_ERROR_INVALID_ARG;
}
const XPTTypeDescriptor *td = &param->type;
while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
td = &mInterface->mDescriptor->
additional_types[td->type.additional_type];
td = &mInterface->mDescriptor->additional_types[td->type.additional_type];
}
if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
@ -432,36 +424,51 @@ xptiInterfaceInfo::GetInfoForParam(uint16 methodIndex,
return NS_ERROR_INVALID_ARG;
}
nsIInterfaceInfo* theInfo =
mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)->
GetInfoAtNoAddRef(td->type.iface - 1);
xptiInterfaceEntry* theEntry =
mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)->
GetEntryAt(td->type.iface - 1);
if(!theInfo)
return NS_ERROR_FAILURE;
NS_ADDREF(*info = theInfo);
NS_ASSERTION(theEntry, "bad state");
*entry = theEntry;
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetIIDForParam(uint16 methodIndex,
const nsXPTParamInfo* param, nsIID** iid)
nsresult
xptiInterfaceEntry::GetInfoForParam(uint16 methodIndex,
const nsXPTParamInfo *param,
nsIInterfaceInfo** info)
{
nsCOMPtr<nsIInterfaceInfo> ii;
nsresult rv = GetInfoForParam(methodIndex, param, getter_AddRefs(ii));
xptiInterfaceEntry* entry;
nsresult rv = GetEntryForParam(methodIndex, param, &entry);
if(NS_FAILED(rv))
return rv;
return ii->GetIID(iid);
xptiInterfaceInfo* theInfo;
rv = entry->GetInterfaceInfo(&theInfo);
if(NS_FAILED(rv))
return rv;
*info = NS_STATIC_CAST(nsIInterfaceInfo*, theInfo);
return NS_OK;
}
nsresult
xptiInterfaceEntry::GetIIDForParam(uint16 methodIndex,
const nsXPTParamInfo* param, nsIID** iid)
{
xptiInterfaceEntry* entry;
nsresult rv = GetEntryForParam(methodIndex, param, &entry);
if(NS_FAILED(rv))
return rv;
return entry->GetIID(iid);
}
// this is a private helper
NS_IMETHODIMP
xptiInterfaceInfo::GetTypeInArray(const nsXPTParamInfo* param,
uint16 dimension,
const XPTTypeDescriptor** type)
nsresult
xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
uint16 dimension,
const XPTTypeDescriptor** type)
{
NS_ASSERTION(param, "bad state");
NS_ASSERTION(type, "bad state");
NS_ASSERTION(IsFullyResolved(), "bad state");
const XPTTypeDescriptor *td = &param->type;
@ -480,21 +487,18 @@ xptiInterfaceInfo::GetTypeInArray(const nsXPTParamInfo* param,
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetTypeForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
nsXPTType* type)
nsresult
xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
nsXPTType* type)
{
NS_PRECONDITION(param, "bad pointer");
NS_PRECONDITION(type, "bad pointer");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
if(methodIndex < mInterface->mMethodBaseIndex)
return mInterface->mParent->GetTypeForParam(methodIndex, param,
dimension, type);
return mInterface->mParent->
GetTypeForParam(methodIndex, param, dimension, type);
if(methodIndex >= mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods)
@ -517,22 +521,18 @@ xptiInterfaceInfo::GetTypeForParam(uint16 methodIndex,
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetSizeIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
uint8* argnum)
nsresult
xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
uint8* argnum)
{
NS_PRECONDITION(param, "bad pointer");
NS_PRECONDITION(argnum, "bad pointer");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
if(methodIndex < mInterface->mMethodBaseIndex)
return mInterface->mParent->
GetSizeIsArgNumberForParam(methodIndex, param,
dimension, argnum);
GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum);
if(methodIndex >= mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods)
@ -566,22 +566,18 @@ xptiInterfaceInfo::GetSizeIsArgNumberForParam(uint16 methodIndex,
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetLengthIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
uint8* argnum)
nsresult
xptiInterfaceEntry::GetLengthIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint16 dimension,
uint8* argnum)
{
NS_PRECONDITION(param, "bad pointer");
NS_PRECONDITION(argnum, "bad pointer");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
if(methodIndex < mInterface->mMethodBaseIndex)
return mInterface->mParent->
GetLengthIsArgNumberForParam(methodIndex, param,
dimension, argnum);
GetLengthIsArgNumberForParam(methodIndex, param, dimension, argnum);
if(methodIndex >= mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods)
@ -616,21 +612,17 @@ xptiInterfaceInfo::GetLengthIsArgNumberForParam(uint16 methodIndex,
return NS_OK;
}
NS_IMETHODIMP
xptiInterfaceInfo::GetInterfaceIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint8* argnum)
nsresult
xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16 methodIndex,
const nsXPTParamInfo* param,
uint8* argnum)
{
NS_PRECONDITION(param, "bad pointer");
NS_PRECONDITION(argnum, "bad pointer");
if(!EnsureResolved())
return NS_ERROR_UNEXPECTED;
if(methodIndex < mInterface->mMethodBaseIndex)
return mInterface->mParent->
GetInterfaceIsArgNumberForParam(methodIndex, param,
argnum);
GetInterfaceIsArgNumberForParam(methodIndex, param, argnum);
if(methodIndex >= mInterface->mMethodBaseIndex +
mInterface->mDescriptor->num_methods)
@ -656,49 +648,39 @@ xptiInterfaceInfo::GetInterfaceIsArgNumberForParam(uint16 methodIndex,
}
/* PRBool isIID (in nsIIDPtr IID); */
NS_IMETHODIMP
xptiInterfaceInfo::IsIID(const nsIID * IID, PRBool *_retval)
nsresult
xptiInterfaceEntry::IsIID(const nsIID * IID, PRBool *_retval)
{
NS_PRECONDITION(IID, "bad pointer");
NS_PRECONDITION(_retval, "bad pointer");
// It is not necessary to Resolve because this info is read from manifest.
*_retval = mIID.Equals(*IID);
return NS_OK;
}
/* void getNameShared ([shared, retval] out string name); */
NS_IMETHODIMP
xptiInterfaceInfo::GetNameShared(const char **name)
nsresult
xptiInterfaceEntry::GetNameShared(const char **name)
{
NS_PRECONDITION(name, "bad param");
if(!mName)
return NS_ERROR_UNEXPECTED;
// It is not necessary to Resolve because this info is read from manifest.
*name = mName;
return NS_OK;
}
/* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */
NS_IMETHODIMP
xptiInterfaceInfo::GetIIDShared(const nsIID * *iid)
nsresult
xptiInterfaceEntry::GetIIDShared(const nsIID * *iid)
{
NS_PRECONDITION(iid, "bad param");
// It is not necessary to Resolve because this info is read from manifest.
*iid = &mIID;
return NS_OK;
}
/* PRBool hasAncestor (in nsIIDPtr iid); */
NS_IMETHODIMP
xptiInterfaceInfo::HasAncestor(const nsIID * iid, PRBool *_retval)
nsresult
xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval)
{
NS_PRECONDITION(iid, "bad param");
NS_PRECONDITION(_retval, "bad param");
*_retval = PR_FALSE;
for(xptiInterfaceInfo* current = this;
for(xptiInterfaceEntry* current = this;
current;
current = current->mInterface->mParent)
{
@ -713,3 +695,106 @@ xptiInterfaceInfo::HasAncestor(const nsIID * iid, PRBool *_retval)
return NS_OK;
}
/***************************************************/
nsresult
xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info)
{
nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
LOG_INFO_MONITOR_ENTRY;
#ifdef SHOW_INFO_COUNT_STATS
static int callCount = 0;
if(!(++callCount%100))
printf("iiii %d xptiInterfaceInfos currently alive\n", DEBUG_CurrentInfos);
#endif
if(!mInfo)
{
mInfo = new xptiInterfaceInfo(this);
if(!mInfo)
{
*info = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
}
NS_ADDREF(*info = mInfo);
return NS_OK;
}
void
xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
{
if(mInfo)
{
mInfo->Invalidate();
mInfo = nsnull;
}
}
/***************************************************************************/
NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo)
xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry)
: mEntry(entry), mParent(nsnull)
{
NS_INIT_ISUPPORTS();
LOG_INFO_CREATE(this);
}
xptiInterfaceInfo::~xptiInterfaceInfo()
{
LOG_INFO_DESTROY(this);
NS_IF_RELEASE(mParent);
NS_ASSERTION(!mEntry, "bad state in dtor");
}
nsrefcnt
xptiInterfaceInfo::AddRef(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt);
NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this));
return cnt;
}
nsrefcnt
xptiInterfaceInfo::Release(void)
{
xptiInterfaceEntry* entry = mEntry;
nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
if(!cnt)
{
nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
LOG_INFO_MONITOR_ENTRY;
// If GetInterfaceInfo added and *released* a reference before we
// acquired the monitor then 'this' might already be dead. In that
// case we would not want to try to access any instance data. We
// would want to bail immediately. If 'this' is already dead then the
// entry will no longer have a pointer to 'this'. So, we can protect
// ourselves from danger without more aggressive locking.
if(entry && !entry->InterfaceInfoEquals(this))
return 0;
// If GetInterfaceInfo added a reference before we acquired the monitor
// then we want to bail out of here without destorying the object.
if(mRefCnt)
return 1;
if(mEntry)
{
mEntry->LockedInterfaceInfoDeathNotification();
mEntry = nsnull;
}
NS_DELETEXPCOM(this);
return 0;
}
return cnt;
}
/***************************************************************************/

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -100,7 +102,8 @@ xptiInterfaceInfoManager::IsValid()
{
return mWorkingSet.IsValid() &&
mResolveLock &&
mAutoRegLock;
mAutoRegLock &&
mInfoMonitor;
}
xptiInterfaceInfoManager::xptiInterfaceInfoManager(nsISupportsArray* aSearchPath)
@ -108,6 +111,7 @@ xptiInterfaceInfoManager::xptiInterfaceInfoManager(nsISupportsArray* aSearchPath
mOpenLogFile(nsnull),
mResolveLock(PR_NewLock()),
mAutoRegLock(PR_NewLock()),
mInfoMonitor(nsAutoMonitor::NewMonitor("xptiInfoMonitor")),
mSearchPath(aSearchPath)
{
NS_INIT_ISUPPORTS();
@ -158,6 +162,12 @@ xptiInterfaceInfoManager::~xptiInterfaceInfoManager()
PR_DestroyLock(mResolveLock);
if(mAutoRegLock)
PR_DestroyLock(mAutoRegLock);
if(mInfoMonitor)
nsAutoMonitor::DestroyMonitor(mInfoMonitor);
#ifdef DEBUG
xptiInterfaceInfo::DEBUG_ShutdownNotification();
#endif
}
static PRBool
@ -210,10 +220,9 @@ PRBool xptiInterfaceInfoManager::BuildFileSearchPath(nsISupportsArray** aPath)
static int callCount = 0;
NS_ASSERTION(!callCount++, "Expected only one call!");
#endif
nsCOMPtr<nsISupportsArray> searchPath =
do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
nsCOMPtr<nsISupportsArray> searchPath;
NS_NewISupportsArray(getter_AddRefs(searchPath));
if(!searchPath)
return PR_FALSE;
@ -486,13 +495,13 @@ xptiInterfaceInfoManager::LoadFile(const xptiTypelib& aTypelibRecord,
if(aTypelibRecord.IsZip())
{
// This also allocs zipItem.GetGuts() used below.
if(!zipItem->SetHeader(header))
if(!zipItem->SetHeader(header, aWorkingSet))
return PR_FALSE;
}
else
{
// This also allocs fileRecord.GetGuts() used below.
if(!fileRecord->SetHeader(header))
if(!fileRecord->SetHeader(header, aWorkingSet))
return PR_FALSE;
}
@ -505,34 +514,40 @@ xptiInterfaceInfoManager::LoadFile(const xptiTypelib& aTypelibRecord,
{ 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
XPTInterfaceDirectoryEntry* iface = header->interface_directory + i;
xptiInterfaceInfo* info;
xptiHashEntry* hashEntry;
if(!iface->iid.Equals(zeroIID))
{
info = (xptiInterfaceInfo*)
PL_HashTableLookup(aWorkingSet->mIIDTable, &iface->iid);
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mIIDTable,
&iface->iid, PL_DHASH_LOOKUP);
}
else
{
info = (xptiInterfaceInfo*)
PL_HashTableLookup(aWorkingSet->mNameTable, iface->name);
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mNameTable,
iface->name, PL_DHASH_LOOKUP);
}
if(!info)
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
if(!entry)
{
// This one is just not resolved anywhere!
continue;
}
if(aTypelibRecord.IsZip())
zipItem->GetGuts()->SetInfoAt(i, info);
zipItem->GetGuts()->SetEntryAt(i, entry);
else
fileRecord->GetGuts()->SetInfoAt(i, info);
fileRecord->GetGuts()->SetEntryAt(i, entry);
XPTInterfaceDescriptor* descriptor = iface->interface_descriptor;
if(descriptor && aTypelibRecord.Equals(info->GetTypelibRecord()))
info->PartiallyResolveLocked(descriptor, aWorkingSet);
if(descriptor && aTypelibRecord.Equals(entry->GetTypelibRecord()))
entry->PartiallyResolveLocked(descriptor, aWorkingSet);
}
return PR_TRUE;
}
@ -588,7 +603,6 @@ xptiSortFileList(const void * p1, const void *p2, void * closure)
nsILocalFile* pFile2 = *((nsILocalFile**) p2);
SortData* data = (SortData*) closure;
nsXPIDLCString name1;
nsXPIDLCString name2;
@ -673,7 +687,6 @@ xptiInterfaceInfoManager::BuildOrderedFileArray(nsISupportsArray* aSearchPath,
// will preceed all zipfile of those files not already in the working set.
// To do this we will do a fancy sort on a copy of aFileList.
nsILocalFile** orderedFileList = nsnull;
PRUint32 countOfFilesInFileList;
PRUint32 i;
@ -917,29 +930,29 @@ xptiInterfaceInfoManager::AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchP
for(PRUint16 k = 0; k < header->num_interfaces; k++)
{
xptiInterfaceInfo* info = nsnull;
xptiInterfaceEntry* entry = nsnull;
if(!VerifyAndAddInterfaceIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&info))
if(!VerifyAndAddEntryIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&entry))
return PR_FALSE;
if(!info)
if(!entry)
continue;
// If this is the first interface we found for this file then
// setup the fileRecord for the header and infos.
if(!AddedFile)
{
if(!fileRecord.SetHeader(header))
if(!fileRecord.SetHeader(header, aWorkingSet))
{
// XXX that would be bad.
return PR_FALSE;
}
AddedFile = PR_TRUE;
}
fileRecord.GetGuts()->SetInfoAt(k, info);
fileRecord.GetGuts()->SetEntryAt(k, entry);
}
// This will correspond to typelibRecord above.
@ -1054,29 +1067,29 @@ xptiInterfaceInfoManager::DoFullValidationMergeFromFileList(nsISupportsArray* aS
for(PRUint16 k = 0; k < header->num_interfaces; k++)
{
xptiInterfaceInfo* info = nsnull;
xptiInterfaceEntry* entry = nsnull;
if(!VerifyAndAddInterfaceIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&info))
if(!VerifyAndAddEntryIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&entry))
return PR_FALSE;
if(!info)
if(!entry)
continue;
// If this is the first interface we found for this file then
// setup the fileRecord for the header and infos.
if(!AddedFile)
{
if(!fileRecord.SetHeader(header))
if(!fileRecord.SetHeader(header, aWorkingSet))
{
// XXX that would be bad.
return PR_FALSE;
}
AddedFile = PR_TRUE;
}
fileRecord.GetGuts()->SetInfoAt(k, info);
fileRecord.GetGuts()->SetEntryAt(k, entry);
}
// This will correspond to typelibRecord above.
@ -1135,15 +1148,15 @@ xptiInterfaceInfoManager::FoundEntry(const char* entryName,
for(PRUint16 k = 0; k < header->num_interfaces; k++)
{
xptiInterfaceInfo* info = nsnull;
xptiInterfaceEntry* entry = nsnull;
if(!VerifyAndAddInterfaceIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&info))
if(!VerifyAndAddEntryIfNew(aWorkingSet,
header->interface_directory + k,
typelibRecord,
&entry))
return PR_FALSE;
if(!info)
if(!entry)
continue;
// If this is the first interface we found for this item
@ -1151,14 +1164,14 @@ xptiInterfaceInfoManager::FoundEntry(const char* entryName,
if(!countOfInterfacesAddedForItem)
{
// XXX fix this!
if(!zipItemRecord.SetHeader(header))
if(!zipItemRecord.SetHeader(header, aWorkingSet))
{
// XXX that would be bad.
return PR_FALSE;
}
}
// zipItemRecord.GetGuts()->SetInfoAt(k, info);
// zipItemRecord.GetGuts()->SetEntryAt(k, entry);
++countOfInterfacesAddedForItem;
}
@ -1179,15 +1192,15 @@ xptiInterfaceInfoManager::FoundEntry(const char* entryName,
}
PRBool
xptiInterfaceInfoManager::VerifyAndAddInterfaceIfNew(xptiWorkingSet* aWorkingSet,
XPTInterfaceDirectoryEntry* iface,
const xptiTypelib& typelibRecord,
xptiInterfaceInfo** infoAdded)
xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet,
XPTInterfaceDirectoryEntry* iface,
const xptiTypelib& typelibRecord,
xptiInterfaceEntry** entryAdded)
{
NS_ASSERTION(iface, "loser!");
NS_ASSERTION(infoAdded, "loser!");
NS_ASSERTION(entryAdded, "loser!");
*infoAdded = nsnull;
*entryAdded = nsnull;
if(!iface->interface_descriptor)
{
@ -1196,42 +1209,49 @@ xptiInterfaceInfoManager::VerifyAndAddInterfaceIfNew(xptiWorkingSet* aWorkingSet
return PR_TRUE;
}
xptiInterfaceInfo* info = (xptiInterfaceInfo*)
PL_HashTableLookup(aWorkingSet->mIIDTable, &iface->iid);
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mIIDTable, &iface->iid, PL_DHASH_LOOKUP);
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
if(info)
if(entry)
{
// XXX validate this info to find possible inconsistencies
LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name));
return PR_TRUE;
}
// Build a new xptiInterfaceInfo object and hook it up.
// Build a new xptiInterfaceEntry object and hook it up.
info = new xptiInterfaceInfo(iface->name, iface->iid,
typelibRecord, aWorkingSet);
if(!info)
entry = xptiInterfaceEntry::NewEntry(iface->name, iface->iid,
typelibRecord, aWorkingSet);
if(!entry)
{
// XXX bad!
return PR_FALSE;
}
NS_ADDREF(info);
if(!info->IsValid())
{
// XXX bad!
NS_RELEASE(info);
return PR_FALSE;
}
//XXX We should SetHeader too as part of the validation, no?
info->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
// The name table now owns the reference we AddRef'd above
PL_HashTableAdd(aWorkingSet->mNameTable, iface->name, info);
PL_HashTableAdd(aWorkingSet->mIIDTable, &iface->iid, info);
// Add our entry to the iid hashtable.
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mNameTable,
entry->GetTheName(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = entry;
*infoAdded = info;
// Add our entry to the name hashtable.
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mIIDTable,
entry->GetTheIID(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = entry;
*entryAdded = entry;
LOG_AUTOREG((" added interface: %s\n", iface->name));
@ -1248,86 +1268,86 @@ struct TwoWorkingSets
xptiWorkingSet* aDestWorkingSet;
};
PR_STATIC_CALLBACK(PRIntn)
xpti_Merger(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_Merger(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
xptiInterfaceInfo* srcInfo = (xptiInterfaceInfo*) he->value;
xptiInterfaceEntry* srcEntry = ((xptiHashEntry*)hdr)->value;
xptiWorkingSet* aSrcWorkingSet = ((TwoWorkingSets*)arg)->aSrcWorkingSet;
xptiWorkingSet* aDestWorkingSet = ((TwoWorkingSets*)arg)->aDestWorkingSet;
xptiInterfaceInfo* destInfo = (xptiInterfaceInfo*)
PL_HashTableLookup(aDestWorkingSet->mIIDTable, srcInfo->GetTheIID());
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aDestWorkingSet->mIIDTable,
srcEntry->GetTheIID(), PL_DHASH_LOOKUP);
xptiInterfaceEntry* destEntry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
if(destInfo)
if(destEntry)
{
// Let's see if this is referring to the same exact typelib
const char* destFilename =
aDestWorkingSet->GetTypelibFileName(destInfo->GetTypelibRecord());
aDestWorkingSet->GetTypelibFileName(destEntry->GetTypelibRecord());
const char* srcFilename =
aSrcWorkingSet->GetTypelibFileName(srcInfo->GetTypelibRecord());
aSrcWorkingSet->GetTypelibFileName(srcEntry->GetTypelibRecord());
if(0 == PL_strcmp(destFilename, srcFilename) &&
(destInfo->GetTypelibRecord().GetZipItemIndex() ==
srcInfo->GetTypelibRecord().GetZipItemIndex()))
(destEntry->GetTypelibRecord().GetZipItemIndex() ==
srcEntry->GetTypelibRecord().GetZipItemIndex()))
{
// This is the same item.
// But... Let's make sure they didn't change the interface name.
// There are wacky developers that do stuff like that!
if(0 == PL_strcmp(destInfo->GetTheName(), srcInfo->GetTheName()))
return HT_ENUMERATE_NEXT;
if(0 == PL_strcmp(destEntry->GetTheName(), srcEntry->GetTheName()))
return PL_DHASH_NEXT;
}
// else...
// We need to remove the old item before adding the new one below.
PL_HashTableRemove(aDestWorkingSet->mNameTable, destInfo->GetTheName());
PL_HashTableRemove(aDestWorkingSet->mIIDTable, destInfo->GetTheIID());
// Release the one reference that was held by the name table.
NS_RELEASE(destInfo);
}
// Clone the xptiInterfaceInfo into our destination WorkingSet.
// Clone the xptiInterfaceEntry into our destination WorkingSet.
xptiTypelib typelibRecord;
uint16 fileIndex = srcInfo->GetTypelibRecord().GetFileIndex();
uint16 zipItemIndex = srcInfo->GetTypelibRecord().GetZipItemIndex();
uint16 fileIndex = srcEntry->GetTypelibRecord().GetFileIndex();
uint16 zipItemIndex = srcEntry->GetTypelibRecord().GetZipItemIndex();
fileIndex += aDestWorkingSet->mFileMergeOffsetMap[fileIndex];
// If it is not a zipItem, then the original index is fine.
if(srcInfo->GetTypelibRecord().IsZip())
if(srcEntry->GetTypelibRecord().IsZip())
zipItemIndex += aDestWorkingSet->mZipItemMergeOffsetMap[zipItemIndex];
typelibRecord.Init(fileIndex, zipItemIndex);
destInfo = new xptiInterfaceInfo(*srcInfo, typelibRecord, aDestWorkingSet);
if(!destInfo)
destEntry = xptiInterfaceEntry::NewEntry(*srcEntry, typelibRecord,
aDestWorkingSet);
if(!destEntry)
{
// XXX bad! should log
return HT_ENUMERATE_NEXT;
return PL_DHASH_NEXT;
}
NS_ADDREF(destInfo);
if(!destInfo->IsValid())
{
// XXX bad! should log
NS_RELEASE(destInfo);
return HT_ENUMERATE_NEXT;
}
// The name table now owns the reference we AddRef'd above
PL_HashTableAdd(aDestWorkingSet->mNameTable, destInfo->GetTheName(), destInfo);
PL_HashTableAdd(aDestWorkingSet->mIIDTable, destInfo->GetTheIID(), destInfo);
// Add our entry to the iid hashtable.
return HT_ENUMERATE_NEXT;
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aDestWorkingSet->mNameTable,
destEntry->GetTheName(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = destEntry;
// Add our entry to the name hashtable.
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aDestWorkingSet->mIIDTable,
destEntry->GetTheIID(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = destEntry;
return PL_DHASH_NEXT;
}
PRBool
xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet,
xptiWorkingSet* aSrcWorkingSet)
@ -1380,8 +1400,7 @@ xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet,
PRUint32 newIndex = aDestWorkingSet->GetFileCount();
aDestWorkingSet->AppendFile(
xptiFile(srcFile, aDestWorkingSet, PR_FALSE));
aDestWorkingSet->AppendFile(xptiFile(srcFile, aDestWorkingSet));
// Fixup the merge offset map.
aDestWorkingSet->mFileMergeOffsetMap[i] = newIndex - i;
@ -1434,7 +1453,7 @@ xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet,
PRUint32 newIndex = aDestWorkingSet->GetZipItemCount();
aDestWorkingSet->AppendZipItem(
xptiZipItem(srcZipItem, aDestWorkingSet, PR_FALSE));
xptiZipItem(srcZipItem, aDestWorkingSet));
// Fixup the merge offset map.
aDestWorkingSet->mZipItemMergeOffsetMap[i] = newIndex - i;
@ -1445,7 +1464,7 @@ xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet,
TwoWorkingSets sets(aSrcWorkingSet, aDestWorkingSet);
PL_HashTableEnumerateEntries(aSrcWorkingSet->mNameTable, xpti_Merger, &sets);
PL_DHashTableEnumerate(aSrcWorkingSet->mNameTable, xpti_Merger, &sets);
return PR_TRUE;
}
@ -1523,18 +1542,19 @@ xptiInterfaceInfoManager::WriteToLog(const char *fmt, ...)
}
}
PR_STATIC_CALLBACK(PRIntn)
xpti_ResolvedFileNameLogger(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_ResolvedFileNameLogger(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
xptiInterfaceInfo* ii = (xptiInterfaceInfo*) he->value;
xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
xptiInterfaceInfoManager* mgr = (xptiInterfaceInfoManager*) arg;
if(ii->IsFullyResolved())
if(entry->IsFullyResolved())
{
xptiWorkingSet* aWorkingSet = mgr->GetWorkingSet();
PRFileDesc* fd = mgr->GetOpenLogFile();
const xptiTypelib& typelib = ii->GetTypelibRecord();
const xptiTypelib& typelib = entry->GetTypelibRecord();
const char* filename =
aWorkingSet->GetFileAt(typelib.GetFileIndex()).GetName();
@ -1543,15 +1563,15 @@ xpti_ResolvedFileNameLogger(PLHashEntry *he, PRIntn i, void *arg)
const char* zipItemName =
aWorkingSet->GetZipItemAt(typelib.GetZipItemIndex()).GetName();
PR_fprintf(fd, "xpti used interface: %s from %s::%s\n",
ii->GetTheName(), filename, zipItemName);
entry->GetTheName(), filename, zipItemName);
}
else
{
PR_fprintf(fd, "xpti used interface: %s from %s\n",
ii->GetTheName(), filename);
entry->GetTheName(), filename);
}
}
return HT_ENUMERATE_NEXT;
return PL_DHASH_NEXT;
}
void
@ -1595,30 +1615,48 @@ xptiInterfaceInfoManager::LogStats()
// Show name of each interface that was fully resolved and the name
// of the file and (perhaps) zip from which it was loaded.
PL_HashTableEnumerateEntries(mWorkingSet.mNameTable,
xpti_ResolvedFileNameLogger, this);
PL_DHashTableEnumerate(mWorkingSet.mNameTable,
xpti_ResolvedFileNameLogger, this);
}
/***************************************************************************/
// this is a private helper
static nsresult
EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
{
xptiInterfaceInfo* info;
nsresult rv;
if(!entry)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
rv = entry->GetInterfaceInfo(&info);
if(NS_FAILED(rv))
return rv;
// Transfer the AddRef done by GetInterfaceInfo.
*_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info);
return NS_OK;
}
/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */
NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval)
{
NS_ASSERTION(iid, "bad param");
NS_ASSERTION(_retval, "bad param");
xptiInterfaceInfo* info = (xptiInterfaceInfo*)
PL_HashTableLookup(mWorkingSet.mIIDTable, iid);
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP);
if(!info)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
NS_ADDREF(*_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info));
return NS_OK;
return EntryToInfo(entry, _retval);
}
/* nsIInterfaceInfo getInfoForName (in string name); */
@ -1627,17 +1665,13 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInte
NS_ASSERTION(name, "bad param");
NS_ASSERTION(_retval, "bad param");
xptiInterfaceInfo* info = (xptiInterfaceInfo*)
PL_HashTableLookup(mWorkingSet.mNameTable, name);
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP);
if(!info)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
NS_ADDREF(*_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info));
return NS_OK;
return EntryToInfo(entry, _retval);
}
/* nsIIDPtr getIIDForName (in string name); */
@ -1646,16 +1680,19 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID *
NS_ASSERTION(name, "bad param");
NS_ASSERTION(_retval, "bad param");
xptiInterfaceInfo* info = (xptiInterfaceInfo*)
PL_HashTableLookup(mWorkingSet.mNameTable, name);
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP);
if(!info)
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
if(!entry)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
return info->GetIID(_retval);
return entry->GetIID(_retval);
}
/* string getNameForIID (in nsIIDPtr iid); */
@ -1664,30 +1701,34 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **
NS_ASSERTION(iid, "bad param");
NS_ASSERTION(_retval, "bad param");
xptiInterfaceInfo* info = (xptiInterfaceInfo*)
PL_HashTableLookup(mWorkingSet.mIIDTable, iid);
xptiHashEntry* hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP);
if(!info)
xptiInterfaceEntry* entry =
PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value;
if(!entry)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
return info->GetName(_retval);
return entry->GetName(_retval);
}
PR_STATIC_CALLBACK(PRIntn)
xpti_ArrayAppender(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_ArrayAppender(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
nsIInterfaceInfo* ii = (nsIInterfaceInfo*) he->value;
xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
nsISupportsArray* array = (nsISupportsArray*) arg;
// XXX nsSupportsArray.h shows that this method returns the wrong value!
array->AppendElement(ii);
return HT_ENUMERATE_NEXT;
nsCOMPtr<nsIInterfaceInfo> ii;
if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii))))
array->AppendElement(ii);
return PL_DHASH_NEXT;
}
/* nsIEnumerator enumerateInterfaces (); */
NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval)
{
@ -1696,13 +1737,50 @@ NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_ret
// the table using an nsISupportsArray and builds an enumerator for that.
// We can afford this transient cost.
nsCOMPtr<nsISupportsArray> array =
do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
nsCOMPtr<nsISupportsArray> array;
NS_NewISupportsArray(getter_AddRefs(array));
if(!array)
return NS_ERROR_UNEXPECTED;
PL_HashTableEnumerateEntries(mWorkingSet.mNameTable, xpti_ArrayAppender,
array);
PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayAppender, array);
return array->Enumerate(_retval);
}
struct ArrayAndPrefix
{
nsISupportsArray* array;
const char* prefix;
PRUint32 length;
};
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_ArrayPrefixAppender(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
ArrayAndPrefix* args = (ArrayAndPrefix*) arg;
const char* name = entry->GetTheName();
if(name != PL_strnstr(name, args->prefix, args->length))
return PL_DHASH_NEXT;
nsCOMPtr<nsIInterfaceInfo> ii;
if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii))))
args->array->AppendElement(ii);
return PL_DHASH_NEXT;
}
/* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */
NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval)
{
nsCOMPtr<nsISupportsArray> array;
NS_NewISupportsArray(getter_AddRefs(array));
if(!array)
return NS_ERROR_UNEXPECTED;
ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)};
PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayPrefixAppender, &args);
return array->Enumerate(_retval);
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -58,7 +60,8 @@ static const int g_VERSION_MINOR = 0;
/***************************************************************************/
static PRBool GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, char** aStr)
static PRBool
GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, char** aStr)
{
nsCOMPtr<nsILocalFile> appDir;
aMgr->GetApplicationDir(getter_AddRefs(appDir));
@ -67,53 +70,52 @@ static PRBool GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, char** aStr
return PR_FALSE;
}
static PRBool CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr, const char* inStr)
static PRBool
CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr,
const char* inStr)
{
nsCOMPtr<nsILocalFile> appDir;
aMgr->GetApplicationDir(getter_AddRefs(appDir));
nsCOMPtr<nsILocalFile> descDir;
nsresult rv = NS_NewLocalFile(nsnull, PR_FALSE, getter_AddRefs(descDir));
if (NS_FAILED(rv))
if(NS_FAILED(rv))
return PR_FALSE;
rv = descDir->SetPersistentDescriptor(inStr);
if (NS_FAILED(rv))
if(NS_FAILED(rv))
return PR_FALSE;
PRBool matches;
rv = appDir->Equals(descDir, &matches);
return (NS_SUCCEEDED(rv) && matches);
return NS_SUCCEEDED(rv) && matches;
}
PR_STATIC_CALLBACK(PRIntn)
xpti_InterfaceWriter(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_InterfaceWriter(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
xptiInterfaceInfo* info = (xptiInterfaceInfo*) he->value;
xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
PRFileDesc* fd = (PRFileDesc*) arg;
if(!info->IsValid())
return HT_ENUMERATE_STOP;
char* iidStr = info->GetTheIID()->ToString();
char* iidStr = entry->GetTheIID()->ToString();
if(!iidStr)
return HT_ENUMERATE_STOP;
return PL_DHASH_STOP;
const xptiTypelib& typelib = info->GetTypelibRecord();
const xptiTypelib& typelib = entry->GetTypelibRecord();
PRBool success = PR_fprintf(fd, "%d,%s,%s,%d,%d,%d\n",
(int) i,
info->GetTheName(),
(int) number,
entry->GetTheName(),
iidStr,
(int) typelib.GetFileIndex(),
(int) (typelib.IsZip() ?
typelib.GetZipItemIndex() : -1),
(int) info->GetScriptableFlag());
(int) entry->GetScriptableFlag());
nsCRT::free(iidStr);
return success ? HT_ENUMERATE_NEXT : HT_ENUMERATE_STOP;
return success ? PL_DHASH_NEXT : PL_DHASH_STOP;
}
@ -136,8 +138,7 @@ PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr,
if(NS_FAILED(tempFile->Append(g_TempManifestFilename)))
return PR_FALSE;
// exist via "goto out;" from here on...
// All exits via "goto out;" from here on...
if(NS_FAILED(tempFile->
OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
@ -230,16 +231,16 @@ PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr,
// write the Interfaces list
interfaceCount = aWorkingSet->mNameTable->nentries;
interfaceCount = aWorkingSet->mNameTable->entryCount;
if(!PR_fprintf(fd, "\n[%s,%d]\n",
g_TOKEN_Interfaces,
(int) interfaceCount))
goto out;
if(interfaceCount !=
PL_HashTableEnumerateEntries(aWorkingSet->mNameTable,
xpti_InterfaceWriter, fd))
if(interfaceCount != (PRIntn)
PL_DHashTableEnumerate(aWorkingSet->mNameTable,
xpti_InterfaceWriter, fd))
goto out;
@ -318,7 +319,7 @@ ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr,
if (!whole)
return nsnull;
// all exits from on here should be via 'goto out'
// All exits from on here should be via 'goto out'
if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd)
goto out;
@ -463,6 +464,7 @@ PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr,
PRBool succeeded = PR_FALSE;
PRUint32 flen;
ManifestLineReader reader;
xptiHashEntry* hashEntry;
int headerCount = 0;
int dirCount = 0;
int fileCount = 0;
@ -481,7 +483,7 @@ PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr,
reader.Init(whole, flen);
// all exits from on here should be via 'goto out'
// All exits from here on should be via 'goto out'
// Look for "Header" section
@ -680,7 +682,7 @@ PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr,
int fileIndex;
int zipItemIndex;
nsIID iid;
xptiInterfaceInfo* info;
xptiInterfaceEntry* entry;
xptiTypelib typelibRecord;
if(!reader.NextLine())
@ -723,23 +725,29 @@ PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr,
typelibRecord.Init(fileIndex);
else
typelibRecord.Init(fileIndex, zipItemIndex);
info = new xptiInterfaceInfo(values[1], iid, typelibRecord, aWorkingSet);
if(!info)
entry = xptiInterfaceEntry::NewEntry(values[1], iid, typelibRecord,
aWorkingSet);
if(!entry)
goto out;
NS_ADDREF(info);
if(!info->IsValid())
{
// XXX bad!
NS_RELEASE(info);
goto out;
}
entry->SetScriptableFlag(flags==1);
info->SetScriptableFlag(flags==1);
// Add our entry to the iid hashtable.
// The name table now owns the reference we AddRef'd above
PL_HashTableAdd(aWorkingSet->mNameTable, info->GetTheName(), info);
PL_HashTableAdd(aWorkingSet->mIIDTable, info->GetTheIID(), info);
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mNameTable,
entry->GetTheName(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = entry;
// Add our entry to the name hashtable.
hashEntry = (xptiHashEntry*)
PL_DHashTableOperate(aWorkingSet->mIIDTable,
entry->GetTheIID(), PL_DHASH_ADD);
if(hashEntry)
hashEntry->value = entry;
}
// success!

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -58,9 +60,9 @@ static const xptiFileTypeEntry g_Entries[] =
xptiFileType::Type xptiFileType::GetType(const char* name)
{
NS_ASSERTION(name, "loser!");
int len = PL_strlen(name);
for(const xptiFileTypeEntry* p = g_Entries; p->name; p++)
{
int len = PL_strlen(name);
if(len > p->len && 0 == PL_strcasecmp(p->name, &(name[len - p->len])))
return p->type;
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -39,78 +41,23 @@
#include "xptiprivate.h"
MOZ_DECL_CTOR_COUNTER(xptiTypelibGuts)
// static
xptiTypelibGuts*
xptiTypelibGuts::NewGuts(XPTHeader* aHeader,
xptiWorkingSet* aWorkingSet)
{
NS_ASSERTION(aHeader, "bad param");
void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
sizeof(xptiTypelibGuts) +
(sizeof(xptiInterfaceEntry*) *
(aHeader->num_interfaces - 1)));
if(!place)
return nsnull;
return new(place) xptiTypelibGuts(aHeader);
}
xptiTypelibGuts::xptiTypelibGuts(XPTHeader* aHeader)
: mHeader(aHeader),
mInfoArray(nsnull)
: mHeader(aHeader)
{
MOZ_COUNT_CTOR(xptiTypelibGuts);
NS_ASSERTION(mHeader, "bad param");
if(mHeader->num_interfaces)
{
mInfoArray = new xptiInterfaceInfo*[GetInfoCount()];
if(mInfoArray)
memset(mInfoArray, 0, sizeof(xptiInterfaceInfo*) * GetInfoCount());
else
mHeader = nsnull;
}
// empty
}
xptiTypelibGuts::~xptiTypelibGuts()
{
MOZ_COUNT_DTOR(xptiTypelibGuts);
if(mHeader && mInfoArray)
for(PRUint16 i = 0; i < GetInfoCount(); ++i)
NS_IF_RELEASE(mInfoArray[i]);
delete [] mInfoArray;
}
xptiTypelibGuts*
xptiTypelibGuts::Clone()
{
xptiTypelibGuts* clone = new xptiTypelibGuts(mHeader);
if(clone && clone->IsValid())
for(PRUint16 i = 0; i < GetInfoCount(); ++i)
clone->SetInfoAt(i, GetInfoAtNoAddRef(i));
return clone;
}
nsresult
xptiTypelibGuts::GetInfoAt(PRUint16 i, xptiInterfaceInfo** ptr)
{
NS_ASSERTION(mHeader,"bad state!");
NS_ASSERTION(mInfoArray,"bad state!");
NS_ASSERTION(i < GetInfoCount(),"bad param!");
NS_ASSERTION(ptr,"bad param!");
NS_IF_ADDREF(*ptr = mInfoArray[i]);
return NS_OK;
}
xptiInterfaceInfo*
xptiTypelibGuts::GetInfoAtNoAddRef(PRUint16 i)
{
NS_ASSERTION(mHeader,"bad state!");
NS_ASSERTION(mInfoArray,"bad state!");
NS_ASSERTION(i < GetInfoCount(),"bad param!");
return mInfoArray[i];
}
nsresult
xptiTypelibGuts::SetInfoAt(PRUint16 i, xptiInterfaceInfo* ptr)
{
NS_ASSERTION(mHeader,"bad state!");
NS_ASSERTION(mInfoArray,"bad state!");
NS_ASSERTION(i < GetInfoCount(),"bad param!");
NS_IF_ADDREF(ptr);
NS_IF_RELEASE(mInfoArray[i]);
mInfoArray[i] = ptr;
return NS_OK;
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -43,17 +45,74 @@
#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 1)
#define XPTI_HASHTABLE_SIZE 128
PR_STATIC_CALLBACK(PLHashNumber)
xpti_HashIID(const void *key)
/***************************************************************************/
PR_STATIC_CALLBACK(const void*)
IIDGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
{
return ((nsID*)key)->m0;
return ((xptiHashEntry*)entry)->value->GetTheIID();
}
PR_STATIC_CALLBACK(PRIntn)
xpti_CompareIIDs(const void *v1, const void *v2)
PR_STATIC_CALLBACK(PLDHashNumber)
IIDHash(PLDHashTable *table, const void *key)
{
return (PRIntn) ((const nsID*)v1)->Equals(*((const nsID*)v2));
}
return (PLDHashNumber) ((const nsIID*)key)->m0;
}
PR_STATIC_CALLBACK(PRBool)
IIDMatch(PLDHashTable *table,
const PLDHashEntryHdr *entry,
const void *key)
{
const nsIID* iid1 = ((xptiHashEntry*)entry)->value->GetTheIID();
const nsIID* iid2 = (const nsIID*)key;
return iid1 == iid2 || iid1->Equals(*iid2);
}
static struct PLDHashTableOps IIDTableOps =
{
PL_DHashAllocTable,
PL_DHashFreeTable,
IIDGetKey,
IIDHash,
IIDMatch,
PL_DHashMoveEntryStub,
PL_DHashClearEntryStub,
PL_DHashFinalizeStub
};
/***************************************************************************/
PR_STATIC_CALLBACK(const void*)
NameGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
{
return ((xptiHashEntry*)entry)->value->GetTheName();
}
PR_STATIC_CALLBACK(PRBool)
NameMatch(PLDHashTable *table,
const PLDHashEntryHdr *entry,
const void *key)
{
const char* str1 = ((xptiHashEntry*)entry)->value->GetTheName();
const char* str2 = (const char*) key;
return str1 == str2 || 0 == PL_strcmp(str1, str2);
}
static struct PLDHashTableOps NameTableOps =
{
PL_DHashAllocTable,
PL_DHashFreeTable,
NameGetKey,
PL_DHashStringKey,
NameMatch,
PL_DHashMoveEntryStub,
PL_DHashClearEntryStub,
PL_DHashFinalizeStub
};
/***************************************************************************/
MOZ_DECL_CTOR_COUNTER(xptiWorkingSet)
@ -69,14 +128,12 @@ xptiWorkingSet::xptiWorkingSet(nsISupportsArray* aDirectories)
mStructArena(XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double),
"xptiWorkingSet structs")),
mDirectories(aDirectories),
mNameTable(PL_NewHashTable(XPTI_HASHTABLE_SIZE, PL_HashString,
PL_CompareStrings, PL_CompareValues,
nsnull, nsnull)),
mIIDTable(PL_NewHashTable(XPTI_HASHTABLE_SIZE, xpti_HashIID,
xpti_CompareIIDs, PL_CompareValues,
nsnull, nsnull)),
mFileMergeOffsetMap(nsnull),
mZipItemMergeOffsetMap(nsnull)
mNameTable(PL_NewDHashTable(&NameTableOps, nsnull, sizeof(xptiHashEntry),
XPTI_HASHTABLE_SIZE)),
mIIDTable(PL_NewDHashTable(&IIDTableOps, nsnull, sizeof(xptiHashEntry),
XPTI_HASHTABLE_SIZE)),
mFileMergeOffsetMap(nsnull),
mZipItemMergeOffsetMap(nsnull)
{
MOZ_COUNT_CTOR(xptiWorkingSet);
// do nothing else...
@ -93,43 +150,40 @@ xptiWorkingSet::IsValid() const
mIIDTable;
}
PR_STATIC_CALLBACK(PRIntn)
xpti_Remover(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_Remover(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
return HT_ENUMERATE_REMOVE;
return PL_DHASH_REMOVE;
}
PR_STATIC_CALLBACK(PRIntn)
xpti_ReleaseAndRemover(PLHashEntry *he, PRIntn i, void *arg)
PR_STATIC_CALLBACK(PLDHashOperator)
xpti_Invalidator(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
nsIInterfaceInfo* ii = (nsIInterfaceInfo*) he->value;
NS_RELEASE(ii);
return HT_ENUMERATE_REMOVE;
}
PR_STATIC_CALLBACK(PRIntn)
xpti_Invalidator(PLHashEntry *he, PRIntn i, void *arg)
{
((xptiInterfaceInfo*)he->value)->Invalidate();
return HT_ENUMERATE_NEXT;
xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
entry->LockedInvalidateInterfaceInfo();
return PL_DHASH_NEXT;
}
void
xptiWorkingSet::InvalidateInterfaceInfos()
{
if(mNameTable)
PL_HashTableEnumerateEntries(mNameTable, xpti_Invalidator, nsnull);
{
nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
PL_DHashTableEnumerate(mNameTable, xpti_Invalidator, nsnull);
}
}
void
xptiWorkingSet::ClearHashTables()
{
if(mNameTable)
PL_HashTableEnumerateEntries(mNameTable, xpti_Remover, nsnull);
PL_DHashTableEnumerate(mNameTable, xpti_Remover, nsnull);
if(mIIDTable)
PL_HashTableEnumerateEntries(mIIDTable, xpti_ReleaseAndRemover, nsnull);
PL_DHashTableEnumerate(mIIDTable, xpti_Remover, nsnull);
}
void
@ -161,10 +215,10 @@ xptiWorkingSet::~xptiWorkingSet()
ClearHashTables();
if(mNameTable)
PL_HashTableDestroy(mNameTable);
PL_DHashTableDestroy(mNameTable);
if(mIIDTable)
PL_HashTableDestroy(mIIDTable);
PL_DHashTableDestroy(mIIDTable);
if(mFileArray)
delete [] mFileArray;
@ -363,15 +417,15 @@ PRBool xptiWorkingSet::DirectoryAtMatchesPersistentDescriptor(PRUint32 i,
nsCOMPtr<nsILocalFile> descDir;
nsresult rv = NS_NewLocalFile(nsnull, PR_FALSE, getter_AddRefs(descDir));
if (NS_FAILED(rv))
if(NS_FAILED(rv))
return PR_FALSE;
rv = descDir->SetPersistentDescriptor(inDesc);
if (NS_FAILED(rv))
if(NS_FAILED(rv))
return PR_FALSE;
PRBool matches;
rv = dir->Equals(descDir, &matches);
return (NS_SUCCEEDED(rv) && matches);
return NS_SUCCEEDED(rv) && matches;
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -42,7 +44,11 @@
MOZ_DECL_CTOR_COUNTER(xptiZipItem)
xptiZipItem::xptiZipItem()
: mName(nsnull),
:
#ifdef DEBUG
mDEBUG_WorkingSet(nsnull),
#endif
mName(nsnull),
mGuts(nsnull)
{
MOZ_COUNT_CTOR(xptiZipItem);
@ -50,54 +56,47 @@ xptiZipItem::xptiZipItem()
}
xptiZipItem::xptiZipItem(const char* aName,
xptiWorkingSet* aWorkingSet,
XPTHeader* aHeader /*= nsnull */)
xptiWorkingSet* aWorkingSet)
: mName(aName),
:
#ifdef DEBUG
mDEBUG_WorkingSet(aWorkingSet),
#endif
mName(aName),
mGuts(nsnull)
{
MOZ_COUNT_CTOR(xptiZipItem);
NS_ASSERTION(aWorkingSet,"bad param");
mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName);
if(aHeader)
SetHeader(aHeader);
}
xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet,
PRBool cloneGuts)
: mName(nsnull),
xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet)
:
#ifdef DEBUG
mDEBUG_WorkingSet(aWorkingSet),
#endif
mName(nsnull),
mGuts(nsnull)
{
MOZ_COUNT_CTOR(xptiZipItem);
NS_ASSERTION(aWorkingSet,"bad param");
mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName);
if(cloneGuts && r.mGuts)
mGuts = r.mGuts->Clone();
}
xptiZipItem::~xptiZipItem()
{
MOZ_COUNT_DTOR(xptiZipItem);
if(mGuts)
delete mGuts;
}
PRBool
xptiZipItem::SetHeader(XPTHeader* aHeader)
xptiZipItem::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet)
{
NS_ASSERTION(!mGuts,"bad state");
NS_ASSERTION(aHeader,"bad param");
NS_ASSERTION(aWorkingSet,"bad param");
mGuts = new xptiTypelibGuts(aHeader);
if(mGuts && !mGuts->IsValid())
{
delete mGuts;
mGuts = nsnull;
}
mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet);
return mGuts != nsnull;
}

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike McCabe <mccabe@netscape.com>
* John Bandhauer <jband@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -82,7 +84,7 @@
#include "nsAutoLock.h"
#include "plhash.h"
#include "pldhash.h"
#include "plstr.h"
#include "prprf.h"
#include "prio.h"
@ -104,11 +106,16 @@
#define LOG_AUTOREG(x) xptiInterfaceInfoManager::WriteToLog x
#endif
#if 1 && defined(DEBUG_jband)
#define SHOW_INFO_COUNT_STATS
#endif
/***************************************************************************/
class xptiFile;
class xptiInterfaceInfo;
class xptiInterfaceInfoManager;
class xptiInterfaceEntry;
class xptiInterfaceGuts;
class xptiTypelibGuts;
class xptiWorkingSet;
@ -142,24 +149,42 @@ private:
/***************************************************************************/
// No virtuals.
// These are always constructed in the struct arena using placement new.
// dtor need not be called.
class xptiTypelibGuts
{
public:
xptiTypelibGuts(); // not implemented
xptiTypelibGuts(XPTHeader* aHeader);
~xptiTypelibGuts();
static xptiTypelibGuts* NewGuts(XPTHeader* aHeader,
xptiWorkingSet* aWorkingSet);
PRBool IsValid() const {return mHeader != nsnull;}
XPTHeader* GetHeader() {return mHeader;}
PRUint16 GetInfoCount() const {return mHeader->num_interfaces;}
nsresult SetInfoAt(PRUint16 i, xptiInterfaceInfo* ptr);
nsresult GetInfoAt(PRUint16 i, xptiInterfaceInfo** ptr);
xptiInterfaceInfo* GetInfoAtNoAddRef(PRUint16 i);
xptiTypelibGuts* Clone();
XPTHeader* GetHeader() {return mHeader;}
PRUint16 GetEntryCount() const {return mHeader->num_interfaces;}
void SetEntryAt(PRUint16 i, xptiInterfaceEntry* ptr)
{
NS_ASSERTION(mHeader,"bad state!");
NS_ASSERTION(i < GetEntryCount(),"bad param!");
mEntryArray[i] = ptr;
}
xptiInterfaceEntry* GetEntryAt(PRUint16 i) const
{
NS_ASSERTION(mHeader,"bad state!");
NS_ASSERTION(i < GetEntryCount(),"bad param!");
return mEntryArray[i];
}
private:
XPTHeader* mHeader; // hold pointer into arena
xptiInterfaceInfo** mInfoArray;
xptiTypelibGuts(); // not implemented
xptiTypelibGuts(XPTHeader* aHeader);
~xptiTypelibGuts() {}
void* operator new(size_t, void* p) {return p;}
private:
XPTHeader* mHeader; // hold pointer into arena
xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit.
};
/***************************************************************************/
@ -171,7 +196,7 @@ public:
const nsInt64& GetDate() const {return mDate;}
const char* GetName() const {return mName;}
const PRUint32 GetDirectory() const {return mDirectory;}
xptiTypelibGuts* GetGuts() {return mGuts;}
xptiTypelibGuts* GetGuts() {return mGuts;}
xptiFile();
@ -179,15 +204,13 @@ public:
const nsInt64& aDate,
PRUint32 aDirectory,
const char* aName,
xptiWorkingSet* aWorkingSet,
XPTHeader* aHeader = nsnull);
xptiWorkingSet* aWorkingSet);
xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet,
PRBool cloneGuts);
xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet);
~xptiFile();
PRBool SetHeader(XPTHeader* aHeader);
PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet);
PRBool Equals(const xptiFile& r) const
{
@ -208,23 +231,29 @@ public:
private:
void CopyFields(const xptiFile& r)
{
#ifdef DEBUG
// If 'this' has a workingset then it better match that of the assigner.
NS_ASSERTION(!mDEBUG_WorkingSet ||
mDEBUG_WorkingSet == r.mDEBUG_WorkingSet,
"illegal xptiFile assignment");
mDEBUG_WorkingSet = r.mDEBUG_WorkingSet;
#endif
mSize = r.mSize;
mDate = r.mDate;
mName = r.mName;
mDirectory = r.mDirectory;
if(mGuts)
delete mGuts;
if(r.mGuts)
mGuts = r.mGuts->Clone();
else
mGuts = nsnull;
mGuts = r.mGuts;
}
private:
#ifdef DEBUG
xptiWorkingSet* mDEBUG_WorkingSet;
#endif
nsInt64 mSize;
nsInt64 mDate;
const char* mName; // hold pointer into arena from initializer
xptiTypelibGuts* mGuts; // new/delete
xptiTypelibGuts* mGuts; // hold pointer into arena
PRUint32 mDirectory;
};
@ -239,15 +268,13 @@ public:
xptiZipItem();
xptiZipItem(const char* aName,
xptiWorkingSet* aWorkingSet,
XPTHeader* aHeader = nsnull);
xptiWorkingSet* aWorkingSet);
xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet,
PRBool cloneGuts);
xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet);
~xptiZipItem();
PRBool SetHeader(XPTHeader* aHeader);
PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet);
PRBool Equals(const xptiZipItem& r) const
{
@ -265,18 +292,24 @@ public:
private:
void CopyFields(const xptiZipItem& r)
{
#ifdef DEBUG
// If 'this' has a workingset then it better match that of the assigner.
NS_ASSERTION(!mDEBUG_WorkingSet ||
mDEBUG_WorkingSet == r.mDEBUG_WorkingSet,
"illegal xptiFile assignment");
mDEBUG_WorkingSet = r.mDEBUG_WorkingSet;
#endif
mName = r.mName;
if(mGuts)
delete mGuts;
if(r.mGuts)
mGuts = r.mGuts->Clone();
else
mGuts = nsnull;
mGuts = r.mGuts;
}
private:
#ifdef DEBUG
xptiWorkingSet* mDEBUG_WorkingSet;
#endif
const char* mName; // hold pointer into arena from initializer
xptiTypelibGuts* mGuts; // new/delete
xptiTypelibGuts* mGuts; // hold pointer into arena
};
/***************************************************************************/
@ -411,27 +444,37 @@ private:
public:
// XXX make these private with accessors
PLHashTable* mNameTable;
PLHashTable* mIIDTable;
PLDHashTable* mNameTable;
PLDHashTable* mIIDTable;
PRUint32* mFileMergeOffsetMap; // always in an arena
PRUint32* mZipItemMergeOffsetMap; // always in an arena
};
/***************************************************************************/
// XXX could move this class to xptiInterfaceInfo.cpp.
class xptiInterfaceGuts
{
public:
uint16 mMethodBaseIndex;
uint16 mConstantBaseIndex;
xptiInterfaceInfo* mParent;
xptiInterfaceEntry* mParent;
XPTInterfaceDescriptor* mDescriptor;
xptiTypelib mTypelib;
xptiWorkingSet* mWorkingSet;
static xptiInterfaceGuts* NewGuts(XPTInterfaceDescriptor* aDescriptor,
const xptiTypelib& aTypelib,
xptiWorkingSet* aWorkingSet)
{
void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
sizeof(xptiInterfaceGuts));
if(!place)
return nsnull;
return new(place) xptiInterfaceGuts(aDescriptor, aTypelib, aWorkingSet);
}
private:
void* operator new(size_t, void* p) {return p;}
xptiInterfaceGuts(XPTInterfaceDescriptor* aDescriptor,
const xptiTypelib& aTypelib,
xptiWorkingSet* aWorkingSet)
@ -442,8 +485,7 @@ public:
mTypelib(aTypelib),
mWorkingSet(aWorkingSet) {}
// method definition below to avoid use before declaring xptiInterfaceInfo
inline ~xptiInterfaceGuts();
~xptiInterfaceGuts() {}
};
/***************************************************************************/
@ -455,6 +497,9 @@ class xptiInfoFlags
{
enum {STATE_MASK = 3};
public:
xptiInfoFlags(uint8 n) : mData(n) {}
xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {}
static uint8 GetStateMask()
{return uint8(STATE_MASK);}
@ -485,30 +530,21 @@ private:
/****************************************************/
class xptiInterfaceInfo : public nsIInterfaceInfo
// No virtual methods.
// We always create in the struct arena and construct using "placement new".
// No members need dtor calls.
class xptiInterfaceEntry
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIINTERFACEINFO
static xptiInterfaceEntry* NewEntry(const char* name,
const nsID& iid,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet);
public:
xptiInterfaceInfo(); // not implemented
xptiInterfaceInfo(const char* name,
const nsID& iid,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet);
xptiInterfaceInfo(const xptiInterfaceInfo& r,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet);
virtual ~xptiInterfaceInfo();
// We use mName[-1] (cast as a xptiInfoFlags) to hold the two bit state
// below and also the bit flags that follow. If the states ever grow beyond
// 2 bits then these flags need to be adjusted along with STATE_MASK in
// xptiInfoFlags.
static xptiInterfaceEntry* NewEntry(const xptiInterfaceEntry& r,
const xptiTypelib& typelib,
xptiWorkingSet* aWorkingSet);
enum {
NOT_RESOLVED = 0,
@ -520,11 +556,7 @@ public:
// Additional bit flags...
enum {SCRIPTABLE = 4};
PRBool IsValid() const
{return mName != nsnull;}
uint8 GetResolveState() const
{return IsValid() ? GetFlags().GetState() : (uint8) RESOLVE_FAILED;}
uint8 GetResolveState() const {return mFlags.GetState();}
PRBool IsFullyResolved() const
{return GetResolveState() == (uint8) FULLY_RESOLVED;}
@ -536,43 +568,11 @@ public:
const xptiTypelib& GetTypelibRecord() const
{return HasInterfaceRecord() ? mInterface->mTypelib : mTypelib;}
void SetScriptableFlag(PRBool on)
{GetFlags().SetFlagBit(uint8(SCRIPTABLE),on);}
PRBool GetScriptableFlag() const
{return GetFlags().GetFlagBit(uint8(SCRIPTABLE));}
xptiInterfaceGuts* GetInterfaceGuts() const
{return HasInterfaceRecord() ? mInterface : nsnull;}
const nsID* GetTheIID() const {return &mIID;}
const char* GetTheName() const {return mName;}
PRBool PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor,
xptiWorkingSet* aWorkingSet);
void Invalidate();
private:
void CopyName(const char* name,
xptiWorkingSet* aWorkingSet);
xptiInfoFlags& GetFlags() const {return (xptiInfoFlags&) mName[-1];}
xptiInfoFlags& GetFlags() {return (xptiInfoFlags&) mName[-1];}
void SetResolvedState(int state)
{NS_ASSERTION(IsValid(),"bad state");
GetFlags().SetState(uint8(state));}
PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull)
{return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);}
PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull);
// We only call these "*Locked" varients after locking. This is done to
// allow reentrace as files are loaded and various interfaces resolved
// without having to worry about the locked state.
PRBool EnsureResolvedLocked(xptiWorkingSet* aWorkingSet = nsnull)
{return IsFullyResolved() ? PR_TRUE : ResolveLocked(aWorkingSet);}
PRBool ResolveLocked(xptiWorkingSet* aWorkingSet = nsnull);
PRBool ScriptableFlagIsValid() const
#ifdef DEBUG
PRBool DEBUG_ScriptableFlagIsValid() const
{int s = (int) GetResolveState();
if((s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface)
{
@ -580,20 +580,190 @@ private:
return GetScriptableFlag();
return !GetScriptableFlag();
}
else return PR_TRUE;
return PR_TRUE;
}
NS_IMETHOD GetTypeInArray(const nsXPTParamInfo* param,
uint16 dimension,
const XPTTypeDescriptor** type);
private:
nsID mIID;
char* mName; // This is in arena (not free'd) and mName[-1] is a flag.
#endif
void SetScriptableFlag(PRBool on)
{mFlags.SetFlagBit(uint8(SCRIPTABLE),on);}
PRBool GetScriptableFlag() const
{return mFlags.GetFlagBit(uint8(SCRIPTABLE));}
const nsID* GetTheIID() const {return &mIID;}
const char* GetTheName() const {return mName;}
PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull)
{return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);}
PRBool PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor,
xptiWorkingSet* aWorkingSet);
nsresult GetInterfaceInfo(xptiInterfaceInfo** info);
PRBool InterfaceInfoEquals(const xptiInterfaceInfo* info) const
{return info == mInfo;}
void LockedInvalidateInterfaceInfo();
void LockedInterfaceInfoDeathNotification() {mInfo = nsnull;}
//////////////////////
// These non-virtual methods handle the delegated nsIInterfaceInfo methods.
nsresult GetName(char * *aName);
nsresult GetIID(nsIID * *aIID);
nsresult IsScriptable(PRBool *_retval);
// Except this one.
//nsresult GetParent(nsIInterfaceInfo * *aParent);
nsresult GetMethodCount(PRUint16 *aMethodCount);
nsresult GetConstantCount(PRUint16 *aConstantCount);
nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info);
nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info);
nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant);
nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval);
nsresult GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval);
nsresult GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval);
nsresult GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval);
nsresult GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval);
nsresult GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval);
nsresult IsIID(const nsIID * IID, PRBool *_retval);
nsresult GetNameShared(const char **name);
nsresult GetIIDShared(const nsIID * *iid);
nsresult IsFunction(PRBool *_retval);
nsresult HasAncestor(const nsIID * iid, PRBool *_retval);
//////////////////////
private:
xptiInterfaceEntry(); // not implemented
xptiInterfaceEntry(const char* name,
size_t nameLength,
const nsID& iid,
const xptiTypelib& typelib);
xptiInterfaceEntry(const xptiInterfaceEntry& r,
size_t nameLength,
const xptiTypelib& typelib);
~xptiInterfaceEntry();
void* operator new(size_t, void* p) {return p;}
void SetResolvedState(int state)
{mFlags.SetState(uint8(state));}
PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull);
// We only call these "*Locked" variants after locking. This is done to
// allow reentrace as files are loaded and various interfaces resolved
// without having to worry about the locked state.
PRBool EnsureResolvedLocked(xptiWorkingSet* aWorkingSet = nsnull)
{return IsFullyResolved() ? PR_TRUE : ResolveLocked(aWorkingSet);}
PRBool ResolveLocked(xptiWorkingSet* aWorkingSet = nsnull);
// private helpers
nsresult GetEntryForParam(PRUint16 methodIndex,
const nsXPTParamInfo * param,
xptiInterfaceEntry** entry);
nsresult GetTypeInArray(const nsXPTParamInfo* param,
uint16 dimension,
const XPTTypeDescriptor** type);
private:
nsID mIID;
union {
xptiTypelib mTypelib; // Valid only until resolved.
xptiInterfaceGuts* mInterface; // Valid only after resolved.
};
xptiInterfaceInfo* mInfo; // May come and go.
xptiInfoFlags mFlags;
char mName[1]; // Always last. Sized to fit.
};
struct xptiHashEntry : public PLDHashEntryHdr
{
xptiInterfaceEntry* value;
};
/****************************************************/
class xptiInterfaceInfo : public nsIInterfaceInfo
{
public:
NS_DECL_ISUPPORTS
// Use delegation to implement (most!) of nsIInterfaceInfo.
NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); }
NS_IMETHOD GetIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); }
NS_IMETHOD IsScriptable(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); }
// Except this one.
NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent)
{
if(!EnsureResolved() || !EnsureParent())
return NS_ERROR_UNEXPECTED;
NS_IF_ADDREF(*aParent = mParent);
return NS_OK;
}
NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); }
NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); }
NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); }
NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); }
NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); }
NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); }
NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); }
NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); }
NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); }
NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetLengthIsArgNumberForParam(methodIndex, param, dimension, _retval); }
NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); }
NS_IMETHOD IsIID(const nsIID * IID, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); }
NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); }
NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); }
NS_IMETHOD IsFunction(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); }
NS_IMETHOD HasAncestor(const nsIID * iid, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); }
public:
xptiInterfaceInfo(xptiInterfaceEntry* entry);
virtual ~xptiInterfaceInfo() ;
void Invalidate()
{NS_IF_RELEASE(mParent); mEntry = nsnull;}
#ifdef DEBUG
static void DEBUG_ShutdownNotification();
#endif
private:
// Note that mParent might still end up as nsnull if we don't have one.
PRBool EnsureParent(xptiWorkingSet* aWorkingSet = nsnull)
{
NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call");
return mParent || !mEntry->GetInterfaceGuts()->mParent || BuildParent();
}
PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull)
{
return mEntry && mEntry->EnsureResolved(aWorkingSet);
}
PRBool BuildParent()
{
NS_ASSERTION(mEntry &&
mEntry->IsFullyResolved() &&
!mParent &&
mEntry->GetInterfaceGuts()->mParent,
"bad BuildParent call");
return NS_SUCCEEDED(mEntry->GetInterfaceGuts()->mParent->
GetInterfaceInfo(&mParent));
}
xptiInterfaceInfo(); // not implemented
private:
xptiInterfaceEntry* mEntry;
xptiInterfaceInfo* mParent;
};
/***************************************************************************/
@ -609,6 +779,7 @@ public:
static PRBool Delete(xptiInterfaceInfoManager* aMgr);
private:
xptiManifest(); // no implementation
};
@ -677,6 +848,8 @@ public:
static PRBool IsZip(const char* name)
{return GetType(name) == ZIP;}
private:
xptiFileType(); // no implementation
};
/***************************************************************************/
@ -746,6 +919,11 @@ public:
return nsnull;
return self->mAutoRegLock;}
static PRMonitor* GetInfoMonitor(xptiInterfaceInfoManager* self = nsnull)
{if(!self && !(self = GetInterfaceInfoManagerNoAddRef()))
return nsnull;
return self->mInfoMonitor;}
static void WriteToLog(const char *fmt, ...);
private:
@ -781,10 +959,10 @@ private:
nsISupportsArray* aFileList,
xptiWorkingSet* aWorkingSet);
PRBool VerifyAndAddInterfaceIfNew(xptiWorkingSet* aWorkingSet,
XPTInterfaceDirectoryEntry* iface,
const xptiTypelib& typelibRecord,
xptiInterfaceInfo** infoAdded);
PRBool VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet,
XPTInterfaceDirectoryEntry* iface,
const xptiTypelib& typelibRecord,
xptiInterfaceEntry** entryAdded);
PRBool MergeWorkingSets(xptiWorkingSet* aDestWorkingSet,
xptiWorkingSet* aSrcWorkingSet);
@ -804,6 +982,7 @@ private:
PRFileDesc* mOpenLogFile;
PRLock* mResolveLock;
PRLock* mAutoRegLock;
PRMonitor* mInfoMonitor;
nsCOMPtr<nsILocalFile> mManifestDir;
nsCOMPtr<nsISupportsArray> mSearchPath;
};
@ -817,10 +996,4 @@ nsresult xptiCloneLocalFile(nsILocalFile* aLocalFile,
nsresult xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex,
nsILocalFile** aLocalFile);
/***************************************************************************/
//inlines...
inline xptiInterfaceGuts::~xptiInterfaceGuts() {NS_IF_RELEASE(mParent);}
#endif /* xptiprivate_h___ */