LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCWrappedJS.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 308 210 68.2 %
Date: 2012-06-02 Functions: 28 21 75.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   John Bandhauer <jband@netscape.com> (original author)
      26                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : /* Class that wraps JS objects to appear as XPCOM objects. */
      43                 : 
      44                 : #include "xpcprivate.h"
      45                 : #include "nsAtomicRefcnt.h"
      46                 : #include "nsProxyRelease.h"
      47                 : #include "nsThreadUtils.h"
      48                 : #include "nsTextFormatter.h"
      49                 : 
      50                 : // NOTE: much of the fancy footwork is done in xpcstubs.cpp
      51                 : 
      52            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXPCWrappedJS)
      53                 : 
      54                 : NS_IMETHODIMP
      55            7425 : NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
      56                 :    (void *p, nsCycleCollectionTraversalCallback &cb)
      57                 : {
      58            7425 :     nsISupports *s = static_cast<nsISupports*>(p);
      59            7425 :     NS_ASSERTION(CheckForRightISupports(s),
      60                 :                  "not the nsISupports pointer we expect");
      61            7425 :     nsXPCWrappedJS *tmp = Downcast(s);
      62                 : 
      63            7425 :     nsrefcnt refcnt = tmp->mRefCnt.get();
      64            7425 :     if (cb.WantDebugInfo()) {
      65                 :         char name[72];
      66               0 :         if (tmp->GetClass())
      67                 :             JS_snprintf(name, sizeof(name), "nsXPCWrappedJS (%s)",
      68               0 :                         tmp->GetClass()->GetInterfaceName());
      69                 :         else
      70               0 :             JS_snprintf(name, sizeof(name), "nsXPCWrappedJS");
      71               0 :         cb.DescribeRefCountedNode(refcnt, sizeof(nsXPCWrappedJS), name);
      72                 :     } else {
      73            7425 :         NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt)
      74                 :     }
      75                 : 
      76                 :     // nsXPCWrappedJS keeps its own refcount artificially at or above 1, see the
      77                 :     // comment above nsXPCWrappedJS::AddRef.
      78            7425 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "self");
      79            7425 :     cb.NoteXPCOMChild(s);
      80                 : 
      81            7425 :     if (refcnt > 1) {
      82                 :         // nsXPCWrappedJS roots its mJSObj when its refcount is > 1, see
      83                 :         // the comment above nsXPCWrappedJS::AddRef.
      84            7425 :         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj");
      85                 :         cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
      86            7425 :                            tmp->GetJSObjectPreserveColor());
      87                 :     }
      88                 : 
      89            7425 :     nsXPCWrappedJS* root = tmp->GetRootWrapper();
      90            7425 :     if (root == tmp) {
      91                 :         // The root wrapper keeps the aggregated native object alive.
      92            7145 :         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "aggregated native");
      93            7145 :         cb.NoteXPCOMChild(tmp->GetAggregatedNativeObject());
      94                 :     } else {
      95                 :         // Non-root wrappers keep their root alive.
      96             280 :         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "root");
      97             280 :         cb.NoteXPCOMChild(static_cast<nsIXPConnectWrappedJS*>(root));
      98                 :     }
      99                 : 
     100            7425 :     return NS_OK;
     101                 : }
     102                 : 
     103             289 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXPCWrappedJS)
     104             289 :     tmp->Unlink();
     105             289 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     106                 : 
     107                 : NS_IMETHODIMP
     108               0 : nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
     109                 : {
     110               0 :     NS_ASSERTION(IsAggregatedToNative(), "bad AggregatedQueryInterface call");
     111                 : 
     112               0 :     if (!IsValid())
     113               0 :         return NS_ERROR_UNEXPECTED;
     114                 : 
     115                 :     // Put this here rather that in DelegatedQueryInterface because it needs
     116                 :     // to be in QueryInterface before the possible delegation to 'outer', but
     117                 :     // we don't want to do this check twice in one call in the normal case:
     118                 :     // once in QueryInterface and once in DelegatedQueryInterface.
     119               0 :     if (aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS))) {
     120               0 :         NS_ADDREF(this);
     121               0 :         *aInstancePtr = (void*) static_cast<nsIXPConnectWrappedJS*>(this);
     122               0 :         return NS_OK;
     123                 :     }
     124                 : 
     125               0 :     return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr);
     126                 : }
     127                 : 
     128                 : NS_IMETHODIMP
     129         1046122 : nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
     130                 : {
     131         1046122 :     if (nsnull == aInstancePtr) {
     132               0 :         NS_PRECONDITION(0, "null pointer");
     133               0 :         return NS_ERROR_NULL_POINTER;
     134                 :     }
     135                 : 
     136         1046122 :     if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {
     137           15771 :         *aInstancePtr = & NS_CYCLE_COLLECTION_NAME(nsXPCWrappedJS);
     138           15771 :         return NS_OK;
     139                 :     }
     140                 : 
     141         1030351 :     if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports))) {
     142                 :         *aInstancePtr =
     143           23447 :             NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Upcast(this);
     144           23447 :         return NS_OK;
     145                 :     }
     146                 : 
     147         1006904 :     if (!IsValid())
     148              24 :         return NS_ERROR_UNEXPECTED;
     149                 : 
     150                 :     // Always check for this first so that our 'outer' can get this interface
     151                 :     // from us without recurring into a call to the outer's QI!
     152         1006880 :     if (aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS))) {
     153           64913 :         NS_ADDREF(this);
     154           64913 :         *aInstancePtr = (void*) static_cast<nsIXPConnectWrappedJS*>(this);
     155           64913 :         return NS_OK;
     156                 :     }
     157                 : 
     158          941967 :     nsISupports* outer = GetAggregatedNativeObject();
     159          941967 :     if (outer)
     160               0 :         return outer->QueryInterface(aIID, aInstancePtr);
     161                 : 
     162                 :     // else...
     163                 : 
     164          941967 :     return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr);
     165                 : }
     166                 : 
     167                 : 
     168                 : // Refcounting is now similar to that used in the chained (pre-flattening)
     169                 : // wrappednative system.
     170                 : //
     171                 : // We are now holding an extra refcount for nsISupportsWeakReference support.
     172                 : //
     173                 : // Non-root wrappers remove themselves from the chain in their destructors.
     174                 : // We root the JSObject as the refcount transitions from 1->2. And we unroot
     175                 : // the JSObject when the refcount transitions from 2->1.
     176                 : //
     177                 : // When the transition from 2->1 is made and no one holds a weak ref to the
     178                 : // (aggregated) object then we decrement the refcount again to 0 (and
     179                 : // destruct) . However, if a weak ref is held at the 2->1 transition, then we
     180                 : // leave the refcount at 1 to indicate that state. This leaves the JSObject
     181                 : // no longer rooted by us and (as far as we know) subject to possible
     182                 : // collection. Code in XPCJSRuntime watches for JS gc to happen and will do
     183                 : // the final release on wrappers whose JSObjects get finalized. Note that
     184                 : // even after tranistioning to this refcount-of-one state callers might do
     185                 : // an addref and cause us to re-root the JSObject and continue on more normally.
     186                 : 
     187                 : nsrefcnt
     188         1475063 : nsXPCWrappedJS::AddRef(void)
     189                 : {
     190         1475063 :     nsrefcnt cnt = NS_AtomicIncrementRefcnt(mRefCnt);
     191         1475063 :     NS_LOG_ADDREF(this, cnt, "nsXPCWrappedJS", sizeof(*this));
     192                 : 
     193         1475063 :     if (2 == cnt && IsValid()) {
     194          114050 :         XPCJSRuntime* rt = mClass->GetRuntime();
     195          114050 :         rt->AddWrappedJSRoot(this);
     196                 :     }
     197                 : 
     198         1475063 :     return cnt;
     199                 : }
     200                 : 
     201                 : nsrefcnt
     202         1376901 : nsXPCWrappedJS::Release(void)
     203                 : {
     204         1376901 :     NS_PRECONDITION(0 != mRefCnt, "dup release");
     205                 : 
     206         1376901 :     if (mMainThreadOnly && !NS_IsMainThread()) {
     207                 :         // We'd like to abort here, but this can happen if someone uses a proxy
     208                 :         // for the nsXPCWrappedJS.
     209            6832 :         nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
     210                 :         // If we can't get the main thread anymore we just leak, but this really
     211                 :         // shouldn't happen.
     212            3416 :         NS_ASSERTION(mainThread,
     213                 :                      "Can't get main thread, leaking nsXPCWrappedJS!");
     214            3416 :         if (mainThread) {
     215                 :             NS_ProxyRelease(mainThread,
     216            3416 :                             static_cast<nsIXPConnectWrappedJS*>(this));
     217                 :         }
     218            3416 :         return mRefCnt;
     219                 :     }
     220                 : 
     221                 :     // need to take the map lock here to prevent GetNewOrUsed from trying
     222                 :     // to reuse a wrapper on one thread while it's being destroyed on another
     223         1373485 :     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     224         2746970 :     XPCAutoLock lock(rt->GetMapLock());
     225                 : 
     226                 : do_decrement:
     227                 : 
     228         1474501 :     nsrefcnt cnt = NS_AtomicDecrementRefcnt(mRefCnt);
     229         1474501 :     NS_LOG_RELEASE(this, cnt, "nsXPCWrappedJS");
     230                 : 
     231         1474501 :     if (0 == cnt) {
     232          106519 :         delete this;   // also unlinks us from chain
     233          106519 :         return 0;
     234                 :     }
     235         1367982 :     if (1 == cnt) {
     236          113769 :         if (IsValid())
     237          113480 :             RemoveFromRootSet(rt->GetMapLock());
     238                 : 
     239                 :         // If we are not the root wrapper or if we are not being used from a
     240                 :         // weak reference, then this extra ref is not needed and we can let
     241                 :         // ourself be deleted.
     242                 :         // Note: HasWeakReferences() could only return true for the root.
     243          113769 :         if (!HasWeakReferences())
     244          101016 :             goto do_decrement;
     245                 :     }
     246         1266966 :     return cnt;
     247                 : }
     248                 : 
     249                 : void
     250          152113 : nsXPCWrappedJS::TraceJS(JSTracer* trc)
     251                 : {
     252          152113 :     NS_ASSERTION(mRefCnt >= 2 && IsValid(), "must be strongly referenced");
     253          152113 :     JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
     254          152113 :     JS_CallTracer(trc, GetJSObjectPreserveColor(), JSTRACE_OBJECT);
     255          152113 : }
     256                 : 
     257                 : #ifdef DEBUG
     258                 : // static
     259                 : void
     260               0 : nsXPCWrappedJS::PrintTraceName(JSTracer* trc, char *buf, size_t bufsize)
     261                 : {
     262                 :     const nsXPCWrappedJS* self = static_cast<const nsXPCWrappedJS*>
     263               0 :                                             (trc->debugPrintArg);
     264                 :     JS_snprintf(buf, bufsize, "nsXPCWrappedJS[%s,0x%p:0x%p].mJSObj",
     265               0 :                 self->GetClass()->GetInterfaceName(), self, self->mXPTCStub);
     266               0 : }
     267                 : #endif
     268                 : 
     269                 : NS_IMETHODIMP
     270            8576 : nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
     271                 : {
     272            8576 :     if (mRoot != this)
     273               0 :         return mRoot->GetWeakReference(aInstancePtr);
     274                 : 
     275            8576 :     return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
     276                 : }
     277                 : 
     278                 : NS_IMETHODIMP
     279           58319 : nsXPCWrappedJS::GetJSObject(JSObject** aJSObj)
     280                 : {
     281           58319 :     NS_PRECONDITION(aJSObj, "bad param");
     282           58319 :     NS_PRECONDITION(IsValid(), "bad wrapper");
     283                 : 
     284           58319 :     if (!(*aJSObj = GetJSObject()))
     285               0 :         return NS_ERROR_OUT_OF_MEMORY;
     286           58319 :     return NS_OK;
     287                 : }
     288                 : 
     289                 : static bool
     290           88800 : CheckMainThreadOnly(nsXPCWrappedJS *aWrapper)
     291                 : {
     292           88800 :     if(aWrapper->IsMainThreadOnly())
     293               0 :         return NS_IsMainThread();
     294                 : 
     295          177600 :     nsCOMPtr<nsIClassInfo> ci;
     296           88800 :     CallQueryInterface(aWrapper, getter_AddRefs(ci));
     297           88800 :     if (ci) {
     298                 :         PRUint32 flags;
     299              86 :         if (NS_SUCCEEDED(ci->GetFlags(&flags)) && !(flags & nsIClassInfo::MAIN_THREAD_ONLY))
     300              86 :             return true;
     301                 : 
     302               0 :         if (!NS_IsMainThread())
     303               0 :             return false;
     304                 :     }
     305                 : 
     306           88714 :     aWrapper->SetIsMainThreadOnly();
     307                 : 
     308           88714 :     return true;
     309                 : }
     310                 : 
     311                 : // static
     312                 : nsresult
     313          156775 : nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx,
     314                 :                              JSObject* aJSObj,
     315                 :                              REFNSIID aIID,
     316                 :                              nsISupports* aOuter,
     317                 :                              nsXPCWrappedJS** wrapperResult)
     318                 : {
     319                 :     JSObject2WrappedJSMap* map;
     320                 :     JSObject* rootJSObj;
     321          156775 :     nsXPCWrappedJS* root = nsnull;
     322          156775 :     nsXPCWrappedJS* wrapper = nsnull;
     323          156775 :     nsXPCWrappedJSClass* clazz = nsnull;
     324          156775 :     XPCJSRuntime* rt = ccx.GetRuntime();
     325          156775 :     JSBool release_root = false;
     326                 : 
     327          156775 :     map = rt->GetWrappedJSMap();
     328          156775 :     if (!map) {
     329               0 :         NS_ASSERTION(map,"bad map");
     330               0 :         return NS_ERROR_FAILURE;
     331                 :     }
     332                 : 
     333          156775 :     nsXPCWrappedJSClass::GetNewOrUsed(ccx, aIID, &clazz);
     334          156775 :     if (!clazz)
     335               0 :         return NS_ERROR_FAILURE;
     336                 :     // from here on we need to return through 'return_wrapper'
     337                 : 
     338                 :     // always find the root JSObject
     339          156775 :     rootJSObj = clazz->GetRootJSObject(ccx, aJSObj);
     340          156775 :     if (!rootJSObj)
     341               0 :         goto return_wrapper;
     342                 : 
     343                 :     // look for the root wrapper, and if found, hold the map lock until
     344                 :     // we've added our ref to prevent another thread from destroying it
     345                 :     // under us
     346                 :     {   // scoped lock
     347          313550 :         XPCAutoLock lock(rt->GetMapLock());
     348          156775 :         root = map->Find(rootJSObj);
     349          156775 :         if (root) {
     350           67975 :             if ((nsnull != (wrapper = root->Find(aIID))) ||
     351                 :                 (nsnull != (wrapper = root->FindInherited(aIID)))) {
     352           49975 :                 NS_ADDREF(wrapper);
     353                 :                 goto return_wrapper;
     354                 :             }
     355                 :         }
     356                 :     }
     357                 : 
     358          106800 :     if (!root) {
     359                 :         // build the root wrapper
     360           88800 :         if (rootJSObj == aJSObj) {
     361                 :             // the root will do double duty as the interface wrapper
     362                 :             wrapper = root = new nsXPCWrappedJS(ccx, aJSObj, clazz, nsnull,
     363           88800 :                                                 aOuter);
     364           88800 :             if (!root)
     365               0 :                 goto return_wrapper;
     366                 : 
     367                 :             {   // scoped lock
     368                 : #if DEBUG_xpc_leaks
     369                 :                 printf("Created nsXPCWrappedJS %p, JSObject is %p\n",
     370                 :                        (void*)wrapper, (void*)aJSObj);
     371                 : #endif
     372          177600 :                 XPCAutoLock lock(rt->GetMapLock());
     373           88800 :                 map->Add(root);
     374                 :             }
     375                 : 
     376           88800 :             if (!CheckMainThreadOnly(root)) {
     377               0 :                 XPCAutoLock lock(rt->GetMapLock());
     378               0 :                 map->Remove(root);
     379                 : 
     380               0 :                 wrapper = NULL;
     381                 :             }
     382                 : 
     383           88800 :             goto return_wrapper;
     384                 :         } else {
     385                 :             // just a root wrapper
     386               0 :             nsXPCWrappedJSClass* rootClazz = nsnull;
     387                 :             nsXPCWrappedJSClass::GetNewOrUsed(ccx, NS_GET_IID(nsISupports),
     388               0 :                                               &rootClazz);
     389               0 :             if (!rootClazz)
     390               0 :                 goto return_wrapper;
     391                 : 
     392               0 :             root = new nsXPCWrappedJS(ccx, rootJSObj, rootClazz, nsnull, aOuter);
     393               0 :             NS_RELEASE(rootClazz);
     394                 : 
     395               0 :             if (!root)
     396               0 :                 goto return_wrapper;
     397                 : 
     398               0 :             release_root = true;
     399                 : 
     400                 :             {   // scoped lock
     401                 : #if DEBUG_xpc_leaks
     402                 :                 printf("Created nsXPCWrappedJS %p, JSObject is %p\n",
     403                 :                        (void*)root, (void*)rootJSObj);
     404                 : #endif
     405               0 :                 XPCAutoLock lock(rt->GetMapLock());
     406               0 :                 map->Add(root);
     407                 :             }
     408                 : 
     409               0 :             if (!CheckMainThreadOnly(root)) {
     410               0 :                 XPCAutoLock lock(rt->GetMapLock());
     411               0 :                 map->Remove(root);
     412                 : 
     413                 :                 goto return_wrapper;
     414                 :             }
     415                 :         }
     416                 :     }
     417                 : 
     418                 :     // at this point we have a root and may need to build the specific wrapper
     419           18000 :     NS_ASSERTION(root,"bad root");
     420           18000 :     NS_ASSERTION(clazz,"bad clazz");
     421                 : 
     422           18000 :     if (!wrapper) {
     423           18000 :         wrapper = new nsXPCWrappedJS(ccx, aJSObj, clazz, root, aOuter);
     424           18000 :         if (!wrapper)
     425               0 :             goto return_wrapper;
     426                 : #if DEBUG_xpc_leaks
     427                 :         printf("Created nsXPCWrappedJS %p, JSObject is %p\n",
     428                 :                (void*)wrapper, (void*)aJSObj);
     429                 : #endif
     430                 :     }
     431                 : 
     432           18000 :     wrapper->mNext = root->mNext;
     433           18000 :     root->mNext = wrapper;
     434                 : 
     435                 : return_wrapper:
     436          156775 :     if (clazz)
     437          156775 :         NS_RELEASE(clazz);
     438                 : 
     439          156775 :     if (release_root)
     440               0 :         NS_RELEASE(root);
     441                 : 
     442          156775 :     if (!wrapper)
     443               0 :         return NS_ERROR_FAILURE;
     444                 : 
     445          156775 :     *wrapperResult = wrapper;
     446          156775 :     return NS_OK;
     447                 : }
     448                 : 
     449          106800 : nsXPCWrappedJS::nsXPCWrappedJS(XPCCallContext& ccx,
     450                 :                                JSObject* aJSObj,
     451                 :                                nsXPCWrappedJSClass* aClass,
     452                 :                                nsXPCWrappedJS* root,
     453                 :                                nsISupports* aOuter)
     454                 :     : mJSObj(aJSObj),
     455                 :       mClass(aClass),
     456                 :       mRoot(root ? root : this),
     457                 :       mNext(nsnull),
     458                 :       mOuter(root ? nsnull : aOuter),
     459          106800 :       mMainThread(NS_IsMainThread()),
     460          213600 :       mMainThreadOnly(root && root->mMainThreadOnly)
     461                 : {
     462                 : #ifdef DEBUG_stats_jband
     463                 :     static int count = 0;
     464                 :     static const int interval = 10;
     465                 :     if (0 == (++count % interval))
     466                 :         printf("//////// %d instances of nsXPCWrappedJS created\n", count);
     467                 : #endif
     468                 : 
     469          106800 :     JS_ASSERT_IF(mMainThreadOnly, mMainThread);
     470                 : 
     471          106800 :     InitStub(GetClass()->GetIID());
     472                 : 
     473                 :     // intentionally do double addref - see Release().
     474          106800 :     NS_ADDREF_THIS();
     475          106800 :     NS_ADDREF_THIS();
     476          106800 :     NS_ADDREF(aClass);
     477          106800 :     NS_IF_ADDREF(mOuter);
     478                 : 
     479          106800 :     if (mRoot != this)
     480           18000 :         NS_ADDREF(mRoot);
     481                 : 
     482          106800 : }
     483                 : 
     484          319557 : nsXPCWrappedJS::~nsXPCWrappedJS()
     485                 : {
     486          106519 :     NS_PRECONDITION(0 == mRefCnt, "refcounting error");
     487                 : 
     488          106519 :     if (mRoot == this) {
     489                 :         // Remove this root wrapper from the map
     490           88520 :         XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     491           88520 :         JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
     492           88520 :         if (map) {
     493          177040 :             XPCAutoLock lock(rt->GetMapLock());
     494           88520 :             map->Remove(this);
     495                 :         }
     496                 :     }
     497          106519 :     Unlink();
     498          426076 : }
     499                 : 
     500                 : void
     501          106808 : nsXPCWrappedJS::Unlink()
     502                 : {
     503          106808 :     if (IsValid()) {
     504          106519 :         XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     505          106519 :         if (rt) {
     506          106519 :             if (mRoot == this) {
     507                 :                 // remove this root wrapper from the map
     508           88520 :                 JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
     509           88520 :                 if (map) {
     510          177040 :                     XPCAutoLock lock(rt->GetMapLock());
     511           88520 :                     map->Remove(this);
     512                 :                 }
     513                 :             }
     514                 : 
     515          106519 :             if (mRefCnt > 1)
     516             289 :                 RemoveFromRootSet(rt->GetMapLock());
     517                 :         }
     518                 : 
     519          106519 :         mJSObj = nsnull;
     520                 :     }
     521                 : 
     522          106808 :     if (mRoot == this) {
     523           88744 :         ClearWeakReferences();
     524           18064 :     } else if (mRoot) {
     525                 :         // unlink this wrapper
     526           17999 :         nsXPCWrappedJS* cur = mRoot;
     527            1145 :         while (1) {
     528           19144 :             if (cur->mNext == this) {
     529           17999 :                 cur->mNext = mNext;
     530                 :                 break;
     531                 :             }
     532            1145 :             cur = cur->mNext;
     533            1145 :             NS_ASSERTION(cur, "failed to find wrapper in its own chain");
     534                 :         }
     535                 :         // let the root go
     536           17999 :         NS_RELEASE(mRoot);
     537                 :     }
     538                 : 
     539          106808 :     NS_IF_RELEASE(mClass);
     540          106808 :     if (mOuter) {
     541               0 :         XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     542               0 :         if (rt->GetThreadRunningGC()) {
     543               0 :             rt->DeferredRelease(mOuter);
     544               0 :             mOuter = nsnull;
     545                 :         } else {
     546               0 :             NS_RELEASE(mOuter);
     547                 :         }
     548                 :     }
     549          106808 : }
     550                 : 
     551                 : nsXPCWrappedJS*
     552          686895 : nsXPCWrappedJS::Find(REFNSIID aIID)
     553                 : {
     554          686895 :     if (aIID.Equals(NS_GET_IID(nsISupports)))
     555          311259 :         return mRoot;
     556                 : 
     557          631296 :     for (nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext) {
     558          477652 :         if (aIID.Equals(cur->GetIID()))
     559          221992 :             return cur;
     560                 :     }
     561                 : 
     562          153644 :     return nsnull;
     563                 : }
     564                 : 
     565                 : // check if asking for an interface that some wrapper in the chain inherits from
     566                 : nsXPCWrappedJS*
     567          153644 : nsXPCWrappedJS::FindInherited(REFNSIID aIID)
     568                 : {
     569          153644 :     NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), "bad call sequence");
     570                 : 
     571          327784 :     for (nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext) {
     572                 :         bool found;
     573          176381 :         if (NS_SUCCEEDED(cur->GetClass()->GetInterfaceInfo()->
     574                 :                          HasAncestor(&aIID, &found)) && found)
     575            2241 :             return cur;
     576                 :     }
     577                 : 
     578          151403 :     return nsnull;
     579                 : }
     580                 : 
     581                 : NS_IMETHODIMP
     582               0 : nsXPCWrappedJS::GetInterfaceInfo(nsIInterfaceInfo** info)
     583                 : {
     584               0 :     NS_ASSERTION(GetClass(), "wrapper without class");
     585               0 :     NS_ASSERTION(GetClass()->GetInterfaceInfo(), "wrapper class without interface");
     586                 : 
     587                 :     // Since failing to get this info will crash some platforms(!), we keep
     588                 :     // mClass valid at shutdown time.
     589                 : 
     590               0 :     if (!(*info = GetClass()->GetInterfaceInfo()))
     591               0 :         return NS_ERROR_UNEXPECTED;
     592               0 :     NS_ADDREF(*info);
     593               0 :     return NS_OK;
     594                 : }
     595                 : 
     596                 : NS_IMETHODIMP
     597         1225634 : nsXPCWrappedJS::CallMethod(PRUint16 methodIndex,
     598                 :                            const XPTMethodDescriptor* info,
     599                 :                            nsXPTCMiniVariant* params)
     600                 : {
     601         1225634 :     if (!IsValid())
     602              64 :         return NS_ERROR_UNEXPECTED;
     603         1225570 :     if (NS_IsMainThread() != mMainThread) {
     604               2 :         NS_NAMED_LITERAL_STRING(kFmt, "Attempt to use JS function on a different thread calling %s.%s. JS objects may not be shared across threads.");
     605                 :         PRUnichar* msg =
     606                 :             nsTextFormatter::smprintf(kFmt.get(),
     607                 :                                       GetClass()->GetInterfaceName(),
     608               1 :                                       info->name);
     609                 :         nsCOMPtr<nsIConsoleService> cs =
     610               2 :             do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     611               1 :         if (cs)
     612               1 :             cs->LogStringMessage(msg);
     613               1 :         NS_Free(msg);
     614                 : 
     615               1 :         return NS_ERROR_NOT_SAME_THREAD;
     616                 :     }
     617         1225569 :     return GetClass()->CallMethod(this, methodIndex, info, params);
     618                 : }
     619                 : 
     620                 : NS_IMETHODIMP
     621               0 : nsXPCWrappedJS::GetInterfaceIID(nsIID** iid)
     622                 : {
     623               0 :     NS_PRECONDITION(iid, "bad param");
     624                 : 
     625               0 :     *iid = (nsIID*) nsMemory::Clone(&(GetIID()), sizeof(nsIID));
     626               0 :     return *iid ? NS_OK : NS_ERROR_UNEXPECTED;
     627                 : }
     628                 : 
     629                 : void
     630             276 : nsXPCWrappedJS::SystemIsBeingShutDown(JSRuntime* rt)
     631                 : {
     632                 :     // XXX It turns out that it is better to leak here then to do any Releases
     633                 :     // and have them propagate into all sorts of mischief as the system is being
     634                 :     // shutdown. This was learned the hard way :(
     635                 : 
     636                 :     // mJSObj == nsnull is used to indicate that the wrapper is no longer valid
     637                 :     // and that calls should fail without trying to use any of the
     638                 :     // xpconnect mechanisms. 'IsValid' is implemented by checking this pointer.
     639                 : 
     640                 :     // NOTE: that mClass is retained so that GetInterfaceInfo can continue to
     641                 :     // work (and avoid crashing some platforms).
     642             276 :     mJSObj = nsnull;
     643                 : 
     644                 :     // Notify other wrappers in the chain.
     645             276 :     if (mNext)
     646               1 :         mNext->SystemIsBeingShutDown(rt);
     647             276 : }
     648                 : 
     649                 : /***************************************************************************/
     650                 : 
     651                 : /* readonly attribute nsISimpleEnumerator enumerator; */
     652                 : NS_IMETHODIMP
     653               0 : nsXPCWrappedJS::GetEnumerator(nsISimpleEnumerator * *aEnumerate)
     654                 : {
     655               0 :     XPCCallContext ccx(NATIVE_CALLER);
     656               0 :     if (!ccx.IsValid())
     657               0 :         return NS_ERROR_UNEXPECTED;
     658                 : 
     659                 :     return nsXPCWrappedJSClass::BuildPropertyEnumerator(ccx, GetJSObject(),
     660               0 :                                                         aEnumerate);
     661                 : }
     662                 : 
     663                 : /* nsIVariant getProperty (in AString name); */
     664                 : NS_IMETHODIMP
     665               6 : nsXPCWrappedJS::GetProperty(const nsAString & name, nsIVariant **_retval)
     666                 : {
     667              12 :     XPCCallContext ccx(NATIVE_CALLER);
     668               6 :     if (!ccx.IsValid())
     669               0 :         return NS_ERROR_UNEXPECTED;
     670                 : 
     671                 :     return nsXPCWrappedJSClass::
     672               6 :         GetNamedPropertyAsVariant(ccx, GetJSObject(), name, _retval);
     673                 : }
     674                 : 
     675                 : /***************************************************************************/
     676                 : 
     677                 : NS_IMETHODIMP
     678               0 : nsXPCWrappedJS::DebugDump(PRInt16 depth)
     679                 : {
     680                 : #ifdef DEBUG
     681               0 :     XPC_LOG_ALWAYS(("nsXPCWrappedJS @ %x with mRefCnt = %d", this, mRefCnt.get()));
     682               0 :         XPC_LOG_INDENT();
     683                 : 
     684               0 :         bool isRoot = mRoot == this;
     685               0 :         XPC_LOG_ALWAYS(("%s wrapper around JSObject @ %x", \
     686                 :                         isRoot ? "ROOT":"non-root", mJSObj));
     687                 :         char* name;
     688               0 :         GetClass()->GetInterfaceInfo()->GetName(&name);
     689               0 :         XPC_LOG_ALWAYS(("interface name is %s", name));
     690               0 :         if (name)
     691               0 :             nsMemory::Free(name);
     692               0 :         char * iid = GetClass()->GetIID().ToString();
     693               0 :         XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
     694               0 :         if (iid)
     695               0 :             NS_Free(iid);
     696               0 :         XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x", mClass));
     697                 : 
     698               0 :         if (!isRoot)
     699               0 :             XPC_LOG_OUTDENT();
     700               0 :         if (mNext) {
     701               0 :             if (isRoot) {
     702               0 :                 XPC_LOG_ALWAYS(("Additional wrappers for this object..."));
     703               0 :                 XPC_LOG_INDENT();
     704                 :             }
     705               0 :             mNext->DebugDump(depth);
     706               0 :             if (isRoot)
     707               0 :                 XPC_LOG_OUTDENT();
     708                 :         }
     709               0 :         if (isRoot)
     710               0 :             XPC_LOG_OUTDENT();
     711                 : #endif
     712               0 :     return NS_OK;
     713            4392 : }

Generated by: LCOV version 1.7