LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCWrappedNative.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1397 927 66.4 %
Date: 2012-06-02 Functions: 90 61 67.8 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=78:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *   John Bandhauer <jband@netscape.com> (original author)
      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                 : /* Wrapper object for reflecting native xpcom objects into JavaScript. */
      43                 : 
      44                 : #include "xpcprivate.h"
      45                 : #include "nsCRT.h"
      46                 : #include "XPCWrapper.h"
      47                 : #include "nsWrapperCacheInlines.h"
      48                 : #include "XPCLog.h"
      49                 : #include "nsINode.h"
      50                 : #include "XPCQuickStubs.h"
      51                 : #include "jsproxy.h"
      52                 : #include "AccessCheck.h"
      53                 : #include "WrapperFactory.h"
      54                 : #include "dombindings.h"
      55                 : 
      56                 : #include "nsContentUtils.h"
      57                 : 
      58                 : #include "mozilla/Util.h"
      59                 : 
      60                 : bool
      61           18474 : xpc_OkToHandOutWrapper(nsWrapperCache *cache)
      62                 : {
      63           18474 :     NS_ABORT_IF_FALSE(cache->GetWrapper(), "Must have wrapper");
      64           18474 :     NS_ABORT_IF_FALSE(cache->IsProxy() || IS_WN_WRAPPER(cache->GetWrapper()),
      65                 :                       "Must have proxy or XPCWrappedNative wrapper");
      66           18474 :     return cache->IsProxy() ?
      67            3093 :         mozilla::dom::binding::instanceIsProxy(cache->GetWrapper()) :
      68           15381 :         !static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(cache->GetWrapper()))->
      69           36948 :             NeedsSOW();
      70                 : }
      71                 : 
      72                 : /***************************************************************************/
      73                 : 
      74            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
      75                 : 
      76                 : NS_IMETHODIMP
      77             322 : NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Unlink(void *p)
      78                 : {
      79             322 :     XPCWrappedNative *tmp = static_cast<XPCWrappedNative*>(p);
      80             322 :     tmp->ExpireWrapper();
      81             322 :     return NS_OK;
      82                 : }
      83                 : 
      84                 : struct TraverseExpandoObjectClosure
      85                 : {
      86                 :     XPCWrappedNative *wn;
      87                 :     nsCycleCollectionTraversalCallback &cb;
      88                 : };
      89                 : 
      90                 : static PLDHashOperator
      91               0 : TraverseExpandoObjects(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
      92                 : {
      93               0 :     TraverseExpandoObjectClosure *closure = static_cast<TraverseExpandoObjectClosure*>(aClosure);
      94                 :     xpc::CompartmentPrivate *priv =
      95               0 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
      96                 : 
      97               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(closure->cb, "XPCWrappedNative expando object");
      98                 :     closure->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
      99               0 :                                 priv->LookupExpandoObjectPreserveColor(closure->wn));
     100                 : 
     101               0 :     return PL_DHASH_NEXT;
     102                 : }
     103                 : 
     104                 : NS_IMETHODIMP
     105             363 : NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
     106                 :                                                           nsCycleCollectionTraversalCallback &cb)
     107                 : {
     108             363 :     XPCWrappedNative *tmp = static_cast<XPCWrappedNative*>(p);
     109             363 :     if (!tmp->IsValid())
     110               0 :         return NS_OK;
     111                 : 
     112             363 :     if (NS_UNLIKELY(cb.WantDebugInfo())) {
     113                 :         char name[72];
     114               0 :         XPCNativeScriptableInfo* si = tmp->GetScriptableInfo();
     115               0 :         if (si)
     116                 :             JS_snprintf(name, sizeof(name), "XPCWrappedNative (%s)",
     117               0 :                         si->GetJSClass()->name);
     118                 :         else
     119               0 :             JS_snprintf(name, sizeof(name), "XPCWrappedNative");
     120                 : 
     121                 :         cb.DescribeRefCountedNode(tmp->mRefCnt.get(),
     122               0 :                                   sizeof(XPCWrappedNative), name);
     123                 :     } else {
     124             363 :         NS_IMPL_CYCLE_COLLECTION_DESCRIBE(XPCWrappedNative, tmp->mRefCnt.get())
     125                 :     }
     126                 : 
     127             363 :     if (tmp->mRefCnt.get() > 1) {
     128                 : 
     129                 :         // If our refcount is > 1, our reference to the flat JS object is
     130                 :         // considered "strong", and we're going to traverse it.
     131                 :         //
     132                 :         // If our refcount is <= 1, our reference to the flat JS object is
     133                 :         // considered "weak", and we're *not* going to traverse it.
     134                 :         //
     135                 :         // This reasoning is in line with the slightly confusing lifecycle rules
     136                 :         // for XPCWrappedNatives, described in a larger comment below and also
     137                 :         // on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping
     138                 : 
     139               0 :         JSObject *obj = tmp->GetFlatJSObjectPreserveColor();
     140               0 :         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFlatJSObject");
     141               0 :         cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, obj);
     142                 :     }
     143                 : 
     144             363 :     if (tmp->MightHaveExpandoObject()) {
     145               0 :         XPCJSRuntime *rt = tmp->GetRuntime();
     146               0 :         TraverseExpandoObjectClosure closure = { tmp, cb };
     147               0 :         rt->GetCompartmentMap().EnumerateRead(TraverseExpandoObjects, &closure);
     148                 :     }
     149                 : 
     150                 :     // XPCWrappedNative keeps its native object alive.
     151             363 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mIdentity");
     152             363 :     cb.NoteXPCOMChild(tmp->GetIdentityObject());
     153                 : 
     154             363 :     tmp->NoteTearoffs(cb);
     155                 : 
     156             363 :     return NS_OK;
     157                 : }
     158                 : 
     159                 : void
     160             363 : XPCWrappedNative::NoteTearoffs(nsCycleCollectionTraversalCallback& cb)
     161                 : {
     162                 :     // Tearoffs hold their native object alive. If their JS object hasn't been
     163                 :     // finalized yet we'll note the edge between the JS object and the native
     164                 :     // (see nsXPConnect::Traverse), but if their JS object has been finalized
     165                 :     // then the tearoff is only reachable through the XPCWrappedNative, so we
     166                 :     // record an edge here.
     167                 :     XPCWrappedNativeTearOffChunk* chunk;
     168             831 :     for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
     169             468 :         XPCWrappedNativeTearOff* to = chunk->mTearOffs;
     170             936 :         for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
     171             468 :             JSObject* jso = to->GetJSObjectPreserveColor();
     172             468 :             if (!jso) {
     173             468 :                 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "tearoff's mNative");
     174             468 :                 cb.NoteXPCOMChild(to->GetNative());
     175                 :             }
     176                 :         }
     177                 :     }
     178             363 : }
     179                 : 
     180                 : #ifdef XPC_CHECK_CLASSINFO_CLAIMS
     181                 : static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper);
     182                 : #else
     183                 : #define DEBUG_CheckClassInfoClaims(wrapper) ((void)0)
     184                 : #endif
     185                 : 
     186                 : #ifdef XPC_TRACK_WRAPPER_STATS
     187                 : static int DEBUG_TotalWrappedNativeCount;
     188                 : static int DEBUG_TotalLiveWrappedNativeCount;
     189                 : static int DEBUG_TotalMaxWrappedNativeCount;
     190                 : static int DEBUG_WrappedNativeWithProtoCount;
     191                 : static int DEBUG_LiveWrappedNativeWithProtoCount;
     192                 : static int DEBUG_MaxWrappedNativeWithProtoCount;
     193                 : static int DEBUG_WrappedNativeNoProtoCount;
     194                 : static int DEBUG_LiveWrappedNativeNoProtoCount;
     195                 : static int DEBUG_MaxWrappedNativeNoProtoCount;
     196                 : static int DEBUG_WrappedNativeTotalCalls;
     197                 : static int DEBUG_WrappedNativeMethodCalls;
     198                 : static int DEBUG_WrappedNativeGetterCalls;
     199                 : static int DEBUG_WrappedNativeSetterCalls;
     200                 : #define DEBUG_CHUNKS_TO_COUNT 4
     201                 : static int DEBUG_WrappedNativeTearOffChunkCounts[DEBUG_CHUNKS_TO_COUNT+1];
     202                 : static bool    DEBUG_DumpedWrapperStats;
     203                 : #endif
     204                 : 
     205                 : #ifdef DEBUG
     206         1256303 : static void DEBUG_TrackNewWrapper(XPCWrappedNative* wrapper)
     207                 : {
     208                 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
     209                 :     if (wrapper->GetRuntime())
     210                 :         wrapper->GetRuntime()->DEBUG_AddWrappedNative(wrapper);
     211                 :     else
     212                 :         NS_ERROR("failed to add wrapper");
     213                 : #endif
     214                 : #ifdef XPC_TRACK_WRAPPER_STATS
     215                 :     DEBUG_TotalWrappedNativeCount++;
     216                 :     DEBUG_TotalLiveWrappedNativeCount++;
     217                 :     if (DEBUG_TotalMaxWrappedNativeCount < DEBUG_TotalLiveWrappedNativeCount)
     218                 :         DEBUG_TotalMaxWrappedNativeCount = DEBUG_TotalLiveWrappedNativeCount;
     219                 : 
     220                 :     if (wrapper->HasProto()) {
     221                 :         DEBUG_WrappedNativeWithProtoCount++;
     222                 :         DEBUG_LiveWrappedNativeWithProtoCount++;
     223                 :         if (DEBUG_MaxWrappedNativeWithProtoCount < DEBUG_LiveWrappedNativeWithProtoCount)
     224                 :             DEBUG_MaxWrappedNativeWithProtoCount = DEBUG_LiveWrappedNativeWithProtoCount;
     225                 :     } else {
     226                 :         DEBUG_WrappedNativeNoProtoCount++;
     227                 :         DEBUG_LiveWrappedNativeNoProtoCount++;
     228                 :         if (DEBUG_MaxWrappedNativeNoProtoCount < DEBUG_LiveWrappedNativeNoProtoCount)
     229                 :             DEBUG_MaxWrappedNativeNoProtoCount = DEBUG_LiveWrappedNativeNoProtoCount;
     230                 :     }
     231                 : #endif
     232         1256303 : }
     233                 : 
     234         1255492 : static void DEBUG_TrackDeleteWrapper(XPCWrappedNative* wrapper)
     235                 : {
     236                 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
     237                 :     nsXPConnect::GetRuntimeInstance()->DEBUG_RemoveWrappedNative(wrapper);
     238                 : #endif
     239                 : #ifdef XPC_TRACK_WRAPPER_STATS
     240                 :     DEBUG_TotalLiveWrappedNativeCount--;
     241                 :     if (wrapper->HasProto())
     242                 :         DEBUG_LiveWrappedNativeWithProtoCount--;
     243                 :     else
     244                 :         DEBUG_LiveWrappedNativeNoProtoCount--;
     245                 : 
     246                 :     int extraChunkCount = wrapper->DEBUG_CountOfTearoffChunks() - 1;
     247                 :     if (extraChunkCount > DEBUG_CHUNKS_TO_COUNT)
     248                 :         extraChunkCount = DEBUG_CHUNKS_TO_COUNT;
     249                 :     DEBUG_WrappedNativeTearOffChunkCounts[extraChunkCount]++;
     250                 : #endif
     251         1255492 : }
     252         6752344 : static void DEBUG_TrackWrapperCall(XPCWrappedNative* wrapper,
     253                 :                                    XPCWrappedNative::CallMode mode)
     254                 : {
     255                 : #ifdef XPC_TRACK_WRAPPER_STATS
     256                 :     DEBUG_WrappedNativeTotalCalls++;
     257                 :     switch (mode) {
     258                 :         case XPCWrappedNative::CALL_METHOD:
     259                 :             DEBUG_WrappedNativeMethodCalls++;
     260                 :             break;
     261                 :         case XPCWrappedNative::CALL_GETTER:
     262                 :             DEBUG_WrappedNativeGetterCalls++;
     263                 :             break;
     264                 :         case XPCWrappedNative::CALL_SETTER:
     265                 :             DEBUG_WrappedNativeSetterCalls++;
     266                 :             break;
     267                 :         default:
     268                 :             NS_ERROR("bad value");
     269                 :     }
     270                 : #endif
     271         6752344 : }
     272                 : 
     273             781 : static void DEBUG_TrackShutdownWrapper(XPCWrappedNative* wrapper)
     274                 : {
     275                 : #ifdef XPC_TRACK_WRAPPER_STATS
     276                 :     if (!DEBUG_DumpedWrapperStats) {
     277                 :         DEBUG_DumpedWrapperStats = true;
     278                 :         printf("%d WrappedNatives were constructed. "
     279                 :                "(%d w/ protos, %d w/o)\n",
     280                 :                DEBUG_TotalWrappedNativeCount,
     281                 :                DEBUG_WrappedNativeWithProtoCount,
     282                 :                DEBUG_WrappedNativeNoProtoCount);
     283                 : 
     284                 :         printf("%d WrappedNatives max alive at one time. "
     285                 :                "(%d w/ protos, %d w/o)\n",
     286                 :                DEBUG_TotalMaxWrappedNativeCount,
     287                 :                DEBUG_MaxWrappedNativeWithProtoCount,
     288                 :                DEBUG_MaxWrappedNativeNoProtoCount);
     289                 : 
     290                 :         printf("%d WrappedNatives alive now. "
     291                 :                "(%d w/ protos, %d w/o)\n",
     292                 :                DEBUG_TotalLiveWrappedNativeCount,
     293                 :                DEBUG_LiveWrappedNativeWithProtoCount,
     294                 :                DEBUG_LiveWrappedNativeNoProtoCount);
     295                 : 
     296                 :         printf("%d calls to WrappedNatives. "
     297                 :                "(%d methods, %d getters, %d setters)\n",
     298                 :                DEBUG_WrappedNativeTotalCalls,
     299                 :                DEBUG_WrappedNativeMethodCalls,
     300                 :                DEBUG_WrappedNativeGetterCalls,
     301                 :                DEBUG_WrappedNativeSetterCalls);
     302                 : 
     303                 :         printf("(wrappers / tearoffs): (");
     304                 :         int i;
     305                 :         for (i = 0; i < DEBUG_CHUNKS_TO_COUNT; i++) {
     306                 :             printf("%d / %d, ",
     307                 :                    DEBUG_WrappedNativeTearOffChunkCounts[i],
     308                 :                    (i+1) * XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK);
     309                 :         }
     310                 :         printf("%d / more)\n", DEBUG_WrappedNativeTearOffChunkCounts[i]);
     311                 :     }
     312                 : #endif
     313             781 : }
     314                 : #else
     315                 : #define DEBUG_TrackNewWrapper(wrapper) ((void)0)
     316                 : #define DEBUG_TrackDeleteWrapper(wrapper) ((void)0)
     317                 : #define DEBUG_TrackWrapperCall(wrapper, mode) ((void)0)
     318                 : #define DEBUG_TrackShutdownWrapper(wrapper) ((void)0)
     319                 : #endif
     320                 : 
     321                 : /***************************************************************************/
     322                 : static nsresult
     323                 : FinishCreate(XPCCallContext& ccx,
     324                 :              XPCWrappedNativeScope* Scope,
     325                 :              XPCNativeInterface* Interface,
     326                 :              nsWrapperCache *cache,
     327                 :              XPCWrappedNative* inWrapper,
     328                 :              XPCWrappedNative** resultWrapper);
     329                 : 
     330                 : // static
     331                 : //
     332                 : // This method handles the special case of wrapping a new global object.
     333                 : //
     334                 : // The normal code path for wrapping natives goes through
     335                 : // XPCConvert::NativeInterface2JSObject, XPCWrappedNative::GetNewOrUsed,
     336                 : // and finally into XPCWrappedNative::Init. Unfortunately, this path assumes
     337                 : // very early on that we have an XPCWrappedNativeScope and corresponding global
     338                 : // JS object, which are the very things we need to create here. So we special-
     339                 : // case the logic and do some things in a different order.
     340                 : nsresult
     341           13217 : XPCWrappedNative::WrapNewGlobal(XPCCallContext &ccx, xpcObjectHelper &nativeHelper,
     342                 :                                 nsIPrincipal *principal, bool initStandardClasses,
     343                 :                                 XPCWrappedNative **wrappedGlobal)
     344                 : {
     345                 :     bool success;
     346                 :     nsresult rv;
     347           13217 :     nsISupports *identity = nativeHelper.GetCanonical();
     348                 : 
     349                 :     // The object should specify that it's meant to be global.
     350           13217 :     MOZ_ASSERT(nativeHelper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
     351                 : 
     352                 :     // We shouldn't be reusing globals.
     353           13217 :     MOZ_ASSERT(!nativeHelper.GetWrapperCache() ||
     354           13217 :                !nativeHelper.GetWrapperCache()->GetWrapperPreserveColor());
     355                 : 
     356                 :     // Put together the ScriptableCreateInfo...
     357           26434 :     XPCNativeScriptableCreateInfo sciProto;
     358           26434 :     XPCNativeScriptableCreateInfo sciMaybe;
     359                 :     const XPCNativeScriptableCreateInfo& sciWrapper =
     360                 :         GatherScriptableCreateInfo(identity, nativeHelper.GetClassInfo(),
     361           13217 :                                    sciProto, sciMaybe);
     362                 : 
     363                 :     // ...and then ScriptableInfo. We need all this stuff now because it's going
     364                 :     // to tell us the JSClass of the object we're going to create.
     365                 :     AutoMarkingNativeScriptableInfoPtr
     366           26434 :         si(ccx, XPCNativeScriptableInfo::Construct(ccx, &sciWrapper));
     367           13217 :     MOZ_ASSERT(si.get());
     368                 : 
     369                 :     // Finally, we get to the JSClass.
     370           13217 :     JSClass *clasp = si->GetJSClass();
     371           13217 :     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
     372                 : 
     373                 :     // Create the global.
     374                 :     JSObject *global;
     375                 :     JSCompartment *compartment;
     376                 :     rv = xpc_CreateGlobalObject(ccx, clasp, principal, nsnull, false,
     377           13217 :                                 &global, &compartment);
     378           13217 :     NS_ENSURE_SUCCESS(rv, rv);
     379                 : 
     380                 :     // Immediately enter the global's compartment, so that everything else we
     381                 :     // create ends up there.
     382           26434 :     JSAutoEnterCompartment ac;
     383           13217 :     success = ac.enter(ccx, global);
     384           13217 :     MOZ_ASSERT(success);
     385                 : 
     386                 :     // If requested, immediately initialize the standard classes on the global.
     387                 :     // We need to do this before creating a scope, because
     388                 :     // XPCWrappedNativeScope::SetGlobal resolves |Object| via
     389                 :     // JS_ResolveStandardClass. JS_InitStandardClasses asserts if any of the
     390                 :     // standard classes are already initialized, so this is a problem.
     391           13217 :     if (initStandardClasses && ! JS_InitStandardClasses(ccx, global))
     392               0 :         return NS_ERROR_FAILURE;
     393                 : 
     394                 :     // Create a scope, but don't do any extra stuff like initializing |Components|.
     395                 :     // All of that stuff happens in the caller.
     396           13217 :     XPCWrappedNativeScope *scope = XPCWrappedNativeScope::GetNewOrUsed(ccx, global, identity);
     397           13217 :     MOZ_ASSERT(scope);
     398                 : 
     399                 :     // Make a proto.
     400                 :     XPCWrappedNativeProto *proto =
     401                 :         XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, nativeHelper.GetClassInfo(), &sciProto,
     402           13217 :                                             UNKNOWN_OFFSETS, /* callPostCreatePrototype = */ false);
     403           13217 :     if (!proto)
     404               0 :         return NS_ERROR_FAILURE;
     405           13217 :     proto->CacheOffsets(identity);
     406                 : 
     407                 :     // Set up the prototype on the global.
     408           13217 :     MOZ_ASSERT(proto->GetJSProtoObject());
     409           13217 :     success = JS_SplicePrototype(ccx, global, proto->GetJSProtoObject());
     410           13217 :     if (!success)
     411               0 :         return NS_ERROR_FAILURE;
     412                 : 
     413                 :     // Construct the wrapper.
     414           39651 :     nsRefPtr<XPCWrappedNative> wrapper = new XPCWrappedNative(identity, proto);
     415                 : 
     416                 :     // The wrapper takes over the strong reference to the native object.
     417           13217 :     nativeHelper.forgetCanonical();
     418                 : 
     419                 :     //
     420                 :     // We don't call ::Init() on this wrapper, because our setup requirements
     421                 :     // are different for globals. We do our setup inline here, instead.
     422                 :     //
     423                 : 
     424                 :     // Share mScriptableInfo with the proto.
     425                 :     //
     426                 :     // This is probably more trouble than it's worth, since we've already created
     427                 :     // an XPCNativeScriptableInfo for ourselves. Moreover, most of that class is
     428                 :     // shared internally via XPCNativeScriptableInfoShared, so the memory
     429                 :     // savings are negligible. Nevertheless, this is what ::Init() does, and we
     430                 :     // want to be as consistent as possible with that code.
     431           13217 :     XPCNativeScriptableInfo* siProto = proto->GetScriptableInfo();
     432           13217 :     if (siProto && siProto->GetCallback() == sciWrapper.GetCallback()) {
     433               0 :         wrapper->mScriptableInfo = siProto;
     434               0 :         delete si;
     435                 :     } else {
     436           13217 :         wrapper->mScriptableInfo = si;
     437                 :     }
     438                 : 
     439                 :     // Set the JS object to the global we already created.
     440           13217 :     wrapper->mFlatJSObject = global;
     441                 : 
     442                 :     // Set the private to the XPCWrappedNative.
     443           13217 :     JS_SetPrivate(global, wrapper);
     444                 : 
     445                 :     // There are dire comments elsewhere in the code about how a GC can
     446                 :     // happen somewhere after wrapper initialization but before the wrapper is
     447                 :     // added to the hashtable in FinishCreate(). It's not clear if that can
     448                 :     // happen here, but let's just be safe for now.
     449           26434 :     AutoMarkingWrappedNativePtr wrapperMarker(ccx, wrapper);
     450                 : 
     451                 :     // Call the common Init finish routine. This mainly just does an AddRef
     452                 :     // on behalf of XPConnect (the corresponding Release is in the finalizer
     453                 :     // hook), but it does some other miscellaneous things too, so we don't
     454                 :     // inline it.
     455           13217 :     success = wrapper->FinishInit(ccx);
     456           13217 :     MOZ_ASSERT(success);
     457                 : 
     458                 :     // Go through some extra work to find the tearoff. This is kind of silly
     459                 :     // on a conceptual level: the point of tearoffs is to cache the results
     460                 :     // of QI-ing mIdentity to different interfaces, and we don't need that
     461                 :     // since we're dealing with nsISupports. But lots of code expects tearoffs
     462                 :     // to exist for everything, so we just follow along.
     463           13217 :     XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
     464           13217 :     MOZ_ASSERT(iface);
     465                 :     nsresult status;
     466           13217 :     success = wrapper->FindTearOff(ccx, iface, false, &status);
     467           13217 :     if (!success)
     468               0 :         return status;
     469                 : 
     470                 :     // Call the common creation finish routine. This does all of the bookkeeping
     471                 :     // like inserting the wrapper into the wrapper map and setting up the wrapper
     472                 :     // cache.
     473                 :     return FinishCreate(ccx, scope, iface, nativeHelper.GetWrapperCache(),
     474           13217 :                         wrapper, wrappedGlobal);
     475                 : }
     476                 : 
     477                 : // static
     478                 : nsresult
     479         2007018 : XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
     480                 :                                xpcObjectHelper& helper,
     481                 :                                XPCWrappedNativeScope* Scope,
     482                 :                                XPCNativeInterface* Interface,
     483                 :                                XPCWrappedNative** resultWrapper)
     484                 : {
     485         2007018 :     nsWrapperCache *cache = helper.GetWrapperCache();
     486                 : 
     487         2007018 :     NS_ASSERTION(!cache || !cache->GetWrapperPreserveColor(),
     488                 :                  "We assume the caller already checked if it could get the "
     489                 :                  "wrapper from the cache.");
     490                 : 
     491                 :     nsresult rv;
     492                 : 
     493         2007018 :     NS_ASSERTION(!Scope->GetRuntime()->GetThreadRunningGC(),
     494                 :                  "XPCWrappedNative::GetNewOrUsed called during GC");
     495                 : 
     496         2007018 :     nsISupports *identity = helper.GetCanonical();
     497                 : 
     498         2007018 :     if (!identity) {
     499               0 :         NS_ERROR("This XPCOM object fails in QueryInterface to nsISupports!");
     500               0 :         return NS_ERROR_FAILURE;
     501                 :     }
     502                 : 
     503         2007018 :     XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
     504                 : 
     505         4014036 :     nsRefPtr<XPCWrappedNative> wrapper;
     506                 : 
     507         2007018 :     Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
     508         2007018 :     if (!cache) {
     509                 :         {   // scoped lock
     510         4004822 :             XPCAutoLock lock(mapLock);
     511         2002411 :             wrapper = map->Find(identity);
     512                 :         }
     513                 : 
     514         2002411 :         if (wrapper) {
     515         1538369 :             if (Interface &&
     516          768373 :                 !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
     517               0 :                 NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
     518               0 :                 return rv;
     519                 :             }
     520          769996 :             DEBUG_CheckWrapperThreadSafety(wrapper);
     521          769996 :             *resultWrapper = wrapper.forget().get();
     522          769996 :             return NS_OK;
     523                 :         }
     524                 :     }
     525                 : #ifdef DEBUG
     526            4607 :     else if (!cache->GetWrapperPreserveColor())
     527                 :     {   // scoped lock
     528            9214 :         XPCAutoLock lock(mapLock);
     529            4607 :         NS_ASSERTION(!map->Find(identity),
     530                 :                      "There's a wrapper in the hashtable but it wasn't cached?");
     531                 :     }
     532                 : #endif
     533                 : 
     534                 :     // There is a chance that the object wants to have the self-same JSObject
     535                 :     // reflection regardless of the scope into which we are reflecting it.
     536                 :     // Many DOM objects require this. The scriptable helper specifies this
     537                 :     // in preCreate by indicating a 'parent' of a particular scope.
     538                 :     //
     539                 :     // To handle this we need to get the scriptable helper early and ask it.
     540                 :     // It is possible that we will then end up forwarding this entire call
     541                 :     // to this same function but with a different scope.
     542                 : 
     543                 :     // If we are making a wrapper for the nsIClassInfo interface then
     544                 :     // We *don't* want to have it use the prototype meant for instances
     545                 :     // of that class.
     546                 :     JSBool isClassInfo = Interface &&
     547         1237022 :                          Interface->GetIID()->Equals(NS_GET_IID(nsIClassInfo));
     548                 : 
     549         1237022 :     nsIClassInfo *info = helper.GetClassInfo();
     550                 : 
     551         2474044 :     XPCNativeScriptableCreateInfo sciProto;
     552         2474044 :     XPCNativeScriptableCreateInfo sci;
     553                 : 
     554                 :     // Gather scriptable create info if we are wrapping something
     555                 :     // other than an nsIClassInfo object. We need to not do this for
     556                 :     // nsIClassInfo objects because often nsIClassInfo implementations
     557                 :     // are also nsIXPCScriptable helper implementations, but the helper
     558                 :     // code is obviously intended for the implementation of the class
     559                 :     // described by the nsIClassInfo, not for the class info object
     560                 :     // itself.
     561                 :     const XPCNativeScriptableCreateInfo& sciWrapper =
     562                 :         isClassInfo ? sci :
     563         1237022 :         GatherScriptableCreateInfo(identity, info, sciProto, sci);
     564                 : 
     565         1237022 :     JSObject* parent = Scope->GetGlobalJSObject();
     566                 : 
     567         1237022 :     jsval newParentVal = JSVAL_NULL;
     568         2474044 :     XPCMarkableJSVal newParentVal_markable(&newParentVal);
     569         2474044 :     AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
     570         1237022 :     JSBool needsSOW = false;
     571         1237022 :     JSBool needsCOW = false;
     572                 : 
     573         2474044 :     JSAutoEnterCompartment ac;
     574                 : 
     575         1237022 :     if (sciWrapper.GetFlags().WantPreCreate()) {
     576           11682 :         JSObject* plannedParent = parent;
     577           11682 :         nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
     578           11682 :                                                           parent, &parent);
     579           11682 :         if (NS_FAILED(rv))
     580               0 :             return rv;
     581                 : 
     582           11682 :         if (rv == NS_SUCCESS_CHROME_ACCESS_ONLY)
     583               0 :             needsSOW = true;
     584           11682 :         rv = NS_OK;
     585                 : 
     586           11682 :         NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(parent),
     587                 :                      "Xray wrapper being used to parent XPCWrappedNative?");
     588                 : 
     589           11682 :         if (!ac.enter(ccx, parent))
     590               0 :             return NS_ERROR_FAILURE;
     591                 : 
     592           11682 :         if (parent != plannedParent) {
     593                 :             XPCWrappedNativeScope* betterScope =
     594               2 :                 XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
     595               2 :             if (betterScope != Scope)
     596               1 :                 return GetNewOrUsed(ccx, helper, betterScope, Interface, resultWrapper);
     597                 : 
     598               1 :             newParentVal = OBJECT_TO_JSVAL(parent);
     599                 :         }
     600                 : 
     601                 :         // Take the performance hit of checking the hashtable again in case
     602                 :         // the preCreate call caused the wrapper to get created through some
     603                 :         // interesting path (the DOM code tends to make this happen sometimes).
     604                 : 
     605           11681 :         if (cache) {
     606            4606 :             JSObject *cached = cache->GetWrapper();
     607            4606 :             if (cached) {
     608               0 :                 if (IS_SLIM_WRAPPER_OBJECT(cached)) {
     609               0 :                     if (!XPCWrappedNative::Morph(ccx, cached, Interface, cache,
     610               0 :                                                  getter_AddRefs(wrapper)))
     611               0 :                         return NS_ERROR_FAILURE;
     612                 :                 } else {
     613               0 :                     wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(cached));
     614                 :                 }
     615                 :             }
     616                 :         } else {
     617                 :             // scoped lock
     618           14150 :             XPCAutoLock lock(mapLock);
     619            7075 :             wrapper = map->Find(identity);
     620                 :         }
     621                 : 
     622           11681 :         if (wrapper) {
     623               0 :             if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
     624               0 :                 NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
     625               0 :                 return rv;
     626                 :             }
     627               0 :             DEBUG_CheckWrapperThreadSafety(wrapper);
     628               0 :             *resultWrapper = wrapper.forget().get();
     629               0 :             return NS_OK;
     630                 :         }
     631                 :     } else {
     632         1225340 :         if (!ac.enter(ccx, parent))
     633               0 :             return NS_ERROR_FAILURE;
     634                 : 
     635         1225340 :         nsISupports *Object = helper.Object();
     636         1225340 :         if (nsXPCWrappedJSClass::IsWrappedJS(Object)) {
     637           34156 :             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
     638                 :             JSObject *obj;
     639           17078 :             wrappedjs->GetJSObject(&obj);
     640           34156 :             if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj)) &&
     641           17078 :                 !xpc::AccessCheck::isChrome(js::GetObjectCompartment(Scope->GetGlobalJSObject()))) {
     642               0 :                 needsCOW = true;
     643                 :             }
     644                 :         }
     645                 :     }
     646                 : 
     647         2474042 :     AutoMarkingWrappedNativeProtoPtr proto(ccx);
     648                 : 
     649                 :     // If there is ClassInfo (and we are not building a wrapper for the
     650                 :     // nsIClassInfo interface) then we use a wrapper that needs a prototype.
     651                 : 
     652                 :     // Note that the security check happens inside FindTearOff - after the
     653                 :     // wrapper is actually created, but before JS code can see it.
     654                 : 
     655         1237021 :     if (info && !isClassInfo) {
     656          354702 :         proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, Scope, info, &sciProto);
     657          354702 :         if (!proto)
     658               0 :             return NS_ERROR_FAILURE;
     659                 : 
     660          354702 :         proto->CacheOffsets(identity);
     661                 : 
     662          709404 :         wrapper = new XPCWrappedNative(identity, proto);
     663          709404 :         if (!wrapper)
     664               0 :             return NS_ERROR_FAILURE;
     665                 :     } else {
     666         1764638 :         AutoMarkingNativeInterfacePtr iface(ccx, Interface);
     667          882319 :         if (!iface)
     668               0 :             iface = XPCNativeInterface::GetISupports(ccx);
     669                 : 
     670         1764638 :         AutoMarkingNativeSetPtr set(ccx);
     671          882319 :         set = XPCNativeSet::GetNewOrUsed(ccx, nsnull, iface, 0);
     672                 : 
     673          882319 :         if (!set)
     674               0 :             return NS_ERROR_FAILURE;
     675                 : 
     676         1764638 :         wrapper = new XPCWrappedNative(identity, Scope, set);
     677          882319 :         if (!wrapper)
     678               0 :             return NS_ERROR_FAILURE;
     679                 : 
     680                 :         DEBUG_ReportShadowedMembers(set, wrapper, nsnull);
     681                 :     }
     682                 : 
     683                 :     // The strong reference was taken over by the wrapper, so make the nsCOMPtr
     684                 :     // forget about it.
     685         1237021 :     helper.forgetCanonical();
     686                 : 
     687         1237021 :     NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(parent),
     688                 :                  "Xray wrapper being used to parent XPCWrappedNative?");
     689                 : 
     690                 :     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
     691                 :     // after we have Init'd the wrapper but *before* we add it to the hashtable.
     692                 :     // This would cause the mSet to get collected and we'd later crash. I've
     693                 :     // *seen* this happen.
     694         2474042 :     AutoMarkingWrappedNativePtr wrapperMarker(ccx, wrapper);
     695                 : 
     696         1237021 :     if (!wrapper->Init(ccx, parent, &sciWrapper))
     697               0 :         return NS_ERROR_FAILURE;
     698                 : 
     699         1237021 :     if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
     700               0 :         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
     701               0 :         return rv;
     702                 :     }
     703                 : 
     704         1237021 :     if (needsSOW)
     705               0 :         wrapper->SetNeedsSOW();
     706         1237021 :     if (needsCOW)
     707               0 :         wrapper->SetNeedsCOW();
     708                 : 
     709         1237021 :     return FinishCreate(ccx, Scope, Interface, cache, wrapper, resultWrapper);
     710                 : }
     711                 : 
     712                 : static nsresult
     713         1256303 : FinishCreate(XPCCallContext& ccx,
     714                 :              XPCWrappedNativeScope* Scope,
     715                 :              XPCNativeInterface* Interface,
     716                 :              nsWrapperCache *cache,
     717                 :              XPCWrappedNative* inWrapper,
     718                 :              XPCWrappedNative** resultWrapper)
     719                 : {
     720         1256303 :     MOZ_ASSERT(inWrapper);
     721                 : 
     722                 : #if DEBUG_xpc_leaks
     723                 :     {
     724                 :         char* s = wrapper->ToString(ccx);
     725                 :         NS_ASSERTION(wrapper->IsValid(), "eh?");
     726                 :         printf("Created wrapped native %s, flat JSObject is %p\n",
     727                 :                s, (void*)wrapper->GetFlatJSObjectNoMark());
     728                 :         if (s)
     729                 :             JS_smprintf_free(s);
     730                 :     }
     731                 : #endif
     732                 : 
     733         1256303 :     XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
     734         1256303 :     Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
     735                 : 
     736         2512606 :     nsRefPtr<XPCWrappedNative> wrapper;
     737                 :     {   // scoped lock
     738                 : 
     739                 :         // Deal with the case where the wrapper got created as a side effect
     740                 :         // of one of our calls out of this code (or on another thread). Add()
     741                 :         // returns the (possibly pre-existing) wrapper that ultimately ends up
     742                 :         // in the map, which is what we want.
     743         2512606 :         XPCAutoLock lock(mapLock);
     744         1256303 :         wrapper = map->Add(inWrapper);
     745         1256303 :         if (!wrapper)
     746               0 :             return NS_ERROR_FAILURE;
     747                 :     }
     748                 : 
     749         1256303 :     if (wrapper == inWrapper) {
     750         1256303 :         JSObject *flat = wrapper->GetFlatJSObject();
     751         1256303 :         NS_ASSERTION(!cache || !cache->GetWrapperPreserveColor() ||
     752                 :                      flat == cache->GetWrapperPreserveColor(),
     753                 :                      "This object has a cached wrapper that's different from "
     754                 :                      "the JSObject held by its native wrapper?");
     755                 : 
     756         1256303 :         if (cache && !cache->GetWrapperPreserveColor())
     757            4606 :             cache->SetWrapper(flat);
     758                 : 
     759                 :         // Our newly created wrapper is the one that we just added to the table.
     760                 :         // All is well. Call PostCreate as necessary.
     761         1256303 :         XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
     762         1256303 :         if (si && si->GetFlags().WantPostCreate()) {
     763            1164 :             nsresult rv = si->GetCallback()->PostCreate(wrapper, ccx, flat);
     764            1164 :             if (NS_FAILED(rv)) {
     765                 :                 // PostCreate failed and that's Very Bad. We'll remove it from
     766                 :                 // the map and mark it as invalid, but the PostCreate function
     767                 :                 // may have handed the partially-constructed-and-now-invalid
     768                 :                 // wrapper to someone before failing. Or, perhaps worse, the
     769                 :                 // PostCreate call could have triggered code that reentered
     770                 :                 // XPConnect and tried to wrap the same object. In that case
     771                 :                 // *we* hand out the invalid wrapper since it is already in our
     772                 :                 // map :(
     773                 :                 NS_ERROR("PostCreate failed! This is known to cause "
     774                 :                          "inconsistent state for some class types and may even "
     775                 :                          "cause a crash in combination with a JS GC. Fix the "
     776               0 :                          "failing PostCreate ASAP!");
     777                 : 
     778                 :                 {   // scoped lock
     779               0 :                     XPCAutoLock lock(mapLock);
     780               0 :                     map->Remove(wrapper);
     781                 :                 }
     782                 : 
     783                 :                 // This would be a good place to tell the wrapper not to remove
     784                 :                 // itself from the map when it dies... See bug 429442.
     785                 : 
     786               0 :                 if (cache)
     787               0 :                     cache->ClearWrapper();
     788               0 :                 wrapper->Release();
     789               0 :                 return rv;
     790                 :             }
     791                 :         }
     792                 :     }
     793                 : 
     794                 :     DEBUG_CheckClassInfoClaims(wrapper);
     795         1256303 :     *resultWrapper = wrapper.forget().get();
     796         1256303 :     return NS_OK;
     797                 : }
     798                 : 
     799                 : // static
     800                 : nsresult
     801            6065 : XPCWrappedNative::Morph(XPCCallContext& ccx,
     802                 :                         JSObject* existingJSObject,
     803                 :                         XPCNativeInterface* Interface,
     804                 :                         nsWrapperCache *cache,
     805                 :                         XPCWrappedNative** resultWrapper)
     806                 : {
     807            6065 :     NS_ASSERTION(IS_SLIM_WRAPPER(existingJSObject),
     808                 :                  "Trying to morph a JSObject that's not a slim wrapper?");
     809                 : 
     810                 :     nsISupports *identity =
     811            6065 :         static_cast<nsISupports*>(xpc_GetJSPrivate(existingJSObject));
     812            6065 :     XPCWrappedNativeProto *proto = GetSlimWrapperProto(existingJSObject);
     813                 : 
     814                 : #if DEBUG
     815                 :     // FIXME Can't assert this until
     816                 :     //       https://bugzilla.mozilla.org/show_bug.cgi?id=343141 is fixed.
     817                 : #if 0
     818                 :     if (proto->GetScriptableInfo()->GetFlags().WantPreCreate()) {
     819                 :         JSObject* parent = JS_GetParent(existingJSObject);
     820                 :         JSObject* plannedParent = parent;
     821                 :         nsresult rv =
     822                 :             proto->GetScriptableInfo()->GetCallback()->PreCreate(identity, ccx,
     823                 :                                                                  parent,
     824                 :                                                                  &parent);
     825                 :         if (NS_FAILED(rv))
     826                 :             return rv;
     827                 : 
     828                 :         NS_ASSERTION(parent == plannedParent,
     829                 :                      "PreCreate returned a different parent");
     830                 :     }
     831                 : #endif
     832                 : #endif
     833                 : 
     834           18195 :     nsRefPtr<XPCWrappedNative> wrapper = new XPCWrappedNative(dont_AddRef(identity), proto);
     835            6065 :     if (!wrapper)
     836               0 :         return NS_ERROR_FAILURE;
     837                 : 
     838            6065 :     NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(js::GetObjectParent(existingJSObject)),
     839                 :                  "Xray wrapper being used to parent XPCWrappedNative?");
     840                 : 
     841                 :     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
     842                 :     // after we have Init'd the wrapper but *before* we add it to the hashtable.
     843                 :     // This would cause the mSet to get collected and we'd later crash. I've
     844                 :     // *seen* this happen.
     845           12130 :     AutoMarkingWrappedNativePtr wrapperMarker(ccx, wrapper);
     846                 : 
     847           12130 :     JSAutoEnterCompartment ac;
     848            6065 :     if (!ac.enter(ccx, existingJSObject)) {
     849               0 :         wrapper->mIdentity = nsnull;
     850               0 :         return NS_ERROR_FAILURE;
     851                 :     }
     852            6065 :     if (!wrapper->Init(ccx, existingJSObject))
     853               0 :         return NS_ERROR_FAILURE;
     854                 : 
     855                 :     nsresult rv;
     856            6065 :     if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
     857               0 :         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
     858               0 :         return rv;
     859                 :     }
     860                 : 
     861            6065 :     return FinishCreate(ccx, wrapper->GetScope(), Interface, cache, wrapper, resultWrapper);
     862                 : }
     863                 : 
     864                 : // static
     865                 : nsresult
     866               0 : XPCWrappedNative::GetUsedOnly(XPCCallContext& ccx,
     867                 :                               nsISupports* Object,
     868                 :                               XPCWrappedNativeScope* Scope,
     869                 :                               XPCNativeInterface* Interface,
     870                 :                               XPCWrappedNative** resultWrapper)
     871                 : {
     872               0 :     NS_ASSERTION(Object, "XPCWrappedNative::GetUsedOnly was called with a null Object");
     873                 : 
     874                 :     XPCWrappedNative* wrapper;
     875               0 :     nsWrapperCache* cache = nsnull;
     876               0 :     CallQueryInterface(Object, &cache);
     877               0 :     if (cache) {
     878               0 :         JSObject *flat = cache->GetWrapper();
     879               0 :         if (flat && IS_SLIM_WRAPPER_OBJECT(flat) && !MorphSlimWrapper(ccx, flat))
     880               0 :            return NS_ERROR_FAILURE;
     881                 : 
     882                 :         wrapper = flat ?
     883               0 :                   static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(flat)) :
     884               0 :                   nsnull;
     885                 : 
     886               0 :         if (!wrapper) {
     887               0 :             *resultWrapper = nsnull;
     888               0 :             return NS_OK;
     889                 :         }
     890               0 :         NS_ADDREF(wrapper);
     891                 :     } else {
     892               0 :         nsCOMPtr<nsISupports> identity = do_QueryInterface(Object);
     893                 : 
     894               0 :         if (!identity) {
     895               0 :             NS_ERROR("This XPCOM object fails in QueryInterface to nsISupports!");
     896               0 :             return NS_ERROR_FAILURE;
     897                 :         }
     898                 : 
     899               0 :         Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
     900                 : 
     901                 :         {   // scoped lock
     902               0 :             XPCAutoLock lock(Scope->GetRuntime()->GetMapLock());
     903               0 :             wrapper = map->Find(identity);
     904               0 :             if (!wrapper) {
     905               0 :                 *resultWrapper = nsnull;
     906               0 :                 return NS_OK;
     907                 :             }
     908               0 :             NS_ADDREF(wrapper);
     909                 :         }
     910                 :     }
     911                 : 
     912                 :     nsresult rv;
     913               0 :     if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
     914               0 :         NS_RELEASE(wrapper);
     915               0 :         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
     916               0 :         return rv;
     917                 :     }
     918                 : 
     919               0 :     *resultWrapper = wrapper;
     920               0 :     return NS_OK;
     921                 : }
     922                 : 
     923                 : // This ctor is used if this object will have a proto.
     924          373984 : XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports> aIdentity,
     925                 :                                    XPCWrappedNativeProto* aProto)
     926                 :     : mMaybeProto(aProto),
     927          373984 :       mSet(aProto->GetSet()),
     928                 :       mFlatJSObject(INVALID_OBJECT), // non-null to pass IsValid() test
     929                 :       mScriptableInfo(nsnull),
     930                 :       mWrapperWord(0)
     931                 : #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
     932          747968 :     , mThread(PR_GetCurrentThread())
     933                 : #endif
     934                 : {
     935          373984 :     mIdentity = aIdentity.get();
     936                 : 
     937          373984 :     NS_ASSERTION(mMaybeProto, "bad ctor param");
     938          373984 :     NS_ASSERTION(mSet, "bad ctor param");
     939                 : 
     940          373984 :     DEBUG_TrackNewWrapper(this);
     941          373984 : }
     942                 : 
     943                 : // This ctor is used if this object will NOT have a proto.
     944          882319 : XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports> aIdentity,
     945                 :                                    XPCWrappedNativeScope* aScope,
     946                 :                                    XPCNativeSet* aSet)
     947                 : 
     948          882319 :     : mMaybeScope(TagScope(aScope)),
     949                 :       mSet(aSet),
     950                 :       mFlatJSObject(INVALID_OBJECT), // non-null to pass IsValid() test
     951                 :       mScriptableInfo(nsnull),
     952                 :       mWrapperWord(0)
     953                 : #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
     954         1764638 :     , mThread(PR_GetCurrentThread())
     955                 : #endif
     956                 : {
     957          882319 :     mIdentity = aIdentity.get();
     958                 : 
     959          882319 :     NS_ASSERTION(aScope, "bad ctor param");
     960          882319 :     NS_ASSERTION(aSet, "bad ctor param");
     961                 : 
     962          882319 :     DEBUG_TrackNewWrapper(this);
     963          882319 : }
     964                 : 
     965         3766476 : XPCWrappedNative::~XPCWrappedNative()
     966                 : {
     967         1255492 :     DEBUG_TrackDeleteWrapper(this);
     968                 : 
     969         1255492 :     Destroy();
     970         5021968 : }
     971                 : 
     972                 : static const PRWord WRAPPER_WORD_POISON = 0xa8a8a8a8;
     973                 : 
     974                 : void
     975         1255814 : XPCWrappedNative::Destroy()
     976                 : {
     977         1255814 :     XPCWrappedNativeProto* proto = GetProto();
     978                 : 
     979         1780786 :     if (mScriptableInfo &&
     980          276245 :         (!HasProto() ||
     981          248727 :          (proto && proto->GetScriptableInfo() != mScriptableInfo))) {
     982          234360 :         delete mScriptableInfo;
     983          234360 :         mScriptableInfo = nsnull;
     984                 :     }
     985                 : 
     986         1255814 :     XPCWrappedNativeScope *scope = GetScope();
     987         1255814 :     if (scope) {
     988         1255492 :         Native2WrappedNativeMap* map = scope->GetWrappedNativeMap();
     989                 : 
     990                 :         // scoped lock
     991         2510984 :         XPCAutoLock lock(GetRuntime()->GetMapLock());
     992                 : 
     993                 :         // Post-1.9 we should not remove this wrapper from the map if it is
     994                 :         // uninitialized.
     995         1255492 :         map->Remove(this);
     996                 :     }
     997                 : 
     998         1255814 :     if (mIdentity) {
     999         1255492 :         XPCJSRuntime* rt = GetRuntime();
    1000         1255492 :         if (rt && rt->GetDoingFinalization()) {
    1001         1255492 :             if (rt->DeferredRelease(mIdentity)) {
    1002         1255492 :                 mIdentity = nsnull;
    1003                 :             } else {
    1004               0 :                 NS_WARNING("Failed to append object for deferred release.");
    1005                 :                 // XXX do we really want to do this???
    1006               0 :                 NS_RELEASE(mIdentity);
    1007                 :             }
    1008                 :         } else {
    1009               0 :             NS_RELEASE(mIdentity);
    1010                 :         }
    1011                 :     }
    1012                 : 
    1013                 :     /*
    1014                 :      * The only time GetRuntime() will be NULL is if Destroy is called a second
    1015                 :      * time on a wrapped native. Since we already unregistered the pointer the
    1016                 :      * first time, there's no need to unregister again. Unregistration is safe
    1017                 :      * the first time because mWrapperWord isn't used afterwards.
    1018                 :      */
    1019         1255814 :     if (XPCJSRuntime *rt = GetRuntime()) {
    1020         1255492 :         if (js::IsIncrementalBarrierNeeded(rt->GetJSRuntime()))
    1021               0 :             js::IncrementalReferenceBarrier(GetWrapperPreserveColor());
    1022         1255492 :         mWrapperWord = WRAPPER_WORD_POISON;
    1023                 :     } else {
    1024             322 :         MOZ_ASSERT(mWrapperWord == WRAPPER_WORD_POISON);
    1025                 :     }
    1026                 : 
    1027         1255814 :     mMaybeScope = nsnull;
    1028         1255814 : }
    1029                 : 
    1030                 : void
    1031               0 : XPCWrappedNative::UpdateScriptableInfo(XPCNativeScriptableInfo *si)
    1032                 : {
    1033               0 :     NS_ASSERTION(mScriptableInfo, "UpdateScriptableInfo expects an existing scriptable info");
    1034                 : 
    1035                 :     // Write barrier for incremental GC.
    1036               0 :     JSRuntime* rt = GetRuntime()->GetJSRuntime();
    1037               0 :     if (js::IsIncrementalBarrierNeeded(rt))
    1038               0 :         mScriptableInfo->Mark();
    1039                 : 
    1040               0 :     mScriptableInfo = si;
    1041               0 : }
    1042                 : 
    1043                 : void
    1044               0 : XPCWrappedNative::SetProto(XPCWrappedNativeProto* p)
    1045                 : {
    1046               0 :     NS_ASSERTION(!IsWrapperExpired(), "bad ptr!");
    1047                 : 
    1048               0 :     MOZ_ASSERT(HasProto());
    1049                 : 
    1050                 :     // Write barrier for incremental GC.
    1051               0 :     JSRuntime* rt = GetRuntime()->GetJSRuntime();
    1052               0 :     GetProto()->WriteBarrierPre(rt);
    1053                 : 
    1054               0 :     mMaybeProto = p;
    1055               0 : }
    1056                 : 
    1057                 : // This is factored out so that it can be called publicly
    1058                 : // static
    1059                 : void
    1060          367920 : XPCWrappedNative::GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
    1061                 :                                                   XPCNativeScriptableCreateInfo& sciProto)
    1062                 : {
    1063          367920 :     NS_ASSERTION(classInfo, "bad param");
    1064          367920 :     NS_ASSERTION(!sciProto.GetCallback(), "bad param");
    1065                 : 
    1066          367920 :     nsXPCClassInfo *classInfoHelper = nsnull;
    1067          367920 :     CallQueryInterface(classInfo, &classInfoHelper);
    1068          367920 :     if (classInfoHelper) {
    1069                 :         nsCOMPtr<nsIXPCScriptable> helper =
    1070           23364 :           dont_AddRef(static_cast<nsIXPCScriptable*>(classInfoHelper));
    1071                 :         uint32_t flags;
    1072           11682 :         nsresult rv = classInfoHelper->GetScriptableFlags(&flags);
    1073           11682 :         if (NS_FAILED(rv))
    1074               0 :             flags = 0;
    1075                 : 
    1076           11682 :         sciProto.SetCallback(helper.forget());
    1077           11682 :         sciProto.SetFlags(flags);
    1078           11682 :         sciProto.SetInterfacesBitmap(classInfoHelper->GetInterfacesBitmap());
    1079                 : 
    1080                 :         return;
    1081                 :     }
    1082                 : 
    1083          712476 :     nsCOMPtr<nsISupports> possibleHelper;
    1084                 :     nsresult rv = classInfo->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
    1085          356238 :                                                   getter_AddRefs(possibleHelper));
    1086          356238 :     if (NS_SUCCEEDED(rv) && possibleHelper) {
    1087          230616 :         nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(possibleHelper));
    1088          115308 :         if (helper) {
    1089                 :             uint32_t flags;
    1090          115308 :             rv = helper->GetScriptableFlags(&flags);
    1091          115308 :             if (NS_FAILED(rv))
    1092               0 :                 flags = 0;
    1093                 : 
    1094          115308 :             sciProto.SetCallback(helper.forget());
    1095          115308 :             sciProto.SetFlags(flags);
    1096                 :         }
    1097                 :     }
    1098                 : }
    1099                 : 
    1100                 : // static
    1101                 : const XPCNativeScriptableCreateInfo&
    1102         1250235 : XPCWrappedNative::GatherScriptableCreateInfo(nsISupports* obj,
    1103                 :                                              nsIClassInfo* classInfo,
    1104                 :                                              XPCNativeScriptableCreateInfo& sciProto,
    1105                 :                                              XPCNativeScriptableCreateInfo& sciWrapper)
    1106                 : {
    1107         1250235 :     NS_ASSERTION(!sciWrapper.GetCallback(), "bad param");
    1108                 : 
    1109                 :     // Get the class scriptable helper (if present)
    1110         1250235 :     if (classInfo) {
    1111          367920 :         GatherProtoScriptableCreateInfo(classInfo, sciProto);
    1112                 : 
    1113          367920 :         if (sciProto.GetFlags().DontAskInstanceForScriptable())
    1114           11682 :             return sciProto;
    1115                 :     }
    1116                 : 
    1117                 :     // Do the same for the wrapper specific scriptable
    1118         2477106 :     nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(obj));
    1119         1238553 :     if (helper) {
    1120                 :         uint32_t flags;
    1121          235121 :         nsresult rv = helper->GetScriptableFlags(&flags);
    1122          235121 :         if (NS_FAILED(rv))
    1123               0 :             flags = 0;
    1124                 : 
    1125          235121 :         sciWrapper.SetCallback(helper.forget());
    1126          235121 :         sciWrapper.SetFlags(flags);
    1127                 : 
    1128                 :         // A whole series of assertions to catch bad uses of scriptable flags on
    1129                 :         // the siWrapper...
    1130                 : 
    1131          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().WantPreCreate() &&
    1132                 :                        !sciProto.GetFlags().WantPreCreate()),
    1133                 :                      "Can't set WANT_PRECREATE on an instance scriptable "
    1134                 :                      "without also setting it on the class scriptable");
    1135                 : 
    1136          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().DontEnumStaticProps() &&
    1137                 :                        !sciProto.GetFlags().DontEnumStaticProps() &&
    1138                 :                        sciProto.GetCallback()),
    1139                 :                      "Can't set DONT_ENUM_STATIC_PROPS on an instance scriptable "
    1140                 :                      "without also setting it on the class scriptable (if present and shared)");
    1141                 : 
    1142          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().DontEnumQueryInterface() &&
    1143                 :                        !sciProto.GetFlags().DontEnumQueryInterface() &&
    1144                 :                        sciProto.GetCallback()),
    1145                 :                      "Can't set DONT_ENUM_QUERY_INTERFACE on an instance scriptable "
    1146                 :                      "without also setting it on the class scriptable (if present and shared)");
    1147                 : 
    1148          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().DontAskInstanceForScriptable() &&
    1149                 :                        !sciProto.GetFlags().DontAskInstanceForScriptable()),
    1150                 :                      "Can't set DONT_ASK_INSTANCE_FOR_SCRIPTABLE on an instance scriptable "
    1151                 :                      "without also setting it on the class scriptable");
    1152                 : 
    1153          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().ClassInfoInterfacesOnly() &&
    1154                 :                        !sciProto.GetFlags().ClassInfoInterfacesOnly() &&
    1155                 :                        sciProto.GetCallback()),
    1156                 :                      "Can't set CLASSINFO_INTERFACES_ONLY on an instance scriptable "
    1157                 :                      "without also setting it on the class scriptable (if present and shared)");
    1158                 : 
    1159          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().AllowPropModsDuringResolve() &&
    1160                 :                        !sciProto.GetFlags().AllowPropModsDuringResolve() &&
    1161                 :                        sciProto.GetCallback()),
    1162                 :                      "Can't set ALLOW_PROP_MODS_DURING_RESOLVE on an instance scriptable "
    1163                 :                      "without also setting it on the class scriptable (if present and shared)");
    1164                 : 
    1165          235121 :         NS_ASSERTION(!(sciWrapper.GetFlags().AllowPropModsToPrototype() &&
    1166                 :                        !sciProto.GetFlags().AllowPropModsToPrototype() &&
    1167                 :                        sciProto.GetCallback()),
    1168                 :                      "Can't set ALLOW_PROP_MODS_TO_PROTOTYPE on an instance scriptable "
    1169                 :                      "without also setting it on the class scriptable (if present and shared)");
    1170                 : 
    1171          235121 :         return sciWrapper;
    1172                 :     }
    1173                 : 
    1174         1003432 :     return sciProto;
    1175                 : }
    1176                 : 
    1177                 : #ifdef DEBUG_slimwrappers
    1178                 : static PRUint32 sMorphedSlimWrappers;
    1179                 : #endif
    1180                 : 
    1181                 : JSBool
    1182         1237021 : XPCWrappedNative::Init(XPCCallContext& ccx, JSObject* parent,
    1183                 :                        const XPCNativeScriptableCreateInfo* sci)
    1184                 : {
    1185                 :     // setup our scriptable info...
    1186                 : 
    1187         1237021 :     if (sci->GetCallback()) {
    1188          257555 :         if (HasProto()) {
    1189          230202 :             XPCNativeScriptableInfo* siProto = GetProto()->GetScriptableInfo();
    1190          230202 :             if (siProto && siProto->GetCallback() == sci->GetCallback())
    1191           35651 :                 mScriptableInfo = siProto;
    1192                 :         }
    1193          257555 :         if (!mScriptableInfo) {
    1194                 :             mScriptableInfo =
    1195          221904 :                 XPCNativeScriptableInfo::Construct(ccx, sci);
    1196                 : 
    1197          221904 :             if (!mScriptableInfo)
    1198               0 :                 return false;
    1199                 :         }
    1200                 :     }
    1201         1237021 :     XPCNativeScriptableInfo* si = mScriptableInfo;
    1202                 : 
    1203                 :     // create our flatJSObject
    1204                 : 
    1205         1237021 :     JSClass* jsclazz = si ? si->GetJSClass() : Jsvalify(&XPC_WN_NoHelper_JSClass.base);
    1206                 : 
    1207                 :     // We should have the global jsclass flag if and only if we're a global.
    1208         1237021 :     MOZ_ASSERT_IF(si, !!si->GetFlags().IsGlobalObject() == !!(jsclazz->flags & JSCLASS_IS_GLOBAL));
    1209                 : 
    1210         1237021 :     NS_ASSERTION(jsclazz &&
    1211                 :                  jsclazz->name &&
    1212                 :                  jsclazz->flags &&
    1213                 :                  jsclazz->addProperty &&
    1214                 :                  jsclazz->delProperty &&
    1215                 :                  jsclazz->getProperty &&
    1216                 :                  jsclazz->setProperty &&
    1217                 :                  jsclazz->enumerate &&
    1218                 :                  jsclazz->resolve &&
    1219                 :                  jsclazz->convert &&
    1220                 :                  jsclazz->finalize, "bad class");
    1221                 : 
    1222         1237021 :     JSObject* protoJSObject = HasProto() ?
    1223          354702 :                                 GetProto()->GetJSProtoObject() :
    1224         1591723 :                                 GetScope()->GetPrototypeNoHelper(ccx);
    1225                 : 
    1226         1237021 :     if (!protoJSObject) {
    1227               0 :         return false;
    1228                 :     }
    1229                 : 
    1230         1237021 :     mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, jsclazz, protoJSObject, false, parent);
    1231         1237021 :     if (!mFlatJSObject)
    1232               0 :         return false;
    1233                 : 
    1234         1237021 :     JS_SetPrivate(mFlatJSObject, this);
    1235                 : 
    1236         1237021 :     return FinishInit(ccx);
    1237                 : }
    1238                 : 
    1239                 : JSBool
    1240            6065 : XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject)
    1241                 : {
    1242            6065 :     JS_SetPrivate(existingJSObject, this);
    1243                 : 
    1244                 :     // Morph the existing object.
    1245            6065 :     JS_SetReservedSlot(existingJSObject, 0, JSVAL_VOID);
    1246                 : 
    1247            6065 :     mScriptableInfo = GetProto()->GetScriptableInfo();
    1248            6065 :     mFlatJSObject = existingJSObject;
    1249                 : 
    1250                 :     SLIM_LOG(("----- %i morphed slim wrapper (mFlatJSObject: %p, %p)\n",
    1251                 :               ++sMorphedSlimWrappers, mFlatJSObject,
    1252                 :               static_cast<nsISupports*>(xpc_GetJSPrivate(mFlatJSObject))));
    1253                 : 
    1254            6065 :     return FinishInit(ccx);
    1255                 : }
    1256                 : 
    1257                 : JSBool
    1258         1256303 : XPCWrappedNative::FinishInit(XPCCallContext &ccx)
    1259                 : {
    1260                 :     // This reference will be released when mFlatJSObject is finalized.
    1261                 :     // Since this reference will push the refcount to 2 it will also root
    1262                 :     // mFlatJSObject;
    1263         1256303 :     NS_ASSERTION(1 == mRefCnt, "unexpected refcount value");
    1264         1256303 :     NS_ADDREF(this);
    1265                 : 
    1266         1256303 :     if (mScriptableInfo && mScriptableInfo->GetFlags().WantCreate() &&
    1267               0 :         NS_FAILED(mScriptableInfo->GetCallback()->Create(this, ccx,
    1268                 :                                                          mFlatJSObject))) {
    1269               0 :         return false;
    1270                 :     }
    1271                 : 
    1272                 : #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
    1273         1256303 :     NS_ASSERTION(mThread, "Should have been set at construction time!");
    1274                 : 
    1275         1256303 :     if (HasProto() && GetProto()->ClassIsMainThreadOnly() && !NS_IsMainThread()) {
    1276                 :         DEBUG_ReportWrapperThreadSafetyError(ccx,
    1277               0 :                                              "MainThread only wrapper created on the wrong thread", this);
    1278               0 :         return false;
    1279                 :     }
    1280                 : #endif
    1281                 : 
    1282                 :     // A hack for bug 517665, increase the probability for GC.
    1283         1256303 :     JS_updateMallocCounter(ccx.GetJSContext(), 2 * sizeof(XPCWrappedNative));
    1284                 : 
    1285         1256303 :     return true;
    1286                 : }
    1287                 : 
    1288                 : 
    1289         2353381 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCWrappedNative)
    1290         2352655 :   NS_INTERFACE_MAP_ENTRY(nsIXPConnectWrappedNative)
    1291          559523 :   NS_INTERFACE_MAP_ENTRY(nsIXPConnectJSObjectHolder)
    1292             389 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPConnectWrappedNative)
    1293             389 : NS_INTERFACE_MAP_END_THREADSAFE
    1294                 : 
    1295         7115345 : NS_IMPL_THREADSAFE_ADDREF(XPCWrappedNative)
    1296         7114534 : NS_IMPL_THREADSAFE_RELEASE(XPCWrappedNative)
    1297                 : 
    1298                 : /*
    1299                 :  *  Wrapped Native lifetime management is messy!
    1300                 :  *
    1301                 :  *  - At creation we push the refcount to 2 (only one of which is owned by
    1302                 :  *    the native caller that caused the wrapper creation).
    1303                 :  *  - During the JS GC Mark phase we mark any wrapper with a refcount > 1.
    1304                 :  *  - The *only* thing that can make the wrapper get destroyed is the
    1305                 :  *    finalization of mFlatJSObject. And *that* should only happen if the only
    1306                 :  *    reference is the single extra (internal) reference we hold.
    1307                 :  *
    1308                 :  *  - The wrapper has a pointer to the nsISupports 'view' of the wrapped native
    1309                 :  *    object i.e... mIdentity. This is held until the wrapper's refcount goes
    1310                 :  *    to zero and the wrapper is released, or until an expired wrapper (i.e.,
    1311                 :  *    one unlinked by the cycle collector) has had its JS object finalized.
    1312                 :  *
    1313                 :  *  - The wrapper also has 'tearoffs'. It has one tearoff for each interface
    1314                 :  *    that is actually used on the native object. 'Used' means we have either
    1315                 :  *    needed to QueryInterface to verify the availability of that interface
    1316                 :  *    of that we've had to QueryInterface in order to actually make a call
    1317                 :  *    into the wrapped object via the pointer for the given interface.
    1318                 :  *
    1319                 :  *  - Each tearoff's 'mNative' member (if non-null) indicates one reference
    1320                 :  *    held by our wrapper on the wrapped native for the given interface
    1321                 :  *    associated with the tearoff. If we release that reference then we set
    1322                 :  *    the tearoff's 'mNative' to null.
    1323                 :  *
    1324                 :  *  - We use the occasion of the JavaScript GCCallback for the JSGC_MARK_END
    1325                 :  *    event to scan the tearoffs of all wrappers for non-null mNative members
    1326                 :  *    that represent unused references. We can tell that a given tearoff's
    1327                 :  *    mNative is unused by noting that no live XPCCallContexts hold a pointer
    1328                 :  *    to the tearoff.
    1329                 :  *
    1330                 :  *  - As a time/space tradeoff we may decide to not do this scanning on
    1331                 :  *    *every* JavaScript GC. We *do* want to do this *sometimes* because
    1332                 :  *    we want to allow for wrapped native's to do their own tearoff patterns.
    1333                 :  *    So, we want to avoid holding references to interfaces that we don't need.
    1334                 :  *    At the same time, we don't want to be bracketing every call into a
    1335                 :  *    wrapped native object with a QueryInterface/Release pair. And we *never*
    1336                 :  *    make a call into the object except via the correct interface for which
    1337                 :  *    we've QI'd.
    1338                 :  *
    1339                 :  *  - Each tearoff *can* have a mJSObject whose lazily resolved properties
    1340                 :  *    represent the methods/attributes/constants of that specific interface.
    1341                 :  *    This is optionally reflected into JavaScript as "foo.nsIFoo" when "foo"
    1342                 :  *    is the name of mFlatJSObject and "nsIFoo" is the name of the given
    1343                 :  *    interface associated with the tearoff. When we create the tearoff's
    1344                 :  *    mJSObject we set it's parent to be mFlatJSObject. This way we know that
    1345                 :  *    when mFlatJSObject get's collected there are no outstanding reachable
    1346                 :  *    tearoff mJSObjects. Note that we must clear the private of any lingering
    1347                 :  *    mJSObjects at this point because we have no guarentee of the *order* of
    1348                 :  *    finalization within a given gc cycle.
    1349                 :  */
    1350                 : 
    1351                 : void
    1352         1255492 : XPCWrappedNative::FlatJSObjectFinalized()
    1353                 : {
    1354         1255492 :     if (!IsValid())
    1355               0 :         return;
    1356                 : 
    1357                 :     // Iterate the tearoffs and null out each of their JSObject's privates.
    1358                 :     // This will keep them from trying to access their pointers to the
    1359                 :     // dying tearoff object. We can safely assume that those remaining
    1360                 :     // JSObjects are about to be finalized too.
    1361                 : 
    1362                 :     XPCWrappedNativeTearOffChunk* chunk;
    1363         2696794 :     for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
    1364         1441302 :         XPCWrappedNativeTearOff* to = chunk->mTearOffs;
    1365         2882604 :         for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
    1366         1441302 :             JSObject* jso = to->GetJSObjectPreserveColor();
    1367         1441302 :             if (jso) {
    1368              41 :                 NS_ASSERTION(JS_IsAboutToBeFinalized(jso), "bad!");
    1369              41 :                 JS_SetPrivate(jso, nsnull);
    1370              41 :                 to->JSObjectFinalized();
    1371                 :             }
    1372                 : 
    1373                 :             // We also need to release any native pointers held...
    1374         1441302 :             nsISupports* obj = to->GetNative();
    1375         1441302 :             if (obj) {
    1376                 : #ifdef XP_WIN
    1377                 :                 // Try to detect free'd pointer
    1378                 :                 NS_ASSERTION(*(int*)obj != 0xdddddddd, "bad pointer!");
    1379                 :                 NS_ASSERTION(*(int*)obj != 0,          "bad pointer!");
    1380                 : #endif
    1381         1139562 :                 XPCJSRuntime* rt = GetRuntime();
    1382         1139562 :                 if (rt) {
    1383         1139562 :                     if (!rt->DeferredRelease(obj)) {
    1384               0 :                         NS_WARNING("Failed to append object for deferred release.");
    1385                 :                         // XXX do we really want to do this???
    1386               0 :                         obj->Release();
    1387                 :                     }
    1388                 :                 } else {
    1389               0 :                     obj->Release();
    1390                 :                 }
    1391         1139562 :                 to->SetNative(nsnull);
    1392                 :             }
    1393                 : 
    1394         1441302 :             to->SetInterface(nsnull);
    1395                 :         }
    1396                 :     }
    1397                 : 
    1398         1255492 :     nsWrapperCache *cache = nsnull;
    1399         1255492 :     CallQueryInterface(mIdentity, &cache);
    1400         1255492 :     if (cache)
    1401           10667 :         cache->ClearWrapper();
    1402                 : 
    1403                 :     // This makes IsValid return false from now on...
    1404         1255492 :     mFlatJSObject = nsnull;
    1405                 : 
    1406         1255492 :     NS_ASSERTION(mIdentity, "bad pointer!");
    1407                 : #ifdef XP_WIN
    1408                 :     // Try to detect free'd pointer
    1409                 :     NS_ASSERTION(*(int*)mIdentity != 0xdddddddd, "bad pointer!");
    1410                 :     NS_ASSERTION(*(int*)mIdentity != 0,          "bad pointer!");
    1411                 : #endif
    1412                 : 
    1413         1255492 :     if (IsWrapperExpired()) {
    1414             322 :         Destroy();
    1415                 :     }
    1416                 : 
    1417                 :     // Note that it's not safe to touch mNativeWrapper here since it's
    1418                 :     // likely that it has already been finalized.
    1419                 : 
    1420         1255492 :     Release();
    1421                 : }
    1422                 : 
    1423                 : void
    1424             781 : XPCWrappedNative::SystemIsBeingShutDown()
    1425                 : {
    1426                 : #ifdef DEBUG_xpc_hacker
    1427                 :     {
    1428                 :         printf("Removing root for still-live XPCWrappedNative %p wrapping:\n",
    1429                 :                static_cast<void*>(this));
    1430                 :         for (PRUint16 i = 0, i_end = mSet->GetInterfaceCount(); i < i_end; ++i) {
    1431                 :             nsXPIDLCString name;
    1432                 :             mSet->GetInterfaceAt(i)->GetInterfaceInfo()
    1433                 :                 ->GetName(getter_Copies(name));
    1434                 :             printf("  %s\n", name.get());
    1435                 :         }
    1436                 :     }
    1437                 : #endif
    1438             781 :     DEBUG_TrackShutdownWrapper(this);
    1439                 : 
    1440             781 :     if (!IsValid())
    1441               0 :         return;
    1442                 : 
    1443                 :     // The long standing strategy is to leak some objects still held at shutdown.
    1444                 :     // The general problem is that propagating release out of xpconnect at
    1445                 :     // shutdown time causes a world of problems.
    1446                 : 
    1447                 :     // We leak mIdentity (see above).
    1448                 : 
    1449                 :     // short circuit future finalization
    1450             781 :     JS_SetPrivate(mFlatJSObject, nsnull);
    1451             781 :     mFlatJSObject = nsnull; // This makes 'IsValid()' return false.
    1452                 : 
    1453             781 :     XPCWrappedNativeProto* proto = GetProto();
    1454                 : 
    1455             781 :     if (HasProto())
    1456             735 :         proto->SystemIsBeingShutDown();
    1457                 : 
    1458            2250 :     if (mScriptableInfo &&
    1459             738 :         (!HasProto() ||
    1460             731 :          (proto && proto->GetScriptableInfo() != mScriptableInfo))) {
    1461             738 :         delete mScriptableInfo;
    1462                 :     }
    1463                 : 
    1464                 :     // cleanup the tearoffs...
    1465                 : 
    1466                 :     XPCWrappedNativeTearOffChunk* chunk;
    1467            1729 :     for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
    1468             948 :         XPCWrappedNativeTearOff* to = chunk->mTearOffs;
    1469            1896 :         for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
    1470             948 :             if (JSObject *jso = to->GetJSObjectPreserveColor()) {
    1471               0 :                 JS_SetPrivate(jso, nsnull);
    1472               0 :                 to->SetJSObject(nsnull);
    1473                 :             }
    1474                 :             // We leak the tearoff mNative
    1475                 :             // (for the same reason we leak mIdentity - see above).
    1476             948 :             to->SetNative(nsnull);
    1477             948 :             to->SetInterface(nsnull);
    1478                 :         }
    1479                 :     }
    1480                 : 
    1481             781 :     if (mFirstChunk.mNextChunk) {
    1482             160 :         delete mFirstChunk.mNextChunk;
    1483             160 :         mFirstChunk.mNextChunk = nsnull;
    1484                 :     }
    1485                 : }
    1486                 : 
    1487                 : /***************************************************************************/
    1488                 : 
    1489                 : // If we have to transplant an object across compartments, we need to be
    1490                 : // careful if the underlying object implements nsWrapperCache and is preserving
    1491                 : // the wrapper.
    1492                 : //
    1493                 : // The class brackets a pair of Unpreserve/Preserve calls in the given scope.
    1494                 : //
    1495                 : // This class _must_ live on the stack, in part so that mPreservedWrapper is
    1496                 : // visible to the stack scanner. The caller wants the wrapper to be preserved,
    1497                 : // so we don't want it to get accidentally GCed.
    1498                 : class AutoWrapperChanger NS_STACK_CLASS {
    1499                 : public:
    1500               0 :     AutoWrapperChanger() : mCache(nsnull)
    1501                 :                          , mCOMObj(nsnull)
    1502               0 :                          , mPreservedWrapper(nsnull)
    1503               0 :     {}
    1504                 : 
    1505               0 :     void init(nsISupports* aCOMObj, nsWrapperCache* aWrapperCache) {
    1506               0 :         mCOMObj = aCOMObj;
    1507               0 :         mCache = aWrapperCache;
    1508               0 :         if (mCache->PreservingWrapper()) {
    1509               0 :             mPreservedWrapper = mCache->GetWrapper();
    1510               0 :             MOZ_ASSERT(mPreservedWrapper);
    1511               0 :             nsContentUtils::ReleaseWrapper(mCOMObj, mCache);
    1512                 :         }
    1513               0 :     }
    1514                 : 
    1515               0 :     ~AutoWrapperChanger() {
    1516               0 :         if (mPreservedWrapper)
    1517               0 :             nsContentUtils::PreserveWrapper(mCOMObj, mCache);
    1518               0 :     }
    1519                 : 
    1520                 : private:
    1521                 :     nsWrapperCache* mCache;
    1522                 :     nsISupports* mCOMObj;
    1523                 :     JSObject* mPreservedWrapper;
    1524                 : };
    1525                 : 
    1526                 : // static
    1527                 : nsresult
    1528               0 : XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
    1529                 :                                          XPCWrappedNativeScope* aOldScope,
    1530                 :                                          XPCWrappedNativeScope* aNewScope,
    1531                 :                                          JSObject* aNewParent,
    1532                 :                                          nsISupports* aCOMObj,
    1533                 :                                          XPCWrappedNative** aWrapper)
    1534                 : {
    1535                 :     XPCNativeInterface* iface =
    1536               0 :         XPCNativeInterface::GetISupports(ccx);
    1537                 : 
    1538               0 :     if (!iface)
    1539               0 :         return NS_ERROR_FAILURE;
    1540                 : 
    1541                 :     nsresult rv;
    1542                 : 
    1543               0 :     nsRefPtr<XPCWrappedNative> wrapper;
    1544               0 :     AutoWrapperChanger wrapperChanger;
    1545                 :     JSObject *flat;
    1546               0 :     nsWrapperCache* cache = nsnull;
    1547               0 :     CallQueryInterface(aCOMObj, &cache);
    1548               0 :     if (cache) {
    1549                 : 
    1550                 :         // There's a wrapper cache. Make sure we keep it sane no matter what
    1551                 :         // happens.
    1552               0 :         wrapperChanger.init(aCOMObj, cache);
    1553                 : 
    1554               0 :         flat = cache->GetWrapper();
    1555               0 :         if (flat && !IS_SLIM_WRAPPER_OBJECT(flat)) {
    1556               0 :             wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(flat));
    1557               0 :             NS_ASSERTION(wrapper->GetScope() == aOldScope,
    1558                 :                          "Incorrect scope passed");
    1559                 :         }
    1560                 :     } else {
    1561                 :         rv = XPCWrappedNative::GetUsedOnly(ccx, aCOMObj, aOldScope, iface,
    1562               0 :                                            getter_AddRefs(wrapper));
    1563               0 :         if (NS_FAILED(rv))
    1564               0 :             return rv;
    1565                 : 
    1566               0 :         flat = wrapper->GetFlatJSObject();
    1567                 :     }
    1568                 : 
    1569               0 :     if (!flat) {
    1570               0 :         *aWrapper = nsnull;
    1571               0 :         return NS_OK;
    1572                 :     }
    1573                 : 
    1574               0 :     bool crosscompartment = js::GetObjectCompartment(aOldScope->GetGlobalJSObject()) !=
    1575               0 :                             js::GetObjectCompartment(aNewScope->GetGlobalJSObject());
    1576                 : #ifdef DEBUG
    1577               0 :     if (crosscompartment) {
    1578               0 :         NS_ASSERTION(aNewParent, "won't be able to find the new parent");
    1579               0 :         NS_ASSERTION(wrapper, "can't transplant slim wrappers");
    1580                 :     }
    1581                 : #endif
    1582                 : 
    1583                 :     // ReparentWrapperIfFound is really only meant to be called from DOM code
    1584                 :     // which must happen only on the main thread. Bail if we're on some other
    1585                 :     // thread or have a non-main-thread-only wrapper.
    1586               0 :     if (!XPCPerThreadData::IsMainThread(ccx) ||
    1587                 :         (wrapper &&
    1588               0 :          wrapper->GetProto() &&
    1589               0 :          !wrapper->GetProto()->ClassIsMainThreadOnly())) {
    1590               0 :         return NS_ERROR_FAILURE;
    1591                 :     }
    1592                 : 
    1593               0 :     JSAutoEnterCompartment ac;
    1594               0 :     if (!ac.enter(ccx, aNewScope->GetGlobalJSObject()))
    1595               0 :         return NS_ERROR_FAILURE;
    1596                 : 
    1597               0 :     if (aOldScope != aNewScope) {
    1598                 :         // Oh, so now we need to move the wrapper to a different scope.
    1599               0 :         AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
    1600               0 :         AutoMarkingWrappedNativeProtoPtr newProto(ccx);
    1601                 : 
    1602               0 :         if (!wrapper)
    1603               0 :             oldProto = GetSlimWrapperProto(flat);
    1604               0 :         else if (wrapper->HasProto())
    1605               0 :             oldProto = wrapper->GetProto();
    1606                 : 
    1607               0 :         if (oldProto) {
    1608               0 :             XPCNativeScriptableInfo *info = oldProto->GetScriptableInfo();
    1609               0 :             XPCNativeScriptableCreateInfo ci(*info);
    1610                 :             newProto =
    1611                 :                 XPCWrappedNativeProto::GetNewOrUsed(ccx, aNewScope,
    1612                 :                                                     oldProto->GetClassInfo(),
    1613               0 :                                                     &ci, oldProto->GetOffsetsMasked());
    1614               0 :             if (!newProto) {
    1615               0 :                 return NS_ERROR_FAILURE;
    1616                 :             }
    1617                 :         }
    1618                 : 
    1619               0 :         if (wrapper) {
    1620               0 :             Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
    1621               0 :             Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
    1622                 : 
    1623                 :             {   // scoped lock
    1624               0 :                 XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock());
    1625                 : 
    1626               0 :                 oldMap->Remove(wrapper);
    1627                 : 
    1628               0 :                 if (wrapper->HasProto())
    1629               0 :                     wrapper->SetProto(newProto);
    1630                 : 
    1631                 :                 // If the wrapper has no scriptable or it has a non-shared
    1632                 :                 // scriptable, then we don't need to mess with it.
    1633                 :                 // Otherwise...
    1634                 : 
    1635               0 :                 if (wrapper->mScriptableInfo &&
    1636               0 :                     wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) {
    1637                 :                     // The new proto had better have the same JSClass stuff as
    1638                 :                     // the old one! We maintain a runtime wide unique map of
    1639                 :                     // this stuff. So, if these don't match then the caller is
    1640                 :                     // doing something bad here.
    1641                 : 
    1642               0 :                     NS_ASSERTION(oldProto->GetScriptableInfo()->GetScriptableShared() ==
    1643                 :                                  newProto->GetScriptableInfo()->GetScriptableShared(),
    1644                 :                                  "Changing proto is also changing JSObject Classname or "
    1645                 :                                  "helper's nsIXPScriptable flags. This is not allowed!");
    1646                 : 
    1647               0 :                     wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo());
    1648                 :                 }
    1649                 : 
    1650               0 :                 NS_ASSERTION(!newMap->Find(wrapper->GetIdentityObject()),
    1651                 :                              "wrapper already in new scope!");
    1652                 : 
    1653               0 :                 (void) newMap->Add(wrapper);
    1654                 :             }
    1655                 : 
    1656                 :             // We only try to fixup the __proto__ JSObject if the wrapper
    1657                 :             // is directly using that of its XPCWrappedNativeProto.
    1658                 : 
    1659               0 :             if (crosscompartment) {
    1660                 :                 JSObject *newobj = JS_CloneObject(ccx, flat,
    1661                 :                                                   newProto->GetJSProtoObject(),
    1662               0 :                                                   aNewParent);
    1663               0 :                 if (!newobj)
    1664               0 :                     return NS_ERROR_FAILURE;
    1665                 : 
    1666               0 :                 JS_SetPrivate(flat, nsnull);
    1667                 : 
    1668                 :                 JSObject *propertyHolder =
    1669               0 :                     JS_NewObjectWithGivenProto(ccx, NULL, NULL, aNewParent);
    1670               0 :                 if (!propertyHolder || !JS_CopyPropertiesFrom(ccx, propertyHolder, flat))
    1671               0 :                     return NS_ERROR_OUT_OF_MEMORY;
    1672                 : 
    1673               0 :                 JSObject *ww = wrapper->GetWrapper();
    1674               0 :                 if (ww) {
    1675                 :                     JSObject *newwrapper;
    1676               0 :                     if (xpc::WrapperFactory::IsLocationObject(flat)) {
    1677               0 :                         newwrapper = xpc::WrapperFactory::WrapLocationObject(ccx, newobj);
    1678               0 :                         if (!newwrapper)
    1679               0 :                             return NS_ERROR_FAILURE;
    1680                 :                     } else {
    1681               0 :                         NS_ASSERTION(wrapper->NeedsSOW(), "weird wrapper wrapper");
    1682               0 :                         newwrapper = xpc::WrapperFactory::WrapSOWObject(ccx, newobj);
    1683               0 :                         if (!newwrapper)
    1684               0 :                             return NS_ERROR_FAILURE;
    1685                 :                     }
    1686                 : 
    1687                 :                     ww = js_TransplantObjectWithWrapper(ccx, flat, ww, newobj,
    1688               0 :                                                         newwrapper);
    1689               0 :                     if (!ww)
    1690               0 :                         return NS_ERROR_FAILURE;
    1691               0 :                     flat = newobj;
    1692               0 :                     wrapper->SetWrapper(ww);
    1693                 :                 } else {
    1694               0 :                     flat = JS_TransplantObject(ccx, flat, newobj);
    1695               0 :                     if (!flat)
    1696               0 :                         return NS_ERROR_FAILURE;
    1697                 :                 }
    1698                 : 
    1699               0 :                 wrapper->mFlatJSObject = flat;
    1700               0 :                 if (cache)
    1701               0 :                     cache->SetWrapper(flat);
    1702               0 :                 if (!JS_CopyPropertiesFrom(ccx, flat, propertyHolder))
    1703               0 :                     return NS_ERROR_FAILURE;
    1704                 :             } else {
    1705               0 :                 if (wrapper->HasProto() &&
    1706               0 :                     js::GetObjectProto(flat) == oldProto->GetJSProtoObject()) {
    1707               0 :                     if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject())) {
    1708                 :                         // this is bad, very bad
    1709               0 :                         NS_ERROR("JS_SetPrototype failed");
    1710               0 :                         return NS_ERROR_FAILURE;
    1711                 :                     }
    1712                 :                 } else {
    1713                 :                     NS_WARNING("Moving XPConnect wrappedNative to new scope, "
    1714               0 :                                "but can't fixup __proto__");
    1715                 :                 }
    1716                 :             }
    1717                 :         } else {
    1718                 :             JS_SetReservedSlot(flat, 0,
    1719               0 :                                PRIVATE_TO_JSVAL(newProto.get()));
    1720               0 :             if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject())) {
    1721                 :                 // this is bad, very bad
    1722               0 :                 JS_SetReservedSlot(flat, 0, JSVAL_NULL);
    1723               0 :                 NS_ERROR("JS_SetPrototype failed");
    1724               0 :                 return NS_ERROR_FAILURE;
    1725                 :             }
    1726                 :         }
    1727                 :     }
    1728                 : 
    1729                 :     // Now we can just fix up the parent and return the wrapper
    1730                 : 
    1731               0 :     if (aNewParent) {
    1732               0 :         if (!JS_SetParent(ccx, flat, aNewParent))
    1733               0 :             return NS_ERROR_FAILURE;
    1734                 : 
    1735                 :         JSObject *nw;
    1736               0 :         if (wrapper &&
    1737               0 :             (nw = wrapper->GetWrapper()) &&
    1738               0 :             !JS_SetParent(ccx, nw, JS_GetGlobalForObject(ccx, aNewParent))) {
    1739               0 :             return NS_ERROR_FAILURE;
    1740                 :         }
    1741                 :     }
    1742                 : 
    1743               0 :     *aWrapper = nsnull;
    1744               0 :     wrapper.swap(*aWrapper);
    1745                 : 
    1746               0 :     return NS_OK;
    1747                 : }
    1748                 : 
    1749                 : #define IS_TEAROFF_CLASS(clazz)                                               \
    1750                 :           ((clazz) == &XPC_WN_Tearoff_JSClass)
    1751                 : 
    1752                 : // static
    1753                 : XPCWrappedNative*
    1754        16185094 : XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx,
    1755                 :                                              JSObject* obj,
    1756                 :                                              JSObject* funobj,
    1757                 :                                              JSObject** pobj2,
    1758                 :                                              XPCWrappedNativeTearOff** pTearOff)
    1759                 : {
    1760        16185094 :     NS_PRECONDITION(obj, "bad param");
    1761                 : 
    1762                 :     // fubobj must be null if called without cx.
    1763        16185094 :     NS_PRECONDITION(cx || !funobj, "bad param");
    1764                 : 
    1765                 :     // *pTeaorOff must be null if pTearOff is given
    1766        16185094 :     NS_PRECONDITION(!pTearOff || !*pTearOff, "bad param");
    1767                 : 
    1768                 :     JSObject* cur;
    1769                 : 
    1770        16185094 :     XPCWrappedNativeProto* proto = nsnull;
    1771        16185094 :     nsIClassInfo* protoClassInfo = nsnull;
    1772                 : 
    1773                 :     // If we were passed a function object then we need to find the correct
    1774                 :     // wrapper out of those that might be in the callee obj's proto chain.
    1775                 : 
    1776        16185094 :     if (funobj) {
    1777         6731238 :         JSObject* funObjParent = js::UnwrapObject(js::GetObjectParent(funobj));
    1778         6731238 :         funObjParent = JS_ObjectToInnerObject(cx, funObjParent);
    1779         6731238 :         NS_ASSERTION(funObjParent, "funobj has no parent");
    1780                 : 
    1781         6731238 :         js::Class* funObjParentClass = js::GetObjectClass(funObjParent);
    1782                 : 
    1783         6731238 :         if (IS_PROTO_CLASS(funObjParentClass)) {
    1784         1181277 :             NS_ASSERTION(js::GetObjectParent(funObjParent), "funobj's parent (proto) is global");
    1785         1181277 :             proto = (XPCWrappedNativeProto*) js::GetObjectPrivate(funObjParent);
    1786         1181277 :             if (proto)
    1787         1181277 :                 protoClassInfo = proto->GetClassInfo();
    1788         5549961 :         } else if (IS_WRAPPER_CLASS(funObjParentClass)) {
    1789         5549871 :             cur = funObjParent;
    1790         5549871 :             goto return_wrapper;
    1791              90 :         } else if (IS_TEAROFF_CLASS(funObjParentClass)) {
    1792              90 :             NS_ASSERTION(js::GetObjectParent(funObjParent), "funobj's parent (tearoff) is global");
    1793              90 :             cur = funObjParent;
    1794              90 :             goto return_tearoff;
    1795                 :         } else {
    1796               0 :             NS_ERROR("function object has parent of unknown class!");
    1797               0 :             return nsnull;
    1798                 :         }
    1799                 :     }
    1800                 : 
    1801                 :   restart:
    1802        11026931 :     for (cur = obj; cur; cur = js::GetObjectProto(cur)) {
    1803                 :         // this is on two lines to make the compiler happy given the goto.
    1804                 :         js::Class* clazz;
    1805        10877961 :         clazz = js::GetObjectClass(cur);
    1806                 : 
    1807        10877961 :         if (IS_WRAPPER_CLASS(clazz)) {
    1808                 : return_wrapper:
    1809        16035876 :             JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
    1810                 :             XPCWrappedNative* wrapper =
    1811        16035876 :                 isWN ? (XPCWrappedNative*) js::GetObjectPrivate(cur) : nsnull;
    1812        16035876 :             if (proto) {
    1813                 :                 XPCWrappedNativeProto* wrapper_proto =
    1814         1181277 :                     isWN ? wrapper->GetProto() : GetSlimWrapperProto(cur);
    1815         1181277 :                 if (proto != wrapper_proto &&
    1816                 :                     (!protoClassInfo || !wrapper_proto ||
    1817               0 :                      protoClassInfo != wrapper_proto->GetClassInfo()))
    1818               0 :                     continue;
    1819                 :             }
    1820        16035876 :             if (pobj2)
    1821        14399909 :                 *pobj2 = isWN ? nsnull : cur;
    1822        16035876 :             return wrapper;
    1823                 :         }
    1824                 : 
    1825          391956 :         if (IS_TEAROFF_CLASS(clazz)) {
    1826                 : return_tearoff:
    1827                 :             XPCWrappedNative* wrapper =
    1828             248 :                 (XPCWrappedNative*) js::GetObjectPrivate(js::GetObjectParent(cur));
    1829             248 :             if (proto && proto != wrapper->GetProto() &&
    1830               0 :                 (proto->GetScope() != wrapper->GetScope() ||
    1831               0 :                  !protoClassInfo || !wrapper->GetProto() ||
    1832               0 :                  protoClassInfo != wrapper->GetProto()->GetClassInfo()))
    1833               0 :                 continue;
    1834             248 :             if (pobj2)
    1835             248 :                 *pobj2 = nsnull;
    1836             248 :             XPCWrappedNativeTearOff* to = (XPCWrappedNativeTearOff*) js::GetObjectPrivate(cur);
    1837             248 :             if (!to)
    1838               0 :                 return nsnull;
    1839             248 :             if (pTearOff)
    1840             248 :                 *pTearOff = to;
    1841             248 :             return wrapper;
    1842                 :         }
    1843                 : 
    1844                 :         // Unwrap any wrapper wrappers.
    1845                 :         JSObject *unsafeObj = cx
    1846                 :                               ? XPCWrapper::Unwrap(cx, cur)
    1847          391798 :                               : XPCWrapper::UnsafeUnwrapSecurityWrapper(cur);
    1848          391798 :         if (unsafeObj) {
    1849               0 :             obj = unsafeObj;
    1850               0 :             goto restart;
    1851                 :         }
    1852                 :     }
    1853                 : 
    1854          148970 :     if (pobj2)
    1855            5605 :         *pobj2 = nsnull;
    1856          148970 :     return nsnull;
    1857                 : }
    1858                 : 
    1859                 : JSBool
    1860          162446 : XPCWrappedNative::ExtendSet(XPCCallContext& ccx, XPCNativeInterface* aInterface)
    1861                 : {
    1862                 :     // This is only called while locked (during XPCWrappedNative::FindTearOff).
    1863                 : 
    1864          162446 :     if (!mSet->HasInterface(aInterface)) {
    1865          324892 :         AutoMarkingNativeSetPtr newSet(ccx);
    1866                 :         newSet = XPCNativeSet::GetNewOrUsed(ccx, mSet, aInterface,
    1867          162446 :                                             mSet->GetInterfaceCount());
    1868          162446 :         if (!newSet)
    1869               0 :             return false;
    1870                 : 
    1871          324892 :         mSet = newSet;
    1872                 : 
    1873                 :         DEBUG_ReportShadowedMembers(newSet, this, GetProto());
    1874                 :     }
    1875          162446 :     return true;
    1876                 : }
    1877                 : 
    1878                 : XPCWrappedNativeTearOff*
    1879               0 : XPCWrappedNative::LocateTearOff(XPCCallContext& ccx,
    1880                 :                                 XPCNativeInterface* aInterface)
    1881                 : {
    1882               0 :     XPCAutoLock al(GetLock()); // hold the lock throughout
    1883                 : 
    1884               0 :     for (XPCWrappedNativeTearOffChunk* chunk = &mFirstChunk;
    1885                 :          chunk != nsnull;
    1886                 :          chunk = chunk->mNextChunk) {
    1887               0 :         XPCWrappedNativeTearOff* tearOff = chunk->mTearOffs;
    1888                 :         XPCWrappedNativeTearOff* const end = tearOff +
    1889               0 :             XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK;
    1890               0 :         for (tearOff = chunk->mTearOffs;
    1891                 :              tearOff < end;
    1892                 :              tearOff++) {
    1893               0 :             if (tearOff->GetInterface() == aInterface) {
    1894               0 :                 return tearOff;
    1895                 :             }
    1896                 :         }
    1897                 :     }
    1898               0 :     return nsnull;
    1899                 : }
    1900                 : 
    1901                 : XPCWrappedNativeTearOff*
    1902         8797385 : XPCWrappedNative::FindTearOff(XPCCallContext& ccx,
    1903                 :                               XPCNativeInterface* aInterface,
    1904                 :                               JSBool needJSObject /* = false */,
    1905                 :                               nsresult* pError /* = nsnull */)
    1906                 : {
    1907        17594770 :     XPCAutoLock al(GetLock()); // hold the lock throughout
    1908                 : 
    1909         8797385 :     nsresult rv = NS_OK;
    1910                 :     XPCWrappedNativeTearOff* to;
    1911         8797385 :     XPCWrappedNativeTearOff* firstAvailable = nsnull;
    1912                 : 
    1913                 :     XPCWrappedNativeTearOffChunk* lastChunk;
    1914                 :     XPCWrappedNativeTearOffChunk* chunk;
    1915        11074035 :     for (lastChunk = chunk = &mFirstChunk;
    1916                 :          chunk;
    1917                 :          lastChunk = chunk, chunk = chunk->mNextChunk) {
    1918         9546469 :         to = chunk->mTearOffs;
    1919                 :         XPCWrappedNativeTearOff* const end = chunk->mTearOffs +
    1920         9546469 :             XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK;
    1921        11823119 :         for (to = chunk->mTearOffs;
    1922                 :              to < end;
    1923                 :              to++) {
    1924         9546469 :             if (to->GetInterface() == aInterface) {
    1925         7269819 :                 if (needJSObject && !to->GetJSObjectPreserveColor()) {
    1926              42 :                     AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to);
    1927              21 :                     JSBool ok = InitTearOffJSObject(ccx, to);
    1928                 :                     // During shutdown, we don't sweep tearoffs.  So make sure
    1929                 :                     // to unmark manually in case the auto-marker marked us.
    1930                 :                     // We shouldn't ever be getting here _during_ our
    1931                 :                     // Mark/Sweep cycle, so this should be safe.
    1932              21 :                     to->Unmark();
    1933              21 :                     if (!ok) {
    1934               0 :                         to = nsnull;
    1935               0 :                         rv = NS_ERROR_OUT_OF_MEMORY;
    1936                 :                     }
    1937                 :                 }
    1938         7269819 :                 goto return_result;
    1939                 :             }
    1940         2276650 :             if (!firstAvailable && to->IsAvailable())
    1941         1341618 :                 firstAvailable = to;
    1942                 :         }
    1943                 :     }
    1944                 : 
    1945         1527566 :     to = firstAvailable;
    1946                 : 
    1947         1527566 :     if (!to) {
    1948                 :         XPCWrappedNativeTearOffChunk* newChunk =
    1949          185980 :             new XPCWrappedNativeTearOffChunk();
    1950          185980 :         if (!newChunk) {
    1951               0 :             rv = NS_ERROR_OUT_OF_MEMORY;
    1952               0 :             goto return_result;
    1953                 :         }
    1954          185980 :         lastChunk->mNextChunk = newChunk;
    1955          185980 :         to = newChunk->mTearOffs;
    1956                 :     }
    1957                 : 
    1958                 :     {
    1959                 :         // Scope keeps |tearoff| from leaking across the return_result: label
    1960         3055132 :         AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to);
    1961         1527566 :         rv = InitTearOff(ccx, to, aInterface, needJSObject);
    1962                 :         // During shutdown, we don't sweep tearoffs.  So make sure to unmark
    1963                 :         // manually in case the auto-marker marked us.  We shouldn't ever be
    1964                 :         // getting here _during_ our Mark/Sweep cycle, so this should be safe.
    1965         1527566 :         to->Unmark();
    1966         1527566 :         if (NS_FAILED(rv))
    1967            6160 :             to = nsnull;
    1968                 :     }
    1969                 : 
    1970                 : return_result:
    1971                 : 
    1972         8797385 :     if (pError)
    1973         8797364 :         *pError = rv;
    1974         8797385 :     return to;
    1975                 : }
    1976                 : 
    1977                 : nsresult
    1978         1527566 : XPCWrappedNative::InitTearOff(XPCCallContext& ccx,
    1979                 :                               XPCWrappedNativeTearOff* aTearOff,
    1980                 :                               XPCNativeInterface* aInterface,
    1981                 :                               JSBool needJSObject)
    1982                 : {
    1983                 :     // This is only called while locked (during XPCWrappedNative::FindTearOff).
    1984                 : 
    1985                 :     // Determine if the object really does this interface...
    1986                 : 
    1987         1527566 :     const nsIID* iid = aInterface->GetIID();
    1988         1527566 :     nsISupports* identity = GetIdentityObject();
    1989                 :     nsISupports* obj;
    1990                 : 
    1991                 :     // If the scriptable helper forbids us from reflecting additional
    1992                 :     // interfaces, then don't even try the QI, just fail.
    1993         1904674 :     if (mScriptableInfo &&
    1994          352327 :         mScriptableInfo->GetFlags().ClassInfoInterfacesOnly() &&
    1995           19705 :         !mSet->HasInterface(aInterface) &&
    1996            5076 :         !mSet->HasInterfaceWithAncestor(aInterface)) {
    1997            4999 :         return NS_ERROR_NO_INTERFACE;
    1998                 :     }
    1999                 : 
    2000                 :     // We are about to call out to unlock and other code.
    2001                 :     // So protect our intended tearoff.
    2002                 : 
    2003         1522567 :     aTearOff->SetReserved();
    2004                 : 
    2005                 :     {   // scoped *un*lock
    2006         3045134 :         XPCAutoUnlock unlock(GetLock());
    2007                 : 
    2008         1522567 :         if (NS_FAILED(identity->QueryInterface(*iid, (void**)&obj)) || !obj) {
    2009            1160 :             aTearOff->SetInterface(nsnull);
    2010            1160 :             return NS_ERROR_NO_INTERFACE;
    2011                 :         }
    2012                 : 
    2013                 :         // Guard against trying to build a tearoff for a shared nsIClassInfo.
    2014         1521407 :         if (iid->Equals(NS_GET_IID(nsIClassInfo))) {
    2015              36 :             nsCOMPtr<nsISupports> alternate_identity(do_QueryInterface(obj));
    2016              18 :             if (alternate_identity.get() != identity) {
    2017               0 :                 NS_RELEASE(obj);
    2018               0 :                 aTearOff->SetInterface(nsnull);
    2019               0 :                 return NS_ERROR_NO_INTERFACE;
    2020                 :             }
    2021                 :         }
    2022                 : 
    2023                 :         // Guard against trying to build a tearoff for an interface that is
    2024                 :         // aggregated and is implemented as a nsIXPConnectWrappedJS using this
    2025                 :         // self-same JSObject. The XBL system does this. If we mutate the set
    2026                 :         // of this wrapper then we will shadow the method that XBL has added to
    2027                 :         // the JSObject that it has inserted in the JS proto chain between our
    2028                 :         // JSObject and our XPCWrappedNativeProto's JSObject. If we let this
    2029                 :         // set mutation happen then the interface's methods will be added to
    2030                 :         // our JSObject, but calls on those methods will get routed up to
    2031                 :         // native code and into the wrappedJS - which will do a method lookup
    2032                 :         // on *our* JSObject and find the same method and make another call
    2033                 :         // into an infinite loop.
    2034                 :         // see: http://bugzilla.mozilla.org/show_bug.cgi?id=96725
    2035                 : 
    2036                 :         // The code in this block also does a check for the double wrapped
    2037                 :         // nsIPropertyBag case.
    2038                 : 
    2039         3042814 :         nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(obj));
    2040         1521407 :         if (wrappedJS) {
    2041           27820 :             JSObject* jso = nsnull;
    2042           27820 :             if (NS_SUCCEEDED(wrappedJS->GetJSObject(&jso)) &&
    2043                 :                 jso == mFlatJSObject) {
    2044                 :                 // The implementing JSObject is the same as ours! Just say OK
    2045                 :                 // without actually extending the set.
    2046                 :                 //
    2047                 :                 // XXX It is a little cheesy to have FindTearOff return an
    2048                 :                 // 'empty' tearoff. But this is the centralized place to do the
    2049                 :                 // QI activities on the underlying object. *And* most caller to
    2050                 :                 // FindTearOff only look for a non-null result and ignore the
    2051                 :                 // actual tearoff returned. The only callers that do use the
    2052                 :                 // returned tearoff make sure to check for either a non-null
    2053                 :                 // JSObject or a matching Interface before proceeding.
    2054                 :                 // I think we can get away with this bit of ugliness.
    2055                 : 
    2056                 : #ifdef DEBUG_xpc_hacker
    2057                 :                 {
    2058                 :                     // I want to make sure this only happens in xbl-like cases.
    2059                 :                     // So, some debug code to verify that there is at least
    2060                 :                     // *some* object between our JSObject and its inital proto.
    2061                 :                     // XXX This is a pretty funky test. Someone might hack it
    2062                 :                     // a bit if false positives start showing up. Note that
    2063                 :                     // this is only going to run for the few people in the
    2064                 :                     // DEBUG_xpc_hacker list.
    2065                 :                     if (HasProto()) {
    2066                 :                         JSObject* proto  = nsnull;
    2067                 :                         JSObject* our_proto = GetProto()->GetJSProtoObject();
    2068                 : 
    2069                 :                         proto = jso->getProto();
    2070                 : 
    2071                 :                         NS_ASSERTION(proto && proto != our_proto,
    2072                 :                                      "!!! xpconnect/xbl check - wrapper has no special proto");
    2073                 : 
    2074                 :                         bool found_our_proto = false;
    2075                 :                         while (proto && !found_our_proto) {
    2076                 :                             proto = proto->getProto();
    2077                 : 
    2078                 :                             found_our_proto = proto == our_proto;
    2079                 :                         }
    2080                 : 
    2081                 :                         NS_ASSERTION(found_our_proto,
    2082                 :                                      "!!! xpconnect/xbl check - wrapper has extra proto");
    2083                 :                     } else {
    2084                 :                         NS_WARNING("!!! xpconnect/xbl check - wrapper has no proto");
    2085                 :                     }
    2086                 :                 }
    2087                 : #endif
    2088               0 :                 NS_RELEASE(obj);
    2089               0 :                 aTearOff->SetInterface(nsnull);
    2090               0 :                 return NS_OK;
    2091                 :             }
    2092                 : 
    2093                 :             // Decide whether or not to expose nsIPropertyBag to calling
    2094                 :             // JS code in the double wrapped case.
    2095                 :             //
    2096                 :             // Our rule here is that when JSObjects are double wrapped and
    2097                 :             // exposed to other JSObjects then the nsIPropertyBag interface
    2098                 :             // is only exposed on an 'opt-in' basis; i.e. if the underlying
    2099                 :             // JSObject wants other JSObjects to be able to see this interface
    2100                 :             // then it must implement QueryInterface and not throw an exception
    2101                 :             // when asked for nsIPropertyBag. It need not actually *implement*
    2102                 :             // nsIPropertyBag - xpconnect will do that work.
    2103                 : 
    2104                 :             nsXPCWrappedJSClass* clazz;
    2105           27824 :             if (iid->Equals(NS_GET_IID(nsIPropertyBag)) && jso &&
    2106               4 :                 NS_SUCCEEDED(nsXPCWrappedJSClass::GetNewOrUsed(ccx,*iid,&clazz))&&
    2107                 :                 clazz) {
    2108                 :                 JSObject* answer =
    2109               4 :                     clazz->CallQueryInterfaceOnJSObject(ccx, jso, *iid);
    2110               4 :                 NS_RELEASE(clazz);
    2111               4 :                 if (!answer) {
    2112               1 :                     NS_RELEASE(obj);
    2113               1 :                     aTearOff->SetInterface(nsnull);
    2114               1 :                     return NS_ERROR_NO_INTERFACE;
    2115                 :                 }
    2116                 :             }
    2117                 :         }
    2118                 : 
    2119                 :         nsIXPCSecurityManager* sm;
    2120         1521406 :            sm = ccx.GetXPCContext()->GetAppropriateSecurityManager(nsIXPCSecurityManager::HOOK_CREATE_WRAPPER);
    2121         1521406 :         if (sm && NS_FAILED(sm->
    2122                 :                             CanCreateWrapper(ccx, *iid, identity,
    2123                 :                                              GetClassInfo(), GetSecurityInfoAddr()))) {
    2124                 :             // the security manager vetoed. It should have set an exception.
    2125               0 :             NS_RELEASE(obj);
    2126               0 :             aTearOff->SetInterface(nsnull);
    2127               0 :             return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
    2128                 :         }
    2129                 :     }
    2130                 :     // We are relocked from here on...
    2131                 : 
    2132                 :     // If this is not already in our set we need to extend our set.
    2133                 :     // Note: we do not cache the result of the previous call to HasInterface()
    2134                 :     // because we unlocked and called out in the interim and the result of the
    2135                 :     // previous call might not be correct anymore.
    2136                 : 
    2137         1521406 :     if (!mSet->HasInterface(aInterface) && !ExtendSet(ccx, aInterface)) {
    2138               0 :         NS_RELEASE(obj);
    2139               0 :         aTearOff->SetInterface(nsnull);
    2140               0 :         return NS_ERROR_NO_INTERFACE;
    2141                 :     }
    2142                 : 
    2143         1521406 :     aTearOff->SetInterface(aInterface);
    2144         1521406 :     aTearOff->SetNative(obj);
    2145         1521406 :     if (needJSObject && !InitTearOffJSObject(ccx, aTearOff))
    2146               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2147                 : 
    2148         1521406 :     return NS_OK;
    2149                 : }
    2150                 : 
    2151                 : JSBool
    2152              60 : XPCWrappedNative::InitTearOffJSObject(XPCCallContext& ccx,
    2153                 :                                       XPCWrappedNativeTearOff* to)
    2154                 : {
    2155                 :     // This is only called while locked (during XPCWrappedNative::FindTearOff).
    2156                 : 
    2157                 :     JSObject* obj =
    2158                 :         xpc_NewSystemInheritingJSObject(ccx, Jsvalify(&XPC_WN_Tearoff_JSClass),
    2159                 :                                         GetScope()->GetPrototypeJSObject(),
    2160              60 :                                         false, mFlatJSObject);
    2161                 : 
    2162              60 :     if (!obj)
    2163               0 :         return false;
    2164                 : 
    2165              60 :     JS_SetPrivate(obj, to);
    2166              60 :     to->SetJSObject(obj);
    2167              60 :     return true;
    2168                 : }
    2169                 : 
    2170                 : /***************************************************************************/
    2171                 : 
    2172               3 : static JSBool Throw(unsigned errNum, XPCCallContext& ccx)
    2173                 : {
    2174               3 :     XPCThrower::Throw(errNum, ccx);
    2175               3 :     return false;
    2176                 : }
    2177                 : 
    2178                 : /***************************************************************************/
    2179                 : 
    2180                 : class CallMethodHelper
    2181                 : {
    2182                 :     XPCCallContext& mCallContext;
    2183                 :     nsIInterfaceInfo* const mIFaceInfo;
    2184                 :     const nsXPTMethodInfo* mMethodInfo;
    2185                 :     nsISupports* const mCallee;
    2186                 :     const uint16_t mVTableIndex;
    2187                 :     const jsid mIdxValueId;
    2188                 : 
    2189                 :     nsAutoTArray<nsXPTCVariant, 8> mDispatchParams;
    2190                 :     uint8_t mJSContextIndex; // TODO make const
    2191                 :     uint8_t mOptArgcIndex; // TODO make const
    2192                 : 
    2193                 :     jsval* const mArgv;
    2194                 :     const PRUint32 mArgc;
    2195                 : 
    2196                 :     JS_ALWAYS_INLINE JSBool
    2197                 :     GetArraySizeFromParam(uint8_t paramIndex, uint32_t* result) const;
    2198                 : 
    2199                 :     JS_ALWAYS_INLINE JSBool
    2200                 :     GetInterfaceTypeFromParam(uint8_t paramIndex,
    2201                 :                               const nsXPTType& datum_type,
    2202                 :                               nsID* result) const;
    2203                 : 
    2204                 :     JS_ALWAYS_INLINE JSBool
    2205                 :     GetOutParamSource(uint8_t paramIndex, jsval* srcp) const;
    2206                 : 
    2207                 :     JS_ALWAYS_INLINE JSBool
    2208                 :     GatherAndConvertResults();
    2209                 : 
    2210                 :     JS_ALWAYS_INLINE JSBool
    2211                 :     QueryInterfaceFastPath() const;
    2212                 : 
    2213                 :     nsXPTCVariant*
    2214        27733756 :     GetDispatchParam(uint8_t paramIndex)
    2215                 :     {
    2216        27733756 :         if (paramIndex >= mJSContextIndex)
    2217          667369 :             paramIndex += 1;
    2218        27733756 :         if (paramIndex >= mOptArgcIndex)
    2219          647199 :             paramIndex += 1;
    2220        27733756 :         return &mDispatchParams[paramIndex];
    2221                 :     }
    2222                 :     const nsXPTCVariant*
    2223          104000 :     GetDispatchParam(uint8_t paramIndex) const
    2224                 :     {
    2225          104000 :         return const_cast<CallMethodHelper*>(this)->GetDispatchParam(paramIndex);
    2226                 :     }
    2227                 : 
    2228                 :     JS_ALWAYS_INLINE JSBool InitializeDispatchParams();
    2229                 : 
    2230                 :     JS_ALWAYS_INLINE JSBool ConvertIndependentParams(JSBool* foundDependentParam);
    2231                 :     JS_ALWAYS_INLINE JSBool ConvertIndependentParam(uint8_t i);
    2232                 :     JS_ALWAYS_INLINE JSBool ConvertDependentParams();
    2233                 :     JS_ALWAYS_INLINE JSBool ConvertDependentParam(uint8_t i);
    2234                 : 
    2235                 :     JS_ALWAYS_INLINE void CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type);
    2236                 : 
    2237                 :     JS_ALWAYS_INLINE JSBool HandleDipperParam(nsXPTCVariant* dp,
    2238                 :                                               const nsXPTParamInfo& paramInfo);
    2239                 : 
    2240                 :     JS_ALWAYS_INLINE nsresult Invoke();
    2241                 : 
    2242                 : public:
    2243                 : 
    2244         6752344 :     CallMethodHelper(XPCCallContext& ccx)
    2245                 :         : mCallContext(ccx)
    2246         6752344 :         , mIFaceInfo(ccx.GetInterface()->GetInterfaceInfo())
    2247                 :         , mMethodInfo(nsnull)
    2248         6752344 :         , mCallee(ccx.GetTearOff()->GetNative())
    2249         6752344 :         , mVTableIndex(ccx.GetMethodIndex())
    2250         6752344 :         , mIdxValueId(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_VALUE))
    2251                 :         , mJSContextIndex(PR_UINT8_MAX)
    2252                 :         , mOptArgcIndex(PR_UINT8_MAX)
    2253         6752344 :         , mArgv(ccx.GetArgv())
    2254        40514064 :         , mArgc(ccx.GetArgc())
    2255                 : 
    2256                 :     {
    2257                 :         // Success checked later.
    2258         6752344 :         mIFaceInfo->GetMethodInfo(mVTableIndex, &mMethodInfo);
    2259         6752344 :     }
    2260                 : 
    2261                 :     ~CallMethodHelper();
    2262                 : 
    2263                 :     JS_ALWAYS_INLINE JSBool Call();
    2264                 : 
    2265                 : };
    2266                 : 
    2267                 : // static
    2268                 : NS_SUPPRESS_STACK_CHECK JSBool
    2269         6752344 : XPCWrappedNative::CallMethod(XPCCallContext& ccx,
    2270                 :                              CallMode mode /*= CALL_METHOD */)
    2271                 : {
    2272         6752344 :     XPCContext* xpcc = ccx.GetXPCContext();
    2273         6752344 :     NS_ASSERTION(xpcc->CallerTypeIsJavaScript(),
    2274                 :                  "Native caller for XPCWrappedNative::CallMethod?");
    2275                 : 
    2276         6752344 :     nsresult rv = ccx.CanCallNow();
    2277         6752344 :     if (NS_FAILED(rv)) {
    2278                 :         // If the security manager is complaining then this is not really an
    2279                 :         // internal error in xpconnect. So, no reason to botch the assertion.
    2280               0 :         NS_ASSERTION(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    2281                 :                      "hmm? CanCallNow failed in XPCWrappedNative::CallMethod. "
    2282                 :                      "We are finding out about this late!");
    2283               0 :         return Throw(rv, ccx);
    2284                 :     }
    2285                 : 
    2286         6752344 :     DEBUG_TrackWrapperCall(ccx.GetWrapper(), mode);
    2287                 : 
    2288                 :     // set up the method index and do the security check if needed
    2289                 : 
    2290                 :     PRUint32 secFlag;
    2291                 :     PRUint32 secAction;
    2292                 : 
    2293         6752344 :     switch (mode) {
    2294                 :         case CALL_METHOD:
    2295         4394905 :             secFlag   = nsIXPCSecurityManager::HOOK_CALL_METHOD;
    2296         4394905 :             secAction = nsIXPCSecurityManager::ACCESS_CALL_METHOD;
    2297         4394905 :             break;
    2298                 :         case CALL_GETTER:
    2299         2255104 :             secFlag   = nsIXPCSecurityManager::HOOK_GET_PROPERTY;
    2300         2255104 :             secAction = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
    2301         2255104 :             break;
    2302                 :         case CALL_SETTER:
    2303          102335 :             secFlag   = nsIXPCSecurityManager::HOOK_SET_PROPERTY;
    2304          102335 :             secAction = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
    2305          102335 :             break;
    2306                 :         default:
    2307               0 :             NS_ERROR("bad value");
    2308               0 :             return false;
    2309                 :     }
    2310                 : 
    2311                 :     nsIXPCSecurityManager* sm =
    2312         6752344 :         xpcc->GetAppropriateSecurityManager(secFlag);
    2313         6752344 :     if (sm && NS_FAILED(sm->CanAccess(secAction, &ccx, ccx,
    2314                 :                                       ccx.GetFlattenedJSObject(),
    2315                 :                                       ccx.GetWrapper()->GetIdentityObject(),
    2316                 :                                       ccx.GetWrapper()->GetClassInfo(),
    2317                 :                                       ccx.GetMember()->GetName(),
    2318                 :                                       ccx.GetWrapper()->GetSecurityInfoAddr()))) {
    2319                 :         // the security manager vetoed. It should have set an exception.
    2320               0 :         return false;
    2321                 :     }
    2322                 : 
    2323         6752344 :     return CallMethodHelper(ccx).Call();
    2324                 : }
    2325                 : 
    2326                 : JSBool
    2327         6752344 : CallMethodHelper::Call()
    2328                 : {
    2329         6752344 :     mCallContext.SetRetVal(JSVAL_VOID);
    2330                 : 
    2331         6752344 :     mCallContext.GetThreadData()->SetException(nsnull);
    2332         6752344 :     mCallContext.GetXPCContext()->SetLastResult(NS_ERROR_UNEXPECTED);
    2333                 : 
    2334         6752344 :     if (mVTableIndex == 0) {
    2335           82703 :         return QueryInterfaceFastPath();
    2336                 :     }
    2337                 : 
    2338         6669641 :     if (!mMethodInfo) {
    2339               0 :         Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, mCallContext);
    2340               0 :         return false;
    2341                 :     }
    2342                 : 
    2343         6669641 :     if (!InitializeDispatchParams())
    2344               3 :         return false;
    2345                 : 
    2346                 :     // Iterate through the params doing conversions of independent params only.
    2347                 :     // When we later convert the dependent params (if any) we will know that
    2348                 :     // the params upon which they depend will have already been converted -
    2349                 :     // regardless of ordering.
    2350         6669638 :     JSBool foundDependentParam = false;
    2351         6669638 :     if (!ConvertIndependentParams(&foundDependentParam))
    2352              18 :         return false;
    2353                 : 
    2354         6669620 :     if (foundDependentParam && !ConvertDependentParams())
    2355               7 :         return false;
    2356                 : 
    2357         6669613 :     nsresult invokeResult = Invoke();
    2358                 : 
    2359         6669613 :     mCallContext.GetXPCContext()->SetLastResult(invokeResult);
    2360                 : 
    2361         6669613 :     if (NS_FAILED(invokeResult)) {
    2362           36291 :         ThrowBadResult(invokeResult, mCallContext);
    2363           36291 :         return false;
    2364                 :     }
    2365                 : 
    2366         6633322 :     if (JS_IsExceptionPending(mCallContext)) {
    2367             172 :         return false;
    2368                 :     }
    2369                 : 
    2370         6633150 :     return GatherAndConvertResults();
    2371                 : }
    2372                 : 
    2373        13504688 : CallMethodHelper::~CallMethodHelper()
    2374                 : {
    2375         6752344 :     uint8_t paramCount = mMethodInfo->GetParamCount();
    2376         6752344 :     if (mDispatchParams.Length()) {
    2377        17336184 :         for (uint8_t i = 0; i < paramCount; i++) {
    2378        10773874 :             nsXPTCVariant* dp = GetDispatchParam(i);
    2379        10773874 :             const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2380                 : 
    2381        10773874 :             if (paramInfo.GetType().IsArray()) {
    2382           67615 :                 void* p = dp->val.p;
    2383           67615 :                 if (!p)
    2384           18898 :                     continue;
    2385                 : 
    2386                 :                 // Clean up the array contents if necessary.
    2387           48717 :                 if (dp->DoesValNeedCleanup()) {
    2388                 :                     // We need some basic information to properly destroy the array.
    2389            8148 :                     uint32_t array_count = 0;
    2390            8148 :                     nsXPTType datum_type;
    2391           16296 :                     if (!GetArraySizeFromParam(i, &array_count) ||
    2392            8148 :                         !NS_SUCCEEDED(mIFaceInfo->GetTypeForParam(mVTableIndex,
    2393                 :                                                                   &paramInfo,
    2394                 :                                                                   1, &datum_type))) {
    2395                 :                         // XXXbholley - I'm not convinced that the above calls will
    2396                 :                         // ever fail.
    2397               0 :                         NS_ERROR("failed to get array information, we'll leak here");
    2398               0 :                         continue;
    2399                 :                     }
    2400                 : 
    2401                 :                     // Loop over the array contents. For each one, we create a
    2402                 :                     // dummy 'val' and pass it to the cleanup helper.
    2403           63022 :                     for (uint32_t k = 0; k < array_count; k++) {
    2404                 :                         nsXPTCMiniVariant v;
    2405           54874 :                         v.val.p = static_cast<void**>(p)[k];
    2406           54874 :                         CleanupParam(v, datum_type);
    2407                 :                     }
    2408                 :                 }
    2409                 : 
    2410                 :                 // always free the array itself
    2411           48717 :                 nsMemory::Free(p);
    2412                 :             } else {
    2413                 :                 // Clean up single parameters (if requested).
    2414        10706259 :                 if (dp->DoesValNeedCleanup())
    2415         7424081 :                     CleanupParam(*dp, dp->type);
    2416                 :             }
    2417                 :         }
    2418                 :     }
    2419                 : 
    2420         6752344 : }
    2421                 : 
    2422                 : JSBool
    2423           76401 : CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
    2424                 :                                         uint32_t* result) const
    2425                 : {
    2426                 :     nsresult rv;
    2427           76401 :     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
    2428                 : 
    2429                 :     // TODO fixup the various exceptions that are thrown
    2430                 : 
    2431           76401 :     rv = mIFaceInfo->GetSizeIsArgNumberForParam(mVTableIndex, &paramInfo, 0, &paramIndex);
    2432           76401 :     if (NS_FAILED(rv))
    2433               0 :         return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
    2434                 : 
    2435           76401 :     *result = GetDispatchParam(paramIndex)->val.u32;
    2436                 : 
    2437           76401 :     return true;
    2438                 : }
    2439                 : 
    2440                 : JSBool
    2441         1088944 : CallMethodHelper::GetInterfaceTypeFromParam(uint8_t paramIndex,
    2442                 :                                             const nsXPTType& datum_type,
    2443                 :                                             nsID* result) const
    2444                 : {
    2445                 :     nsresult rv;
    2446         1088944 :     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
    2447         1088944 :     uint8_t tag = datum_type.TagPart();
    2448                 : 
    2449                 :     // TODO fixup the various exceptions that are thrown
    2450                 : 
    2451         1088944 :     if (tag == nsXPTType::T_INTERFACE) {
    2452         1061345 :         rv = mIFaceInfo->GetIIDForParamNoAlloc(mVTableIndex, &paramInfo, result);
    2453         1061345 :         if (NS_FAILED(rv))
    2454                 :             return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
    2455               0 :                                  paramIndex, mCallContext);
    2456           27599 :     } else if (tag == nsXPTType::T_INTERFACE_IS) {
    2457                 :         rv = mIFaceInfo->GetInterfaceIsArgNumberForParam(mVTableIndex, &paramInfo,
    2458           27599 :                                                          &paramIndex);
    2459           27599 :         if (NS_FAILED(rv))
    2460               0 :             return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
    2461                 : 
    2462           27599 :         nsID* p = (nsID*) GetDispatchParam(paramIndex)->val.p;
    2463           27599 :         if (!p)
    2464                 :             return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
    2465               0 :                                  paramIndex, mCallContext);
    2466           27599 :         *result = *p;
    2467                 :     }
    2468         1088944 :     return true;
    2469                 : }
    2470                 : 
    2471                 : JSBool
    2472         8644547 : CallMethodHelper::GetOutParamSource(uint8_t paramIndex, jsval* srcp) const
    2473                 : {
    2474         8644547 :     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
    2475                 : 
    2476        12632673 :     if ((paramInfo.IsOut() || paramInfo.IsDipper()) &&
    2477         3988126 :         !paramInfo.IsRetval()) {
    2478           33469 :         NS_ASSERTION(paramIndex < mArgc || paramInfo.IsOptional(),
    2479                 :                      "Expected either enough arguments or an optional argument");
    2480           33469 :         jsval arg = paramIndex < mArgc ? mArgv[paramIndex] : JSVAL_NULL;
    2481           62811 :         if (paramIndex < mArgc &&
    2482           14681 :             (JSVAL_IS_PRIMITIVE(arg) ||
    2483                 :              !JS_GetPropertyById(mCallContext,
    2484                 :                                  JSVAL_TO_OBJECT(arg),
    2485                 :                                  mIdxValueId,
    2486           14661 :                                  srcp))) {
    2487                 :             // Explicitly passed in unusable value for out param.  Note
    2488                 :             // that if i >= mArgc we already know that |arg| is JSVAL_NULL,
    2489                 :             // and that's ok.
    2490                 :             ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, paramIndex,
    2491              20 :                           mCallContext);
    2492              20 :             return false;
    2493                 :         }
    2494                 :     }
    2495                 : 
    2496         8644527 :     return true;
    2497                 : }
    2498                 : 
    2499                 : JSBool
    2500         6633150 : CallMethodHelper::GatherAndConvertResults()
    2501                 : {
    2502                 :     // now we iterate through the native params to gather and convert results
    2503         6633150 :     uint8_t paramCount = mMethodInfo->GetParamCount();
    2504        17335539 :     for (uint8_t i = 0; i < paramCount; i++) {
    2505        10702389 :         const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2506        10702389 :         if (!paramInfo.IsOut() && !paramInfo.IsDipper())
    2507         4620349 :             continue;
    2508                 : 
    2509         6082040 :         const nsXPTType& type = paramInfo.GetType();
    2510         6082040 :         nsXPTCVariant* dp = GetDispatchParam(i);
    2511         6082040 :         jsval v = JSVAL_NULL;
    2512        12164080 :         AUTO_MARK_JSVAL(mCallContext, &v);
    2513         6082040 :         uint32_t array_count = 0;
    2514         6082040 :         nsXPTType datum_type;
    2515         6082040 :         bool isArray = type.IsArray();
    2516                 :         bool isSizedString = isArray ?
    2517                 :                 false :
    2518         6043221 :                 type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
    2519        12125261 :                 type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
    2520                 : 
    2521         6082040 :         if (isArray) {
    2522           38819 :             if (NS_FAILED(mIFaceInfo->GetTypeForParam(mVTableIndex, &paramInfo, 1,
    2523                 :                                                       &datum_type))) {
    2524               0 :                 Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
    2525               0 :                 return false;
    2526                 :             }
    2527                 :         } else
    2528         6043221 :             datum_type = type;
    2529                 : 
    2530         6082040 :         if (isArray || isSizedString) {
    2531           39471 :             if (!GetArraySizeFromParam(i, &array_count))
    2532               0 :                 return false;
    2533                 :         }
    2534                 : 
    2535                 :         nsID param_iid;
    2536         7167588 :         if (datum_type.IsInterfacePointer() &&
    2537         1085548 :             !GetInterfaceTypeFromParam(i, datum_type, &param_iid))
    2538               0 :             return false;
    2539                 : 
    2540                 :         nsresult err;
    2541         6082040 :         if (isArray) {
    2542           77638 :             XPCLazyCallContext lccx(mCallContext);
    2543           38819 :             if (!XPCConvert::NativeArray2JS(lccx, &v, (const void**)&dp->val,
    2544                 :                                             datum_type, &param_iid,
    2545           38819 :                                             array_count, &err)) {
    2546                 :                 // XXX need exception scheme for arrays to indicate bad element
    2547               0 :                 ThrowBadParam(err, i, mCallContext);
    2548               0 :                 return false;
    2549                 :             }
    2550         6043221 :         } else if (isSizedString) {
    2551             652 :             if (!XPCConvert::NativeStringWithSize2JS(mCallContext, &v,
    2552                 :                                                      (const void*)&dp->val,
    2553                 :                                                      datum_type,
    2554             652 :                                                      array_count, &err)) {
    2555               0 :                 ThrowBadParam(err, i, mCallContext);
    2556               0 :                 return false;
    2557                 :             }
    2558                 :         } else {
    2559         6042569 :             if (!XPCConvert::NativeData2JS(mCallContext, &v, &dp->val, datum_type,
    2560         6042569 :                                            &param_iid, &err)) {
    2561               0 :                 ThrowBadParam(err, i, mCallContext);
    2562               0 :                 return false;
    2563                 :             }
    2564                 :         }
    2565                 : 
    2566         6082040 :         if (paramInfo.IsRetval()) {
    2567         6027691 :             mCallContext.SetRetVal(v);
    2568           54349 :         } else if (i < mArgc) {
    2569                 :             // we actually assured this before doing the invoke
    2570           35562 :             NS_ASSERTION(JSVAL_IS_OBJECT(mArgv[i]), "out var is not object");
    2571           35562 :             if (!JS_SetPropertyById(mCallContext,
    2572           35562 :                                     JSVAL_TO_OBJECT(mArgv[i]),
    2573           35562 :                                     mIdxValueId, &v)) {
    2574               0 :                 ThrowBadParam(NS_ERROR_XPC_CANT_SET_OUT_VAL, i, mCallContext);
    2575               0 :                 return false;
    2576                 :             }
    2577                 :         } else {
    2578           18787 :             NS_ASSERTION(paramInfo.IsOptional(),
    2579                 :                          "Expected either enough arguments or an optional argument");
    2580                 :         }
    2581                 :     }
    2582                 : 
    2583         6633150 :     return true;
    2584                 : }
    2585                 : 
    2586                 : JSBool
    2587           82703 : CallMethodHelper::QueryInterfaceFastPath() const
    2588                 : {
    2589           82703 :     NS_ASSERTION(mVTableIndex == 0,
    2590                 :                  "Using the QI fast-path for a method other than QueryInterface");
    2591                 : 
    2592           82703 :     if (mArgc < 1) {
    2593               0 :         Throw(NS_ERROR_XPC_NOT_ENOUGH_ARGS, mCallContext);
    2594               0 :         return false;
    2595                 :     }
    2596                 :     const nsID* iid;
    2597                 :     JSObject* obj;
    2598          248109 :     if (!JSVAL_IS_OBJECT(mArgv[0]) ||
    2599           82703 :         (!(obj = JSVAL_TO_OBJECT(mArgv[0]))) ||
    2600           82703 :         (!(iid = xpc_JSObjectToID(mCallContext, obj)))) {
    2601               0 :         ThrowBadParam(NS_ERROR_XPC_BAD_CONVERT_JS, 0, mCallContext);
    2602               0 :         return false;
    2603                 :     }
    2604                 : 
    2605                 :     nsresult invokeResult;
    2606           82703 :     nsISupports* qiresult = nsnull;
    2607           82703 :     if (XPCPerThreadData::IsMainThread(mCallContext)) {
    2608           82703 :         invokeResult = mCallee->QueryInterface(*iid, (void**) &qiresult);
    2609                 :     } else {
    2610               0 :         JSAutoSuspendRequest suspended(mCallContext);
    2611               0 :         invokeResult = mCallee->QueryInterface(*iid, (void**) &qiresult);
    2612                 :     }
    2613                 : 
    2614           82703 :     mCallContext.GetXPCContext()->SetLastResult(invokeResult);
    2615                 : 
    2616           82703 :     if (NS_FAILED(invokeResult)) {
    2617            1755 :         ThrowBadResult(invokeResult, mCallContext);
    2618            1755 :         return false;
    2619                 :     }
    2620                 : 
    2621           80948 :     jsval v = JSVAL_NULL;
    2622                 :     unsigned err;
    2623                 :     JSBool success =
    2624                 :         XPCConvert::NativeData2JS(mCallContext, &v, &qiresult,
    2625                 :                                   nsXPTType::T_INTERFACE_IS,
    2626           80948 :                                   iid, &err);
    2627           80948 :     NS_IF_RELEASE(qiresult);
    2628                 : 
    2629           80948 :     if (!success) {
    2630               0 :         ThrowBadParam(err, 0, mCallContext);
    2631               0 :         return false;
    2632                 :     }
    2633                 : 
    2634           80948 :     mCallContext.SetRetVal(v);
    2635           80948 :     return true;
    2636                 : }
    2637                 : 
    2638                 : JSBool
    2639         6669641 : CallMethodHelper::InitializeDispatchParams()
    2640                 : {
    2641         6669641 :     const uint8_t wantsOptArgc = mMethodInfo->WantsOptArgc() ? 1 : 0;
    2642         6669641 :     const uint8_t wantsJSContext = mMethodInfo->WantsContext() ? 1 : 0;
    2643         6669641 :     const uint8_t paramCount = mMethodInfo->GetParamCount();
    2644         6669641 :     uint8_t requiredArgs = paramCount;
    2645         6669641 :     uint8_t hasRetval = 0;
    2646                 : 
    2647                 :     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
    2648         6669641 :     if (paramCount && mMethodInfo->GetParam(paramCount-1).IsRetval()) {
    2649         6062944 :         hasRetval = 1;
    2650         6062944 :         requiredArgs--;
    2651                 :     }
    2652                 : 
    2653         6669641 :     if (mArgc < requiredArgs || wantsOptArgc) {
    2654          244797 :         if (wantsOptArgc)
    2655          216330 :             mOptArgcIndex = requiredArgs;
    2656                 : 
    2657                 :         // skip over any optional arguments
    2658          744600 :         while (requiredArgs && mMethodInfo->GetParam(requiredArgs-1).IsOptional())
    2659          255006 :             requiredArgs--;
    2660                 : 
    2661          244797 :         if (mArgc < requiredArgs) {
    2662               3 :             Throw(NS_ERROR_XPC_NOT_ENOUGH_ARGS, mCallContext);
    2663               3 :             return false;
    2664                 :         }
    2665                 :     }
    2666                 : 
    2667         6669638 :     if (wantsJSContext) {
    2668          223435 :         if (wantsOptArgc)
    2669                 :             // Need to bump mOptArgcIndex up one here.
    2670          216265 :             mJSContextIndex = mOptArgcIndex++;
    2671            7170 :         else if (mMethodInfo->IsSetter() || mMethodInfo->IsGetter())
    2672                 :             // For attributes, we always put the JSContext* first.
    2673              65 :             mJSContextIndex = 0;
    2674                 :         else
    2675            7105 :             mJSContextIndex = paramCount - hasRetval;
    2676                 :     }
    2677                 : 
    2678                 :     // iterate through the params to clear flags (for safe cleanup later)
    2679        17883277 :     for (uint8_t i = 0; i < paramCount + wantsJSContext + wantsOptArgc; i++) {
    2680        11213639 :         nsXPTCVariant* dp = mDispatchParams.AppendElement();
    2681        11213639 :         dp->ClearFlags();
    2682        11213639 :         dp->val.p = nsnull;
    2683                 :     }
    2684                 : 
    2685                 :     // Fill in the JSContext argument
    2686         6669638 :     if (wantsJSContext) {
    2687          223435 :         nsXPTCVariant* dp = &mDispatchParams[mJSContextIndex];
    2688          223435 :         dp->type = nsXPTType::T_VOID;
    2689          223435 :         dp->val.p = mCallContext;
    2690                 :     }
    2691                 : 
    2692                 :     // Fill in the optional_argc argument
    2693         6669638 :     if (wantsOptArgc) {
    2694          216330 :         nsXPTCVariant* dp = &mDispatchParams[mOptArgcIndex];
    2695          216330 :         dp->type = nsXPTType::T_U8;
    2696          216330 :         dp->val.u8 = NS_MIN<PRUint32>(mArgc, paramCount) - requiredArgs;
    2697                 :     }
    2698                 : 
    2699         6669638 :     return true;
    2700                 : }
    2701                 : 
    2702                 : JSBool
    2703         6669638 : CallMethodHelper::ConvertIndependentParams(JSBool* foundDependentParam)
    2704                 : {
    2705         6669638 :     const uint8_t paramCount = mMethodInfo->GetParamCount();
    2706        17443474 :     for (uint8_t i = 0; i < paramCount; i++) {
    2707        10773854 :         const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2708                 : 
    2709        10773854 :         if (paramInfo.GetType().IsDependent())
    2710           97477 :             *foundDependentParam = true;
    2711        10676377 :         else if (!ConvertIndependentParam(i))
    2712              18 :             return false;
    2713                 : 
    2714                 :     }
    2715                 : 
    2716         6669620 :     return true;
    2717                 : }
    2718                 : 
    2719                 : JSBool
    2720        10676377 : CallMethodHelper::ConvertIndependentParam(uint8_t i)
    2721                 : {
    2722        10676377 :     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2723        10676377 :     const nsXPTType& type = paramInfo.GetType();
    2724        10676377 :     uint8_t type_tag = type.TagPart();
    2725        10676377 :     nsXPTCVariant* dp = GetDispatchParam(i);
    2726        10676377 :     dp->type = type;
    2727        10676377 :     NS_ABORT_IF_FALSE(!paramInfo.IsShared(), "[shared] implies [noscript]!");
    2728                 : 
    2729                 :     // Handle dipper types separately.
    2730        10676377 :     if (paramInfo.IsDipper())
    2731         2129295 :         return HandleDipperParam(dp, paramInfo);
    2732                 : 
    2733                 :     // Specify the correct storage/calling semantics.
    2734         8547082 :     if (paramInfo.IsIndirect())
    2735         4141676 :         dp->SetIndirect();
    2736                 : 
    2737                 :     // The JSVal proper is always stored within the 'val' union and passed
    2738                 :     // indirectly, regardless of in/out-ness.
    2739         8547082 :     if (type_tag == nsXPTType::T_JSVAL) {
    2740                 :         // Root the value.
    2741          441243 :         dp->val.j = JSVAL_VOID;
    2742          441243 :         if (!JS_AddValueRoot(mCallContext, &dp->val.j))
    2743               0 :             return false;
    2744                 :     }
    2745                 : 
    2746                 :     // Flag cleanup for anything that isn't self-contained.
    2747         8547082 :     if (!type.IsArithmetic())
    2748         5264917 :         dp->SetValNeedsCleanup();
    2749                 : 
    2750                 :     // Even if there's nothing to convert, we still need to examine the
    2751                 :     // JSObject container for out-params. If it's null or otherwise invalid,
    2752                 :     // we want to know before the call, rather than after.
    2753                 :     //
    2754                 :     // This is a no-op for 'in' params.
    2755                 :     jsval src;
    2756         8547082 :     if (!GetOutParamSource(i, &src))
    2757              17 :         return false;
    2758                 : 
    2759                 :     // All that's left to do is value conversion. Bail early if we don't need
    2760                 :     // to do that.
    2761         8547065 :     if (!paramInfo.IsIn())
    2762         3917182 :         return true;
    2763                 : 
    2764                 :     // We're definitely some variety of 'in' now, so there's something to
    2765                 :     // convert. The source value for conversion depends on whether we're
    2766                 :     // dealing with an 'in' or an 'inout' parameter. 'inout' was handled above,
    2767                 :     // so all that's left is 'in'.
    2768         4629883 :     if (!paramInfo.IsOut()) {
    2769                 :         // Handle the 'in' case.
    2770         4627657 :         NS_ASSERTION(i < mArgc || paramInfo.IsOptional(),
    2771                 :                      "Expected either enough arguments or an optional argument");
    2772         4627657 :         if (i < mArgc)
    2773         4559589 :             src = mArgv[i];
    2774           68068 :         else if (type_tag == nsXPTType::T_JSVAL)
    2775           50096 :             src = JSVAL_VOID;
    2776                 :         else
    2777           17972 :             src = JSVAL_NULL;
    2778                 :     }
    2779                 : 
    2780                 :     nsID param_iid;
    2781         5855296 :     if (type_tag == nsXPTType::T_INTERFACE &&
    2782         1225413 :         NS_FAILED(mIFaceInfo->GetIIDForParamNoAlloc(mVTableIndex, &paramInfo,
    2783                 :                                                     &param_iid))) {
    2784               0 :         ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, i, mCallContext);
    2785               0 :         return false;
    2786                 :     }
    2787                 : 
    2788                 :     unsigned err;
    2789         4629883 :     if (!XPCConvert::JSData2Native(mCallContext, &dp->val, src, type,
    2790         4629883 :                                    true, &param_iid, &err)) {
    2791               1 :         ThrowBadParam(err, i, mCallContext);
    2792               1 :         return false;
    2793                 :     }
    2794                 : 
    2795         4629882 :     return true;
    2796                 : }
    2797                 : 
    2798                 : JSBool
    2799           97421 : CallMethodHelper::ConvertDependentParams()
    2800                 : {
    2801           97421 :     const uint8_t paramCount = mMethodInfo->GetParamCount();
    2802          340433 :     for (uint8_t i = 0; i < paramCount; i++) {
    2803          243019 :         const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2804                 : 
    2805          243019 :         if (!paramInfo.GetType().IsDependent())
    2806          145554 :             continue;
    2807           97465 :         if (!ConvertDependentParam(i))
    2808               7 :             return false;
    2809                 :     }
    2810                 : 
    2811           97414 :     return true;
    2812                 : }
    2813                 : 
    2814                 : JSBool
    2815           97465 : CallMethodHelper::ConvertDependentParam(uint8_t i)
    2816                 : {
    2817           97465 :     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
    2818           97465 :     const nsXPTType& type = paramInfo.GetType();
    2819           97465 :     nsXPTType datum_type;
    2820           97465 :     uint32_t array_count = 0;
    2821           97465 :     bool isArray = type.IsArray();
    2822                 : 
    2823                 :     bool isSizedString = isArray ?
    2824                 :         false :
    2825           29869 :         type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
    2826          127334 :         type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
    2827                 : 
    2828           97465 :     nsXPTCVariant* dp = GetDispatchParam(i);
    2829           97465 :     dp->type = type;
    2830                 : 
    2831           97465 :     if (isArray) {
    2832           67596 :         if (NS_FAILED(mIFaceInfo->GetTypeForParam(mVTableIndex, &paramInfo, 1,
    2833                 :                                                   &datum_type))) {
    2834               0 :             Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
    2835               0 :             return false;
    2836                 :         }
    2837           67596 :         NS_ABORT_IF_FALSE(datum_type.TagPart() != nsXPTType::T_JSVAL,
    2838                 :                           "Arrays of JSVals not currently supported - "
    2839                 :                           "see bug 693337.");
    2840                 :     } else {
    2841           29869 :         datum_type = type;
    2842                 :     }
    2843                 : 
    2844                 :     // Specify the correct storage/calling semantics.
    2845           97465 :     if (paramInfo.IsIndirect())
    2846           68701 :         dp->SetIndirect();
    2847                 : 
    2848                 :     // We have 3 possible type of dependent parameters: Arrays, Sized Strings,
    2849                 :     // and iid_is Interface pointers. The latter two always need cleanup, and
    2850                 :     // arrays need cleanup for all non-arithmetic types. Since the latter two
    2851                 :     // cases also happen to be non-arithmetic, we can just inspect datum_type
    2852                 :     // here.
    2853           97465 :     if (!datum_type.IsArithmetic())
    2854           41404 :         dp->SetValNeedsCleanup();
    2855                 : 
    2856                 :     // Even if there's nothing to convert, we still need to examine the
    2857                 :     // JSObject container for out-params. If it's null or otherwise invalid,
    2858                 :     // we want to know before the call, rather than after.
    2859                 :     //
    2860                 :     // This is a no-op for 'in' params.
    2861                 :     jsval src;
    2862           97465 :     if (!GetOutParamSource(i, &src))
    2863               3 :         return false;
    2864                 : 
    2865                 :     // All that's left to do is value conversion. Bail early if we don't need
    2866                 :     // to do that.
    2867           97462 :     if (!paramInfo.IsIn())
    2868           68676 :         return true;
    2869                 : 
    2870                 :     // We're definitely some variety of 'in' now, so there's something to
    2871                 :     // convert. The source value for conversion depends on whether we're
    2872                 :     // dealing with an 'in' or an 'inout' parameter. 'inout' was handled above,
    2873                 :     // so all that's left is 'in'.
    2874           28786 :     if (!paramInfo.IsOut()) {
    2875                 :         // Handle the 'in' case.
    2876           28764 :         NS_ASSERTION(i < mArgc || paramInfo.IsOptional(),
    2877                 :                      "Expected either enough arguments or an optional argument");
    2878           28764 :         src = i < mArgc ? mArgv[i] : JSVAL_NULL;
    2879                 :     }
    2880                 : 
    2881                 :     nsID param_iid;
    2882           32182 :     if (datum_type.IsInterfacePointer() &&
    2883            3396 :         !GetInterfaceTypeFromParam(i, datum_type, &param_iid))
    2884               0 :         return false;
    2885                 : 
    2886                 :     unsigned err;
    2887                 : 
    2888           28786 :     if (isArray || isSizedString) {
    2889           28782 :         if (!GetArraySizeFromParam(i, &array_count))
    2890               0 :             return false;
    2891                 : 
    2892           57560 :         if (isArray) {
    2893           56398 :             if (array_count &&
    2894                 :                 !XPCConvert::JSArray2Native(mCallContext, (void**)&dp->val, src,
    2895                 :                                             array_count, datum_type, &param_iid,
    2896           27626 :                                             &err)) {
    2897                 :                 // XXX need exception scheme for arrays to indicate bad element
    2898               4 :                 ThrowBadParam(err, i, mCallContext);
    2899               4 :                 return false;
    2900                 :             }
    2901                 :         } else // if (isSizedString)
    2902                 :         {
    2903              10 :             if (!XPCConvert::JSStringWithSize2Native(mCallContext,
    2904                 :                                                      (void*)&dp->val,
    2905                 :                                                      src, array_count,
    2906              10 :                                                      datum_type, &err)) {
    2907               0 :                 ThrowBadParam(err, i, mCallContext);
    2908               0 :                 return false;
    2909                 :             }
    2910                 :         }
    2911                 :     } else {
    2912               4 :         if (!XPCConvert::JSData2Native(mCallContext, &dp->val, src, type,
    2913               4 :                                        true, &param_iid, &err)) {
    2914               0 :             ThrowBadParam(err, i, mCallContext);
    2915               0 :             return false;
    2916                 :         }
    2917                 :     }
    2918                 : 
    2919           28782 :     return true;
    2920                 : }
    2921                 : 
    2922                 : // Performs all necessary teardown on a parameter after method invocation.
    2923                 : //
    2924                 : // This method should only be called if the value in question was flagged
    2925                 : // for cleanup (ie, if dp->DoesValNeedCleanup()).
    2926                 : void
    2927         7478955 : CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
    2928                 : {
    2929                 :     // We handle array elements, but not the arrays themselves.
    2930         7478955 :     NS_ABORT_IF_FALSE(type.TagPart() != nsXPTType::T_ARRAY, "Can't handle arrays.");
    2931                 : 
    2932                 :     // Pointers may sometimes be null even if cleanup was requested. Combine
    2933                 :     // the null checking for all the different types into one check here.
    2934         7478955 :     if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nsnull)
    2935          244613 :         return;
    2936                 : 
    2937         7234342 :     switch (type.TagPart()) {
    2938                 :         case nsXPTType::T_JSVAL:
    2939          441243 :             JS_RemoveValueRoot(mCallContext, (jsval*)&param.val);
    2940          441243 :             break;
    2941                 :         case nsXPTType::T_INTERFACE:
    2942                 :         case nsXPTType::T_INTERFACE_IS:
    2943         2181379 :             ((nsISupports*)param.val.p)->Release();
    2944         2181379 :             break;
    2945                 :         case nsXPTType::T_ASTRING:
    2946                 :         case nsXPTType::T_DOMSTRING:
    2947         1599508 :             mCallContext.DeleteString((nsAString*)param.val.p);
    2948         1599508 :             break;
    2949                 :         case nsXPTType::T_UTF8STRING:
    2950                 :         case nsXPTType::T_CSTRING:
    2951         1806551 :             delete (nsCString*) param.val.p;
    2952         1806551 :             break;
    2953                 :         default:
    2954         1205661 :             NS_ABORT_IF_FALSE(!type.IsArithmetic(),
    2955                 :                               "Cleanup requested on unexpected type.");
    2956         1205661 :             nsMemory::Free(param.val.p);
    2957         1205661 :             break;
    2958                 :     }
    2959                 : }
    2960                 : 
    2961                 : // Handle parameters with dipper types.
    2962                 : //
    2963                 : // Dipper types are one of the more inscrutable aspects of xpidl. In a
    2964                 : // nutshell, dippers are empty container objects, created and passed by
    2965                 : // the caller, and filled by the callee. The callee receives a
    2966                 : // fully-formed object, and thus does not have to construct anything. But
    2967                 : // the object is functionally empty, and the callee is responsible for
    2968                 : // putting something useful inside of it.
    2969                 : //
    2970                 : // XPIDL decides which types to make dippers. The list of these types
    2971                 : // is given in the isDipperType() function in typelib.py, and is currently
    2972                 : // limited to 4 string types.
    2973                 : //
    2974                 : // When a dipper type is declared as an 'out' parameter, xpidl internally
    2975                 : // converts it to an 'in', and sets the XPT_PD_DIPPER flag on it. For this
    2976                 : // reason, dipper types are sometimes referred to as 'out parameters
    2977                 : // masquerading as in'. The burden of maintaining this illusion falls mostly
    2978                 : // on XPConnect - we create the empty containers, and harvest the results
    2979                 : // after the call.
    2980                 : //
    2981                 : // This method creates these empty containers.
    2982                 : JSBool
    2983         2129295 : CallMethodHelper::HandleDipperParam(nsXPTCVariant* dp,
    2984                 :                                     const nsXPTParamInfo& paramInfo)
    2985                 : {
    2986                 :     // Get something we can make comparisons with.
    2987         2129295 :     uint8_t type_tag = paramInfo.GetType().TagPart();
    2988                 : 
    2989                 :     // Dippers always have the 'in' and 'dipper' flags set. Never 'out'.
    2990         2129295 :     NS_ABORT_IF_FALSE(!paramInfo.IsOut(), "Dipper has unexpected flags.");
    2991                 : 
    2992                 :     // xpidl.h specifies that dipper types will be used in exactly four
    2993                 :     // cases, all strings. Verify that here.
    2994         2129295 :     NS_ABORT_IF_FALSE(type_tag == nsXPTType::T_ASTRING ||
    2995                 :                       type_tag == nsXPTType::T_DOMSTRING ||
    2996                 :                       type_tag == nsXPTType::T_UTF8STRING ||
    2997                 :                       type_tag == nsXPTType::T_CSTRING,
    2998                 :                       "Unexpected dipper type!");
    2999                 : 
    3000                 :     // ASTRING and DOMSTRING are very similar, and both use nsAutoString.
    3001                 :     // UTF8_STRING and CSTRING are also quite similar, and both use nsCString.
    3002         2129295 :     if (type_tag == nsXPTType::T_ASTRING || type_tag == nsXPTType::T_DOMSTRING)
    3003         1314593 :         dp->val.p = new nsAutoString();
    3004                 :     else
    3005          814702 :         dp->val.p = new nsCString();
    3006                 : 
    3007                 :     // Check for OOM, in either case.
    3008         2129295 :     if (!dp->val.p) {
    3009               0 :         JS_ReportOutOfMemory(mCallContext);
    3010               0 :         return false;
    3011                 :     }
    3012                 : 
    3013                 :     // We allocated, so we need to deallocate after the method call completes.
    3014         2129295 :     dp->SetValNeedsCleanup();
    3015                 : 
    3016         2129295 :     return true;
    3017                 : }
    3018                 : 
    3019                 : nsresult
    3020         6669613 : CallMethodHelper::Invoke()
    3021                 : {
    3022         6669613 :     PRUint32 argc = mDispatchParams.Length();
    3023         6669613 :     nsXPTCVariant* argv = mDispatchParams.Elements();
    3024                 : 
    3025         6669613 :     if (XPCPerThreadData::IsMainThread(mCallContext))
    3026         6669613 :         return NS_InvokeByIndex(mCallee, mVTableIndex, argc, argv);
    3027                 : 
    3028               0 :     JSAutoSuspendRequest suspended(mCallContext);
    3029               0 :     return NS_InvokeByIndex(mCallee, mVTableIndex, argc, argv);
    3030                 : }
    3031                 : 
    3032                 : /***************************************************************************/
    3033                 : // interface methods
    3034                 : 
    3035                 : /* readonly attribute JSObjectPtr JSObject; */
    3036          873436 : NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject)
    3037                 : {
    3038          873436 :     *aJSObject = GetFlatJSObject();
    3039          873436 :     return NS_OK;
    3040                 : }
    3041                 : 
    3042                 : /* readonly attribute nsISupports Native; */
    3043               0 : NS_IMETHODIMP XPCWrappedNative::GetNative(nsISupports * *aNative)
    3044                 : {
    3045                 :     // No need to QI here, we already have the correct nsISupports
    3046                 :     // vtable.
    3047               0 :     *aNative = mIdentity;
    3048               0 :     NS_ADDREF(*aNative);
    3049               0 :     return NS_OK;
    3050                 : }
    3051                 : 
    3052                 : /* reaonly attribute JSObjectPtr JSObjectPrototype; */
    3053               0 : NS_IMETHODIMP XPCWrappedNative::GetJSObjectPrototype(JSObject * *aJSObjectPrototype)
    3054                 : {
    3055               0 :     *aJSObjectPrototype = HasProto() ?
    3056               0 :                 GetProto()->GetJSProtoObject() : GetFlatJSObject();
    3057               0 :     return NS_OK;
    3058                 : }
    3059                 : 
    3060                 : nsIPrincipal*
    3061         1867645 : XPCWrappedNative::GetObjectPrincipal() const
    3062                 : {
    3063         1867645 :     nsIPrincipal* principal = GetScope()->GetPrincipal();
    3064                 : #ifdef DEBUG
    3065                 :     // Because of inner window reuse, we can have objects with one principal
    3066                 :     // living in a scope with a different (but same-origin) principal. So
    3067                 :     // just check same-origin here.
    3068         3735290 :     nsCOMPtr<nsIScriptObjectPrincipal> objPrin(do_QueryInterface(mIdentity));
    3069         1867645 :     if (objPrin) {
    3070                 :         bool equal;
    3071         1867645 :         if (!principal)
    3072               0 :             equal = !objPrin->GetPrincipal();
    3073                 :         else
    3074         1867645 :             principal->Equals(objPrin->GetPrincipal(), &equal);
    3075         1867645 :         NS_ASSERTION(equal, "Principal mismatch.  Expect bad things to happen");
    3076                 :     }
    3077                 : #endif
    3078         1867645 :     return principal;
    3079                 : }
    3080                 : 
    3081                 : /* readonly attribute nsIXPConnect XPConnect; */
    3082          133896 : NS_IMETHODIMP XPCWrappedNative::GetXPConnect(nsIXPConnect * *aXPConnect)
    3083                 : {
    3084          133896 :     if (IsValid()) {
    3085          133896 :         nsIXPConnect* temp = GetRuntime()->GetXPConnect();
    3086          133896 :         NS_IF_ADDREF(temp);
    3087          133896 :         *aXPConnect = temp;
    3088                 :     } else
    3089               0 :         *aXPConnect = nsnull;
    3090          133896 :     return NS_OK;
    3091                 : }
    3092                 : 
    3093                 : /* XPCNativeInterface FindInterfaceWithMember (in jsval name); */
    3094               0 : NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(jsid name, nsIInterfaceInfo * *_retval)
    3095                 : {
    3096                 :     XPCNativeInterface* iface;
    3097                 :     XPCNativeMember*  member;
    3098                 : 
    3099               0 :     if (GetSet()->FindMember(name, &member, &iface) && iface) {
    3100               0 :         nsIInterfaceInfo* temp = iface->GetInterfaceInfo();
    3101               0 :         NS_IF_ADDREF(temp);
    3102               0 :         *_retval = temp;
    3103                 :     } else
    3104               0 :         *_retval = nsnull;
    3105               0 :     return NS_OK;
    3106                 : }
    3107                 : 
    3108                 : /* XPCNativeInterface FindInterfaceWithName (in jsval name); */
    3109               0 : NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithName(jsid name, nsIInterfaceInfo * *_retval)
    3110                 : {
    3111               0 :     XPCNativeInterface* iface = GetSet()->FindNamedInterface(name);
    3112               0 :     if (iface) {
    3113               0 :         nsIInterfaceInfo* temp = iface->GetInterfaceInfo();
    3114               0 :         NS_IF_ADDREF(temp);
    3115               0 :         *_retval = temp;
    3116                 :     } else
    3117               0 :         *_retval = nsnull;
    3118               0 :     return NS_OK;
    3119                 : }
    3120                 : 
    3121               0 : inline nsresult UnexpectedFailure(nsresult rv)
    3122                 : {
    3123               0 :     NS_ERROR("This is not supposed to fail!");
    3124               0 :     return rv;
    3125                 : }
    3126                 : 
    3127                 : /* void finishInitForWrappedGlobal (); */
    3128               0 : NS_IMETHODIMP XPCWrappedNative::FinishInitForWrappedGlobal()
    3129                 : {
    3130                 :     // We can only be called under certain conditions.
    3131               0 :     MOZ_ASSERT(mScriptableInfo);
    3132               0 :     MOZ_ASSERT(mScriptableInfo->GetFlags().IsGlobalObject());
    3133               0 :     MOZ_ASSERT(HasProto());
    3134                 : 
    3135                 :     // Build a CCX.
    3136               0 :     XPCCallContext ccx(NATIVE_CALLER);
    3137               0 :     if (!ccx.IsValid())
    3138               0 :         return UnexpectedFailure(NS_ERROR_FAILURE);
    3139                 : 
    3140                 :     // Call PostCreateProrotype.
    3141               0 :     bool success = GetProto()->CallPostCreatePrototype(ccx);
    3142               0 :     if (!success)
    3143               0 :         return NS_ERROR_FAILURE;
    3144                 : 
    3145               0 :     return NS_OK;
    3146                 : }
    3147                 : 
    3148               0 : NS_IMETHODIMP XPCWrappedNative::GetSecurityInfoAddress(void*** securityInfoAddrPtr)
    3149                 : {
    3150               0 :     NS_ENSURE_ARG_POINTER(securityInfoAddrPtr);
    3151               0 :     *securityInfoAddrPtr = GetSecurityInfoAddr();
    3152               0 :     return NS_OK;
    3153                 : }
    3154                 : 
    3155                 : /* void debugDump (in short depth); */
    3156               0 : NS_IMETHODIMP XPCWrappedNative::DebugDump(PRInt16 depth)
    3157                 : {
    3158                 : #ifdef DEBUG
    3159               0 :     depth-- ;
    3160               0 :     XPC_LOG_ALWAYS(("XPCWrappedNative @ %x with mRefCnt = %d", this, mRefCnt.get()));
    3161               0 :     XPC_LOG_INDENT();
    3162                 : 
    3163               0 :         if (HasProto()) {
    3164               0 :             XPCWrappedNativeProto* proto = GetProto();
    3165               0 :             if (depth && proto)
    3166               0 :                 proto->DebugDump(depth);
    3167                 :             else
    3168               0 :                 XPC_LOG_ALWAYS(("mMaybeProto @ %x", proto));
    3169                 :         } else
    3170               0 :             XPC_LOG_ALWAYS(("Scope @ %x", GetScope()));
    3171                 : 
    3172               0 :         if (depth && mSet)
    3173               0 :             mSet->DebugDump(depth);
    3174                 :         else
    3175               0 :             XPC_LOG_ALWAYS(("mSet @ %x", mSet));
    3176                 : 
    3177               0 :         XPC_LOG_ALWAYS(("mFlatJSObject of %x", mFlatJSObject));
    3178               0 :         XPC_LOG_ALWAYS(("mIdentity of %x", mIdentity));
    3179               0 :         XPC_LOG_ALWAYS(("mScriptableInfo @ %x", mScriptableInfo));
    3180                 : 
    3181               0 :         if (depth && mScriptableInfo) {
    3182               0 :             XPC_LOG_INDENT();
    3183               0 :             XPC_LOG_ALWAYS(("mScriptable @ %x", mScriptableInfo->GetCallback()));
    3184               0 :             XPC_LOG_ALWAYS(("mFlags of %x", (PRUint32)mScriptableInfo->GetFlags()));
    3185               0 :             XPC_LOG_ALWAYS(("mJSClass @ %x", mScriptableInfo->GetJSClass()));
    3186               0 :             XPC_LOG_OUTDENT();
    3187                 :         }
    3188               0 :     XPC_LOG_OUTDENT();
    3189                 : #endif
    3190               0 :     return NS_OK;
    3191                 : }
    3192                 : 
    3193                 : /***************************************************************************/
    3194                 : 
    3195                 : char*
    3196           18545 : XPCWrappedNative::ToString(XPCCallContext& ccx,
    3197                 :                            XPCWrappedNativeTearOff* to /* = nsnull */ ) const
    3198                 : {
    3199                 : #ifdef DEBUG
    3200                 : #  define FMT_ADDR " @ 0x%p"
    3201                 : #  define FMT_STR(str) str
    3202                 : #  define PARAM_ADDR(w) , w
    3203                 : #else
    3204                 : #  define FMT_ADDR ""
    3205                 : #  define FMT_STR(str)
    3206                 : #  define PARAM_ADDR(w)
    3207                 : #endif
    3208                 : 
    3209           18545 :     char* sz = nsnull;
    3210           18545 :     char* name = nsnull;
    3211                 : 
    3212           18545 :     XPCNativeScriptableInfo* si = GetScriptableInfo();
    3213           18545 :     if (si)
    3214             301 :         name = JS_smprintf("%s", si->GetJSClass()->name);
    3215           18545 :     if (to) {
    3216               0 :         const char* fmt = name ? " (%s)" : "%s";
    3217                 :         name = JS_sprintf_append(name, fmt,
    3218               0 :                                  to->GetInterface()->GetNameString());
    3219           18545 :     } else if (!name) {
    3220           18244 :         XPCNativeSet* set = GetSet();
    3221           18244 :         XPCNativeInterface** array = set->GetInterfaceArray();
    3222           18244 :         PRUint16 count = set->GetInterfaceCount();
    3223                 : 
    3224           18244 :         if (count == 1)
    3225              12 :             name = JS_sprintf_append(name, "%s", array[0]->GetNameString());
    3226           22649 :         else if (count == 2 &&
    3227            4417 :                  array[0] == XPCNativeInterface::GetISupports(ccx)) {
    3228            4417 :             name = JS_sprintf_append(name, "%s", array[1]->GetNameString());
    3229                 :         } else {
    3230           77323 :             for (PRUint16 i = 0; i < count; i++) {
    3231                 :                 const char* fmt = (i == 0) ?
    3232                 :                                     "(%s" : (i == count-1) ?
    3233           63508 :                                         ", %s)" : ", %s";
    3234                 :                 name = JS_sprintf_append(name, fmt,
    3235           63508 :                                          array[i]->GetNameString());
    3236                 :             }
    3237                 :         }
    3238                 :     }
    3239                 : 
    3240           18545 :     if (!name) {
    3241               0 :         return nsnull;
    3242                 :     }
    3243                 :     const char* fmt = "[xpconnect wrapped %s" FMT_ADDR FMT_STR(" (native")
    3244           18545 :         FMT_ADDR FMT_STR(")") "]";
    3245           18545 :     if (si) {
    3246             301 :         fmt = "[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]";
    3247                 :     }
    3248           18545 :     sz = JS_smprintf(fmt, name PARAM_ADDR(this) PARAM_ADDR(mIdentity));
    3249                 : 
    3250           18545 :     JS_smprintf_free(name);
    3251                 : 
    3252                 : 
    3253           18545 :     return sz;
    3254                 : 
    3255                 : #undef FMT_ADDR
    3256                 : #undef PARAM_ADDR
    3257                 : }
    3258                 : 
    3259                 : /***************************************************************************/
    3260                 : 
    3261                 : #ifdef XPC_CHECK_CLASSINFO_CLAIMS
    3262                 : static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper)
    3263                 : {
    3264                 :     if (!wrapper || !wrapper->GetClassInfo())
    3265                 :         return;
    3266                 : 
    3267                 :     nsISupports* obj = wrapper->GetIdentityObject();
    3268                 :     XPCNativeSet* set = wrapper->GetSet();
    3269                 :     PRUint16 count = set->GetInterfaceCount();
    3270                 :     for (PRUint16 i = 0; i < count; i++) {
    3271                 :         nsIClassInfo* clsInfo = wrapper->GetClassInfo();
    3272                 :         XPCNativeInterface* iface = set->GetInterfaceAt(i);
    3273                 :         nsIInterfaceInfo* info = iface->GetInterfaceInfo();
    3274                 :         const nsIID* iid;
    3275                 :         nsISupports* ptr;
    3276                 : 
    3277                 :         info->GetIIDShared(&iid);
    3278                 :         nsresult rv = obj->QueryInterface(*iid, (void**)&ptr);
    3279                 :         if (NS_SUCCEEDED(rv)) {
    3280                 :             NS_RELEASE(ptr);
    3281                 :             continue;
    3282                 :         }
    3283                 :         if (rv == NS_ERROR_OUT_OF_MEMORY)
    3284                 :             continue;
    3285                 : 
    3286                 :         // Houston, We have a problem...
    3287                 : 
    3288                 :         char* className = nsnull;
    3289                 :         char* contractID = nsnull;
    3290                 :         const char* interfaceName;
    3291                 : 
    3292                 :         info->GetNameShared(&interfaceName);
    3293                 :         clsInfo->GetContractID(&contractID);
    3294                 :         if (wrapper->GetScriptableInfo()) {
    3295                 :             wrapper->GetScriptableInfo()->GetCallback()->
    3296                 :                 GetClassName(&className);
    3297                 :         }
    3298                 : 
    3299                 : 
    3300                 :         printf("\n!!! Object's nsIClassInfo lies about its interfaces!!!\n"
    3301                 :                "   classname: %s \n"
    3302                 :                "   contractid: %s \n"
    3303                 :                "   unimplemented interface name: %s\n\n",
    3304                 :                className ? className : "<unknown>",
    3305                 :                contractID ? contractID : "<unknown>",
    3306                 :                interfaceName);
    3307                 : 
    3308                 : #ifdef XPC_ASSERT_CLASSINFO_CLAIMS
    3309                 :         NS_ERROR("Fix this QueryInterface or nsIClassInfo");
    3310                 : #endif
    3311                 : 
    3312                 :         if (className)
    3313                 :             nsMemory::Free(className);
    3314                 :         if (contractID)
    3315                 :             nsMemory::Free(contractID);
    3316                 :     }
    3317                 : }
    3318                 : #endif
    3319                 : 
    3320                 : #ifdef XPC_REPORT_SHADOWED_WRAPPED_NATIVE_MEMBERS
    3321                 : static void DEBUG_PrintShadowObjectInfo(const char* header,
    3322                 :                                         XPCNativeSet* set,
    3323                 :                                         XPCWrappedNative* wrapper,
    3324                 :                                         XPCWrappedNativeProto* proto)
    3325                 : 
    3326                 : {
    3327                 :     if (header)
    3328                 :         printf("%s\n", header);
    3329                 : 
    3330                 :     printf("   XPCNativeSet @ 0x%p for the class:\n", (void*)set);
    3331                 : 
    3332                 :     char* className = nsnull;
    3333                 :     char* contractID = nsnull;
    3334                 : 
    3335                 :     nsIClassInfo* clsInfo = proto ? proto->GetClassInfo() : nsnull;
    3336                 :     if (clsInfo)
    3337                 :         clsInfo->GetContractID(&contractID);
    3338                 : 
    3339                 :     XPCNativeScriptableInfo* si = wrapper ?
    3340                 :             wrapper->GetScriptableInfo() :
    3341                 :             proto->GetScriptableInfo();
    3342                 :     if (si)
    3343                 :         si->GetCallback()->GetClassName(&className);
    3344                 : 
    3345                 :     printf("   classname: %s \n"
    3346                 :            "   contractid: %s \n",
    3347                 :            className ? className : "<unknown>",
    3348                 :            contractID ? contractID : "<unknown>");
    3349                 : 
    3350                 :     if (className)
    3351                 :         nsMemory::Free(className);
    3352                 :     if (contractID)
    3353                 :         nsMemory::Free(contractID);
    3354                 : 
    3355                 :     printf("   claims to implement interfaces:\n");
    3356                 : 
    3357                 :     PRUint16 count = set->GetInterfaceCount();
    3358                 :     for (PRUint16 i = 0; i < count; i++) {
    3359                 :         XPCNativeInterface* iface = set->GetInterfaceAt(i);
    3360                 :         nsIInterfaceInfo* info = iface->GetInterfaceInfo();
    3361                 :         const char* interfaceName;
    3362                 :         info->GetNameShared(&interfaceName);
    3363                 :         printf("      %s\n", interfaceName);
    3364                 :     }
    3365                 : }
    3366                 : 
    3367                 : static void ReportSingleMember(jsval ifaceName,
    3368                 :                                jsval memberName)
    3369                 : {
    3370                 :     JS_FileEscapedString(stdout, ifaceName, 0);
    3371                 :     if (JSVAL_IS_STRING(memberName)) {
    3372                 :         fputs("::", stdout);
    3373                 :         JS_FileEscapedString(stdout, memberName, 0);
    3374                 :     }
    3375                 : }
    3376                 : 
    3377                 : static void ShowHeader(JSBool* printedHeader,
    3378                 :                        const char* header,
    3379                 :                        XPCNativeSet* set,
    3380                 :                        XPCWrappedNative* wrapper,
    3381                 :                        XPCWrappedNativeProto* proto)
    3382                 : {
    3383                 :     if (!*printedHeader) {
    3384                 :         DEBUG_PrintShadowObjectInfo(header, set, wrapper, proto);
    3385                 :         *printedHeader = true;
    3386                 :     }
    3387                 : 
    3388                 : }
    3389                 : 
    3390                 : static void ShowOneShadow(jsval ifaceName1,
    3391                 :                           jsval memberName1,
    3392                 :                           jsval ifaceName2,
    3393                 :                           jsval memberName2)
    3394                 : {
    3395                 :     ReportSingleMember(ifaceName1, memberName1);
    3396                 :     printf(" shadows ");
    3397                 :     ReportSingleMember(ifaceName2, memberName2);
    3398                 :     printf("\n");
    3399                 : }
    3400                 : 
    3401                 : static void ShowDuplicateInterface(jsval ifaceName)
    3402                 : {
    3403                 :     fputs(" ! ", stdout);
    3404                 :     JS_FileEscapedString(stdout, ifaceName, 0);
    3405                 :     fputs(" appears twice in the nsIClassInfo interface set!\n", stdout);
    3406                 : }
    3407                 : 
    3408                 : static JSBool InterfacesAreRelated(XPCNativeInterface* iface1,
    3409                 :                                    XPCNativeInterface* iface2)
    3410                 : {
    3411                 :     nsIInterfaceInfo* info1 = iface1->GetInterfaceInfo();
    3412                 :     nsIInterfaceInfo* info2 = iface2->GetInterfaceInfo();
    3413                 : 
    3414                 :     NS_ASSERTION(info1 != info2, "should not have different iface!");
    3415                 : 
    3416                 :     bool match;
    3417                 : 
    3418                 :     return
    3419                 :         (NS_SUCCEEDED(info1->HasAncestor(iface2->GetIID(), &match)) && match) ||
    3420                 :         (NS_SUCCEEDED(info2->HasAncestor(iface1->GetIID(), &match)) && match);
    3421                 : }
    3422                 : 
    3423                 : static JSBool MembersAreTheSame(XPCNativeInterface* iface1,
    3424                 :                                 PRUint16 memberIndex1,
    3425                 :                                 XPCNativeInterface* iface2,
    3426                 :                                 PRUint16 memberIndex2)
    3427                 : {
    3428                 :     nsIInterfaceInfo* info1 = iface1->GetInterfaceInfo();
    3429                 :     nsIInterfaceInfo* info2 = iface2->GetInterfaceInfo();
    3430                 : 
    3431                 :     XPCNativeMember* member1 = iface1->GetMemberAt(memberIndex1);
    3432                 :     XPCNativeMember* member2 = iface2->GetMemberAt(memberIndex2);
    3433                 : 
    3434                 :     PRUint16 index1 = member1->GetIndex();
    3435                 :     PRUint16 index2 = member2->GetIndex();
    3436                 : 
    3437                 :     // If they are both constants, then we'll just be sure that they are equivalent.
    3438                 : 
    3439                 :     if (member1->IsConstant()) {
    3440                 :         if (!member2->IsConstant())
    3441                 :             return false;
    3442                 : 
    3443                 :         const nsXPTConstant* constant1;
    3444                 :         const nsXPTConstant* constant2;
    3445                 : 
    3446                 :         return NS_SUCCEEDED(info1->GetConstant(index1, &constant1)) &&
    3447                 :                NS_SUCCEEDED(info2->GetConstant(index2, &constant2)) &&
    3448                 :                constant1->GetType() == constant2->GetType() &&
    3449                 :                constant1->GetValue() == constant2->GetValue();
    3450                 :     }
    3451                 : 
    3452                 :     // Else we make sure they are of the same 'type' and return true only if
    3453                 :     // they are inherited from the same interface.
    3454                 : 
    3455                 :     if (member1->IsMethod() != member2->IsMethod() ||
    3456                 :         member1->IsWritableAttribute() != member2->IsWritableAttribute() ||
    3457                 :         member1->IsReadOnlyAttribute() != member2->IsReadOnlyAttribute()) {
    3458                 :         return false;
    3459                 :     }
    3460                 : 
    3461                 :     const nsXPTMethodInfo* mi1;
    3462                 :     const nsXPTMethodInfo* mi2;
    3463                 : 
    3464                 :     return NS_SUCCEEDED(info1->GetMethodInfo(index1, &mi1)) &&
    3465                 :            NS_SUCCEEDED(info2->GetMethodInfo(index2, &mi2)) &&
    3466                 :            mi1 == mi2;
    3467                 : }
    3468                 : 
    3469                 : void DEBUG_ReportShadowedMembers(XPCNativeSet* set,
    3470                 :                                  XPCWrappedNative* wrapper,
    3471                 :                                  XPCWrappedNativeProto* proto)
    3472                 : {
    3473                 :     // NOTE: Either wrapper or proto could be null...
    3474                 : 
    3475                 :     if (!(proto || wrapper) || !set || set->GetInterfaceCount() < 2)
    3476                 :         return;
    3477                 : 
    3478                 :     NS_ASSERTION(proto || wrapper, "bad param!");
    3479                 :     XPCJSRuntime* rt = proto ? proto->GetRuntime() : wrapper->GetRuntime();
    3480                 : 
    3481                 :     // a quicky hack to avoid reporting info for the same set too often
    3482                 :     static int nextSeenSet = 0;
    3483                 :     static const int MAX_SEEN_SETS = 128;
    3484                 :     static XPCNativeSet* SeenSets[MAX_SEEN_SETS];
    3485                 :     for (int seen = 0; seen < MAX_SEEN_SETS; seen++)
    3486                 :         if (set == SeenSets[seen])
    3487                 :             return;
    3488                 :     SeenSets[nextSeenSet] = set;
    3489                 : 
    3490                 : #ifdef off_DEBUG_jband
    3491                 :     static int seenCount = 0;
    3492                 :     printf("--- adding SeenSets[%d] = 0x%p\n", nextSeenSet, set);
    3493                 :     DEBUG_PrintShadowObjectInfo(nsnull, set, wrapper, proto);
    3494                 : #endif
    3495                 :     int localNext = nextSeenSet+1;
    3496                 :     nextSeenSet = localNext < MAX_SEEN_SETS ? localNext : 0;
    3497                 : 
    3498                 :     XPCNativeScriptableInfo* si = wrapper ?
    3499                 :             wrapper->GetScriptableInfo() :
    3500                 :             proto->GetScriptableInfo();
    3501                 : 
    3502                 :     // We just want to skip some classes...
    3503                 :     if (si) {
    3504                 :         // Add any classnames to skip to this (null terminated) array...
    3505                 :         static const char* skipClasses[] = {
    3506                 :             "Window",
    3507                 :             "HTMLDocument",
    3508                 :             "HTMLCollection",
    3509                 :             "Event",
    3510                 :             "ChromeWindow",
    3511                 :             nsnull
    3512                 :         };
    3513                 : 
    3514                 :         static bool warned = false;
    3515                 :         if (!warned) {
    3516                 :             printf("!!! XPConnect won't warn about Shadowed Members of...\n  ");
    3517                 :             for (const char** name = skipClasses; *name; name++)
    3518                 :                 printf("%s %s", name == skipClasses ? "" : ",", *name);
    3519                 :              printf("\n");
    3520                 :             warned = true;
    3521                 :         }
    3522                 : 
    3523                 :         bool quit = false;
    3524                 :         char* className = nsnull;
    3525                 :         si->GetCallback()->GetClassName(&className);
    3526                 :         if (className) {
    3527                 :             for (const char** name = skipClasses; *name; name++) {
    3528                 :                 if (!strcmp(*name, className)) {
    3529                 :                     quit = true;
    3530                 :                     break;
    3531                 :                 }
    3532                 :             }
    3533                 :             nsMemory::Free(className);
    3534                 :         }
    3535                 :         if (quit)
    3536                 :             return;
    3537                 :     }
    3538                 : 
    3539                 :     const char header[] =
    3540                 :         "!!!Object wrapped by XPConnect has members whose names shadow each other!!!";
    3541                 : 
    3542                 :     JSBool printedHeader = false;
    3543                 : 
    3544                 :     jsval QIName = rt->GetStringJSVal(XPCJSRuntime::IDX_QUERY_INTERFACE);
    3545                 : 
    3546                 :     PRUint16 ifaceCount = set->GetInterfaceCount();
    3547                 :     PRUint16 i, j, k, m;
    3548                 : 
    3549                 :     // First look for duplicate interface entries
    3550                 : 
    3551                 :     for (i = 0; i < ifaceCount; i++) {
    3552                 :         XPCNativeInterface* ifaceOuter = set->GetInterfaceAt(i);
    3553                 :         for (k = i+1; k < ifaceCount; k++) {
    3554                 :             XPCNativeInterface* ifaceInner = set->GetInterfaceAt(k);
    3555                 :             if (ifaceInner == ifaceOuter) {
    3556                 :                 ShowHeader(&printedHeader, header, set, wrapper, proto);
    3557                 :                 ShowDuplicateInterface(ifaceOuter->GetName());
    3558                 :             }
    3559                 :         }
    3560                 :     }
    3561                 : 
    3562                 :     // Now scan for shadowing names
    3563                 : 
    3564                 :     for (i = 0; i < ifaceCount; i++) {
    3565                 :         XPCNativeInterface* ifaceOuter = set->GetInterfaceAt(i);
    3566                 :         jsval ifaceOuterName = ifaceOuter->GetName();
    3567                 : 
    3568                 :         PRUint16 memberCountOuter = ifaceOuter->GetMemberCount();
    3569                 :         for (j = 0; j < memberCountOuter; j++) {
    3570                 :             XPCNativeMember* memberOuter = ifaceOuter->GetMemberAt(j);
    3571                 :             jsval memberOuterName = memberOuter->GetName();
    3572                 : 
    3573                 :             if (memberOuterName == QIName)
    3574                 :                 continue;
    3575                 : 
    3576                 :             for (k = i+1; k < ifaceCount; k++) {
    3577                 :                 XPCNativeInterface* ifaceInner = set->GetInterfaceAt(k);
    3578                 :                 jsval ifaceInnerName = ifaceInner->GetName();
    3579                 : 
    3580                 :                 // Reported elsewhere.
    3581                 :                 if (ifaceInner == ifaceOuter)
    3582                 :                     continue;
    3583                 : 
    3584                 :                 // We consider this not worth reporting because callers will
    3585                 :                 // almost certainly be getting what they expect.
    3586                 :                 if (InterfacesAreRelated(ifaceInner, ifaceOuter))
    3587                 :                     continue;
    3588                 : 
    3589                 :                 if (ifaceInnerName == memberOuterName) {
    3590                 :                     ShowHeader(&printedHeader, header, set, wrapper, proto);
    3591                 :                     ShowOneShadow(ifaceInnerName, JSVAL_NULL,
    3592                 :                                   ifaceOuterName, memberOuterName);
    3593                 :                 }
    3594                 : 
    3595                 :                 PRUint16 memberCountInner = ifaceInner->GetMemberCount();
    3596                 : 
    3597                 :                 for (m = 0; m < memberCountInner; m++) {
    3598                 :                     XPCNativeMember* memberInner = ifaceInner->GetMemberAt(m);
    3599                 :                     jsval memberInnerName = memberInner->GetName();
    3600                 : 
    3601                 :                     if (memberInnerName == QIName)
    3602                 :                         continue;
    3603                 : 
    3604                 :                     if (memberOuterName == memberInnerName &&
    3605                 :                         !MembersAreTheSame(ifaceOuter, j, ifaceInner, m))
    3606                 : 
    3607                 :                     {
    3608                 :                         ShowHeader(&printedHeader, header, set, wrapper, proto);
    3609                 :                         ShowOneShadow(ifaceOuterName, memberOuterName,
    3610                 :                                       ifaceInnerName, memberInnerName);
    3611                 :                     }
    3612                 :                 }
    3613                 :             }
    3614                 :         }
    3615                 :     }
    3616                 : }
    3617                 : #endif
    3618                 : 
    3619                 : #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
    3620               0 : void DEBUG_ReportWrapperThreadSafetyError(XPCCallContext& ccx,
    3621                 :                                           const char* msg,
    3622                 :                                           const XPCWrappedNative* wrapper)
    3623                 : {
    3624               0 :     XPCPerThreadData* tls = ccx.GetThreadData();
    3625               0 :     if (1 != tls->IncrementWrappedNativeThreadsafetyReportDepth())
    3626               0 :         return;
    3627                 : 
    3628               0 :     printf("---------------------------------------------------------------\n");
    3629               0 :     printf("!!!!! XPConnect wrapper thread use error...\n");
    3630                 : 
    3631               0 :     char* wrapperDump = wrapper->ToString(ccx);
    3632               0 :     if (wrapperDump) {
    3633               0 :         printf("  %s\n  wrapper: %s\n", msg, wrapperDump);
    3634               0 :         JS_smprintf_free(wrapperDump);
    3635                 :     } else
    3636               0 :         printf("  %s\n  wrapper @ 0x%p\n", msg, (void *)wrapper);
    3637                 : 
    3638               0 :     printf("  JS call stack...\n");
    3639               0 :     xpc_DumpJSStack(ccx, true, true, true);
    3640               0 :     printf("---------------------------------------------------------------\n");
    3641                 : 
    3642               0 :     tls->ClearWrappedNativeThreadsafetyReportDepth();
    3643                 : }
    3644                 : 
    3645        12599809 : void DEBUG_CheckWrapperThreadSafety(const XPCWrappedNative* wrapper)
    3646                 : {
    3647        12599809 :     XPCWrappedNativeProto* proto = wrapper->GetProto();
    3648        12599809 :     if (proto && proto->ClassIsThreadSafe())
    3649         3019965 :         return;
    3650                 : 
    3651         9579844 :     if (proto && proto->ClassIsMainThreadOnly()) {
    3652                 :         // NS_IsMainThread is safe to call even after we've started shutting
    3653                 :         // down.
    3654          196978 :         if (!NS_IsMainThread()) {
    3655               0 :             XPCCallContext ccx(NATIVE_CALLER);
    3656                 :             DEBUG_ReportWrapperThreadSafetyError(ccx,
    3657               0 :                                                  "Main Thread Only wrapper accessed on another thread", wrapper);
    3658                 :         }
    3659         9382866 :     } else if (PR_GetCurrentThread() != wrapper->mThread) {
    3660               0 :         XPCCallContext ccx(NATIVE_CALLER);
    3661                 :         DEBUG_ReportWrapperThreadSafetyError(ccx,
    3662                 :                                              "XPConnect WrappedNative is being accessed on multiple threads but "
    3663                 :                                              "the underlying native xpcom object does not have a "
    3664               0 :                                              "nsIClassInfo with the 'THREADSAFE' flag set", wrapper);
    3665                 :     }
    3666                 : }
    3667                 : #endif
    3668                 : 
    3669               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(XPCJSObjectHolder, nsIXPConnectJSObjectHolder)
    3670                 : 
    3671                 : NS_IMETHODIMP
    3672               0 : XPCJSObjectHolder::GetJSObject(JSObject** aJSObj)
    3673                 : {
    3674               0 :     NS_PRECONDITION(aJSObj, "bad param");
    3675               0 :     NS_PRECONDITION(mJSObj, "bad object state");
    3676               0 :     *aJSObj = mJSObj;
    3677               0 :     return NS_OK;
    3678                 : }
    3679                 : 
    3680               0 : XPCJSObjectHolder::XPCJSObjectHolder(XPCCallContext& ccx, JSObject* obj)
    3681               0 :     : mJSObj(obj)
    3682                 : {
    3683               0 :     ccx.GetRuntime()->AddObjectHolderRoot(this);
    3684               0 : }
    3685                 : 
    3686               0 : XPCJSObjectHolder::~XPCJSObjectHolder()
    3687                 : {
    3688               0 :     RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
    3689               0 : }
    3690                 : 
    3691                 : void
    3692               0 : XPCJSObjectHolder::TraceJS(JSTracer *trc)
    3693                 : {
    3694               0 :     JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
    3695               0 :     JS_CallTracer(trc, mJSObj, JSTRACE_OBJECT);
    3696               0 : }
    3697                 : 
    3698                 : #ifdef DEBUG
    3699                 : // static
    3700                 : void
    3701               0 : XPCJSObjectHolder::PrintTraceName(JSTracer* trc, char *buf, size_t bufsize)
    3702                 : {
    3703                 :     JS_snprintf(buf, bufsize, "XPCJSObjectHolder[0x%p].mJSObj",
    3704               0 :                 trc->debugPrintArg);
    3705               0 : }
    3706                 : #endif
    3707                 : 
    3708                 : // static
    3709                 : XPCJSObjectHolder*
    3710               0 : XPCJSObjectHolder::newHolder(XPCCallContext& ccx, JSObject* obj)
    3711                 : {
    3712               0 :     if (!obj) {
    3713               0 :         NS_ERROR("bad param");
    3714               0 :         return nsnull;
    3715                 :     }
    3716               0 :     return new XPCJSObjectHolder(ccx, obj);
    3717                 : }
    3718                 : 
    3719                 : JSBool
    3720            6065 : MorphSlimWrapper(JSContext *cx, JSObject *obj)
    3721                 : {
    3722                 :     SLIM_LOG(("***** morphing from MorphSlimToWrapper (%p, %p)\n",
    3723                 :               obj, static_cast<nsISupports*>(xpc_GetJSPrivate(obj))));
    3724                 : 
    3725           12130 :     XPCCallContext ccx(JS_CALLER, cx);
    3726                 : 
    3727            6065 :     nsISupports* object = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
    3728            6065 :     nsWrapperCache *cache = nsnull;
    3729            6065 :     CallQueryInterface(object, &cache);
    3730           12130 :     nsRefPtr<XPCWrappedNative> wn;
    3731                 :     nsresult rv = XPCWrappedNative::Morph(ccx, obj, nsnull, cache,
    3732            6065 :                                           getter_AddRefs(wn));
    3733            6065 :     return NS_SUCCEEDED(rv);
    3734                 : }
    3735                 : 
    3736                 : #ifdef DEBUG_slimwrappers
    3737                 : static PRUint32 sSlimWrappers;
    3738                 : #endif
    3739                 : 
    3740                 : JSBool
    3741           19761 : ConstructSlimWrapper(XPCCallContext &ccx,
    3742                 :                      xpcObjectHelper &aHelper,
    3743                 :                      XPCWrappedNativeScope* xpcScope, jsval *rval)
    3744                 : {
    3745           19761 :     nsISupports *identityObj = aHelper.GetCanonical();
    3746           19761 :     nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo();
    3747                 : 
    3748                 :     uint32_t flagsInt;
    3749           19761 :     nsresult rv = classInfoHelper->GetScriptableFlags(&flagsInt);
    3750           19761 :     if (NS_FAILED(rv))
    3751               0 :         flagsInt = 0;
    3752                 : 
    3753           19761 :     XPCNativeScriptableFlags flags(flagsInt);
    3754                 : 
    3755           19761 :     NS_ASSERTION(flags.DontAskInstanceForScriptable(),
    3756                 :                  "Not supported for cached wrappers!");
    3757                 : 
    3758           19761 :     JSObject* parent = xpcScope->GetGlobalJSObject();
    3759           19761 :     if (!flags.WantPreCreate()) {
    3760                 :         SLIM_LOG_NOT_CREATED(ccx, identityObj,
    3761                 :                              "scriptable helper has no PreCreate hook");
    3762                 : 
    3763               0 :         return false;
    3764                 :     }
    3765                 : 
    3766           19761 :     JSObject* plannedParent = parent;
    3767           19761 :     rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent);
    3768           19761 :     if (rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) {
    3769                 :         SLIM_LOG_NOT_CREATED(ccx, identityObj, "PreCreate hook refused");
    3770                 : 
    3771            4605 :         return false;
    3772                 :     }
    3773                 : 
    3774           15156 :     if (!js::IsObjectInContextCompartment(parent, ccx.GetJSContext())) {
    3775                 :         SLIM_LOG_NOT_CREATED(ccx, identityObj, "wrong compartment");
    3776                 : 
    3777               0 :         return false;
    3778                 :     }
    3779                 : 
    3780           30312 :     JSAutoEnterCompartment ac;
    3781           15156 :     if (!ac.enter(ccx, parent)) {
    3782                 :         SLIM_LOG_NOT_CREATED(ccx, identityObj, "unable to enter compartment");
    3783                 : 
    3784               0 :         return false;
    3785                 :     }
    3786                 : 
    3787           15156 :     if (parent != plannedParent) {
    3788                 :         XPCWrappedNativeScope *newXpcScope =
    3789           15156 :             XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
    3790           15156 :         if (newXpcScope != xpcScope) {
    3791                 :             SLIM_LOG_NOT_CREATED(ccx, identityObj, "crossing origins");
    3792                 : 
    3793               1 :             return false;
    3794                 :         }
    3795                 :     }
    3796                 : 
    3797                 :     // The PreCreate hook could have forced the creation of a wrapper, need
    3798                 :     // to check for that here and return early.
    3799           15155 :     nsWrapperCache *cache = aHelper.GetWrapperCache();
    3800           15155 :     JSObject* wrapper = cache->GetWrapper();
    3801           15155 :     if (wrapper) {
    3802               0 :         *rval = OBJECT_TO_JSVAL(wrapper);
    3803                 : 
    3804               0 :         return true;
    3805                 :     }
    3806                 : 
    3807           15155 :     PRUint32 interfacesBitmap = classInfoHelper->GetInterfacesBitmap();
    3808                 :     XPCNativeScriptableCreateInfo
    3809           30310 :         sciProto(aHelper.forgetXPCClassInfo(), flags, interfacesBitmap);
    3810                 : 
    3811           30310 :     AutoMarkingWrappedNativeProtoPtr xpcproto(ccx);
    3812                 :     xpcproto = XPCWrappedNativeProto::GetNewOrUsed(ccx, xpcScope,
    3813           15155 :                                                    classInfoHelper, &sciProto);
    3814           15155 :     if (!xpcproto)
    3815               0 :         return false;
    3816                 : 
    3817           15155 :     xpcproto->CacheOffsets(identityObj);
    3818                 : 
    3819           15155 :     XPCNativeScriptableInfo* si = xpcproto->GetScriptableInfo();
    3820           15155 :     JSClass* jsclazz = si->GetSlimJSClass();
    3821           15155 :     if (!jsclazz)
    3822               0 :         return false;
    3823                 : 
    3824                 :     wrapper = xpc_NewSystemInheritingJSObject(ccx, jsclazz,
    3825                 :                                               xpcproto->GetJSProtoObject(),
    3826           15155 :                                               false, parent);
    3827           15155 :     if (!wrapper)
    3828               0 :         return false;
    3829                 : 
    3830           15155 :     JS_SetPrivate(wrapper, identityObj);
    3831           15155 :     JS_SetReservedSlot(wrapper, 0, PRIVATE_TO_JSVAL(xpcproto.get()));
    3832                 : 
    3833                 :     // Transfer ownership to the wrapper's private.
    3834           15155 :     aHelper.forgetCanonical();
    3835                 : 
    3836           15155 :     cache->SetWrapper(wrapper);
    3837                 : 
    3838                 :     SLIM_LOG(("+++++ %i created slim wrapper (%p, %p, %p)\n", ++sSlimWrappers,
    3839                 :               wrapper, p, xpcScope));
    3840                 : 
    3841           15155 :     *rval = OBJECT_TO_JSVAL(wrapper);
    3842                 : 
    3843           15155 :     return true;
    3844            4392 : }

Generated by: LCOV version 1.7