1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* Library-private header for Interface Info system. */ 7 8 #ifndef xptiprivate_h___ 9 #define xptiprivate_h___ 10 11 #include "nscore.h" 12 #include <new> 13 #include "nsISupports.h" 14 15 // this after nsISupports, to pick up IID 16 // so that xpt stuff doesn't try to define it itself... 17 #include "xpt_struct.h" 18 #include "xpt_xdr.h" 19 20 #include "nsIInterfaceInfo.h" 21 #include "nsIInterfaceInfoManager.h" 22 #include "xptinfo.h" 23 #include "ShimInterfaceInfo.h" 24 25 #include "nsIServiceManager.h" 26 #include "nsIFile.h" 27 #include "nsIDirectoryService.h" 28 #include "nsDirectoryServiceDefs.h" 29 #include "nsAppDirectoryServiceDefs.h" 30 #include "nsIWeakReference.h" 31 32 #include "mozilla/ReentrantMonitor.h" 33 #include "mozilla/Mutex.h" 34 #include "mozilla/Attributes.h" 35 36 #include "js/TypeDecls.h" 37 38 #include "nsCRT.h" 39 #include "nsMemory.h" 40 41 #include "nsCOMArray.h" 42 #include "nsQuickSort.h" 43 44 #include "nsString.h" 45 46 #include "nsIInputStream.h" 47 48 #include "nsHashKeys.h" 49 #include "nsDataHashtable.h" 50 #include "plstr.h" 51 #include "prprf.h" 52 #include "prio.h" 53 #include "prtime.h" 54 #include "prenv.h" 55 56 #include <stdio.h> 57 #include <stdarg.h> 58 59 /***************************************************************************/ 60 61 class xptiInterfaceInfo; 62 class xptiInterfaceEntry; 63 class xptiTypelibGuts; 64 65 extern XPTArena *gXPTIStructArena; 66 67 /***************************************************************************/ 68 69 /***************************************************************************/ 70 71 // No virtuals. 72 // These are always constructed in the struct arena using placement new. 73 // dtor need not be called. 74 75 class xptiTypelibGuts { 76 public: 77 static xptiTypelibGuts *Create(const XPTHeader *aHeader); 78 GetEntryCount()79 uint16_t GetEntryCount() const { return mHeader->mNumInterfaces; } 80 SetEntryAt(uint16_t i,xptiInterfaceEntry * ptr)81 void SetEntryAt(uint16_t i, xptiInterfaceEntry *ptr) { 82 NS_ASSERTION(mHeader, "bad state!"); 83 NS_ASSERTION(i < GetEntryCount(), "bad param!"); 84 mEntryArray[i] = ptr; 85 } 86 87 xptiInterfaceEntry *GetEntryAt(uint16_t i); 88 const char *GetEntryNameAt(uint16_t i); 89 90 private: xptiTypelibGuts(const XPTHeader * aHeader)91 explicit xptiTypelibGuts(const XPTHeader *aHeader) : mHeader(aHeader) {} 92 ~xptiTypelibGuts(); 93 94 private: 95 const XPTHeader *mHeader; // hold pointer into arena 96 xptiInterfaceEntry *mEntryArray[1]; // Always last. Sized to fit. 97 }; 98 99 /***************************************************************************/ 100 101 /***************************************************************************/ 102 103 // This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value 104 // and a set of bitflags in one 8bit value. See below. 105 106 class xptiInfoFlags { 107 enum { STATE_MASK = 3 }; 108 109 public: xptiInfoFlags(uint8_t n)110 explicit xptiInfoFlags(uint8_t n) : mData(n) {} xptiInfoFlags(const xptiInfoFlags & r)111 xptiInfoFlags(const xptiInfoFlags &r) : mData(r.mData) {} 112 GetStateMask()113 static uint8_t GetStateMask() { return uint8_t(STATE_MASK); } 114 Clear()115 void Clear() { mData = 0; } 116 GetData()117 uint8_t GetData() const { return mData; } 118 GetState()119 uint8_t GetState() const { return mData & GetStateMask(); } 120 SetState(uint8_t state)121 void SetState(uint8_t state) { 122 mData &= ~GetStateMask(); 123 mData |= state; 124 } 125 SetFlagBit(uint8_t flag,bool on)126 void SetFlagBit(uint8_t flag, bool on) { 127 if (on) 128 mData |= ~GetStateMask() & flag; 129 else 130 mData &= GetStateMask() | ~flag; 131 } 132 GetFlagBit(uint8_t flag)133 bool GetFlagBit(uint8_t flag) const { return (mData & flag) ? true : false; } 134 135 private: 136 uint8_t mData; 137 }; 138 139 /****************************************************/ 140 141 // No virtual methods. 142 // We always create in the struct arena and construct using "placement new". 143 // No members need dtor calls. 144 145 class xptiInterfaceEntry { 146 public: 147 static xptiInterfaceEntry *Create(const char *aName, const nsID &aIID, 148 const XPTInterfaceDescriptor *aDescriptor, 149 xptiTypelibGuts *aTypelib); 150 151 enum { PARTIALLY_RESOLVED = 1, FULLY_RESOLVED = 2, RESOLVE_FAILED = 3 }; 152 153 // Additional bit flags... 154 enum { 155 SCRIPTABLE = 4, 156 BUILTINCLASS = 8, 157 HASNOTXPCOM = 16, 158 MAIN_PROCESS_SCRIPTABLE_ONLY = 32 159 }; 160 GetResolveState()161 uint8_t GetResolveState() const { return mFlags.GetState(); } 162 IsFullyResolved()163 bool IsFullyResolved() const { 164 return GetResolveState() == (uint8_t)FULLY_RESOLVED; 165 } 166 SetScriptableFlag(bool on)167 void SetScriptableFlag(bool on) { 168 mFlags.SetFlagBit(uint8_t(SCRIPTABLE), on); 169 } GetScriptableFlag()170 bool GetScriptableFlag() const { 171 return mFlags.GetFlagBit(uint8_t(SCRIPTABLE)); 172 } SetBuiltinClassFlag(bool on)173 void SetBuiltinClassFlag(bool on) { 174 mFlags.SetFlagBit(uint8_t(BUILTINCLASS), on); 175 } GetBuiltinClassFlag()176 bool GetBuiltinClassFlag() const { 177 return mFlags.GetFlagBit(uint8_t(BUILTINCLASS)); 178 } SetMainProcessScriptableOnlyFlag(bool on)179 void SetMainProcessScriptableOnlyFlag(bool on) { 180 mFlags.SetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY), on); 181 } GetMainProcessScriptableOnlyFlag()182 bool GetMainProcessScriptableOnlyFlag() const { 183 return mFlags.GetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY)); 184 } 185 186 // AddRef/Release are special and are not considered for the NOTXPCOM flag. SetHasNotXPCOMFlag()187 void SetHasNotXPCOMFlag() { mFlags.SetFlagBit(HASNOTXPCOM, true); } GetHasNotXPCOMFlag()188 bool GetHasNotXPCOMFlag() const { return mFlags.GetFlagBit(HASNOTXPCOM); } 189 GetTheIID()190 const nsID *GetTheIID() const { return &mIID; } GetTheName()191 const char *GetTheName() const { return mName; } 192 EnsureResolved()193 bool EnsureResolved() { return IsFullyResolved() ? true : Resolve(); } 194 195 already_AddRefed<xptiInterfaceInfo> InterfaceInfo(); InterfaceInfoEquals(const xptiInterfaceInfo * info)196 bool InterfaceInfoEquals(const xptiInterfaceInfo *info) const { 197 return info == mInfo; 198 } 199 200 void LockedInvalidateInterfaceInfo(); LockedInterfaceInfoDeathNotification()201 void LockedInterfaceInfoDeathNotification() { mInfo = nullptr; } 202 Parent()203 xptiInterfaceEntry *Parent() const { 204 NS_ASSERTION(IsFullyResolved(), "Parent() called while not resolved?"); 205 return mParent; 206 } 207 IID()208 const nsID &IID() const { return mIID; } 209 210 ////////////////////// 211 // These non-virtual methods handle the delegated nsIInterfaceInfo methods. 212 213 nsresult GetName(char **aName); 214 nsresult GetIID(nsIID **aIID); 215 nsresult IsScriptable(bool *_retval); IsBuiltinClass(bool * _retval)216 nsresult IsBuiltinClass(bool *_retval) { 217 *_retval = GetBuiltinClassFlag(); 218 return NS_OK; 219 } IsMainProcessScriptableOnly(bool * _retval)220 nsresult IsMainProcessScriptableOnly(bool *_retval) { 221 *_retval = GetMainProcessScriptableOnlyFlag(); 222 return NS_OK; 223 } 224 // Except this one. 225 // nsresult GetParent(nsIInterfaceInfo * *aParent); 226 nsresult GetMethodCount(uint16_t *aMethodCount); 227 nsresult GetConstantCount(uint16_t *aConstantCount); 228 nsresult GetMethodInfo(uint16_t index, const nsXPTMethodInfo **info); 229 nsresult GetMethodInfoForName(const char *methodName, uint16_t *index, 230 const nsXPTMethodInfo **info); 231 nsresult GetConstant(uint16_t index, JS::MutableHandleValue, char **constant); 232 nsresult GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 233 nsIInterfaceInfo **_retval); 234 nsresult GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 235 nsIID **_retval); 236 nsresult GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 237 uint16_t dimension, nsXPTType *_retval); 238 nsresult GetSizeIsArgNumberForParam(uint16_t methodIndex, 239 const nsXPTParamInfo *param, 240 uint16_t dimension, uint8_t *_retval); 241 nsresult GetInterfaceIsArgNumberForParam(uint16_t methodIndex, 242 const nsXPTParamInfo *param, 243 uint8_t *_retval); 244 nsresult IsIID(const nsIID *IID, bool *_retval); 245 nsresult GetNameShared(const char **name); 246 nsresult GetIIDShared(const nsIID **iid); 247 nsresult IsFunction(bool *_retval); 248 nsresult HasAncestor(const nsIID *iid, bool *_retval); 249 nsresult GetIIDForParamNoAlloc(uint16_t methodIndex, 250 const nsXPTParamInfo *param, nsIID *iid); 251 252 private: 253 xptiInterfaceEntry(const char *aName, const nsID &aIID, 254 const XPTInterfaceDescriptor *aDescriptor, 255 xptiTypelibGuts *aTypelib); 256 ~xptiInterfaceEntry(); 257 SetResolvedState(int state)258 void SetResolvedState(int state) { mFlags.SetState(uint8_t(state)); } 259 260 bool Resolve(); 261 262 // We only call these "*Locked" variants after locking. This is done to 263 // allow reentrace as files are loaded and various interfaces resolved 264 // without having to worry about the locked state. 265 EnsureResolvedLocked()266 bool EnsureResolvedLocked() { 267 return IsFullyResolved() ? true : ResolveLocked(); 268 } 269 bool ResolveLocked(); 270 271 // private helpers 272 273 nsresult GetEntryForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 274 xptiInterfaceEntry **entry); 275 276 nsresult GetTypeInArray(const nsXPTParamInfo *param, uint16_t dimension, 277 const XPTTypeDescriptor **type); 278 279 nsresult GetInterfaceIndexForParam(uint16_t methodIndex, 280 const nsXPTParamInfo *param, 281 uint16_t *interfaceIndex); 282 283 already_AddRefed<ShimInterfaceInfo> GetShimForParam( 284 uint16_t methodIndex, const nsXPTParamInfo *param); 285 286 private: 287 nsID mIID; 288 const XPTInterfaceDescriptor *mDescriptor; 289 290 xptiTypelibGuts *mTypelib; 291 292 xptiInterfaceEntry *mParent; // Valid only when fully resolved 293 294 xptiInterfaceInfo *MOZ_UNSAFE_REF( 295 "The safety of this pointer is ensured " 296 "by the semantics of xptiWorkingSet.") mInfo; // May come and go. 297 298 uint16_t mMethodBaseIndex; 299 uint16_t mConstantBaseIndex; 300 301 xptiInfoFlags mFlags; 302 303 const char *mName; 304 }; 305 306 class xptiInterfaceInfo final : public nsIInterfaceInfo { 307 public: 308 NS_DECL_THREADSAFE_ISUPPORTS 309 310 // Use delegation to implement (most!) of nsIInterfaceInfo. GetName(char ** aName)311 NS_IMETHOD GetName(char **aName) override { 312 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); 313 } GetInterfaceIID(nsIID ** aIID)314 NS_IMETHOD GetInterfaceIID(nsIID **aIID) override { 315 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); 316 } IsScriptable(bool * _retval)317 NS_IMETHOD IsScriptable(bool *_retval) override { 318 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); 319 } IsBuiltinClass(bool * _retval)320 NS_IMETHOD IsBuiltinClass(bool *_retval) override { 321 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); 322 } IsMainProcessScriptableOnly(bool * _retval)323 NS_IMETHOD IsMainProcessScriptableOnly(bool *_retval) override { 324 return !mEntry ? NS_ERROR_UNEXPECTED 325 : mEntry->IsMainProcessScriptableOnly(_retval); 326 } 327 // Except this one. GetParent(nsIInterfaceInfo ** aParent)328 NS_IMETHOD GetParent(nsIInterfaceInfo **aParent) override { 329 if (!EnsureResolved() || !EnsureParent()) return NS_ERROR_UNEXPECTED; 330 NS_IF_ADDREF(*aParent = mParent); 331 return NS_OK; 332 } GetMethodCount(uint16_t * aMethodCount)333 NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) override { 334 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); 335 } GetConstantCount(uint16_t * aConstantCount)336 NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) override { 337 return !mEntry ? NS_ERROR_UNEXPECTED 338 : mEntry->GetConstantCount(aConstantCount); 339 } GetMethodInfo(uint16_t index,const nsXPTMethodInfo ** info)340 NS_IMETHOD GetMethodInfo(uint16_t index, 341 const nsXPTMethodInfo **info) override { 342 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); 343 } GetMethodInfoForName(const char * methodName,uint16_t * index,const nsXPTMethodInfo ** info)344 NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index, 345 const nsXPTMethodInfo **info) override { 346 return !mEntry ? NS_ERROR_UNEXPECTED 347 : mEntry->GetMethodInfoForName(methodName, index, info); 348 } GetConstant(uint16_t index,JS::MutableHandleValue constant,char ** name)349 NS_IMETHOD GetConstant(uint16_t index, JS::MutableHandleValue constant, 350 char **name) override { 351 return !mEntry ? NS_ERROR_UNEXPECTED 352 : mEntry->GetConstant(index, constant, name); 353 } GetInfoForParam(uint16_t methodIndex,const nsXPTParamInfo * param,nsIInterfaceInfo ** _retval)354 NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 355 nsIInterfaceInfo **_retval) override { 356 return !mEntry ? NS_ERROR_UNEXPECTED 357 : mEntry->GetInfoForParam(methodIndex, param, _retval); 358 } GetIIDForParam(uint16_t methodIndex,const nsXPTParamInfo * param,nsIID ** _retval)359 NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 360 nsIID **_retval) override { 361 return !mEntry ? NS_ERROR_UNEXPECTED 362 : mEntry->GetIIDForParam(methodIndex, param, _retval); 363 } GetTypeForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint16_t dimension,nsXPTType * _retval)364 NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo *param, 365 uint16_t dimension, nsXPTType *_retval) override { 366 return !mEntry ? NS_ERROR_UNEXPECTED 367 : mEntry->GetTypeForParam(methodIndex, param, dimension, 368 _retval); 369 } GetSizeIsArgNumberForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint16_t dimension,uint8_t * _retval)370 NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex, 371 const nsXPTParamInfo *param, 372 uint16_t dimension, 373 uint8_t *_retval) override { 374 return !mEntry ? NS_ERROR_UNEXPECTED 375 : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, 376 dimension, _retval); 377 } GetInterfaceIsArgNumberForParam(uint16_t methodIndex,const nsXPTParamInfo * param,uint8_t * _retval)378 NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex, 379 const nsXPTParamInfo *param, 380 uint8_t *_retval) override { 381 return !mEntry ? NS_ERROR_UNEXPECTED 382 : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, 383 _retval); 384 } IsIID(const nsIID * IID,bool * _retval)385 NS_IMETHOD IsIID(const nsIID *IID, bool *_retval) override { 386 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); 387 } GetNameShared(const char ** name)388 NS_IMETHOD GetNameShared(const char **name) override { 389 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); 390 } GetIIDShared(const nsIID ** iid)391 NS_IMETHOD GetIIDShared(const nsIID **iid) override { 392 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); 393 } IsFunction(bool * _retval)394 NS_IMETHOD IsFunction(bool *_retval) override { 395 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); 396 } HasAncestor(const nsIID * iid,bool * _retval)397 NS_IMETHOD HasAncestor(const nsIID *iid, bool *_retval) override { 398 return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); 399 } GetIIDForParamNoAlloc(uint16_t methodIndex,const nsXPTParamInfo * param,nsIID * iid)400 NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex, 401 const nsXPTParamInfo *param, 402 nsIID *iid) override { 403 return !mEntry ? NS_ERROR_UNEXPECTED 404 : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); 405 } 406 407 public: 408 explicit xptiInterfaceInfo(xptiInterfaceEntry *entry); 409 410 void Invalidate(); 411 412 private: 413 ~xptiInterfaceInfo(); 414 415 // Note that mParent might still end up as nullptr if we don't have one. EnsureParent()416 bool EnsureParent() { 417 NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call"); 418 return mParent || !mEntry->Parent() || BuildParent(); 419 } 420 EnsureResolved()421 bool EnsureResolved() { return mEntry && mEntry->EnsureResolved(); } 422 423 bool BuildParent(); 424 425 xptiInterfaceInfo(); // not implemented 426 427 private: 428 xptiInterfaceEntry *mEntry; 429 RefPtr<xptiInterfaceInfo> mParent; 430 }; 431 432 /***************************************************************************/ 433 434 #endif /* xptiprivate_h___ */ 435