Back to index

lightning-sunbird  0.9+nobinonly
xpcwrappednativescope.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1999
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   John Bandhauer <jband@netscape.com> (original author)
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /* Class used to manage the wrapped native objects within a JS scope. */
00042 
00043 #include "xpcprivate.h"
00044 #include "XPCNativeWrapper.h"
00045 
00046 /***************************************************************************/
00047 
00048 #ifdef XPC_TRACK_SCOPE_STATS
00049 static int DEBUG_TotalScopeCount;
00050 static int DEBUG_TotalLiveScopeCount;
00051 static int DEBUG_TotalMaxScopeCount;
00052 static int DEBUG_TotalScopeTraversalCount;
00053 static PRBool  DEBUG_DumpedStats;
00054 #endif
00055 
00056 #ifdef DEBUG
00057 static void DEBUG_TrackNewScope(XPCWrappedNativeScope* scope)
00058 {
00059 #ifdef XPC_TRACK_SCOPE_STATS
00060     DEBUG_TotalScopeCount++;
00061     DEBUG_TotalLiveScopeCount++;
00062     if(DEBUG_TotalMaxScopeCount < DEBUG_TotalLiveScopeCount)
00063         DEBUG_TotalMaxScopeCount = DEBUG_TotalLiveScopeCount;
00064 #endif
00065 }
00066 
00067 static void DEBUG_TrackDeleteScope(XPCWrappedNativeScope* scope)
00068 {
00069 #ifdef XPC_TRACK_SCOPE_STATS
00070     DEBUG_TotalLiveScopeCount--;
00071 #endif
00072 }
00073 
00074 static void DEBUG_TrackScopeTraversal()
00075 {
00076 #ifdef XPC_TRACK_SCOPE_STATS
00077     DEBUG_TotalScopeTraversalCount++;
00078 #endif
00079 }
00080 
00081 static void DEBUG_TrackScopeShutdown()
00082 {
00083 #ifdef XPC_TRACK_SCOPE_STATS
00084     if(!DEBUG_DumpedStats)
00085     {
00086         DEBUG_DumpedStats = PR_TRUE;
00087         printf("%d XPCWrappedNativeScope(s) were constructed.\n",
00088                DEBUG_TotalScopeCount);
00089 
00090         printf("%d XPCWrappedNativeScopes(s) max alive at one time.\n",
00091                DEBUG_TotalMaxScopeCount);
00092 
00093         printf("%d XPCWrappedNativeScope(s) alive now.\n" ,
00094                DEBUG_TotalLiveScopeCount);
00095 
00096         printf("%d traversals of Scope list.\n",
00097                DEBUG_TotalScopeTraversalCount);
00098     }
00099 #endif
00100 }
00101 #else
00102 #define DEBUG_TrackNewScope(scope) ((void)0)
00103 #define DEBUG_TrackDeleteScope(scope) ((void)0)
00104 #define DEBUG_TrackScopeTraversal() ((void)0)
00105 #define DEBUG_TrackScopeShutdown() ((void)0)
00106 #endif
00107 
00108 /***************************************************************************/
00109 
00110 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nsnull;
00111 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nsnull;
00112 
00113 // static
00114 XPCWrappedNativeScope*
00115 XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal)
00116 {
00117 
00118     XPCWrappedNativeScope* scope = FindInJSObjectScope(ccx, aGlobal, JS_TRUE);
00119     if(!scope)
00120         scope = new XPCWrappedNativeScope(ccx, aGlobal);
00121     else
00122     {
00123         // We need to call SetGlobal in order to refresh our cached 
00124         // mPrototypeJSObject and mPrototypeJSFunction in the case where
00125         // the global object is being reused (JS_ClearScope has been
00126         // called).
00127         // NOTE: We are only called by nsXPConnect::InitClasses. 
00128         scope->SetGlobal(ccx, aGlobal);
00129     }
00130     return scope;
00131 }
00132 
00133 MOZ_DECL_CTOR_COUNTER(XPCWrappedNativeScope)
00134 
00135 XPCWrappedNativeScope::XPCWrappedNativeScope(XPCCallContext& ccx,
00136                                              JSObject* aGlobal)
00137     :   mRuntime(ccx.GetRuntime()),
00138         mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)),
00139         mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)),
00140         mComponents(nsnull),
00141         mNext(nsnull),
00142         mGlobalJSObject(nsnull),
00143         mPrototypeJSObject(nsnull),
00144         mPrototypeJSFunction(nsnull)
00145 {
00146     // add ourselves to the scopes list
00147     {   // scoped lock
00148         XPCAutoLock lock(mRuntime->GetMapLock());
00149 
00150 #ifdef DEBUG
00151         for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00152             NS_ASSERTION(aGlobal != cur->GetGlobalJSObject(), "dup object");
00153 #endif
00154 
00155         mNext = gScopes;
00156         gScopes = this;
00157     }
00158 
00159     if(aGlobal)
00160         SetGlobal(ccx, aGlobal);
00161 
00162     DEBUG_TrackNewScope(this);
00163     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
00164 }
00165 
00166 void
00167 XPCWrappedNativeScope::SetComponents(nsXPCComponents* aComponents)
00168 {
00169     NS_IF_ADDREF(aComponents);
00170     NS_IF_RELEASE(mComponents);
00171     mComponents = aComponents;
00172 }
00173 
00174 void
00175 XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
00176 {
00177     // We allow for calling this more than once. This feature is used by
00178     // nsXPConnect::InitClassesWithNewWrappedGlobal.
00179 
00180     mGlobalJSObject = aGlobal;
00181 
00182     // Lookup 'globalObject.Object.prototype' for our wrapper's proto
00183     {
00184         AutoJSErrorAndExceptionEater eater(ccx); // scoped error eater
00185 
00186         jsval val;
00187         jsid idObj = mRuntime->GetStringID(XPCJSRuntime::IDX_OBJECT);
00188         jsid idFun = mRuntime->GetStringID(XPCJSRuntime::IDX_FUNCTION);
00189         jsid idProto = mRuntime->GetStringID(XPCJSRuntime::IDX_PROTOTYPE);
00190 
00191         if(OBJ_GET_PROPERTY(ccx, aGlobal, idObj, &val) &&
00192            !JSVAL_IS_PRIMITIVE(val) &&
00193            OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(val), idProto, &val) &&
00194            !JSVAL_IS_PRIMITIVE(val))
00195         {
00196             mPrototypeJSObject = JSVAL_TO_OBJECT(val);
00197         }
00198         else
00199         {
00200             NS_ERROR("Can't get globalObject.Object.prototype");
00201         }
00202 
00203         if(OBJ_GET_PROPERTY(ccx, aGlobal, idFun, &val) &&
00204            !JSVAL_IS_PRIMITIVE(val) &&
00205            OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(val), idProto, &val) &&
00206            !JSVAL_IS_PRIMITIVE(val))
00207         {
00208             mPrototypeJSFunction = JSVAL_TO_OBJECT(val);
00209         }
00210         else
00211         {
00212             NS_ERROR("Can't get globalObject.Function.prototype");
00213         }
00214     }
00215 }
00216 
00217 XPCWrappedNativeScope::~XPCWrappedNativeScope()
00218 {
00219     MOZ_COUNT_DTOR(XPCWrappedNativeScope);
00220     DEBUG_TrackDeleteScope(this);
00221 
00222     // We can do additional cleanup assertions here...
00223 
00224     if(mWrappedNativeMap)
00225     {
00226         NS_ASSERTION(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
00227         delete mWrappedNativeMap;
00228     }
00229 
00230     if(mWrappedNativeProtoMap)
00231     {
00232         NS_ASSERTION(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
00233         delete mWrappedNativeProtoMap;
00234     }
00235 
00236     // XXX we should assert that we are dead or that xpconnect has shutdown
00237     // XXX might not want to do this at xpconnect shutdown time???
00238     NS_IF_RELEASE(mComponents);
00239 }
00240 
00241 
00242 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00243 WrappedNativeJSGCThingMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
00244                              uint32 number, void *arg)
00245 {
00246     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
00247     if(wrapper->HasExternalReference())
00248     {
00249         JS_MarkGCThing((JSContext*)arg, wrapper->GetFlatJSObject(), 
00250                        "XPCWrappedNative::mFlatJSObject", nsnull);
00251     }
00252     return JS_DHASH_NEXT;
00253 }
00254 
00255 // static
00256 void
00257 XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt)
00258 {
00259     // Hold the lock until return...
00260     XPCAutoLock lock(rt->GetMapLock());
00261 
00262     XPCWrappedNativeScope* cur;
00263     
00264     // Do JS_MarkGCThing for all wrapperednatives with external references.
00265     for(cur = gScopes; cur; cur = cur->mNext)
00266     {
00267         cur->mWrappedNativeMap->Enumerate(WrappedNativeJSGCThingMarker, cx);
00268     }
00269 
00270     // Since the JSGC_END call happens outside of a lock,
00271     // it is possible for us to get called here twice before the FinshedGC
00272     // call happens. So, we allow for gDyingScopes not being null.
00273 
00274     XPCWrappedNativeScope* prev = nsnull;
00275     cur = gScopes;
00276 
00277     while(cur)
00278     {
00279         XPCWrappedNativeScope* next = cur->mNext;
00280         if(cur->mGlobalJSObject &&
00281            JS_IsAboutToBeFinalized(cx, cur->mGlobalJSObject))
00282         {
00283             cur->mGlobalJSObject = nsnull;
00284 
00285             // Move this scope from the live list to the dying list.
00286             if(prev)
00287                 prev->mNext = next;
00288             else
00289                 gScopes = next;
00290             cur->mNext = gDyingScopes;
00291             gDyingScopes = cur;
00292             cur = nsnull;
00293         }
00294         else
00295         {
00296             if(cur->mPrototypeJSObject &&
00297                JS_IsAboutToBeFinalized(cx, cur->mPrototypeJSObject))
00298             {
00299                 cur->mPrototypeJSObject = nsnull;
00300             }
00301             if(cur->mPrototypeJSFunction &&
00302                JS_IsAboutToBeFinalized(cx, cur->mPrototypeJSFunction))
00303             {
00304                 cur->mPrototypeJSFunction = nsnull;
00305             }
00306         }
00307         if(cur)
00308             prev = cur;
00309         cur = next;
00310     }
00311 }
00312 
00313 // static
00314 void
00315 XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC(JSContext* cx)
00316 {
00317     XPCJSRuntime* rt = nsXPConnect::GetRuntime();
00318     if(!rt)
00319         return;
00320 
00321     // Hold the lock until return...
00322     XPCAutoLock lock(rt->GetMapLock());
00323     KillDyingScopes();
00324 }
00325 
00326 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00327 WrappedNativeMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
00328                     uint32 number, void *arg)
00329 {
00330     ((Native2WrappedNativeMap::Entry*)hdr)->value->Mark();
00331     return JS_DHASH_NEXT;
00332 }
00333 
00334 // We need to explicitly mark all the protos too because some protos may be
00335 // alive in the hashtable but not currently in use by any wrapper
00336 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00337 WrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
00338                          uint32 number, void *arg)
00339 {
00340     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->Mark();
00341     return JS_DHASH_NEXT;
00342 }
00343 
00344 // static
00345 void
00346 XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos()
00347 {
00348     for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00349     {
00350         cur->mWrappedNativeMap->Enumerate(WrappedNativeMarker, nsnull);
00351         cur->mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMarker, nsnull);
00352     }
00353 
00354     DEBUG_TrackScopeTraversal();
00355 }
00356 
00357 #ifdef DEBUG
00358 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00359 ASSERT_WrappedNativeSetNotMarked(JSDHashTable *table, JSDHashEntryHdr *hdr,
00360                                  uint32 number, void *arg)
00361 {
00362     ((Native2WrappedNativeMap::Entry*)hdr)->value->ASSERT_SetsNotMarked();
00363     return JS_DHASH_NEXT;
00364 }
00365 
00366 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00367 ASSERT_WrappedNativeProtoSetNotMarked(JSDHashTable *table, JSDHashEntryHdr *hdr,
00368                                       uint32 number, void *arg)
00369 {
00370     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->ASSERT_SetNotMarked();
00371     return JS_DHASH_NEXT;
00372 }
00373 
00374 // static
00375 void
00376 XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked()
00377 {
00378     for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00379     {
00380         cur->mWrappedNativeMap->Enumerate(
00381             ASSERT_WrappedNativeSetNotMarked, nsnull);
00382         cur->mWrappedNativeProtoMap->Enumerate(
00383             ASSERT_WrappedNativeProtoSetNotMarked, nsnull);
00384     }
00385 }
00386 #endif
00387 
00388 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00389 WrappedNativeTearoffSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
00390                             uint32 number, void *arg)
00391 {
00392     ((Native2WrappedNativeMap::Entry*)hdr)->value->SweepTearOffs();
00393     return JS_DHASH_NEXT;
00394 }
00395 
00396 // static
00397 void
00398 XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
00399 {
00400     for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00401         cur->mWrappedNativeMap->Enumerate(WrappedNativeTearoffSweeper, nsnull);
00402 
00403     DEBUG_TrackScopeTraversal();
00404 }
00405 
00406 // static
00407 void
00408 XPCWrappedNativeScope::KillDyingScopes()
00409 {
00410     // always called inside the lock!
00411     XPCWrappedNativeScope* cur = gDyingScopes;
00412     while(cur)
00413     {
00414         XPCWrappedNativeScope* next = cur->mNext;
00415         delete cur;
00416         cur = next;
00417     }
00418     gDyingScopes = nsnull;
00419 }
00420 
00421 struct ShutdownData
00422 {
00423     ShutdownData(XPCCallContext& accx)
00424         : ccx(accx), wrapperCount(0),
00425           sharedProtoCount(0), nonSharedProtoCount(0) {}
00426     XPCCallContext& ccx;
00427     int wrapperCount;
00428     int sharedProtoCount;
00429     int nonSharedProtoCount;
00430 };
00431 
00432 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00433 WrappedNativeShutdownEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
00434                                 uint32 number, void *arg)
00435 {
00436     ShutdownData* data = (ShutdownData*) arg;
00437     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
00438 
00439     if(wrapper->IsValid())
00440     {
00441         if(wrapper->HasProto() && !wrapper->HasSharedProto())
00442             data->nonSharedProtoCount++;
00443         wrapper->SystemIsBeingShutDown(data->ccx);
00444         data->wrapperCount++;
00445     }
00446     return JS_DHASH_REMOVE;
00447 }
00448 
00449 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00450 WrappedNativeProtoShutdownEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
00451                                      uint32 number, void *arg)
00452 {
00453     ShutdownData* data = (ShutdownData*) arg;
00454     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->
00455         SystemIsBeingShutDown(data->ccx);
00456     data->sharedProtoCount++;
00457     return JS_DHASH_REMOVE;
00458 }
00459 
00460 //static
00461 void
00462 XPCWrappedNativeScope::SystemIsBeingShutDown(XPCCallContext& ccx)
00463 {
00464     DEBUG_TrackScopeTraversal();
00465     DEBUG_TrackScopeShutdown();
00466 
00467     int liveScopeCount = 0;
00468 
00469     ShutdownData data(ccx);
00470 
00471     XPCWrappedNativeScope* cur;
00472 
00473     // First move all the scopes to the dying list.
00474 
00475     cur = gScopes;
00476     while(cur)
00477     {
00478         XPCWrappedNativeScope* next = cur->mNext;
00479         cur->mNext = gDyingScopes;
00480         gDyingScopes = cur;
00481         cur = next;
00482         liveScopeCount++;
00483     }
00484     gScopes = nsnull;
00485 
00486     // Walk the unified dying list and call shutdown on all wrappers and protos
00487 
00488     for(cur = gDyingScopes; cur; cur = cur->mNext)
00489     {
00490         // Give the Components object a chance to try to clean up.
00491         if(cur->mComponents)
00492             cur->mComponents->SystemIsBeingShutDown();
00493 
00494         // Walk the protos first. Wrapper shutdown can leave dangling
00495         // proto pointers in the proto map.
00496         cur->mWrappedNativeProtoMap->
00497                 Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
00498         cur->mWrappedNativeMap->
00499                 Enumerate(WrappedNativeShutdownEnumerator,  &data);
00500     }
00501 
00502     // Now it is safe to kill all the scopes.
00503     KillDyingScopes();
00504 
00505 #ifdef XPC_DUMP_AT_SHUTDOWN
00506     if(data.wrapperCount)
00507         printf("deleting nsXPConnect  with %d live XPCWrappedNatives\n",
00508                data.wrapperCount);
00509     if(data.sharedProtoCount + data.nonSharedProtoCount)
00510         printf("deleting nsXPConnect  with %d live XPCWrappedNativeProtos (%d shared)\n",
00511                data.sharedProtoCount + data.nonSharedProtoCount,
00512                data.sharedProtoCount);
00513     if(liveScopeCount)
00514         printf("deleting nsXPConnect  with %d live XPCWrappedNativeScopes\n",
00515                liveScopeCount);
00516 #endif
00517 }
00518 
00519 
00520 /***************************************************************************/
00521 
00522 static
00523 XPCWrappedNativeScope*
00524 GetScopeOfObject(JSContext* cx, JSObject* obj)
00525 {
00526     nsISupports* supports;
00527     JSClass* clazz = JS_GET_CLASS(cx, obj);
00528 
00529     if(!clazz ||
00530        !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
00531        !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
00532        !(supports = (nsISupports*) JS_GetPrivate(cx, obj)))
00533         return nsnull;
00534 
00535     nsCOMPtr<nsIXPConnectWrappedNative> iface = do_QueryInterface(supports);
00536     if(iface)
00537     {
00538         // We can fairly safely assume that this is really one of our
00539         // nsXPConnectWrappedNative objects. No other component in our
00540         // universe should be creating objects that implement the
00541         // nsIXPConnectWrappedNative interface!
00542         return ((XPCWrappedNative*)supports)->GetScope();
00543     }
00544     return nsnull;
00545 }
00546 
00547 
00548 #ifdef DEBUG
00549 void DEBUG_CheckForComponentsInScope(XPCCallContext& ccx, JSObject* obj,
00550                                      JSBool OKIfNotInitialized)
00551 {
00552     if(OKIfNotInitialized)
00553         return;
00554 
00555     const char* name = ccx.GetRuntime()->GetStringName(XPCJSRuntime::IDX_COMPONENTS);
00556     jsval prop;
00557     if(JS_LookupProperty(ccx, obj, name, &prop) && !JSVAL_IS_PRIMITIVE(prop))
00558         return;
00559 
00560     static const char msg[] =
00561     "XPConnect is being called on a scope without a 'Components' property!\n"
00562     "\n"
00563     "This is pretty much always bad. It usually means that native code is\n"
00564     "making a callback to an interface implemented in JavaScript, but the\n"
00565     "document where the JS object was created has already been cleared and the\n"
00566     "global properties of that document's window are *gone*. Generally this\n"
00567     "indicates a problem that should be addressed in the design and use of the\n"
00568     "callback code."
00569     "\n";
00570 
00571 #ifdef I_FOOLISHLY_WANT_TO_IGNORE_THIS_LIKE_THE_OTHER_CRAP_WE_PRINTF
00572     NS_WARNING(msg);
00573 #else
00574     NS_ERROR(msg);
00575 #endif
00576 }
00577 #else
00578 #define DEBUG_CheckForComponentsInScope(ccx, obj, OKIfNotInitialized) ((void)0)
00579 #endif
00580 
00581 // static
00582 XPCWrappedNativeScope*
00583 XPCWrappedNativeScope::FindInJSObjectScope(XPCCallContext& ccx, JSObject* obj,
00584                                            JSBool OKIfNotInitialized)
00585 {
00586     XPCWrappedNativeScope* scope;
00587 
00588     if(!obj)
00589         return nsnull;
00590 
00591     // If this object is itself a wrapped native then we can get the
00592     // scope directly.
00593 
00594     scope = GetScopeOfObject(ccx, obj);
00595     if(scope)
00596         return scope;
00597 
00598     // Else we'll have to look up the parent chain to get the scope
00599 
00600     JSObject* parent;
00601 
00602     while(nsnull != (parent = JS_GetParent(ccx, obj)))
00603         obj = parent;
00604 
00605     // XXX We are assuming that the scope count is low enough that traversing
00606     // the linked list is more reasonable then doing a hashtable lookup.
00607     {   // scoped lock
00608         XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
00609 
00610         DEBUG_TrackScopeTraversal();
00611 
00612         for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00613         {
00614             if(obj == cur->GetGlobalJSObject())
00615             {
00616                 DEBUG_CheckForComponentsInScope(ccx, obj, OKIfNotInitialized);
00617                 return cur;
00618             }
00619         }
00620     }
00621 
00622     // Failure to find the scope is only OK if the caller told us it might fail.
00623     // This flag would only be set in the call from
00624     // XPCWrappedNativeScope::GetNewOrUsed
00625     NS_ASSERTION(OKIfNotInitialized, "No scope has this global object!");
00626     return nsnull;
00627 }
00628 
00629 
00630 /***************************************************************************/
00631 
00632 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00633 WNProtoSecPolicyClearer(JSDHashTable *table, JSDHashEntryHdr *hdr,
00634                         uint32 number, void *arg)
00635 {
00636     XPCWrappedNativeProto* proto =
00637         ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
00638     *(proto->GetSecurityInfoAddr()) = nsnull;
00639     return JS_DHASH_NEXT;
00640 }
00641 
00642 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00643 WNSecPolicyClearer(JSDHashTable *table, JSDHashEntryHdr *hdr,
00644                     uint32 number, void *arg)
00645 {
00646     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
00647     if(wrapper->HasProto() && !wrapper->HasSharedProto())
00648         *(wrapper->GetProto()->GetSecurityInfoAddr()) = nsnull;
00649     return JS_DHASH_NEXT;
00650 }
00651 
00652 // static
00653 nsresult
00654 XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies(XPCCallContext& ccx)
00655 {
00656     // Hold the lock throughout.
00657     XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
00658 
00659     for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
00660     {
00661         cur->mWrappedNativeProtoMap->Enumerate(WNProtoSecPolicyClearer, nsnull);
00662         cur->mWrappedNativeMap->Enumerate(WNSecPolicyClearer, nsnull);
00663     }
00664 
00665     DEBUG_TrackScopeTraversal();
00666 
00667     return NS_OK;
00668 }
00669 
00670 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00671 WNProtoRemover(JSDHashTable *table, JSDHashEntryHdr *hdr,
00672                uint32 number, void *arg)
00673 {
00674     XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg;
00675     
00676     XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*)
00677         ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
00678 
00679     detachedMap->Add(proto);
00680 
00681     return JS_DHASH_REMOVE;
00682 }
00683 
00684 void
00685 XPCWrappedNativeScope::RemoveWrappedNativeProtos()
00686 {
00687     XPCAutoLock al(mRuntime->GetMapLock());
00688     
00689     mWrappedNativeProtoMap->Enumerate(WNProtoRemover, 
00690         GetRuntime()->GetDetachedWrappedNativeProtoMap());
00691 }
00692 
00693 /***************************************************************************/
00694 
00695 // static
00696 void
00697 XPCWrappedNativeScope::DebugDumpAllScopes(PRInt16 depth)
00698 {
00699 #ifdef DEBUG
00700     depth-- ;
00701 
00702     // get scope count.
00703     int count = 0;
00704     XPCWrappedNativeScope* cur;
00705     for(cur = gScopes; cur; cur = cur->mNext)
00706         count++ ;
00707 
00708     XPC_LOG_ALWAYS(("chain of %d XPCWrappedNativeScope(s)", count));
00709     XPC_LOG_INDENT();
00710         XPC_LOG_ALWAYS(("gDyingScopes @ %x", gDyingScopes));
00711         if(depth)
00712             for(cur = gScopes; cur; cur = cur->mNext)
00713                 cur->DebugDump(depth);
00714     XPC_LOG_OUTDENT();
00715 #endif
00716 }
00717 
00718 #ifdef DEBUG
00719 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00720 WrappedNativeMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
00721                                uint32 number, void *arg)
00722 {
00723     ((Native2WrappedNativeMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
00724     return JS_DHASH_NEXT;
00725 }
00726 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
00727 WrappedNativeProtoMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
00728                                     uint32 number, void *arg)
00729 {
00730     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
00731     return JS_DHASH_NEXT;
00732 }
00733 #endif
00734 
00735 void
00736 XPCWrappedNativeScope::DebugDump(PRInt16 depth)
00737 {
00738 #ifdef DEBUG
00739     depth-- ;
00740     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this));
00741     XPC_LOG_INDENT();
00742         XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
00743         XPC_LOG_ALWAYS(("mNext @ %x", mNext));
00744         XPC_LOG_ALWAYS(("mComponents @ %x", mComponents));
00745         XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject));
00746         XPC_LOG_ALWAYS(("mPrototypeJSObject @ %x", mPrototypeJSObject));
00747         XPC_LOG_ALWAYS(("mPrototypeJSFunction @ %x", mPrototypeJSFunction));
00748 
00749         XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)", \
00750                          mWrappedNativeMap, \
00751                          mWrappedNativeMap ? mWrappedNativeMap->Count() : 0));
00752         // iterate contexts...
00753         if(depth && mWrappedNativeMap && mWrappedNativeMap->Count())
00754         {
00755             XPC_LOG_INDENT();
00756             mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth);
00757             XPC_LOG_OUTDENT();
00758         }
00759 
00760         XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)", \
00761                          mWrappedNativeProtoMap, \
00762                          mWrappedNativeProtoMap ? mWrappedNativeProtoMap->Count() : 0));
00763         // iterate contexts...
00764         if(depth && mWrappedNativeProtoMap && mWrappedNativeProtoMap->Count())
00765         {
00766             XPC_LOG_INDENT();
00767             mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
00768             XPC_LOG_OUTDENT();
00769         }
00770     XPC_LOG_OUTDENT();
00771 #endif
00772 }
00773