1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Mike McCabe <mccabe@netscape.com>
24 : * John Bandhauer <jband@netscape.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* Library-private header for Interface Info system. */
41 :
42 : #ifndef xptiprivate_h___
43 : #define xptiprivate_h___
44 :
45 : #include "nscore.h"
46 : #include NEW_H
47 : #include "nsISupports.h"
48 :
49 : // this after nsISupports, to pick up IID
50 : // so that xpt stuff doesn't try to define it itself...
51 : #include "xpt_struct.h"
52 : #include "xpt_xdr.h"
53 :
54 : #include "nsIInterfaceInfo.h"
55 : #include "nsIInterfaceInfoManager.h"
56 : #include "xptinfo.h"
57 :
58 : #include "nsIServiceManager.h"
59 : #include "nsILocalFile.h"
60 : #include "nsIDirectoryService.h"
61 : #include "nsDirectoryServiceDefs.h"
62 : #include "nsAppDirectoryServiceDefs.h"
63 : #include "nsIWeakReference.h"
64 :
65 : #include "mozilla/ReentrantMonitor.h"
66 : #include "mozilla/Mutex.h"
67 :
68 : #include "nsCRT.h"
69 : #include "nsMemory.h"
70 :
71 : #include "nsCOMArray.h"
72 : #include "nsQuickSort.h"
73 :
74 : #include "nsXPIDLString.h"
75 :
76 : #include "nsIInputStream.h"
77 :
78 : #include "nsHashKeys.h"
79 : #include "nsDataHashtable.h"
80 : #include "plstr.h"
81 : #include "prprf.h"
82 : #include "prio.h"
83 : #include "prtime.h"
84 : #include "prenv.h"
85 :
86 : #include <stdio.h>
87 : #include <stdarg.h>
88 :
89 : /***************************************************************************/
90 :
91 : #if 0 && defined(DEBUG_jband)
92 : #define LOG_RESOLVE(x) printf x
93 : #define LOG_LOAD(x) printf x
94 : #define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0)
95 : #else
96 : #define LOG_RESOLVE(x) ((void)0)
97 : #define LOG_LOAD(x) ((void)0)
98 : #define LOG_AUTOREG(x) ((void)0)
99 : #endif
100 :
101 : #if 1 && defined(DEBUG_jband)
102 : #define SHOW_INFO_COUNT_STATS
103 : #endif
104 :
105 : /***************************************************************************/
106 :
107 : class xptiInterfaceInfo;
108 : class xptiInterfaceInfoManager;
109 : class xptiInterfaceEntry;
110 : class xptiTypelibGuts;
111 : class xptiWorkingSet;
112 :
113 : extern XPTArena* gXPTIStructArena;
114 :
115 : /***************************************************************************/
116 :
117 : /***************************************************************************/
118 :
119 : // No virtuals.
120 : // These are always constructed in the struct arena using placement new.
121 : // dtor need not be called.
122 :
123 : class xptiTypelibGuts
124 : {
125 : public:
126 : static xptiTypelibGuts* Create(XPTHeader* aHeader);
127 :
128 : XPTHeader* GetHeader() {return mHeader;}
129 5070580 : PRUint16 GetEntryCount() const {return mHeader->num_interfaces;}
130 :
131 2207705 : void SetEntryAt(PRUint16 i, xptiInterfaceEntry* ptr)
132 : {
133 2207705 : NS_ASSERTION(mHeader,"bad state!");
134 2207705 : NS_ASSERTION(i < GetEntryCount(),"bad param!");
135 2207705 : mEntryArray[i] = ptr;
136 2207705 : }
137 :
138 : xptiInterfaceEntry* GetEntryAt(PRUint16 i);
139 :
140 : private:
141 218497 : xptiTypelibGuts(XPTHeader* aHeader)
142 218497 : : mHeader(aHeader)
143 218497 : { }
144 : ~xptiTypelibGuts();
145 :
146 : private:
147 : XPTHeader* mHeader; // hold pointer into arena
148 : xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit.
149 : };
150 :
151 : /***************************************************************************/
152 :
153 : class xptiWorkingSet
154 : {
155 : public:
156 : xptiWorkingSet();
157 : ~xptiWorkingSet();
158 :
159 : bool IsValid() const;
160 :
161 : void InvalidateInterfaceInfos();
162 : void ClearHashTables();
163 :
164 : // utility methods...
165 :
166 : enum {NOT_FOUND = 0xffffffff};
167 :
168 : // Directory stuff...
169 :
170 : PRUint32 GetDirectoryCount();
171 : nsresult GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir);
172 : nsresult GetDirectoryAt(PRUint32 i, nsILocalFile** dir);
173 : bool FindDirectory(nsILocalFile* dir, PRUint32* index);
174 : bool FindDirectoryOfFile(nsILocalFile* file, PRUint32* index);
175 : bool DirectoryAtMatchesPersistentDescriptor(PRUint32 i, const char* desc);
176 :
177 : private:
178 : PRUint32 mFileCount;
179 : PRUint32 mMaxFileCount;
180 :
181 : public:
182 : // XXX make these private with accessors
183 : // mTableMonitor must be held across:
184 : // * any read from or write to mIIDTable or mNameTable
185 : // * any writing to the links between an xptiInterfaceEntry
186 : // and its xptiInterfaceInfo (mEntry/mInfo)
187 : mozilla::ReentrantMonitor mTableReentrantMonitor;
188 : nsDataHashtable<nsIDHashKey, xptiInterfaceEntry*> mIIDTable;
189 : nsDataHashtable<nsDepCharHashKey, xptiInterfaceEntry*> mNameTable;
190 : };
191 :
192 : /***************************************************************************/
193 :
194 : // This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value
195 : // and a set of bitflags in one 8bit value. See below.
196 :
197 : class xptiInfoFlags
198 : {
199 : enum {STATE_MASK = 3};
200 : public:
201 2159718 : xptiInfoFlags(PRUint8 n) : mData(n) {}
202 : xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {}
203 :
204 25879516 : static PRUint8 GetStateMask()
205 25879516 : {return PRUint8(STATE_MASK);}
206 :
207 : void Clear()
208 : {mData = 0;}
209 :
210 : PRUint8 GetData() const
211 : {return mData;}
212 :
213 19201103 : PRUint8 GetState() const
214 19201103 : {return mData & GetStateMask();}
215 :
216 2358977 : void SetState(PRUint8 state)
217 2358977 : {mData &= ~GetStateMask(); mData |= state;}
218 :
219 4319436 : void SetFlagBit(PRUint8 flag, bool on)
220 4319436 : {if(on)
221 2162556 : mData |= ~GetStateMask() & flag;
222 : else
223 2156880 : mData &= GetStateMask() | ~flag;}
224 :
225 595387 : bool GetFlagBit(PRUint8 flag) const
226 595387 : {return (mData & flag) ? true : false;}
227 :
228 : private:
229 : PRUint8 mData;
230 : };
231 :
232 : /****************************************************/
233 :
234 : // No virtual methods.
235 : // We always create in the struct arena and construct using "placement new".
236 : // No members need dtor calls.
237 :
238 : class xptiInterfaceEntry
239 : {
240 : public:
241 : static xptiInterfaceEntry* Create(const char* name,
242 : const nsID& iid,
243 : XPTInterfaceDescriptor* aDescriptor,
244 : xptiTypelibGuts* aTypelib);
245 :
246 : enum {
247 : PARTIALLY_RESOLVED = 1,
248 : FULLY_RESOLVED = 2,
249 : RESOLVE_FAILED = 3
250 : };
251 :
252 : // Additional bit flags...
253 : enum {SCRIPTABLE = 4, BUILTINCLASS = 8};
254 :
255 19201103 : PRUint8 GetResolveState() const {return mFlags.GetState();}
256 :
257 18802585 : bool IsFullyResolved() const
258 18802585 : {return GetResolveState() == (PRUint8) FULLY_RESOLVED;}
259 :
260 2159718 : void SetScriptableFlag(bool on)
261 2159718 : {mFlags.SetFlagBit(PRUint8(SCRIPTABLE),on);}
262 394017 : bool GetScriptableFlag() const
263 394017 : {return mFlags.GetFlagBit(PRUint8(SCRIPTABLE));}
264 2159718 : void SetBuiltinClassFlag(bool on)
265 2159718 : {mFlags.SetFlagBit(PRUint8(BUILTINCLASS),on);}
266 201370 : bool GetBuiltinClassFlag() const
267 201370 : {return mFlags.GetFlagBit(PRUint8(BUILTINCLASS));}
268 :
269 : const nsID* GetTheIID() const {return &mIID;}
270 2625450 : const char* GetTheName() const {return mName;}
271 :
272 17864737 : bool EnsureResolved()
273 17864737 : {return IsFullyResolved() ? true : Resolve();}
274 :
275 : nsresult GetInterfaceInfo(xptiInterfaceInfo** info);
276 518726 : bool InterfaceInfoEquals(const xptiInterfaceInfo* info) const
277 518726 : {return info == mInfo;}
278 :
279 : void LockedInvalidateInterfaceInfo();
280 518726 : void LockedInterfaceInfoDeathNotification() {mInfo = nsnull;}
281 :
282 372839 : xptiInterfaceEntry* Parent() const {
283 372839 : NS_ASSERTION(IsFullyResolved(), "Parent() called while not resolved?");
284 372839 : return mParent;
285 : }
286 :
287 3352478 : const nsID& IID() const { return mIID; }
288 :
289 : //////////////////////
290 : // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
291 :
292 : nsresult GetName(char * *aName);
293 : nsresult GetIID(nsIID * *aIID);
294 : nsresult IsScriptable(bool *_retval);
295 94566 : nsresult IsBuiltinClass(bool *_retval) {
296 94566 : *_retval = GetBuiltinClassFlag();
297 94566 : return NS_OK;
298 : }
299 : // Except this one.
300 : //nsresult GetParent(nsIInterfaceInfo * *aParent);
301 : nsresult GetMethodCount(PRUint16 *aMethodCount);
302 : nsresult GetConstantCount(PRUint16 *aConstantCount);
303 : nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info);
304 : nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info);
305 : nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant);
306 : nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval);
307 : nsresult GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval);
308 : nsresult GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval);
309 : nsresult GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval);
310 : nsresult GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval);
311 : nsresult IsIID(const nsIID * IID, bool *_retval);
312 : nsresult GetNameShared(const char **name);
313 : nsresult GetIIDShared(const nsIID * *iid);
314 : nsresult IsFunction(bool *_retval);
315 : nsresult HasAncestor(const nsIID * iid, bool *_retval);
316 : nsresult GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid);
317 :
318 : private:
319 : xptiInterfaceEntry(const char* name,
320 : size_t nameLength,
321 : const nsID& iid,
322 : XPTInterfaceDescriptor* aDescriptor,
323 : xptiTypelibGuts* aTypelib);
324 : ~xptiInterfaceEntry();
325 :
326 2358977 : void SetResolvedState(int state)
327 2358977 : {mFlags.SetState(PRUint8(state));}
328 :
329 : bool Resolve();
330 :
331 : // We only call these "*Locked" variants after locking. This is done to
332 : // allow reentrace as files are loaded and various interfaces resolved
333 : // without having to worry about the locked state.
334 :
335 197824 : bool EnsureResolvedLocked()
336 197824 : {return IsFullyResolved() ? true : ResolveLocked();}
337 : bool ResolveLocked();
338 :
339 : // private helpers
340 :
341 : nsresult GetEntryForParam(PRUint16 methodIndex,
342 : const nsXPTParamInfo * param,
343 : xptiInterfaceEntry** entry);
344 :
345 : nsresult GetTypeInArray(const nsXPTParamInfo* param,
346 : PRUint16 dimension,
347 : const XPTTypeDescriptor** type);
348 :
349 : private:
350 : nsID mIID;
351 : XPTInterfaceDescriptor* mDescriptor;
352 :
353 : PRUint16 mMethodBaseIndex;
354 : PRUint16 mConstantBaseIndex;
355 : xptiTypelibGuts* mTypelib;
356 :
357 : xptiInterfaceEntry* mParent; // Valid only when fully resolved
358 :
359 : xptiInterfaceInfo* mInfo; // May come and go.
360 : xptiInfoFlags mFlags;
361 : char mName[1]; // Always last. Sized to fit.
362 : };
363 :
364 : class xptiInterfaceInfo : public nsIInterfaceInfo
365 : {
366 : public:
367 : NS_DECL_ISUPPORTS
368 :
369 : // Use delegation to implement (most!) of nsIInterfaceInfo.
370 43735 : NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); }
371 0 : NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); }
372 394017 : NS_IMETHOD IsScriptable(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); }
373 94566 : NS_IMETHOD IsBuiltinClass(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); }
374 : // Except this one.
375 127481 : NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent)
376 : {
377 127481 : if(!EnsureResolved() || !EnsureParent())
378 0 : return NS_ERROR_UNEXPECTED;
379 127481 : NS_IF_ADDREF(*aParent = mParent);
380 127481 : return NS_OK;
381 : }
382 160071 : NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); }
383 127559 : NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); }
384 9477170 : NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); }
385 0 : NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); }
386 408273 : NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); }
387 0 : NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); }
388 0 : NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); }
389 116380 : NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); }
390 78222 : NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); }
391 37143 : NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); }
392 109454 : NS_IMETHOD IsIID(const nsIID * IID, bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); }
393 543837 : NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); }
394 4691180 : NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); }
395 448172 : NS_IMETHOD IsFunction(bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); }
396 360310 : NS_IMETHOD HasAncestor(const nsIID * iid, bool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); }
397 2665051 : NS_IMETHOD GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); }
398 :
399 : public:
400 : xptiInterfaceInfo(xptiInterfaceEntry* entry);
401 :
402 25 : void Invalidate()
403 25 : {NS_IF_RELEASE(mParent); mEntry = nsnull;}
404 :
405 : private:
406 :
407 : ~xptiInterfaceInfo();
408 :
409 : // Note that mParent might still end up as nsnull if we don't have one.
410 127481 : bool EnsureParent()
411 : {
412 127481 : NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call");
413 127481 : return mParent || !mEntry->Parent() || BuildParent();
414 : }
415 :
416 127481 : bool EnsureResolved()
417 : {
418 127481 : return mEntry && mEntry->EnsureResolved();
419 : }
420 :
421 : bool BuildParent();
422 :
423 : xptiInterfaceInfo(); // not implemented
424 :
425 : private:
426 : xptiInterfaceEntry* mEntry;
427 : xptiInterfaceInfo* mParent;
428 : };
429 :
430 : /***************************************************************************/
431 :
432 : class xptiInterfaceInfoManager
433 : : public nsIInterfaceInfoSuperManager
434 : {
435 : NS_DECL_ISUPPORTS
436 : NS_DECL_NSIINTERFACEINFOMANAGER
437 : NS_DECL_NSIINTERFACEINFOSUPERMANAGER
438 :
439 : typedef mozilla::ReentrantMonitor ReentrantMonitor;
440 : typedef mozilla::Mutex Mutex;
441 :
442 : public:
443 : // GetSingleton() is infallible
444 : static xptiInterfaceInfoManager* GetSingleton();
445 : static void FreeInterfaceInfoManager();
446 :
447 : void RegisterBuffer(char *buf, PRUint32 length);
448 :
449 1459047 : xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;}
450 :
451 182456 : static Mutex& GetResolveLock(xptiInterfaceInfoManager* self = nsnull)
452 : {
453 182456 : self = self ? self : GetSingleton();
454 182456 : return self->mResolveLock;
455 : }
456 :
457 : xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid);
458 :
459 : private:
460 : xptiInterfaceInfoManager();
461 : ~xptiInterfaceInfoManager();
462 :
463 : void RegisterXPTHeader(XPTHeader* aHeader);
464 :
465 : // idx is the index of this interface in the XPTHeader
466 : void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
467 : PRUint16 idx,
468 : xptiTypelibGuts* typelib);
469 :
470 : private:
471 : xptiWorkingSet mWorkingSet;
472 : Mutex mResolveLock;
473 : Mutex mAdditionalManagersLock;
474 : nsCOMArray<nsISupports> mAdditionalManagers;
475 : };
476 :
477 : #endif /* xptiprivate_h___ */
|