michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Library-private header for Interface Info system. */ michael@0: michael@0: #ifndef xptiprivate_h___ michael@0: #define xptiprivate_h___ michael@0: michael@0: #include "nscore.h" michael@0: #include michael@0: #include "nsISupports.h" michael@0: michael@0: // this after nsISupports, to pick up IID michael@0: // so that xpt stuff doesn't try to define it itself... michael@0: #include "xpt_struct.h" michael@0: #include "xpt_xdr.h" michael@0: michael@0: #include "nsIInterfaceInfo.h" michael@0: #include "nsIInterfaceInfoManager.h" michael@0: #include "xptinfo.h" michael@0: michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIDirectoryService.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsIWeakReference.h" michael@0: michael@0: #include "mozilla/ReentrantMonitor.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #include "nsCRT.h" michael@0: #include "nsMemory.h" michael@0: michael@0: #include "nsCOMArray.h" michael@0: #include "nsQuickSort.h" michael@0: michael@0: #include "nsXPIDLString.h" michael@0: michael@0: #include "nsIInputStream.h" michael@0: michael@0: #include "nsHashKeys.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "plstr.h" michael@0: #include "prprf.h" michael@0: #include "prio.h" michael@0: #include "prtime.h" michael@0: #include "prenv.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: #if 0 && defined(DEBUG_jband) michael@0: #define LOG_RESOLVE(x) printf x michael@0: #define LOG_LOAD(x) printf x michael@0: #define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0) michael@0: #else michael@0: #define LOG_RESOLVE(x) ((void)0) michael@0: #define LOG_LOAD(x) ((void)0) michael@0: #define LOG_AUTOREG(x) ((void)0) michael@0: #endif michael@0: michael@0: #if 1 && defined(DEBUG_jband) michael@0: #define SHOW_INFO_COUNT_STATS michael@0: #endif michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: class xptiInterfaceInfo; michael@0: class xptiInterfaceEntry; michael@0: class xptiTypelibGuts; michael@0: michael@0: extern XPTArena* gXPTIStructArena; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: // No virtuals. michael@0: // These are always constructed in the struct arena using placement new. michael@0: // dtor need not be called. michael@0: michael@0: class xptiTypelibGuts michael@0: { michael@0: public: michael@0: static xptiTypelibGuts* Create(XPTHeader* aHeader); michael@0: michael@0: XPTHeader* GetHeader() {return mHeader;} michael@0: uint16_t GetEntryCount() const {return mHeader->num_interfaces;} michael@0: michael@0: void SetEntryAt(uint16_t i, xptiInterfaceEntry* ptr) michael@0: { michael@0: NS_ASSERTION(mHeader,"bad state!"); michael@0: NS_ASSERTION(i < GetEntryCount(),"bad param!"); michael@0: mEntryArray[i] = ptr; michael@0: } michael@0: michael@0: xptiInterfaceEntry* GetEntryAt(uint16_t i); michael@0: michael@0: private: michael@0: xptiTypelibGuts(XPTHeader* aHeader) michael@0: : mHeader(aHeader) michael@0: { } michael@0: ~xptiTypelibGuts(); michael@0: michael@0: private: michael@0: XPTHeader* mHeader; // hold pointer into arena michael@0: xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit. michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: // This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value michael@0: // and a set of bitflags in one 8bit value. See below. michael@0: michael@0: class xptiInfoFlags michael@0: { michael@0: enum {STATE_MASK = 3}; michael@0: public: michael@0: xptiInfoFlags(uint8_t n) : mData(n) {} michael@0: xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {} michael@0: michael@0: static uint8_t GetStateMask() michael@0: {return uint8_t(STATE_MASK);} michael@0: michael@0: void Clear() michael@0: {mData = 0;} michael@0: michael@0: uint8_t GetData() const michael@0: {return mData;} michael@0: michael@0: uint8_t GetState() const michael@0: {return mData & GetStateMask();} michael@0: michael@0: void SetState(uint8_t state) michael@0: {mData &= ~GetStateMask(); mData |= state;} michael@0: michael@0: void SetFlagBit(uint8_t flag, bool on) michael@0: {if(on) michael@0: mData |= ~GetStateMask() & flag; michael@0: else michael@0: mData &= GetStateMask() | ~flag;} michael@0: michael@0: bool GetFlagBit(uint8_t flag) const michael@0: {return (mData & flag) ? true : false;} michael@0: michael@0: private: michael@0: uint8_t mData; michael@0: }; michael@0: michael@0: /****************************************************/ michael@0: michael@0: // No virtual methods. michael@0: // We always create in the struct arena and construct using "placement new". michael@0: // No members need dtor calls. michael@0: michael@0: class xptiInterfaceEntry michael@0: { michael@0: public: michael@0: static xptiInterfaceEntry* Create(const char* name, michael@0: const nsID& iid, michael@0: XPTInterfaceDescriptor* aDescriptor, michael@0: xptiTypelibGuts* aTypelib); michael@0: michael@0: enum { michael@0: PARTIALLY_RESOLVED = 1, michael@0: FULLY_RESOLVED = 2, michael@0: RESOLVE_FAILED = 3 michael@0: }; michael@0: michael@0: // Additional bit flags... michael@0: enum {SCRIPTABLE = 4, BUILTINCLASS = 8}; michael@0: michael@0: uint8_t GetResolveState() const {return mFlags.GetState();} michael@0: michael@0: bool IsFullyResolved() const michael@0: {return GetResolveState() == (uint8_t) FULLY_RESOLVED;} michael@0: michael@0: void SetScriptableFlag(bool on) michael@0: {mFlags.SetFlagBit(uint8_t(SCRIPTABLE),on);} michael@0: bool GetScriptableFlag() const michael@0: {return mFlags.GetFlagBit(uint8_t(SCRIPTABLE));} michael@0: void SetBuiltinClassFlag(bool on) michael@0: {mFlags.SetFlagBit(uint8_t(BUILTINCLASS),on);} michael@0: bool GetBuiltinClassFlag() const michael@0: {return mFlags.GetFlagBit(uint8_t(BUILTINCLASS));} michael@0: michael@0: const nsID* GetTheIID() const {return &mIID;} michael@0: const char* GetTheName() const {return mName;} michael@0: michael@0: bool EnsureResolved() michael@0: {return IsFullyResolved() ? true : Resolve();} michael@0: michael@0: already_AddRefed InterfaceInfo(); michael@0: bool InterfaceInfoEquals(const xptiInterfaceInfo* info) const michael@0: {return info == mInfo;} michael@0: michael@0: void LockedInvalidateInterfaceInfo(); michael@0: void LockedInterfaceInfoDeathNotification() {mInfo = nullptr;} michael@0: michael@0: xptiInterfaceEntry* Parent() const { michael@0: NS_ASSERTION(IsFullyResolved(), "Parent() called while not resolved?"); michael@0: return mParent; michael@0: } michael@0: michael@0: const nsID& IID() const { return mIID; } michael@0: michael@0: ////////////////////// michael@0: // These non-virtual methods handle the delegated nsIInterfaceInfo methods. michael@0: michael@0: nsresult GetName(char * *aName); michael@0: nsresult GetIID(nsIID * *aIID); michael@0: nsresult IsScriptable(bool *_retval); michael@0: nsresult IsBuiltinClass(bool *_retval) { michael@0: *_retval = GetBuiltinClassFlag(); michael@0: return NS_OK; michael@0: } michael@0: // Except this one. michael@0: //nsresult GetParent(nsIInterfaceInfo * *aParent); michael@0: nsresult GetMethodCount(uint16_t *aMethodCount); michael@0: nsresult GetConstantCount(uint16_t *aConstantCount); michael@0: nsresult GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info); michael@0: nsresult GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info); michael@0: nsresult GetConstant(uint16_t index, const nsXPTConstant * *constant); michael@0: nsresult GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval); michael@0: nsresult GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval); michael@0: nsresult GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval); michael@0: nsresult GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval); michael@0: nsresult GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval); michael@0: nsresult IsIID(const nsIID * IID, bool *_retval); michael@0: nsresult GetNameShared(const char **name); michael@0: nsresult GetIIDShared(const nsIID * *iid); michael@0: nsresult IsFunction(bool *_retval); michael@0: nsresult HasAncestor(const nsIID * iid, bool *_retval); michael@0: nsresult GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid); michael@0: michael@0: private: michael@0: xptiInterfaceEntry(const char* name, michael@0: size_t nameLength, michael@0: const nsID& iid, michael@0: XPTInterfaceDescriptor* aDescriptor, michael@0: xptiTypelibGuts* aTypelib); michael@0: ~xptiInterfaceEntry(); michael@0: michael@0: void SetResolvedState(int state) michael@0: {mFlags.SetState(uint8_t(state));} michael@0: michael@0: bool Resolve(); michael@0: michael@0: // We only call these "*Locked" variants after locking. This is done to michael@0: // allow reentrace as files are loaded and various interfaces resolved michael@0: // without having to worry about the locked state. michael@0: michael@0: bool EnsureResolvedLocked() michael@0: {return IsFullyResolved() ? true : ResolveLocked();} michael@0: bool ResolveLocked(); michael@0: michael@0: // private helpers michael@0: michael@0: nsresult GetEntryForParam(uint16_t methodIndex, michael@0: const nsXPTParamInfo * param, michael@0: xptiInterfaceEntry** entry); michael@0: michael@0: nsresult GetTypeInArray(const nsXPTParamInfo* param, michael@0: uint16_t dimension, michael@0: const XPTTypeDescriptor** type); michael@0: michael@0: private: michael@0: nsID mIID; michael@0: XPTInterfaceDescriptor* mDescriptor; michael@0: michael@0: uint16_t mMethodBaseIndex; michael@0: uint16_t mConstantBaseIndex; michael@0: xptiTypelibGuts* mTypelib; michael@0: michael@0: xptiInterfaceEntry* mParent; // Valid only when fully resolved michael@0: michael@0: xptiInterfaceInfo* mInfo; // May come and go. michael@0: xptiInfoFlags mFlags; michael@0: char mName[1]; // Always last. Sized to fit. michael@0: }; michael@0: michael@0: class xptiInterfaceInfo MOZ_FINAL : public nsIInterfaceInfo michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: // Use delegation to implement (most!) of nsIInterfaceInfo. michael@0: NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); } michael@0: NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); } michael@0: NS_IMETHOD IsScriptable(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); } michael@0: NS_IMETHOD IsBuiltinClass(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); } michael@0: // Except this one. michael@0: NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) michael@0: { michael@0: if(!EnsureResolved() || !EnsureParent()) michael@0: return NS_ERROR_UNEXPECTED; michael@0: NS_IF_ADDREF(*aParent = mParent); michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); } michael@0: NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); } michael@0: NS_IMETHOD GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); } michael@0: NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); } michael@0: NS_IMETHOD GetConstant(uint16_t index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); } michael@0: NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); } michael@0: NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); } michael@0: NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); } michael@0: NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); } michael@0: NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); } michael@0: NS_IMETHOD IsIID(const nsIID * IID, bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); } michael@0: NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); } michael@0: NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); } michael@0: NS_IMETHOD IsFunction(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); } michael@0: NS_IMETHOD HasAncestor(const nsIID * iid, bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); } michael@0: NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); } michael@0: michael@0: public: michael@0: xptiInterfaceInfo(xptiInterfaceEntry* entry); michael@0: michael@0: void Invalidate() michael@0: {NS_IF_RELEASE(mParent); mEntry = nullptr;} michael@0: michael@0: private: michael@0: michael@0: ~xptiInterfaceInfo(); michael@0: michael@0: // Note that mParent might still end up as nullptr if we don't have one. michael@0: bool EnsureParent() michael@0: { michael@0: NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call"); michael@0: return mParent || !mEntry->Parent() || BuildParent(); michael@0: } michael@0: michael@0: bool EnsureResolved() michael@0: { michael@0: return mEntry && mEntry->EnsureResolved(); michael@0: } michael@0: michael@0: bool BuildParent(); michael@0: michael@0: xptiInterfaceInfo(); // not implemented michael@0: michael@0: private: michael@0: xptiInterfaceEntry* mEntry; michael@0: xptiInterfaceInfo* mParent; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: #endif /* xptiprivate_h___ */