Back to index

lightning-sunbird  0.9+nobinonly
xpcwrappednative.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=78:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *   John Bandhauer <jband@netscape.com> (original author)
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 /* Wrapper object for reflecting native xpcom objects into JavaScript. */
00043 
00044 #include "xpcprivate.h"
00045 #include "nsCRT.h"
00046 #include "XPCNativeWrapper.h"
00047 
00048 /***************************************************************************/
00049 
00050 #ifdef XPC_CHECK_CLASSINFO_CLAIMS
00051 static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper);
00052 #else
00053 #define DEBUG_CheckClassInfoClaims(wrapper) ((void)0)
00054 #endif
00055 
00056 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
00057 PRThread* XPCWrappedNative::gMainThread = nsnull;
00058 #endif
00059 
00060 #ifdef XPC_TRACK_WRAPPER_STATS
00061 static int DEBUG_TotalWrappedNativeCount;
00062 static int DEBUG_TotalLiveWrappedNativeCount;
00063 static int DEBUG_TotalMaxWrappedNativeCount;
00064 static int DEBUG_WrappedNativeWithProtoCount;
00065 static int DEBUG_LiveWrappedNativeWithProtoCount;
00066 static int DEBUG_MaxWrappedNativeWithProtoCount;
00067 static int DEBUG_WrappedNativeNoProtoCount;
00068 static int DEBUG_LiveWrappedNativeNoProtoCount;
00069 static int DEBUG_MaxWrappedNativeNoProtoCount;
00070 static int DEBUG_WrappedNativeTotalCalls;
00071 static int DEBUG_WrappedNativeMethodCalls;
00072 static int DEBUG_WrappedNativeGetterCalls;
00073 static int DEBUG_WrappedNativeSetterCalls;
00074 #define DEBUG_CHUNKS_TO_COUNT 4
00075 static int DEBUG_WrappedNativeTearOffChunkCounts[DEBUG_CHUNKS_TO_COUNT+1];
00076 static PRBool  DEBUG_DumpedWrapperStats;
00077 #endif
00078 
00079 #ifdef DEBUG
00080 static void DEBUG_TrackNewWrapper(XPCWrappedNative* wrapper)
00081 {
00082 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
00083     if(wrapper->GetRuntime())
00084         wrapper->GetRuntime()->DEBUG_AddWrappedNative(wrapper);
00085     else
00086         NS_ERROR("failed to add wrapper");
00087 #endif
00088 #ifdef XPC_TRACK_WRAPPER_STATS
00089     DEBUG_TotalWrappedNativeCount++;
00090     DEBUG_TotalLiveWrappedNativeCount++;
00091     if(DEBUG_TotalMaxWrappedNativeCount < DEBUG_TotalLiveWrappedNativeCount)
00092         DEBUG_TotalMaxWrappedNativeCount = DEBUG_TotalLiveWrappedNativeCount;
00093 
00094     if(wrapper->HasProto())
00095     {
00096         DEBUG_WrappedNativeWithProtoCount++;
00097         DEBUG_LiveWrappedNativeWithProtoCount++;
00098         if(DEBUG_MaxWrappedNativeWithProtoCount < DEBUG_LiveWrappedNativeWithProtoCount)
00099             DEBUG_MaxWrappedNativeWithProtoCount = DEBUG_LiveWrappedNativeWithProtoCount;
00100     }
00101     else
00102     {
00103         DEBUG_WrappedNativeNoProtoCount++;
00104         DEBUG_LiveWrappedNativeNoProtoCount++;
00105         if(DEBUG_MaxWrappedNativeNoProtoCount < DEBUG_LiveWrappedNativeNoProtoCount)
00106             DEBUG_MaxWrappedNativeNoProtoCount = DEBUG_LiveWrappedNativeNoProtoCount;
00107     }
00108 #endif
00109 }
00110 
00111 static void DEBUG_TrackDeleteWrapper(XPCWrappedNative* wrapper)
00112 {
00113 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
00114     if(wrapper->GetRuntime())
00115         wrapper->GetRuntime()->DEBUG_RemoveWrappedNative(wrapper);
00116     else
00117         NS_ERROR("failed to remove wrapper");
00118 #endif
00119 #ifdef XPC_TRACK_WRAPPER_STATS
00120     DEBUG_TotalLiveWrappedNativeCount--;
00121     if(wrapper->HasProto())
00122         DEBUG_LiveWrappedNativeWithProtoCount--;
00123     else
00124         DEBUG_LiveWrappedNativeNoProtoCount--;
00125 
00126     int extraChunkCount = wrapper->DEBUG_CountOfTearoffChunks() - 1;
00127     if(extraChunkCount > DEBUG_CHUNKS_TO_COUNT)
00128         extraChunkCount = DEBUG_CHUNKS_TO_COUNT;
00129     DEBUG_WrappedNativeTearOffChunkCounts[extraChunkCount]++;
00130 #endif
00131 }
00132 static void DEBUG_TrackWrapperCall(XPCWrappedNative* wrapper,
00133                                    XPCWrappedNative::CallMode mode)
00134 {
00135 #ifdef XPC_TRACK_WRAPPER_STATS
00136     DEBUG_WrappedNativeTotalCalls++;
00137     switch(mode)
00138     {
00139         case XPCWrappedNative::CALL_METHOD:
00140             DEBUG_WrappedNativeMethodCalls++;
00141             break;
00142         case XPCWrappedNative::CALL_GETTER:
00143             DEBUG_WrappedNativeGetterCalls++;
00144             break;
00145         case XPCWrappedNative::CALL_SETTER:
00146             DEBUG_WrappedNativeSetterCalls++;
00147             break;
00148         default:
00149             NS_ERROR("bad value");
00150     }
00151 #endif
00152 }
00153 
00154 static void DEBUG_TrackShutdownWrapper(XPCWrappedNative* wrapper)
00155 {
00156 #ifdef XPC_TRACK_WRAPPER_STATS
00157     if(!DEBUG_DumpedWrapperStats)
00158     {
00159         DEBUG_DumpedWrapperStats = PR_TRUE;
00160         printf("%d WrappedNatives were constructed. "
00161                "(%d w/ protos, %d w/o)\n",
00162                DEBUG_TotalWrappedNativeCount,
00163                DEBUG_WrappedNativeWithProtoCount,
00164                DEBUG_WrappedNativeNoProtoCount);
00165 
00166         printf("%d WrappedNatives max alive at one time. "
00167                "(%d w/ protos, %d w/o)\n",
00168                DEBUG_TotalMaxWrappedNativeCount,
00169                DEBUG_MaxWrappedNativeWithProtoCount,
00170                DEBUG_MaxWrappedNativeNoProtoCount);
00171 
00172         printf("%d WrappedNatives alive now. "
00173                "(%d w/ protos, %d w/o)\n",
00174                DEBUG_TotalLiveWrappedNativeCount,
00175                DEBUG_LiveWrappedNativeWithProtoCount,
00176                DEBUG_LiveWrappedNativeNoProtoCount);
00177 
00178         printf("%d calls to WrappedNatives. "
00179                "(%d methods, %d getters, %d setters)\n",
00180                DEBUG_WrappedNativeTotalCalls,
00181                DEBUG_WrappedNativeMethodCalls,
00182                DEBUG_WrappedNativeGetterCalls,
00183                DEBUG_WrappedNativeSetterCalls);
00184 
00185         printf("(wrappers / tearoffs): (");
00186         int i;
00187         for(i = 0; i < DEBUG_CHUNKS_TO_COUNT; i++)
00188         {
00189             printf("%d / %d, ",
00190                    DEBUG_WrappedNativeTearOffChunkCounts[i],
00191                    (i+1) * XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK);
00192         }
00193         printf("%d / more)\n", DEBUG_WrappedNativeTearOffChunkCounts[i]);
00194     }
00195 #endif
00196 }
00197 #else
00198 #define DEBUG_TrackNewWrapper(wrapper) ((void)0)
00199 #define DEBUG_TrackDeleteWrapper(wrapper) ((void)0)
00200 #define DEBUG_TrackWrapperCall(wrapper, mode) ((void)0)
00201 #define DEBUG_TrackShutdownWrapper(wrapper) ((void)0)
00202 #endif
00203 
00204 /***************************************************************************/
00205 
00206 // static
00207 nsresult
00208 XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
00209                                nsISupports* Object,
00210                                XPCWrappedNativeScope* Scope,
00211                                XPCNativeInterface* Interface,
00212                                JSBool isGlobal,
00213                                XPCWrappedNative** resultWrapper)
00214 {
00215     nsresult rv;
00216 
00217     NS_ASSERTION(!Scope->GetRuntime()->GetThreadRunningGC(), 
00218                  "XPCWrappedNative::GetNewOrUsed called during GC");
00219 
00220     nsCOMPtr<nsISupports> identity;
00221 #ifdef XPC_IDISPATCH_SUPPORT
00222     // XXX This is done for the benefit of some warped COM implementations
00223     // where QI(IID_IUnknown, a.b) == QI(IID_IUnknown, a). If someone passes
00224     // in a pointer that hasn't been QI'd to IDispatch properly this could
00225     // create multiple wrappers for the same object, creating a fair bit of
00226     // confusion.
00227     PRBool isIDispatch = Interface->GetIID()->Equals(NSID_IDISPATCH);
00228     if(isIDispatch)
00229         identity = Object;
00230     else
00231 #endif
00232         identity = do_QueryInterface(Object);
00233 
00234     if(!identity)
00235     {
00236         NS_ERROR("This XPCOM object fails in QueryInterface to nsISupports!");
00237         return NS_ERROR_FAILURE;
00238     }
00239 
00240     XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
00241     
00242     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
00243     // after we have Init'd the wrapper but *before* we add it to the hashtable.
00244     // This would cause the mSet to get collected and we'd later crash. I've
00245     // *seen* this happen.
00246     AutoMarkingWrappedNativePtr wrapper(ccx);
00247 
00248     Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
00249     {   // scoped lock
00250         XPCAutoLock lock(mapLock);
00251         wrapper = map->Find(identity);
00252         if(wrapper)
00253             wrapper->AddRef();
00254     }
00255 
00256     if(wrapper)
00257     {
00258         if(!wrapper->FindTearOff(ccx, Interface, JS_FALSE, &rv))
00259         {
00260             NS_RELEASE(wrapper);
00261             NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
00262             return rv;
00263         }
00264         DEBUG_CheckWrapperThreadSafety(wrapper);
00265         *resultWrapper = wrapper;
00266         return NS_OK;
00267     }
00268 
00269     // There is a chance that the object wants to have the self-same JSObject
00270     // reflection regardless of the scope into which we are reflecting it.
00271     // Many DOM objects require this. The scriptable helper specifies this
00272     // in preCreate by indicating a 'parent' of a particular scope.
00273     //
00274     // To handle this we need to get the scriptable helper early and ask it.
00275     // It is possible that we will then end up forwarding this entire call
00276     // to this same function but with a different scope.
00277 
00278     // If we are making a wrapper for the nsIClassInfo interface then
00279     // We *don't* want to have it use the prototype meant for instances
00280     // of that class.
00281     JSBool isClassInfo = Interface->GetIID()->Equals(NS_GET_IID(nsIClassInfo));
00282 
00283     nsCOMPtr<nsIClassInfo> info;
00284 
00285     if(!isClassInfo)
00286         info = do_QueryInterface(identity);
00287 
00288 #ifdef XPC_IDISPATCH_SUPPORT
00289     // If this is an IDispatch wrapper and it didn't give us a class info
00290     // we'll provide a default one
00291     if(isIDispatch && !info)
00292     {
00293         info = dont_AddRef(NS_STATIC_CAST(nsIClassInfo*,
00294                                           XPCIDispatchClassInfo::GetSingleton()));
00295     }
00296 #endif
00297 
00298     XPCNativeScriptableCreateInfo sciProto;
00299     XPCNativeScriptableCreateInfo sciWrapper;
00300 
00301     // Gather scriptable create info if we are wrapping something
00302     // other than an nsIClassInfo object. We need to not do this for
00303     // nsIClassInfo objects because often nsIClassInfo implementations
00304     // are also nsIXPCScriptable helper implmentations, but the helper
00305     // code is obviously intended for the implementation of the class
00306     // described by the nsIClassInfo, not for the class info object
00307     // itself.
00308     if(!isClassInfo &&
00309        NS_FAILED(GatherScriptableCreateInfo(identity, info.get(),
00310                                             &sciProto, &sciWrapper)))
00311         return NS_ERROR_FAILURE;
00312 
00313     JSObject* parent = Scope->GetGlobalJSObject();
00314 
00315     jsval newParentVal = JSVAL_NULL;
00316     XPCMarkableJSVal newParentVal_markable(&newParentVal);
00317     AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
00318 
00319     if(sciWrapper.GetFlags().WantPreCreate())
00320     {
00321         JSObject* plannedParent = parent;
00322         nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
00323                                                           parent, &parent);
00324         if(NS_FAILED(rv))
00325             return rv;
00326 
00327         NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(ccx, parent),
00328                      "Parent should never be an XPCNativeWrapper here");
00329 
00330         if(parent != plannedParent)
00331         {
00332             XPCWrappedNativeScope* betterScope =
00333                 XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
00334             if(betterScope != Scope)
00335                 return GetNewOrUsed(ccx, identity, betterScope, Interface,
00336                                     isGlobal, resultWrapper);
00337 
00338             newParentVal = OBJECT_TO_JSVAL(parent);
00339         }
00340 
00341         // Take the performance hit of checking the hashtable again in case
00342         // the preCreate call caused the wrapper to get created through some
00343         // interesting path (the DOM code tends to make this happen sometimes).
00344 
00345         {   // scoped lock
00346             XPCAutoLock lock(mapLock);
00347             wrapper = map->Find(identity);
00348             if(wrapper)
00349                 wrapper->AddRef();
00350         }
00351 
00352         if(wrapper)
00353         {
00354             if(!wrapper->FindTearOff(ccx, Interface, JS_FALSE, &rv))
00355             {
00356                 NS_RELEASE(wrapper);
00357                 NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
00358                 return rv;
00359             }
00360             DEBUG_CheckWrapperThreadSafety(wrapper);
00361             *resultWrapper = wrapper;
00362             return NS_OK;
00363         }
00364     }
00365 
00366     AutoMarkingWrappedNativeProtoPtr proto(ccx);
00367 
00368     // If there is ClassInfo (and we are not building a wrapper for the
00369     // nsIClassInfo interface) then we use a wrapper that needs a prototype.
00370 
00371     // Note that the security check happens inside FindTearOff - after the
00372     // wrapper is actually created, but before JS code can see it.
00373 
00374     if(info && !isClassInfo)
00375     {
00376         proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, Scope, info, &sciProto,
00377                                                     JS_FALSE, isGlobal);
00378         if(!proto)
00379             return NS_ERROR_FAILURE;
00380 
00381         wrapper = new XPCWrappedNative(identity, proto);
00382         if(!wrapper)
00383             return NS_ERROR_FAILURE;
00384     }
00385     else
00386     {
00387         AutoMarkingNativeSetPtr set(ccx);
00388         set = XPCNativeSet::GetNewOrUsed(ccx, nsnull, Interface, 0);
00389 
00390         if(!set)
00391             return NS_ERROR_FAILURE;
00392 
00393         wrapper = new XPCWrappedNative(identity, Scope, set);
00394         if(!wrapper)
00395             return NS_ERROR_FAILURE;
00396 
00397         DEBUG_ReportShadowedMembers(set, wrapper, nsnull);
00398     }
00399 
00400     NS_ADDREF(wrapper);
00401 
00402     NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(ccx, parent),
00403                  "XPCNativeWrapper being used to parent XPCWrappedNative?");
00404     
00405     if(!wrapper->Init(ccx, parent, isGlobal, &sciWrapper))
00406     {
00407         NS_RELEASE(wrapper);
00408         return NS_ERROR_FAILURE;
00409     }
00410 
00411     if(!wrapper->FindTearOff(ccx, Interface, JS_FALSE, &rv))
00412     {
00413         // Second reference will be released by the FlatJSObject's finializer.
00414         wrapper->Release();
00415         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
00416         return rv;
00417     }
00418 
00419 #if DEBUG_XPCNativeWrapper
00420     {
00421         char* s = wrapper->ToString(ccx);
00422         NS_ASSERTION(wrapper->GetFlatJSObject(), "eh?");
00423         printf("Created wrapped native %s, flat JSObject is %p\n",
00424                s, (void*)wrapper->GetFlatJSObject());
00425         if (s)
00426             JS_smprintf_free(s);
00427     }
00428 #endif
00429 
00430     // Redundant wrapper must be killed outside of the map lock.
00431     XPCWrappedNative* wrapperToKill = nsnull;
00432 
00433     {   // scoped lock
00434         XPCAutoLock lock(mapLock);
00435 
00436         // Deal with the case where the wrapper got created as a side effect
00437         // of one of our calls out of this code (or on another thread).
00438         XPCWrappedNative* wrapper2 = map->Add(wrapper);
00439         if(!wrapper2)
00440         {
00441             NS_ERROR("failed to add our wrapper!");
00442             wrapperToKill = wrapper;
00443             wrapper = nsnull;
00444         }
00445         else if(wrapper2 != wrapper)
00446         {
00447             NS_ADDREF(wrapper2);
00448             wrapperToKill = wrapper;
00449             wrapper = wrapper2;
00450         }
00451     }
00452 
00453     if(wrapperToKill)
00454     {
00455         // Second reference will be released by the FlatJSObject's finializer.
00456         wrapperToKill->Release();
00457     }
00458     else if(wrapper)
00459     {
00460         // Our newly created wrapper is the one that we just added to the table.
00461         // All is well. Call PostCreate as necessary.
00462         XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
00463         if(si && si->GetFlags().WantPostCreate())
00464         {
00465             rv = si->GetCallback()->
00466                      PostCreate(wrapper, ccx, wrapper->GetFlatJSObject());
00467             if(NS_FAILED(rv))
00468             {
00469                 {   // scoped lock
00470                     XPCAutoLock lock(mapLock);
00471                     map->Remove(wrapper);
00472                 }
00473 
00474                 wrapper->Release();
00475                 return rv;
00476             }
00477         }
00478     }
00479 
00480     if(!wrapper)
00481         return NS_ERROR_FAILURE;
00482 
00483     DEBUG_CheckClassInfoClaims(wrapper);
00484     *resultWrapper = wrapper;
00485     return NS_OK;
00486 }
00487 
00488 // static
00489 nsresult
00490 XPCWrappedNative::GetUsedOnly(XPCCallContext& ccx,
00491                               nsISupports* Object,
00492                               XPCWrappedNativeScope* Scope,
00493                               XPCNativeInterface* Interface,
00494                               XPCWrappedNative** resultWrapper)
00495 {
00496     NS_ASSERTION(Object, "XPCWrappedNative::GetUsedOnly was called with a null Object");
00497     nsCOMPtr<nsISupports> identity;
00498 #ifdef XPC_IDISPATCH_SUPPORT
00499     // XXX See GetNewOrUsed for more info on this
00500     if(Interface->GetIID()->Equals(NSID_IDISPATCH))
00501         identity = Object;
00502     else
00503 #endif
00504         identity = do_QueryInterface(Object);
00505 
00506     if(!identity)
00507     {
00508         NS_ERROR("This XPCOM object fails in QueryInterface to nsISupports!");
00509         return NS_ERROR_FAILURE;
00510     }
00511 
00512     XPCWrappedNative* wrapper;
00513     Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
00514 
00515     {   // scoped lock
00516         XPCAutoLock lock(Scope->GetRuntime()->GetMapLock());
00517         wrapper = map->Find(identity);
00518         if(!wrapper)
00519         {
00520             *resultWrapper = nsnull;
00521             return NS_OK;
00522         }
00523         NS_ADDREF(wrapper);
00524     }
00525 
00526     nsresult rv;
00527     if(!wrapper->FindTearOff(ccx, Interface, JS_FALSE, &rv))
00528     {
00529         NS_RELEASE(wrapper);
00530         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
00531         return rv;
00532     }
00533 
00534     *resultWrapper = wrapper;
00535     return NS_OK;
00536 }
00537 
00538 // This ctor is used if this object will have a proto.
00539 XPCWrappedNative::XPCWrappedNative(nsISupports* aIdentity,
00540                                    XPCWrappedNativeProto* aProto)
00541     : mMaybeProto(aProto),
00542       mSet(aProto->GetSet()),
00543       mFlatJSObject((JSObject*)JSVAL_ONE), // non-null to pass IsValid() test
00544       mScriptableInfo(nsnull),
00545       mNativeWrapper(nsnull)
00546 {
00547     NS_ADDREF(mIdentity = aIdentity);
00548 
00549     NS_ASSERTION(mMaybeProto, "bad ctor param");
00550     NS_ASSERTION(mSet, "bad ctor param");
00551 
00552     DEBUG_TrackNewWrapper(this);
00553 }
00554 
00555 // This ctor is used if this object will NOT have a proto.
00556 XPCWrappedNative::XPCWrappedNative(nsISupports* aIdentity,
00557                                    XPCWrappedNativeScope* aScope,
00558                                    XPCNativeSet* aSet)
00559 
00560     : mMaybeScope(TagScope(aScope)),
00561       mSet(aSet),
00562       mFlatJSObject((JSObject*)JSVAL_ONE), // non-null to pass IsValid() test
00563       mScriptableInfo(nsnull),
00564       mNativeWrapper(nsnull)
00565 {
00566     NS_ADDREF(mIdentity = aIdentity);
00567 
00568     NS_ASSERTION(aScope, "bad ctor param");
00569     NS_ASSERTION(aSet, "bad ctor param");
00570 
00571     DEBUG_TrackNewWrapper(this);
00572 }
00573 
00574 XPCWrappedNative::~XPCWrappedNative()
00575 {
00576     DEBUG_TrackDeleteWrapper(this);
00577 
00578     XPCWrappedNativeProto* proto = GetProto();
00579 
00580     if(mScriptableInfo &&
00581        (!HasProto() ||
00582         (proto && proto->GetScriptableInfo() != mScriptableInfo)))
00583     {
00584         delete mScriptableInfo;
00585     }
00586 
00587     Native2WrappedNativeMap* map = GetScope()->GetWrappedNativeMap();
00588     {   // scoped lock
00589         XPCAutoLock lock(GetRuntime()->GetMapLock());
00590         map->Remove(this);
00591     }
00592 
00593     if(mIdentity)
00594     {
00595         XPCJSRuntime* rt = GetRuntime();
00596         if(rt && rt->GetDeferReleases() && rt->GetDoingFinalization())
00597         {
00598             if(!rt->DeferredRelease(mIdentity))
00599             {
00600                 NS_WARNING("Failed to append object for deferred release.");
00601                 // XXX do we really want to do this???
00602                 NS_RELEASE(mIdentity);
00603             }
00604         }
00605         else
00606         {
00607             NS_RELEASE(mIdentity);
00608         }
00609     }
00610 }
00611 
00612 // This is factored out so that it can be called publicly 
00613 // static
00614 nsresult 
00615 XPCWrappedNative::GatherProtoScriptableCreateInfo(
00616                         nsIClassInfo* classInfo,
00617                         XPCNativeScriptableCreateInfo* sciProto)
00618 {
00619     NS_ASSERTION(classInfo, "bad param");
00620     NS_ASSERTION(sciProto && !sciProto->GetCallback(), "bad param");
00621 
00622     nsCOMPtr<nsISupports> possibleHelper;
00623     nsresult rv = classInfo->GetHelperForLanguage(
00624                                     nsIProgrammingLanguage::JAVASCRIPT,
00625                                     getter_AddRefs(possibleHelper));
00626     if(NS_SUCCEEDED(rv) && possibleHelper)
00627     {
00628         nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(possibleHelper));
00629         if(helper)
00630         {
00631             JSUint32 flags;
00632             rv = helper->GetScriptableFlags(&flags);
00633             if(NS_FAILED(rv))
00634                 flags = 0;
00635 
00636             sciProto->SetCallback(helper);
00637             sciProto->SetFlags(flags);
00638         }
00639     }
00640     return NS_OK;
00641 }
00642 
00643 // static
00644 nsresult
00645 XPCWrappedNative::GatherScriptableCreateInfo(
00646                         nsISupports* obj,
00647                         nsIClassInfo* classInfo,
00648                         XPCNativeScriptableCreateInfo* sciProto,
00649                         XPCNativeScriptableCreateInfo* sciWrapper)
00650 {
00651     NS_ASSERTION(sciProto   && !sciProto->GetCallback(), "bad param");
00652     NS_ASSERTION(sciWrapper && !sciWrapper->GetCallback(), "bad param");
00653 
00654     // Get the class scriptable helper (if present)
00655     if(classInfo)
00656     {
00657         GatherProtoScriptableCreateInfo(classInfo, sciProto);
00658 
00659         sciWrapper->SetCallback(sciProto->GetCallback());
00660         sciWrapper->SetFlags(sciProto->GetFlags());
00661 
00662         if(sciProto->GetFlags().DontAskInstanceForScriptable())
00663             return NS_OK;
00664     }
00665 
00666     // Do the same for the wrapper specific scriptable
00667     nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(obj));
00668     if(helper)
00669     {
00670         JSUint32 flags;
00671         nsresult rv = helper->GetScriptableFlags(&flags);
00672         if(NS_FAILED(rv))
00673             flags = 0;
00674 
00675         sciWrapper->SetCallback(helper);
00676         sciWrapper->SetFlags(flags);
00677 
00678         // A whole series of assertions to catch bad uses of scriptable flags on
00679         // the siWrapper...
00680 
00681         NS_ASSERTION(!(sciWrapper->GetFlags().WantPreCreate() &&
00682                         !sciProto->GetFlags().WantPreCreate()),
00683                      "Can't set WANT_PRECREATE on an instance scriptable "
00684                      "without also setting it on the class scriptable");
00685 
00686         NS_ASSERTION(!(sciWrapper->GetFlags().DontEnumStaticProps() &&
00687                         !sciProto->GetFlags().DontEnumStaticProps() &&
00688                         sciProto->GetCallback() &&
00689                         !sciProto->GetFlags().DontSharePrototype()),
00690                      "Can't set DONT_ENUM_STATIC_PROPS on an instance scriptable "
00691                      "without also setting it on the class scriptable (if present and shared)");
00692 
00693         NS_ASSERTION(!(sciWrapper->GetFlags().DontEnumQueryInterface() &&
00694                         !sciProto->GetFlags().DontEnumQueryInterface() &&
00695                         sciProto->GetCallback() &&
00696                         !sciProto->GetFlags().DontSharePrototype()),
00697                      "Can't set DONT_ENUM_QUERY_INTERFACE on an instance scriptable "
00698                      "without also setting it on the class scriptable (if present and shared)");
00699 
00700         NS_ASSERTION(!(sciWrapper->GetFlags().DontAskInstanceForScriptable() &&
00701                         !sciProto->GetFlags().DontAskInstanceForScriptable()),
00702                      "Can't set DONT_ASK_INSTANCE_FOR_SCRIPTABLE on an instance scriptable "
00703                      "without also setting it on the class scriptable");
00704 
00705         NS_ASSERTION(!(sciWrapper->GetFlags().ClassInfoInterfacesOnly() &&
00706                         !sciProto->GetFlags().ClassInfoInterfacesOnly() &&
00707                         sciProto->GetCallback() &&
00708                         !sciProto->GetFlags().DontSharePrototype()),
00709                      "Can't set CLASSINFO_INTERFACES_ONLY on an instance scriptable "
00710                      "without also setting it on the class scriptable (if present and shared)");
00711 
00712         NS_ASSERTION(!(sciWrapper->GetFlags().AllowPropModsDuringResolve() &&
00713                         !sciProto->GetFlags().AllowPropModsDuringResolve() &&
00714                         sciProto->GetCallback() &&
00715                         !sciProto->GetFlags().DontSharePrototype()),
00716                      "Can't set ALLOW_PROP_MODS_DURING_RESOLVE on an instance scriptable "
00717                      "without also setting it on the class scriptable (if present and shared)");
00718 
00719         NS_ASSERTION(!(sciWrapper->GetFlags().AllowPropModsToPrototype() &&
00720                         !sciProto->GetFlags().AllowPropModsToPrototype() &&
00721                         sciProto->GetCallback() &&
00722                         !sciProto->GetFlags().DontSharePrototype()),
00723                      "Can't set ALLOW_PROP_MODS_TO_PROTOTYPE on an instance scriptable "
00724                      "without also setting it on the class scriptable (if present and shared)");
00725 
00726         NS_ASSERTION(!(sciWrapper->GetFlags().DontSharePrototype() &&
00727                         !sciProto->GetFlags().DontSharePrototype() &&
00728                         sciProto->GetCallback()),
00729                      "Can't set DONT_SHARE_PROTOTYPE on an instance scriptable "
00730                      "without also setting it on the class scriptable (if present and shared)");
00731     }
00732 
00733     return NS_OK;
00734 }
00735 
00736 JSBool
00737 XPCWrappedNative::Init(XPCCallContext& ccx, JSObject* parent, JSBool isGlobal,
00738                        const XPCNativeScriptableCreateInfo* sci)
00739 {
00740     // setup our scriptable info...
00741 
00742     if(sci->GetCallback())
00743     {
00744         if(HasProto())
00745         {
00746             XPCNativeScriptableInfo* siProto = GetProto()->GetScriptableInfo();
00747             if(siProto && siProto->GetCallback() == sci->GetCallback())
00748                 mScriptableInfo = siProto;
00749         }
00750         if(!mScriptableInfo)
00751         {
00752             mScriptableInfo =
00753                 XPCNativeScriptableInfo::Construct(ccx, isGlobal, sci);
00754 
00755             if(!mScriptableInfo)
00756                 return JS_FALSE;
00757 
00758             // If we have a one-off proto, then it should share our scriptable.
00759             // This allows the proto's JSClass callbacks to do the right things
00760             // (like respecting the DONT_ENUM_STATIC_PROPS flag) w/o requiring
00761             // scriptable objects to have an nsIClassInfo.
00762             if(HasProto() && !HasSharedProto())
00763                 GetProto()->SetScriptableInfo(mScriptableInfo);
00764         }
00765     }
00766     XPCNativeScriptableInfo* si = mScriptableInfo;
00767 
00768     // create our flatJSObject
00769 
00770     JSClass* jsclazz = si ? si->GetJSClass() : &XPC_WN_NoHelper_JSClass.base;
00771 
00772     NS_ASSERTION(jsclazz &&
00773                  jsclazz->name &&
00774                  jsclazz->flags &&
00775                  jsclazz->addProperty &&
00776                  jsclazz->delProperty &&
00777                  jsclazz->getProperty &&
00778                  jsclazz->setProperty &&
00779                  jsclazz->enumerate &&
00780                  jsclazz->resolve &&
00781                  jsclazz->convert &&
00782                  jsclazz->finalize, "bad class");
00783 
00784     JSObject* protoJSObject = HasProto() ?
00785                                 GetProto()->GetJSProtoObject() :
00786                                 GetScope()->GetPrototypeJSObject();
00787 
00788     mFlatJSObject = JS_NewObject(ccx, jsclazz, protoJSObject, parent);
00789 
00790     if(!mFlatJSObject)
00791         return JS_FALSE;
00792 
00793     // In the current JS engine JS_SetPrivate can't fail. But if it *did*
00794     // fail then we would not receive our finalizer call and would not be
00795     // able to properly cleanup. So, if it fails we null out mFlatJSObject
00796     // to indicate the invalid state of this object and return false. 
00797     if(!JS_SetPrivate(ccx, mFlatJSObject, this))
00798     {
00799         mFlatJSObject = nsnull;
00800         return JS_FALSE;
00801     }
00802 
00803     // Propagate the system flag from parent to child.
00804     if(JS_IsSystemObject(ccx, parent))
00805         JS_FlagSystemObject(ccx, mFlatJSObject);
00806 
00807     // This reference will be released when mFlatJSObject is finalized.
00808     // Since this reference will push the refcount to 2 it will also root
00809     // mFlatJSObject;
00810     NS_ASSERTION(1 == mRefCnt, "unexpected refcount value");
00811     NS_ADDREF(this);
00812 
00813     if(si && si->GetFlags().WantCreate() &&
00814        NS_FAILED(si->GetCallback()->Create(this, ccx, mFlatJSObject)))
00815     {
00816         return JS_FALSE;
00817     }
00818 
00819 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
00820     if(!gMainThread)
00821         gMainThread = nsXPConnect::GetMainThread();
00822 
00823     mThread = PR_GetCurrentThread();
00824 
00825     if(HasProto() && GetProto()->ClassIsMainThreadOnly() && gMainThread != mThread)
00826         DEBUG_ReportWrapperThreadSafetyError(ccx,
00827             "MainThread only wrapper created on the wrong thread", this);
00828 #endif
00829 
00830     return JS_TRUE;
00831 }
00832 
00833 
00834 NS_INTERFACE_MAP_BEGIN(XPCWrappedNative)
00835   NS_INTERFACE_MAP_ENTRY(nsIXPConnectWrappedNative)
00836   NS_INTERFACE_MAP_ENTRY(nsIXPConnectJSObjectHolder)
00837   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPConnectWrappedNative)
00838 NS_INTERFACE_MAP_END_THREADSAFE
00839 
00840 NS_IMPL_THREADSAFE_ADDREF(XPCWrappedNative)
00841 NS_IMPL_THREADSAFE_RELEASE(XPCWrappedNative)
00842 
00843 /*
00844  *  Wrapped Native lifetime management is messy!
00845  *
00846  *  - At creation we push the refcount to 2 (only one of which is owned by
00847  *    the native caller that caused the wrapper creation).
00848  *  - During the JS GC Mark phase we mark any wrapper with a refcount > 1.
00849  *  - The *only* thing that can make the wrapper get destroyed is the
00850  *    finalization of mFlatJSObject. And *that* should only happen if the only
00851  *    reference is the single extra (internal) reference we hold.
00852  *
00853  *  - The wrapper has a pointer to the nsISupports 'view' of the wrapped native
00854  *    object i.e... mIdentity. This is held until the wrapper's refcount goes
00855  *    to zero and the wrapper is released.
00856  *
00857  *  - The wrapper also has 'tearoffs'. It has one tearoff for each interface
00858  *    that is actually used on the native object. 'Used' means we have either
00859  *    needed to QueryInterface to verify the availability of that interface
00860  *    of that we've had to QueryInterface in order to actually make a call
00861  *    into the wrapped object via the pointer for the given interface.
00862  *
00863  *  - Each tearoff's 'mNative' member (if non-null) indicates one reference
00864  *    held by our wrapper on the wrapped native for the given interface
00865  *    associated with the tearoff. If we release that reference then we set
00866  *    the tearoff's 'mNative' to null.
00867  *
00868  *  - We use the occasion of the JavaScript GCCallback for the JSGC_MARK_END
00869  *    event to scan the tearoffs of all wrappers for non-null mNative members
00870  *    that represent unused references. We can tell that a given tearoff's
00871  *    mNative is unused by noting that no live XPCCallContexts hold a pointer
00872  *    to the tearoff.
00873  *
00874  *  - As a time/space tradeoff we may decide to not do this scanning on
00875  *    *every* JavaScript GC. We *do* want to do this *sometimes* because
00876  *    we want to allow for wrapped native's to do their own tearoff patterns.
00877  *    So, we want to avoid holding references to interfaces that we don't need.
00878  *    At the same time, we don't want to be bracketing every call into a
00879  *    wrapped native object with a QueryInterface/Release pair. And we *never*
00880  *    make a call into the object except via the correct interface for which
00881  *    we've QI'd.
00882  *
00883  *  - Each tearoff *can* have a mJSObject whose lazily resolved properties
00884  *    represent the methods/attributes/constants of that specific interface.
00885  *    This is optionally reflected into JavaScript as "foo.nsIFoo" when "foo"
00886  *    is the name of mFlatJSObject and "nsIFoo" is the name of the given
00887  *    interface associated with the tearoff. When we create the tearoff's
00888  *    mJSObject we set it's parent to be mFlatJSObject. This way we know that
00889  *    when mFlatJSObject get's collected there are no outstanding reachable
00890  *    tearoff mJSObjects. Note that we must clear the private of any lingering
00891  *    mJSObjects at this point because we have no guarentee of the *order* of
00892  *    finalization within a given gc cycle.
00893  */
00894 
00895 void
00896 XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx, JSObject *obj)
00897 {
00898     if(!IsValid())
00899         return;
00900 
00901     // Iterate the tearoffs and null out each of their JSObject's privates.
00902     // This will keep them from trying to access their pointers to the
00903     // dying tearoff object. We can safely assume that those remaining
00904     // JSObjects are about to be finalized too.
00905 
00906     XPCWrappedNativeTearOffChunk* chunk;
00907     for(chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk)
00908     {
00909         XPCWrappedNativeTearOff* to = chunk->mTearOffs;
00910         for(int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++)
00911         {
00912             JSObject* jso = to->GetJSObject();
00913             if(jso)
00914             {
00915                 NS_ASSERTION(JS_IsAboutToBeFinalized(cx, jso), "bad!");
00916                 JS_SetPrivate(cx, jso, nsnull);
00917                 to->JSObjectFinalized();
00918             }
00919 
00920             // We also need to release any native pointers held...
00921             nsISupports* obj = to->GetNative();
00922             if(obj)
00923             {
00924 #ifdef XP_WIN
00925                 // Try to detect free'd pointer
00926                 NS_ASSERTION(*(int*)obj != 0xdddddddd, "bad pointer!");
00927                 NS_ASSERTION(*(int*)obj != 0,          "bad pointer!");
00928 #endif
00929                 XPCJSRuntime* rt = GetRuntime();
00930                 if(rt && rt->GetDeferReleases())
00931                 {
00932                     if(!rt->DeferredRelease(obj))
00933                     {
00934                         NS_WARNING("Failed to append object for deferred release.");
00935                         // XXX do we really want to do this???
00936                         obj->Release();
00937                     }
00938                 }
00939                 else
00940                 {
00941                     obj->Release();
00942                 }
00943                 to->SetNative(nsnull);
00944             }
00945 
00946             to->SetInterface(nsnull);
00947         }
00948     }
00949 
00950     //This makes IsValid return false from now on...
00951     mFlatJSObject = nsnull;
00952 
00953     NS_ASSERTION(mIdentity, "bad pointer!");
00954 #ifdef XP_WIN
00955     // Try to detect free'd pointer
00956     NS_ASSERTION(*(int*)mIdentity != 0xdddddddd, "bad pointer!");
00957     NS_ASSERTION(*(int*)mIdentity != 0,          "bad pointer!");
00958 #endif
00959 
00960     // Note that it's not safe to touch mNativeWrapper here since it's
00961     // likely that it has already been finalized.
00962 
00963     Release();
00964 }
00965 
00966 void
00967 XPCWrappedNative::SystemIsBeingShutDown(XPCCallContext& ccx)
00968 {
00969     DEBUG_TrackShutdownWrapper(this);
00970 
00971     if(!IsValid())
00972         return;
00973 
00974     // The long standing strategy is to leak some objects still held at shutdown.
00975     // The general problem is that propagating release out of xpconnect at
00976     // shutdown time causes a world of problems.
00977 
00978     // We leak mIdentity (see above).
00979 
00980     // short circuit future finalization
00981     JS_SetPrivate(ccx, mFlatJSObject, nsnull);
00982     mFlatJSObject = nsnull; // This makes 'IsValid()' return false.
00983 
00984     XPCWrappedNativeProto* proto = GetProto();
00985 
00986     if(HasProto())
00987         proto->SystemIsBeingShutDown(ccx);
00988 
00989     if(mScriptableInfo &&
00990        (!HasProto() ||
00991         (proto && proto->GetScriptableInfo() != mScriptableInfo)))
00992     {
00993         delete mScriptableInfo;
00994     }
00995 
00996     // cleanup the tearoffs...
00997 
00998     XPCWrappedNativeTearOffChunk* chunk;
00999     for(chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk)
01000     {
01001         XPCWrappedNativeTearOff* to = chunk->mTearOffs;
01002         for(int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++)
01003         {
01004             if(to->GetJSObject())
01005             {
01006                 JS_SetPrivate(ccx, to->GetJSObject(), nsnull);
01007 #ifdef XPC_IDISPATCH_SUPPORT
01008                 if(to->IsIDispatch())
01009                     delete to->GetIDispatchInfo();
01010 #endif
01011                 to->SetJSObject(nsnull);
01012             }
01013             // We leak the tearoff mNative
01014             // (for the same reason we leak mIdentity - see above).
01015             to->SetNative(nsnull);
01016             to->SetInterface(nsnull);
01017         }
01018     }
01019 
01020     if(mFirstChunk.mNextChunk)
01021     {
01022         delete mFirstChunk.mNextChunk;
01023         mFirstChunk.mNextChunk = nsnull;
01024     }
01025 }
01026 
01027 /***************************************************************************/
01028 
01029 // static
01030 nsresult
01031 XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
01032                                          XPCWrappedNativeScope* aOldScope,
01033                                          XPCWrappedNativeScope* aNewScope,
01034                                          JSObject* aNewParent,
01035                                          nsISupports* aCOMObj,
01036                                          XPCWrappedNative** aWrapper)
01037 {
01038     XPCNativeInterface* iface =
01039         XPCNativeInterface::GetISupports(ccx);
01040 
01041     if(!iface)
01042         return NS_ERROR_FAILURE;
01043 
01044     nsresult rv;
01045     XPCWrappedNative* wrapper;
01046 
01047     rv = XPCWrappedNative::GetUsedOnly(ccx, aCOMObj, aOldScope, iface, &wrapper);
01048     if(NS_FAILED(rv))
01049         return rv;
01050 
01051     if(!wrapper || !wrapper->IsValid())
01052     {
01053         NS_IF_RELEASE(wrapper);
01054         *aWrapper = nsnull;
01055         return NS_OK;
01056     }
01057 
01058     if(aOldScope != aNewScope)
01059     {
01060         // Oh, so now we need to move the wrapper to a different scope.
01061 
01062         AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
01063         AutoMarkingWrappedNativeProtoPtr newProto(ccx);
01064 
01065         if(wrapper->HasProto())
01066         {
01067             oldProto = wrapper->GetProto();
01068             XPCNativeScriptableInfo *info = oldProto->GetScriptableInfo();
01069             XPCNativeScriptableCreateInfo ci(*info);
01070             newProto =
01071                 XPCWrappedNativeProto::GetNewOrUsed(ccx, aNewScope,
01072                                                     oldProto->GetClassInfo(),
01073                                                     &ci,
01074                                                     !oldProto->IsShared(),
01075                                                     (info->GetJSClass()->flags & JSCLASS_IS_GLOBAL));
01076             if(!newProto)
01077             {
01078                 NS_RELEASE(wrapper);
01079                 return NS_ERROR_FAILURE;
01080             }
01081         }
01082 
01083         Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
01084         Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
01085 
01086         {   // scoped lock
01087             XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock());
01088 
01089             // We only try to fixup the __proto__ JSObject if the wrapper
01090             // is directly using that of its XPCWrappedNativeProto.
01091 
01092             if(wrapper->HasProto() &&
01093                JS_GetPrototype(ccx, wrapper->GetFlatJSObject()) ==
01094                oldProto->GetJSProtoObject())
01095             {
01096                 if(!JS_SetPrototype(ccx, wrapper->GetFlatJSObject(),
01097                                     newProto->GetJSProtoObject()))
01098                 {
01099                     // this is bad, very bad
01100                     NS_ERROR("JS_SetPrototype failed");
01101                     NS_RELEASE(wrapper);
01102                     return NS_ERROR_FAILURE;
01103                 }
01104             }
01105             else
01106             {
01107                 NS_WARNING("Moving XPConnect wrappedNative to new scope, "
01108                            "but can't fixup __proto__");
01109             }
01110 
01111             oldMap->Remove(wrapper);
01112 
01113             if(wrapper->HasProto())
01114                 wrapper->mMaybeProto = newProto;
01115 
01116             // If the wrapper has no scriptable or it has a non-shared
01117             // scriptable, then we don't need to mess with it.
01118             // Otherwise...
01119 
01120             if(wrapper->mScriptableInfo &&
01121                wrapper->mScriptableInfo == oldProto->GetScriptableInfo())
01122             {
01123                 // The new proto had better have the same JSClass stuff as the
01124                 // old one! We maintain a runtime wide unique map of this stuff.
01125                 // So, if these don't match then the caller is doing something
01126                 // bad here.
01127 
01128                 NS_ASSERTION(
01129                      oldProto->GetScriptableInfo()->GetScriptableShared() ==
01130                      newProto->GetScriptableInfo()->GetScriptableShared(),
01131                     "Changing proto is also changing JSObject Classname or "
01132                     "helper's nsIXPScriptable flags. This is not allowed!");
01133 
01134                 wrapper->mScriptableInfo = newProto->GetScriptableInfo();
01135             }
01136 
01137             NS_ASSERTION(!newMap->Find(wrapper->GetIdentityObject()),
01138                          "wrapper already in new scope!");
01139 
01140             (void) newMap->Add(wrapper);
01141         }
01142     }
01143 
01144     // Now we can just fix up the parent and return the wrapper
01145 
01146     if(!JS_SetParent(ccx, wrapper->GetFlatJSObject(), aNewParent))
01147     {
01148         NS_RELEASE(wrapper);
01149         return NS_ERROR_FAILURE;
01150     }
01151 
01152     *aWrapper = wrapper;
01153     return NS_OK;
01154 }
01155 
01156 #define IS_WRAPPER_CLASS(clazz)                                               \
01157           ((clazz) == &XPC_WN_NoHelper_JSClass.base ||                        \
01158            (clazz)->getObjectOps == XPC_WN_GetObjectOpsNoCall ||              \
01159            (clazz)->getObjectOps == XPC_WN_GetObjectOpsWithCall)
01160 
01161 #define IS_TEAROFF_CLASS(clazz)                                               \
01162           ((clazz) == &XPC_WN_Tearoff_JSClass)
01163 
01164 // static
01165 XPCWrappedNative*
01166 XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx,
01167                                              JSObject* obj,
01168                                              JSObject* funobj,
01169                                              JSObject** pobj2,
01170                                              XPCWrappedNativeTearOff** pTearOff)
01171 {
01172     NS_PRECONDITION(obj, "bad param");
01173 
01174     JSObject* cur;
01175 
01176     XPCWrappedNativeProto* proto = nsnull;
01177     nsIClassInfo* protoClassInfo = nsnull;
01178 
01179     // If we were passed a function object then we need to find the correct
01180     // wrapper out of those that might be in the callee obj's proto chain.
01181 
01182     if(funobj)
01183     {
01184         JSObject* funObjParent = JS_GetParent(cx, funobj);
01185         NS_ASSERTION(funObjParent, "funobj has no parent");
01186 
01187         JSClass* funObjParentClass = JS_GET_CLASS(cx, funObjParent);
01188 
01189         if(IS_PROTO_CLASS(funObjParentClass))
01190         {
01191             NS_ASSERTION(JS_GetParent(cx, funObjParent), "funobj's parent (proto) is global");
01192             proto = (XPCWrappedNativeProto*) JS_GetPrivate(cx, funObjParent);
01193             if(proto)
01194                 protoClassInfo = proto->GetClassInfo();
01195         }
01196         else if(IS_WRAPPER_CLASS(funObjParentClass))
01197         {
01198             cur = funObjParent;
01199             goto return_wrapper;
01200         }
01201         else if(IS_TEAROFF_CLASS(funObjParentClass))
01202         {
01203             NS_ASSERTION(JS_GetParent(cx, funObjParent), "funobj's parent (tearoff) is global");
01204             cur = funObjParent;
01205             goto return_tearoff;
01206         }
01207         else
01208         {
01209             NS_ERROR("function object has parent of unknown class!");
01210             return nsnull;
01211         }
01212     }
01213 
01214     for(cur = obj; cur; cur = JS_GetPrototype(cx, cur))
01215     {
01216         // this is on two lines to make the compiler happy given the goto.
01217         JSClass* clazz;
01218         clazz = JS_GET_CLASS(cx, cur);
01219 
01220         if(IS_WRAPPER_CLASS(clazz))
01221         {
01222 return_wrapper:
01223             XPCWrappedNative* wrapper =
01224                 (XPCWrappedNative*) JS_GetPrivate(cx, cur);
01225             if(proto && proto != wrapper->GetProto() &&
01226                (proto->GetScope() != wrapper->GetScope() ||
01227                 !protoClassInfo || !wrapper->GetProto() ||
01228                 protoClassInfo != wrapper->GetProto()->GetClassInfo()))
01229                 continue;
01230             if(pobj2)
01231                 *pobj2 = cur;
01232             return wrapper;
01233         }
01234 
01235         if(IS_TEAROFF_CLASS(clazz))
01236         {
01237 return_tearoff:
01238             XPCWrappedNative* wrapper =
01239                 (XPCWrappedNative*) JS_GetPrivate(cx, JS_GetParent(cx,cur));
01240             if(proto && proto != wrapper->GetProto() &&
01241                (proto->GetScope() != wrapper->GetScope() ||
01242                 !protoClassInfo || !wrapper->GetProto() ||
01243                 protoClassInfo != wrapper->GetProto()->GetClassInfo()))
01244                 continue;
01245             if(pobj2)
01246                 *pobj2 = cur;
01247             XPCWrappedNativeTearOff* to =
01248                 (XPCWrappedNativeTearOff*) JS_GetPrivate(cx, cur);
01249             if(!to)
01250                 return nsnull;
01251             if(pTearOff)
01252                 *pTearOff = to;
01253             return wrapper;
01254         }
01255 
01256         if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
01257         {
01258             if(pobj2)
01259                 *pobj2 = cur;
01260 
01261             return XPCNativeWrapper::GetWrappedNative(cx, cur);
01262         }
01263     }
01264 
01265     // If we didn't find a wrapper using the given funobj and obj, try
01266     // again with obj's outer object, if it's got one.
01267 
01268     JSClass *clazz = JS_GET_CLASS(cx, obj);
01269 
01270     if((clazz->flags & JSCLASS_IS_EXTENDED) &&
01271        ((JSExtendedClass*)clazz)->outerObject)
01272     {
01273         JSObject *outer = ((JSExtendedClass*)clazz)->outerObject(cx, obj);
01274 
01275         if(outer && outer != obj)
01276             return GetWrappedNativeOfJSObject(cx, outer, funobj, pobj2,
01277                                               pTearOff);
01278     }
01279 
01280     return nsnull;
01281 }
01282 
01283 JSBool
01284 XPCWrappedNative::ExtendSet(XPCCallContext& ccx, XPCNativeInterface* aInterface)
01285 {
01286     // This is only called while locked (during XPCWrappedNative::FindTearOff).
01287 
01288     if(!mSet->HasInterface(aInterface))
01289     {
01290         AutoMarkingNativeSetPtr newSet(ccx);
01291         newSet = XPCNativeSet::GetNewOrUsed(ccx, mSet, aInterface,
01292                                             mSet->GetInterfaceCount());
01293         if(!newSet)
01294             return JS_FALSE;
01295 
01296         mSet = newSet;
01297 
01298         DEBUG_ReportShadowedMembers(newSet, this, GetProto());
01299     }
01300     return JS_TRUE;
01301 }
01302 
01303 XPCWrappedNativeTearOff*
01304 XPCWrappedNative::LocateTearOff(XPCCallContext& ccx,
01305                               XPCNativeInterface* aInterface)
01306 {
01307     XPCAutoLock al(GetLock()); // hold the lock throughout
01308 
01309     for(
01310         XPCWrappedNativeTearOffChunk* chunk = &mFirstChunk;
01311         chunk != nsnull;
01312         chunk = chunk->mNextChunk)
01313     {
01314         XPCWrappedNativeTearOff* tearOff = chunk->mTearOffs;
01315         XPCWrappedNativeTearOff* const end = tearOff + 
01316             XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK;
01317         for(
01318             tearOff = chunk->mTearOffs;
01319             tearOff < end; 
01320             tearOff++)
01321         {
01322             if(tearOff->GetInterface() == aInterface)
01323             {
01324                 return tearOff;
01325             }
01326         }
01327     }
01328     return nsnull;
01329 }
01330 
01331 XPCWrappedNativeTearOff*
01332 XPCWrappedNative::FindTearOff(XPCCallContext& ccx,
01333                               XPCNativeInterface* aInterface,
01334                               JSBool needJSObject /* = JS_FALSE */,
01335                               nsresult* pError /* = nsnull */)
01336 {
01337     XPCAutoLock al(GetLock()); // hold the lock throughout
01338 
01339     nsresult rv = NS_OK;
01340     XPCWrappedNativeTearOff* to;
01341     XPCWrappedNativeTearOff* firstAvailable = nsnull;
01342 
01343     XPCWrappedNativeTearOffChunk* lastChunk;
01344     XPCWrappedNativeTearOffChunk* chunk;
01345     for(lastChunk = chunk = &mFirstChunk;
01346         chunk;
01347         lastChunk = chunk, chunk = chunk->mNextChunk)
01348     {
01349         to = chunk->mTearOffs;
01350         XPCWrappedNativeTearOff* const end = chunk->mTearOffs + 
01351             XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK;
01352         for(
01353             to = chunk->mTearOffs;
01354             to < end; 
01355             to++)
01356         {
01357             if(to->GetInterface() == aInterface)
01358             {
01359                 if(needJSObject && !to->GetJSObject())
01360                 {
01361                     AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to);
01362                     rv = InitTearOffJSObject(ccx, to);
01363                     // During shutdown, we don't sweep tearoffs.  So make sure
01364                     // to unmark manually in case the auto-marker marked us.
01365                     // We shouldn't ever be getting here _during_ our
01366                     // Mark/Sweep cycle, so this should be safe.
01367                     to->Unmark();
01368                     if(NS_FAILED(rv))
01369                         to = nsnull;
01370                 }
01371                 goto return_result;
01372             }
01373             if(!firstAvailable && to->IsAvailable())
01374                 firstAvailable = to;
01375         }
01376     }
01377 
01378     to = firstAvailable;
01379 
01380     if(!to)
01381     {
01382         XPCWrappedNativeTearOffChunk* newChunk =
01383             new XPCWrappedNativeTearOffChunk();
01384         if(!newChunk)
01385         {
01386             rv = NS_ERROR_OUT_OF_MEMORY;
01387             goto return_result;
01388         }
01389         lastChunk->mNextChunk = newChunk;
01390         to = newChunk->mTearOffs;
01391     }
01392 
01393     {
01394         // Scope keeps |tearoff| from leaking across the return_result: label
01395         AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to);
01396         rv = InitTearOff(ccx, to, aInterface, needJSObject);
01397         // During shutdown, we don't sweep tearoffs.  So make sure to unmark
01398         // manually in case the auto-marker marked us.  We shouldn't ever be
01399         // getting here _during_ our Mark/Sweep cycle, so this should be safe.
01400         to->Unmark();
01401         if(NS_FAILED(rv))
01402             to = nsnull;
01403     }
01404 
01405 return_result:
01406 
01407     if(pError)
01408         *pError = rv;
01409     return to;
01410 }
01411 
01412 nsresult
01413 XPCWrappedNative::InitTearOff(XPCCallContext& ccx,
01414                               XPCWrappedNativeTearOff* aTearOff,
01415                               XPCNativeInterface* aInterface,
01416                               JSBool needJSObject)
01417 {
01418     // This is only called while locked (during XPCWrappedNative::FindTearOff).
01419 
01420     // Determine if the object really does this interface...
01421 
01422     const nsIID* iid = aInterface->GetIID();
01423     nsISupports* identity = GetIdentityObject();
01424     nsISupports* obj;
01425 
01426     // If the scriptable helper forbids us from reflecting additional
01427     // interfaces, then don't even try the QI, just fail.
01428     if(mScriptableInfo &&
01429        mScriptableInfo->GetFlags().ClassInfoInterfacesOnly() &&
01430        !mSet->HasInterface(aInterface) &&
01431        !mSet->HasInterfaceWithAncestor(aInterface))
01432     {
01433         return NS_ERROR_NO_INTERFACE;
01434     }
01435 
01436     // We are about to call out to unlock and other code.
01437     // So protect our intended tearoff.
01438 
01439     aTearOff->SetReserved();
01440 
01441     {   // scoped *un*lock
01442         XPCAutoUnlock unlock(GetLock());
01443 
01444         if(NS_FAILED(identity->QueryInterface(*iid, (void**)&obj)) || !obj)
01445         {
01446             aTearOff->SetInterface(nsnull);
01447             return NS_ERROR_NO_INTERFACE;
01448         }
01449 
01450         // Guard against trying to build a tearoff for a shared nsIClassInfo.
01451         if(iid->Equals(NS_GET_IID(nsIClassInfo)))
01452         {
01453             nsCOMPtr<nsISupports> alternate_identity(do_QueryInterface(obj));
01454             if(alternate_identity.get() != identity)
01455             {
01456                 NS_RELEASE(obj);
01457                 aTearOff->SetInterface(nsnull);
01458                 return NS_ERROR_NO_INTERFACE;
01459             }
01460         }
01461 
01462         // Guard against trying to build a tearoff for an interface that is
01463         // aggregated and is implemented as a nsIXPConnectWrappedJS using this
01464         // self-same JSObject. The XBL system does this. If we mutate the set
01465         // of this wrapper then we will shadow the method that XBL has added to
01466         // the JSObject that it has inserted in the JS proto chain between our
01467         // JSObject and our XPCWrappedNativeProto's JSObject. If we let this
01468         // set mutation happen then the interface's methods will be added to 
01469         // our JSObject, but calls on those methods will get routed up to
01470         // native code and into the wrappedJS - which will do a method lookup
01471         // on *our* JSObject and find the same method and make another call
01472         // into an infinite loop.
01473         // see: http://bugzilla.mozilla.org/show_bug.cgi?id=96725
01474 
01475         // The code in this block also does a check for the double wrapped
01476         // nsIPropertyBag case.
01477 
01478         nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(obj));
01479         if(wrappedJS)
01480         {
01481             JSObject* jso = nsnull;
01482             if(NS_SUCCEEDED(wrappedJS->GetJSObject(&jso)) &&
01483                jso == GetFlatJSObject())
01484             {
01485                 // The implementing JSObject is the same as ours! Just say OK
01486                 // without actually extending the set.
01487                 //
01488                 // XXX It is a little cheesy to have FindTearOff return an
01489                 // 'empty' tearoff. But this is the centralized place to do the
01490                 // QI activities on the underlying object. *And* most caller to
01491                 // FindTearOff only look for a non-null result and ignore the
01492                 // actual tearoff returned. The only callers that do use the
01493                 // returned tearoff make sure to check for either a non-null 
01494                 // JSObject or a matching Interface before proceeding.
01495                 // I think we can get away with this bit of ugliness.
01496                 
01497 #ifdef DEBUG_xpc_hacker
01498                 {
01499                     // I want to make sure this only happens in xbl-like cases.
01500                     // So, some debug code to verify that there is at least
01501                     // *some* object between our JSObject and its inital proto.
01502                     // XXX This is a pretty funky test. Someone might hack it
01503                     // a bit if false positives start showing up. Note that 
01504                     // this is only going to run for the few people in the
01505                     // DEBUG_xpc_hacker list.
01506                     if(HasProto())
01507                     {
01508                         JSObject* proto  = nsnull;
01509                         JSObject* our_proto = GetProto()->GetJSProtoObject();
01510 
01511                         proto = JS_GetPrototype(ccx, jso);
01512 
01513                         NS_WARN_IF_FALSE(proto && proto != our_proto,
01514                             "!!! xpconnect/xbl check - wrapper has no special proto");
01515 
01516                         PRBool found_our_proto = PR_FALSE;
01517                         while (proto && !found_our_proto) {
01518                             proto = JS_GetPrototype(ccx, proto);
01519 
01520                             found_our_proto = proto == our_proto;
01521                         }
01522 
01523                         NS_WARN_IF_FALSE(found_our_proto,
01524                             "!!! xpconnect/xbl check - wrapper has extra proto");
01525                     }
01526                     else
01527                     {
01528                         NS_WARNING("!!! xpconnect/xbl check - wrapper has no proto");
01529                     }
01530                 }
01531 #endif
01532                 NS_RELEASE(obj);
01533                 aTearOff->SetInterface(nsnull);
01534                 return NS_OK;
01535             }
01536             
01537             // Decide whether or not to expose nsIPropertyBag to calling
01538             // JS code in the double wrapped case.
01539             //
01540             // Our rule here is that when JSObjects are double wrapped and
01541             // exposed to other JSObjects then the nsIPropertyBag interface
01542             // is only exposed on an 'opt-in' basis; i.e. if the underlying
01543             // JSObject wants other JSObjects to be able to see this interface
01544             // then it must implement QueryInterface and not throw an exception
01545             // when asked for nsIPropertyBag. It need not actually *implement*
01546             // nsIPropertyBag - xpconnect will do that work.
01547 
01548             nsXPCWrappedJSClass* clazz;
01549             if(iid->Equals(NS_GET_IID(nsIPropertyBag)) && jso &&
01550                NS_SUCCEEDED(nsXPCWrappedJSClass::GetNewOrUsed(ccx,*iid,&clazz))&&
01551                clazz)
01552             {
01553                 JSObject* answer =
01554                     clazz->CallQueryInterfaceOnJSObject(ccx, jso, *iid);
01555                 NS_RELEASE(clazz);
01556                 if(!answer)
01557                 {
01558                     NS_RELEASE(obj);
01559                     aTearOff->SetInterface(nsnull);
01560                     return NS_ERROR_NO_INTERFACE;
01561                 }
01562             }
01563         }
01564 
01565         nsIXPCSecurityManager* sm;
01566            sm = ccx.GetXPCContext()->GetAppropriateSecurityManager(
01567                                 nsIXPCSecurityManager::HOOK_CREATE_WRAPPER);
01568         if(sm && NS_FAILED(sm->
01569                     CanCreateWrapper(ccx, *iid, identity,
01570                                      GetClassInfo(), GetSecurityInfoAddr())))
01571         {
01572             // the security manager vetoed. It should have set an exception.
01573             NS_RELEASE(obj);
01574             aTearOff->SetInterface(nsnull);
01575             return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
01576         }
01577     }
01578     // We are relocked from here on...
01579 
01580     // If this is not already in our set we need to extend our set.
01581     // Note: we do not cache the result of the previous call to HasInterface()
01582     // because we unlocked and called out in the interim and the result of the
01583     // previous call might not be correct anymore.
01584 
01585     if(!mSet->HasInterface(aInterface) && !ExtendSet(ccx, aInterface))
01586     {
01587         NS_RELEASE(obj);
01588         aTearOff->SetInterface(nsnull);
01589         return NS_ERROR_NO_INTERFACE;
01590     }
01591 
01592     aTearOff->SetInterface(aInterface);
01593     aTearOff->SetNative(obj);
01594 #ifdef XPC_IDISPATCH_SUPPORT
01595     // Are we building a tearoff for IDispatch?
01596     if(iid->Equals(NSID_IDISPATCH))
01597     {
01598         aTearOff->SetIDispatch(ccx);
01599     }  
01600 #endif
01601     if(needJSObject && !InitTearOffJSObject(ccx, aTearOff))
01602         return NS_ERROR_OUT_OF_MEMORY;
01603 
01604     return NS_OK;
01605 }
01606 
01607 JSBool
01608 XPCWrappedNative::InitTearOffJSObject(XPCCallContext& ccx,
01609                                       XPCWrappedNativeTearOff* to)
01610 {
01611     // This is only called while locked (during XPCWrappedNative::FindTearOff).
01612 
01613     JSObject* obj = JS_NewObject(ccx, &XPC_WN_Tearoff_JSClass,
01614                                  GetScope()->GetPrototypeJSObject(),
01615                                  mFlatJSObject);
01616 
01617     if(!obj || !JS_SetPrivate(ccx, obj, to))
01618         return JS_FALSE;
01619 
01620     // Propagate the system flag from parent to child.
01621     if(JS_IsSystemObject(ccx, mFlatJSObject))
01622         JS_FlagSystemObject(ccx, obj);
01623 
01624     to->SetJSObject(obj);
01625     return JS_TRUE;
01626 }
01627 
01628 /***************************************************************************/
01629 
01630 static JSBool Throw(uintN errNum, XPCCallContext& ccx)
01631 {
01632     XPCThrower::Throw(errNum, ccx);
01633     return JS_FALSE;
01634 }
01635 
01636 enum SizeMode {GET_SIZE, GET_LENGTH};
01637 
01638 /***************************************************************************/
01639 
01640 static JSBool
01641 GetArraySizeFromParam(XPCCallContext& ccx,
01642                       nsIInterfaceInfo* ifaceInfo,
01643                       const nsXPTMethodInfo* methodInfo,
01644                       const nsXPTParamInfo& paramInfo,
01645                       uint16 vtblIndex,
01646                       uint8 paramIndex,
01647                       SizeMode mode,
01648                       nsXPTCVariant* dispatchParams,
01649                       JSUint32* result)
01650 {
01651     uint8 argnum;
01652     nsresult rv;
01653 
01654     // XXX fixup the various exceptions that are thrown
01655 
01656     if(mode == GET_SIZE)
01657         rv = ifaceInfo->GetSizeIsArgNumberForParam(vtblIndex, &paramInfo, 0, &argnum);
01658     else
01659         rv = ifaceInfo->GetLengthIsArgNumberForParam(vtblIndex, &paramInfo, 0, &argnum);
01660     if(NS_FAILED(rv))
01661         return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, ccx);
01662 
01663     const nsXPTParamInfo& arg_param = methodInfo->GetParam(argnum);
01664     const nsXPTType& arg_type = arg_param.GetType();
01665 
01666     // The xpidl compiler ensures this. We reaffirm it for safety.
01667     if(arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_U32)
01668         return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, ccx);
01669 
01670     *result = dispatchParams[argnum].val.u32;
01671 
01672     return JS_TRUE;
01673 }
01674 
01675 
01676 static JSBool
01677 GetInterfaceTypeFromParam(XPCCallContext& ccx,
01678                           nsIInterfaceInfo* ifaceInfo,
01679                           const nsXPTMethodInfo* methodInfo,
01680                           const nsXPTParamInfo& paramInfo,
01681                           uint16 vtblIndex,
01682                           uint8 paramIndex,
01683                           const nsXPTType& datum_type,
01684                           nsXPTCVariant* dispatchParams,
01685                           nsID* result)
01686 {
01687     uint8 argnum;
01688     nsresult rv;
01689     uint8 type_tag = datum_type.TagPart();
01690 
01691     // XXX fixup the various exceptions that are thrown
01692 
01693     if(type_tag == nsXPTType::T_INTERFACE)
01694     {
01695         rv = ifaceInfo->GetIIDForParamNoAlloc(vtblIndex, &paramInfo, result);
01696         if(NS_FAILED(rv))
01697             return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, paramIndex, ccx);
01698     }
01699     else if(type_tag == nsXPTType::T_INTERFACE_IS)
01700     {
01701         rv = ifaceInfo->GetInterfaceIsArgNumberForParam(vtblIndex, &paramInfo, &argnum);
01702         if(NS_FAILED(rv))
01703             return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, ccx);
01704 
01705         const nsXPTParamInfo& arg_param = methodInfo->GetParam(argnum);
01706         const nsXPTType& arg_type = arg_param.GetType();
01707         
01708         // The xpidl compiler ensures this. We reaffirm it for safety.
01709         if(!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID)
01710             return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, paramIndex, ccx);
01711 
01712         nsID* p = (nsID*) dispatchParams[argnum].val.p;
01713         if(!p)
01714             return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, paramIndex, ccx);
01715         *result = *p;
01716     }
01717     return JS_TRUE;
01718 }
01719 
01720 /***************************************************************************/
01721 
01722 // static
01723 JSBool
01724 XPCWrappedNative::CallMethod(XPCCallContext& ccx,
01725                              CallMode mode /*= CALL_METHOD */)
01726 {
01727     NS_ASSERTION(ccx.GetXPCContext()->CallerTypeIsJavaScript(),
01728                  "Native caller for XPCWrappedNative::CallMethod?");
01729     
01730     nsresult rv = ccx.CanCallNow();
01731     if(NS_FAILED(rv))
01732     {
01733         // If the security manager is complaining then this is not really an
01734         // internal error in xpconnect. So, no reason to botch the assertion.
01735         NS_ASSERTION(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, 
01736                      "hmm? CanCallNow failed in XPCWrappedNative::CallMethod. "
01737                      "We are finding out about this late!");
01738         return Throw(rv, ccx);
01739     }
01740 
01741     DEBUG_TrackWrapperCall(ccx.GetWrapper(), mode);
01742 
01743     // From here on ALL exits are through 'goto done;'
01744 
01745 #define PARAM_BUFFER_COUNT     8
01746 
01747     nsXPTCVariant paramBuffer[PARAM_BUFFER_COUNT];
01748 
01749     // Number of nsAutoStrings to construct on the stack for use with method
01750     // calls that use 'out' AStrings (aka [domstring]). These can save us from 
01751     // a new/delete of an nsString. But the cost is that the ctor/dtor code 
01752     // is run for each nsAutoString in the array for each call - whether or not 
01753     // a specific call actually uses *any* AStrings. Also, we have these
01754     // large-ish nsAutoString objects using up stack space.
01755     //
01756     // Set this to zero to disable use of these auto strings.
01757 #define PARAM_AUTOSTRING_COUNT     1
01758 
01759 #if PARAM_AUTOSTRING_COUNT
01760     nsVoidableString autoStrings[PARAM_AUTOSTRING_COUNT];
01761     int autoStringIndex = 0;
01762 #endif
01763 
01764     JSBool retval = JS_FALSE;
01765 
01766     nsXPTCVariant* dispatchParams = nsnull;
01767     uint8 i;
01768     const nsXPTMethodInfo* methodInfo;
01769     uint8 requiredArgs;
01770     uint8 paramCount;
01771     jsval src;
01772     nsresult invokeResult;
01773     nsID param_iid;
01774     uintN err;
01775     nsIXPCSecurityManager* sm;
01776     JSBool foundDependentParam;
01777 
01778     XPCJSRuntime* rt = ccx.GetRuntime();
01779     XPCContext* xpcc = ccx.GetXPCContext();
01780     nsISupports* callee = ccx.GetTearOff()->GetNative();
01781     XPCPerThreadData* tls = ccx.GetThreadData();
01782     uint16 vtblIndex = ccx.GetMethodIndex();
01783     nsIInterfaceInfo* ifaceInfo = ccx.GetInterface()->GetInterfaceInfo();
01784     jsval name = ccx.GetMember()->GetName();
01785     jsval* argv = ccx.GetArgv();
01786 
01787 #ifdef DEBUG_stats_jband
01788     PRIntervalTime startTime = PR_IntervalNow();
01789     PRIntervalTime endTime = 0;
01790     static int totalTime = 0;
01791     static int count = 0;
01792     static const int interval = 10;
01793     if(0 == (++count % interval))
01794         printf(">>>>>>>> %d calls on XPCWrappedNatives made.  (%d)\n", count, PR_IntervalToMilliseconds(totalTime));
01795 #endif
01796 
01797     ccx.SetRetVal(JSVAL_VOID);
01798 
01799     tls->SetException(nsnull);
01800     xpcc->SetLastResult(NS_ERROR_UNEXPECTED);
01801 
01802     // set up the method index and do the security check if needed
01803 
01804     PRUint32 secFlag;
01805     PRUint32 secAction;
01806 
01807     switch(mode)
01808     {
01809         case CALL_METHOD:
01810             secFlag   = nsIXPCSecurityManager::HOOK_CALL_METHOD;
01811             secAction = nsIXPCSecurityManager::ACCESS_CALL_METHOD;
01812             break;
01813         case CALL_GETTER:
01814             secFlag   = nsIXPCSecurityManager::HOOK_GET_PROPERTY;
01815             secAction = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
01816             break;
01817         case CALL_SETTER:
01818             secFlag   = nsIXPCSecurityManager::HOOK_SET_PROPERTY;
01819             secAction = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
01820             break;
01821         default:
01822             NS_ASSERTION(0,"bad value");
01823             goto done;
01824     }
01825 
01826     sm = xpcc->GetAppropriateSecurityManager(secFlag);
01827     if(sm && NS_FAILED(sm->CanAccess(secAction, &ccx, ccx,
01828                                      ccx.GetFlattenedJSObject(),
01829                                      ccx.GetWrapper()->GetIdentityObject(),
01830                                      ccx.GetWrapper()->GetClassInfo(), name,
01831                                      ccx.GetWrapper()->GetSecurityInfoAddr())))
01832     {
01833         // the security manager vetoed. It should have set an exception.
01834         goto done;
01835     }
01836 
01837     if(NS_FAILED(ifaceInfo->GetMethodInfo(vtblIndex, &methodInfo)))
01838     {
01839         Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, ccx);
01840         goto done;
01841     }
01842 
01843     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
01844     paramCount = methodInfo->GetParamCount();
01845     requiredArgs = paramCount;
01846     if(paramCount && methodInfo->GetParam(paramCount-1).IsRetval())
01847         requiredArgs--;
01848     if(ccx.GetArgc() < requiredArgs)
01849     {
01850         Throw(NS_ERROR_XPC_NOT_ENOUGH_ARGS, ccx);
01851         goto done;
01852     }
01853 
01854     // setup variant array pointer
01855     if(paramCount > PARAM_BUFFER_COUNT)
01856     {
01857         if(!(dispatchParams = new nsXPTCVariant[paramCount]))
01858         {
01859             JS_ReportOutOfMemory(ccx);
01860             goto done;
01861         }
01862     }
01863     else
01864         dispatchParams = paramBuffer;
01865 
01866     // iterate through the params to clear flags (for safe cleanup later)
01867     for(i = 0; i < paramCount; i++)
01868     {
01869         nsXPTCVariant* dp = &dispatchParams[i];
01870         dp->ClearFlags();
01871         dp->val.p = nsnull;
01872     }
01873 
01874     // Iterate through the params doing conversions of independent params only.
01875     // When we later convert the dependent params (if any) we will know that
01876     // the params upon which they depend will have already been converted -
01877     // regardless of ordering.
01878     foundDependentParam = JS_FALSE;
01879     for(i = 0; i < paramCount; i++)
01880     {
01881         JSBool useAllocator = JS_FALSE;
01882         const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i);
01883         const nsXPTType& type = paramInfo.GetType();
01884         uint8 type_tag = type.TagPart();
01885 
01886         if(type.IsDependent())
01887         {
01888             foundDependentParam = JS_TRUE;
01889             continue;
01890         }
01891 
01892         nsXPTCVariant* dp = &dispatchParams[i];
01893         dp->type = type;
01894 
01895         if(type_tag == nsXPTType::T_INTERFACE)
01896         {
01897             dp->SetValIsInterface();
01898         }
01899 
01900         // set 'src' to be the object from which we get the value and
01901         // prepare for out param
01902 
01903         if(paramInfo.IsOut())
01904         {
01905             dp->SetPtrIsData();
01906             dp->ptr = &dp->val;
01907 
01908             if(!paramInfo.IsRetval() &&
01909                (JSVAL_IS_PRIMITIVE(argv[i]) ||
01910                 !OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(argv[i]),
01911                                   rt->GetStringID(XPCJSRuntime::IDX_VALUE),
01912                                   &src)))
01913             {
01914                 ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, i, ccx);
01915                 goto done;
01916             }
01917 
01918             if(type.IsPointer() &&
01919                type_tag != nsXPTType::T_INTERFACE &&
01920                !paramInfo.IsShared())
01921             {
01922                 useAllocator = JS_TRUE;
01923                 dp->SetValIsAllocated();
01924             }
01925 
01926             if(!paramInfo.IsIn())
01927                 continue;
01928         }
01929         else
01930         {
01931             if(type.IsPointer())
01932             {
01933                 switch(type_tag)
01934                 {
01935                 case nsXPTType::T_IID:
01936                     dp->SetValIsAllocated();
01937                     useAllocator = JS_TRUE;
01938                     break;
01939 
01940                 case nsXPTType::T_ASTRING:
01941                     // Fall through to the T_DOMSTRING case
01942 
01943                 case nsXPTType::T_DOMSTRING:
01944                     if(paramInfo.IsDipper())
01945                     {
01946                         // Is an 'out' DOMString. Make a new nsAString
01947                         // now and then continue in order to skip the call to
01948                         // JSData2Native
01949 
01950                         // If autoStrings array support is enabld, then use
01951                         // one of them if they are not already used up.
01952 #if PARAM_AUTOSTRING_COUNT
01953                         if(autoStringIndex < PARAM_AUTOSTRING_COUNT)
01954                         {
01955                             // Don't call SetValIsDOMString because we don't 
01956                             // want to delete this pointer.
01957                             dp->val.p = &autoStrings[autoStringIndex++];
01958                             continue;
01959                         }
01960 #endif
01961                         dp->SetValIsDOMString();
01962                         if(!(dp->val.p = new nsVoidableString()))
01963                         {
01964                             JS_ReportOutOfMemory(ccx);
01965                             goto done;
01966                         }
01967                         continue;
01968                     }
01969                     // else...
01970 
01971                     // Is an 'in' DOMString. Set 'useAllocator' to indicate
01972                     // that JSData2Native should allocate a new
01973                     // nsAString.
01974                     dp->SetValIsDOMString();
01975                     useAllocator = JS_TRUE;
01976                     break;
01977 
01978                 case nsXPTType::T_UTF8STRING:                    
01979                     // Fall through to the C string case for now...                    
01980                 case nsXPTType::T_CSTRING:                    
01981                     dp->SetValIsCString();
01982                     if(paramInfo.IsDipper())
01983                     {
01984                         // Is an 'out' CString.
01985                         if(!(dp->val.p = new nsCString()))
01986                         {
01987                             JS_ReportOutOfMemory(ccx);
01988                             goto done;
01989                         }
01990                         continue;
01991                     }
01992                     // else ...
01993                     // Is an 'in' CString.
01994                     useAllocator = JS_TRUE;
01995                     break;
01996                 }
01997             }
01998 
01999             // Do this *after* the above because in the case where we have a
02000             // "T_DOMSTRING && IsDipper()" then argv might be null since this
02001             // is really an 'out' param masquerading as an 'in' param.
02002             src = argv[i];
02003         }
02004 
02005         if(type_tag == nsXPTType::T_INTERFACE &&
02006            NS_FAILED(ifaceInfo->GetIIDForParamNoAlloc(vtblIndex, &paramInfo,
02007                                                &param_iid)))
02008         {
02009             ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, i, ccx);
02010             goto done;
02011         }
02012 
02013         if(!XPCConvert::JSData2Native(ccx, &dp->val, src, type,
02014                                       useAllocator, &param_iid, &err))
02015         {
02016             ThrowBadParam(err, i, ccx);
02017             goto done;
02018         }
02019     }
02020 
02021     // if any params were dependent, then we must iterate again to convert them.
02022     if(foundDependentParam)
02023     {
02024         for(i = 0; i < paramCount; i++)
02025         {
02026             const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i);
02027             const nsXPTType& type = paramInfo.GetType();
02028 
02029             if(!type.IsDependent())
02030                 continue;
02031 
02032             nsXPTType datum_type;
02033             JSUint32 array_count;
02034             JSUint32 array_capacity;
02035             JSBool useAllocator = JS_FALSE;
02036             PRBool isArray = type.IsArray();
02037 
02038             PRBool isSizedString = isArray ?
02039                     JS_FALSE :
02040                     type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
02041                     type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
02042 
02043             nsXPTCVariant* dp = &dispatchParams[i];
02044             dp->type = type;
02045 
02046             if(isArray)
02047             {
02048                 dp->SetValIsArray();
02049 
02050                 if(NS_FAILED(ifaceInfo->GetTypeForParam(vtblIndex, &paramInfo, 1,
02051                                                     &datum_type)))
02052                 {
02053                     Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, ccx);
02054                     goto done;
02055                 }
02056             }
02057             else
02058                 datum_type = type;
02059 
02060             if(datum_type.IsInterfacePointer())
02061             {
02062                 dp->SetValIsInterface();
02063             }
02064 
02065             // set 'src' to be the object from which we get the value and
02066             // prepare for out param
02067 
02068             if(paramInfo.IsOut())
02069             {
02070                 dp->SetPtrIsData();
02071                 dp->ptr = &dp->val;
02072 
02073                 if(!paramInfo.IsRetval() &&
02074                    (JSVAL_IS_PRIMITIVE(argv[i]) ||
02075                     !OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(argv[i]),
02076                         rt->GetStringID(XPCJSRuntime::IDX_VALUE), &src)))
02077                 {
02078                     ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, i, ccx);
02079                     goto done;
02080                 }
02081 
02082                 if(datum_type.IsPointer() &&
02083                    !datum_type.IsInterfacePointer() &&
02084                    (isArray || !paramInfo.IsShared()))
02085                 {
02086                     useAllocator = JS_TRUE;
02087                     dp->SetValIsAllocated();
02088                 }
02089 
02090                 if(!paramInfo.IsIn())
02091                     continue;
02092             }
02093             else
02094             {
02095                 src = argv[i];
02096 
02097                 if(datum_type.IsPointer() &&
02098                    datum_type.TagPart() == nsXPTType::T_IID)
02099                 {
02100                     useAllocator = JS_TRUE;
02101                     dp->SetValIsAllocated();
02102                 }
02103             }
02104 
02105             if(datum_type.IsInterfacePointer() &&
02106                !GetInterfaceTypeFromParam(ccx, ifaceInfo, methodInfo, paramInfo,
02107                                           vtblIndex, i, datum_type,
02108                                           dispatchParams, &param_iid))
02109                 goto done;
02110 
02111             if(isArray || isSizedString)
02112             {
02113                 if(!GetArraySizeFromParam(ccx, ifaceInfo, methodInfo, paramInfo,
02114                                           vtblIndex, i, GET_SIZE,
02115                                           dispatchParams, &array_capacity)||
02116                    !GetArraySizeFromParam(ccx, ifaceInfo, methodInfo, paramInfo,
02117                                           vtblIndex, i, GET_LENGTH,
02118                                           dispatchParams, &array_count))
02119                     goto done;
02120 
02121                 if(isArray)
02122                 {
02123                     if(array_count &&
02124                        !XPCConvert::JSArray2Native(ccx, (void**)&dp->val, src,
02125                                                    array_count, array_capacity,
02126                                                    datum_type,
02127                                                    useAllocator,
02128                                                    &param_iid, &err))
02129                     {
02130                         // XXX need exception scheme for arrays to indicate bad element
02131                         ThrowBadParam(err, i, ccx);
02132                         goto done;
02133                     }
02134                 }
02135                 else // if(isSizedString)
02136                 {
02137                     if(!XPCConvert::JSStringWithSize2Native(ccx,
02138                                                    (void*)&dp->val,
02139                                                    src,
02140                                                    array_count, array_capacity,
02141                                                    datum_type, useAllocator,
02142                                                    &err))
02143                     {
02144                         ThrowBadParam(err, i, ccx);
02145                         goto done;
02146                     }
02147                 }
02148             }
02149             else
02150             {
02151                 if(!XPCConvert::JSData2Native(ccx, &dp->val, src, type,
02152                                               useAllocator, &param_iid,
02153                                               &err))
02154                 {
02155                     ThrowBadParam(err, i, ccx);
02156                     goto done;
02157                 }
02158             }
02159         }
02160     }
02161 
02162 
02163     {
02164         // avoid deadlock in case the native method blocks somehow
02165         AutoJSSuspendRequest req(ccx);  // scoped suspend of request
02166 
02167         // do the invoke
02168         invokeResult = XPTC_InvokeByIndex(callee, vtblIndex,
02169                                           paramCount, dispatchParams);
02170         // resume non-blocking JS operations now
02171     }
02172 
02173 
02174     xpcc->SetLastResult(invokeResult);
02175 
02176     if(NS_FAILED(invokeResult))
02177     {
02178         ThrowBadResult(invokeResult, ccx);
02179         goto done;
02180     }
02181     else if(ccx.GetExceptionWasThrown())
02182     {
02183         // the native callee claims to have already set a JSException
02184         goto done;
02185     }
02186 
02187     // now we iterate through the native params to gather and convert results
02188     for(i = 0; i < paramCount; i++)
02189     {
02190         const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i);
02191         if(!paramInfo.IsOut() && !paramInfo.IsDipper())
02192             continue;
02193 
02194         const nsXPTType& type = paramInfo.GetType();
02195         nsXPTCVariant* dp = &dispatchParams[i];
02196         jsval v = JSVAL_NULL;
02197         AUTO_MARK_JSVAL(ccx, &v);
02198         JSUint32 array_count;
02199         nsXPTType datum_type;
02200         PRBool isArray = type.IsArray();
02201         PRBool isSizedString = isArray ?
02202                 JS_FALSE :
02203                 type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
02204                 type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
02205 
02206         if(isArray)
02207         {
02208             if(NS_FAILED(ifaceInfo->GetTypeForParam(vtblIndex, &paramInfo, 1,
02209                                                     &datum_type)))
02210             {
02211                 Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, ccx);
02212                 goto done;
02213             }
02214         }
02215         else
02216             datum_type = type;
02217 
02218         if(isArray || isSizedString)
02219         {
02220             if(!GetArraySizeFromParam(ccx, ifaceInfo, methodInfo, paramInfo,
02221                                       vtblIndex, i, GET_LENGTH, dispatchParams,
02222                                       &array_count))
02223                 goto done;
02224         }
02225 
02226         if(datum_type.IsInterfacePointer() &&
02227            !GetInterfaceTypeFromParam(ccx, ifaceInfo, methodInfo, paramInfo,
02228                                       vtblIndex, i, datum_type, dispatchParams,
02229                                       &param_iid))
02230             goto done;
02231 
02232         if(isArray)
02233         {
02234             if(!XPCConvert::NativeArray2JS(ccx, &v, (const void**)&dp->val,
02235                                            datum_type, &param_iid,
02236                                            array_count, ccx.GetCurrentJSObject(),
02237                                            &err))
02238             {
02239                 // XXX need exception scheme for arrays to indicate bad element
02240                 ThrowBadParam(err, i, ccx);
02241                 goto done;
02242             }
02243         }
02244         else if(isSizedString)
02245         {
02246             if(!XPCConvert::NativeStringWithSize2JS(ccx, &v,
02247                                            (const void*)&dp->val,
02248                                            datum_type,
02249                                            array_count, &err))
02250             {
02251                 ThrowBadParam(err, i, ccx);
02252                 goto done;
02253             }
02254         }
02255         else
02256         {
02257             if(!XPCConvert::NativeData2JS(ccx, &v, &dp->val, datum_type,
02258                                           &param_iid,
02259                                           ccx.GetCurrentJSObject(), &err))
02260             {
02261                 ThrowBadParam(err, i, ccx);
02262                 goto done;
02263             }
02264         }
02265 
02266         if(paramInfo.IsRetval())
02267         {
02268             if(!ccx.GetReturnValueWasSet())
02269                 ccx.SetRetVal(v);
02270         }
02271         else
02272         {
02273             // we actually assured this before doing the invoke
02274             NS_ASSERTION(JSVAL_IS_OBJECT(argv[i]), "out var is not object");
02275             if(!OBJ_SET_PROPERTY(ccx, JSVAL_TO_OBJECT(argv[i]),
02276                         rt->GetStringID(XPCJSRuntime::IDX_VALUE), &v))
02277             {
02278                 ThrowBadParam(NS_ERROR_XPC_CANT_SET_OUT_VAL, i, ccx);
02279                 goto done;
02280             }
02281         }
02282     }
02283 
02284     retval = JS_TRUE;
02285 done:
02286     // iterate through the params (again!) and clean up
02287     // any alloc'd stuff and release wrappers of params
02288     if(dispatchParams)
02289     {
02290         for(i = 0; i < paramCount; i++)
02291         {
02292             nsXPTCVariant* dp = &dispatchParams[i];
02293             void* p = dp->val.p;
02294             if(!p)
02295                 continue;
02296 
02297             if(dp->IsValArray())
02298             {
02299                 // going to have to cleanup the array and perhaps its contents
02300                 if(dp->IsValAllocated() || dp->IsValInterface())
02301                 {
02302                     // we need to figure out how many elements are present.
02303                     JSUint32 array_count;
02304 
02305                     const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i);
02306                     if(!GetArraySizeFromParam(ccx, ifaceInfo, methodInfo,
02307                                               paramInfo, vtblIndex,
02308                                               i, GET_LENGTH, dispatchParams,
02309                                               &array_count))
02310                     {
02311                         NS_ASSERTION(0,"failed to get array length, we'll leak here");
02312                         continue;
02313                     }
02314                     if(dp->IsValAllocated())
02315                     {
02316                         void** a = (void**)p;
02317                         for(JSUint32 k = 0; k < array_count; k++)
02318                         {
02319                             void* o = a[k];
02320                             if(o) nsMemory::Free(o);
02321                         }
02322                     }
02323                     else // if(dp->IsValInterface())
02324                     {
02325                         nsISupports** a = (nsISupports**)p;
02326                         for(JSUint32 k = 0; k < array_count; k++)
02327                         {
02328                             nsISupports* o = a[k];
02329                             NS_IF_RELEASE(o);
02330                         }
02331                     }
02332                 }
02333                 // always free the array itself
02334                 nsMemory::Free(p);
02335             }
02336             else if(dp->IsValAllocated())
02337                 nsMemory::Free(p);
02338             else if(dp->IsValInterface())
02339                 ((nsISupports*)p)->Release();
02340             else if(dp->IsValDOMString())
02341                 delete (nsAString*)p;
02342             else if(dp->IsValUTF8String())
02343                 delete (nsCString*) p;
02344             else if(dp->IsValCString())
02345                 delete (nsCString*) p;
02346         }   
02347     }
02348 
02349     if(dispatchParams && dispatchParams != paramBuffer)
02350         delete [] dispatchParams;
02351 
02352 #ifdef off_DEBUG_stats_jband
02353     endTime = PR_IntervalNow();
02354 
02355     printf("%s::%s %d ( js->c ) \n",
02356            ccx.GetInterface()->GetNameString(),
02357            ccx.GetInterface()->GetMemberName(ccx, ccx.GetMember()),
02358            PR_IntervalToMilliseconds(endTime-startTime));
02359 
02360     totalTime += (endTime-startTime);
02361 #endif
02362 
02363     return retval;
02364 }
02365 
02366 /***************************************************************************/
02367 // interface methods
02368 
02369 /* readonly attribute JSObjectPtr JSObject; */
02370 NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject)
02371 {
02372     *aJSObject = mFlatJSObject;
02373     return NS_OK;
02374 }
02375 
02376 /* readonly attribute nsISupports Native; */
02377 NS_IMETHODIMP XPCWrappedNative::GetNative(nsISupports * *aNative)
02378 {
02379     // No need to QI here, we already have the correct nsISupports
02380     // vtable.
02381     *aNative = mIdentity;
02382     NS_ADDREF(*aNative);
02383     return NS_OK;
02384 }
02385 
02386 /* readonly attribute JSObjectPtr JSObjectPrototype; */
02387 NS_IMETHODIMP XPCWrappedNative::GetJSObjectPrototype(JSObject * *aJSObjectPrototype)
02388 {
02389     *aJSObjectPrototype = HasProto() ?
02390                 GetProto()->GetJSProtoObject() : GetFlatJSObject();
02391     return NS_OK;
02392 }
02393 
02394 /* readonly attribute nsIXPConnect XPConnect; */
02395 NS_IMETHODIMP XPCWrappedNative::GetXPConnect(nsIXPConnect * *aXPConnect)
02396 {
02397     if(IsValid())
02398     {
02399         nsIXPConnect* temp = GetRuntime()->GetXPConnect();
02400         NS_IF_ADDREF(temp);
02401         *aXPConnect = temp;
02402     }
02403     else
02404         *aXPConnect = nsnull;
02405     return NS_OK;
02406 }
02407 
02408 /* XPCNativeInterface FindInterfaceWithMember (in JSVal name); */
02409 NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(jsval name, nsIInterfaceInfo * *_retval)
02410 {
02411     XPCNativeInterface* iface;
02412     XPCNativeMember*  member;
02413 
02414     if(GetSet()->FindMember(name, &member, &iface) && iface)
02415     {
02416         nsIInterfaceInfo* temp = iface->GetInterfaceInfo();
02417         NS_IF_ADDREF(temp);
02418         *_retval = temp;
02419     }
02420     else
02421         *_retval = nsnull;
02422     return NS_OK;
02423 }
02424 
02425 /* XPCNativeInterface FindInterfaceWithName (in JSVal name); */
02426 NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithName(jsval name, nsIInterfaceInfo * *_retval)
02427 {
02428     XPCNativeInterface* iface = GetSet()->FindNamedInterface(name);
02429     if(iface)
02430     {
02431         nsIInterfaceInfo* temp = iface->GetInterfaceInfo();
02432         NS_IF_ADDREF(temp);
02433         *_retval = temp;
02434     }
02435     else
02436         *_retval = nsnull;
02437     return NS_OK;
02438 }
02439 
02440 inline nsresult UnexpectedFailure(nsresult rv)
02441 {
02442     NS_ERROR("This is not supposed to fail!");
02443     return rv;
02444 }
02445 
02446 /* void refreshPrototype (); */
02447 NS_IMETHODIMP XPCWrappedNative::RefreshPrototype()
02448 {
02449     XPCCallContext ccx(NATIVE_CALLER);
02450     if(!ccx.IsValid())
02451         return UnexpectedFailure(NS_ERROR_FAILURE);
02452 
02453     if(!HasProto())
02454         return NS_OK;
02455 
02456     if(!GetFlatJSObject())
02457         return UnexpectedFailure(NS_ERROR_FAILURE);
02458 
02459     AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
02460     AutoMarkingWrappedNativeProtoPtr newProto(ccx);
02461     
02462     oldProto = GetProto();
02463 
02464     XPCNativeScriptableInfo *info = oldProto->GetScriptableInfo();
02465     XPCNativeScriptableCreateInfo ci(*info);
02466     newProto = XPCWrappedNativeProto::GetNewOrUsed(ccx, oldProto->GetScope(),
02467                                                    oldProto->GetClassInfo(),
02468                                                    &ci,
02469                                                    !oldProto->IsShared(),
02470                                                    (info->GetJSClass()->flags & JSCLASS_IS_GLOBAL));
02471     if(!newProto)
02472         return UnexpectedFailure(NS_ERROR_FAILURE);
02473 
02474     // If nothing needs to change then we're done.
02475 
02476     if(newProto.get() == oldProto.get())
02477         return NS_OK;
02478 
02479     if(!JS_SetPrototype(ccx, GetFlatJSObject(), newProto->GetJSProtoObject()))
02480         return UnexpectedFailure(NS_ERROR_FAILURE);
02481 
02482     mMaybeProto = newProto;
02483 
02484     if(mScriptableInfo == oldProto->GetScriptableInfo())
02485         mScriptableInfo = newProto->GetScriptableInfo();
02486 
02487     return NS_OK;
02488 }
02489 
02490 NS_IMETHODIMP XPCWrappedNative::GetSecurityInfoAddress(void*** securityInfoAddrPtr)
02491 {
02492     NS_ENSURE_ARG_POINTER(securityInfoAddrPtr);
02493     *securityInfoAddrPtr = GetSecurityInfoAddr();
02494     return NS_OK;
02495 }
02496 
02497 /* void debugDump (in short depth); */
02498 NS_IMETHODIMP XPCWrappedNative::DebugDump(PRInt16 depth)
02499 {
02500 #ifdef DEBUG
02501     depth-- ;
02502     XPC_LOG_ALWAYS(("XPCWrappedNative @ %x with mRefCnt = %d", this, mRefCnt.get()));
02503     XPC_LOG_INDENT();
02504 
02505         if(HasProto())
02506         {
02507             if(depth && mMaybeProto)
02508                 mMaybeProto->DebugDump(depth);
02509             else
02510                 XPC_LOG_ALWAYS(("mMaybeProto @ %x", mMaybeProto));
02511         }
02512         else
02513             XPC_LOG_ALWAYS(("Scope @ %x", UnTagScope(mMaybeScope)));
02514 
02515         if(depth && mSet)
02516             mSet->DebugDump(depth);
02517         else
02518             XPC_LOG_ALWAYS(("mSet @ %x", mSet));
02519 
02520         XPC_LOG_ALWAYS(("mFlatJSObject of %x", mFlatJSObject));
02521         XPC_LOG_ALWAYS(("mScriptableInfo @ %x", mScriptableInfo));
02522 
02523         if(depth && mScriptableInfo)
02524         {
02525             XPC_LOG_INDENT();
02526             XPC_LOG_ALWAYS(("mScriptable @ %x", mScriptableInfo->GetCallback()));
02527             XPC_LOG_ALWAYS(("mFlags of %x", (PRUint32)mScriptableInfo->GetFlags()));
02528             XPC_LOG_ALWAYS(("mJSClass @ %x", mScriptableInfo->GetJSClass()));
02529             XPC_LOG_OUTDENT();
02530         }
02531     XPC_LOG_OUTDENT();
02532 #endif
02533     return NS_OK;
02534 }
02535 
02536 /***************************************************************************/
02537 
02538 char*
02539 XPCWrappedNative::ToString(XPCCallContext& ccx,
02540                            XPCWrappedNativeTearOff* to /* = nsnull */ ) const
02541 {
02542 #ifdef DEBUG
02543 #  define FMT_ADDR " @ 0x%p"
02544 #  define FMT_STR(str) str
02545 #  define PARAM_ADDR(w) , w
02546 #else
02547 #  define FMT_ADDR ""
02548 #  define FMT_STR(str)
02549 #  define PARAM_ADDR(w)
02550 #endif
02551 
02552     char* sz = nsnull;
02553     char* name = nsnull;
02554 
02555     XPCNativeScriptableInfo* si = GetScriptableInfo();
02556     if(si)
02557         name = JS_smprintf("%s", si->GetJSClass()->name);
02558     if(to)
02559     {
02560         const char* fmt = name ? " (%s)" : "%s";
02561         name = JS_sprintf_append(name, fmt,
02562                                  to->GetInterface()->GetNameString());
02563     }
02564     else if(!name)
02565     {
02566         XPCNativeSet* set = GetSet();
02567         XPCNativeInterface** array = set->GetInterfaceArray();
02568         PRUint16 count = set->GetInterfaceCount();
02569 
02570         if(count == 1)
02571             name = JS_sprintf_append(name, "%s", array[0]->GetNameString());
02572         else if(count == 2 &&
02573                 array[0] == XPCNativeInterface::GetISupports(ccx))
02574         {
02575             name = JS_sprintf_append(name, "%s", array[1]->GetNameString());
02576         }
02577         else
02578         {
02579             for(PRUint16 i = 0; i < count; i++)
02580             {
02581                 const char* fmt = (i == 0) ?
02582                                     "(%s" : (i == count-1) ?
02583                                         ", %s)" : ", %s";
02584                 name = JS_sprintf_append(name, fmt,
02585                                          array[i]->GetNameString());
02586             }
02587         }
02588     }
02589 
02590     if(!name)
02591     {
02592         return nsnull;
02593     }
02594     const char* fmt = "[xpconnect wrapped %s" FMT_ADDR FMT_STR(" (native")
02595         FMT_ADDR FMT_STR(")") "]";
02596     if(si)
02597     {
02598         fmt = "[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]";
02599     }
02600     sz = JS_smprintf(fmt, name PARAM_ADDR(this) PARAM_ADDR(mIdentity));
02601 
02602     JS_smprintf_free(name);
02603 
02604 
02605     return sz;
02606 
02607 #undef FMT_ADDR
02608 #undef PARAM_ADDR
02609 }
02610 
02611 /***************************************************************************/
02612 
02613 #ifdef XPC_DETECT_LEADING_UPPERCASE_ACCESS_ERRORS
02614 // static
02615 void
02616 XPCWrappedNative::HandlePossibleNameCaseError(JSContext* cx,
02617                                               XPCNativeSet* set,
02618                                               XPCNativeInterface* iface,
02619                                               jsval name)
02620 {
02621     XPCCallContext ccx(JS_CALLER, cx);
02622     HandlePossibleNameCaseError(ccx, set, iface, name);
02623 }
02624 
02625 // static
02626 void
02627 XPCWrappedNative::HandlePossibleNameCaseError(XPCCallContext& ccx,
02628                                               XPCNativeSet* set,
02629                                               XPCNativeInterface* iface,
02630                                               jsval name)
02631 {
02632     if(!ccx.IsValid())
02633         return;
02634 
02635     JSString* oldJSStr;
02636     JSString* newJSStr;
02637     PRUnichar* oldStr;
02638     PRUnichar* newStr;
02639     XPCNativeMember* member;
02640     XPCNativeInterface* localIface;
02641 
02642     /* PRUnichar->char->PRUnichar hack is to avoid pulling in i18n code. */
02643     if(JSVAL_IS_STRING(name) &&
02644        nsnull != (oldJSStr = JSVAL_TO_STRING(name)) &&
02645        nsnull != (oldStr = (PRUnichar*) JS_GetStringChars(oldJSStr)) &&
02646        oldStr[0] != 0 &&
02647        oldStr[0] >> 8 == 0 &&
02648        nsCRT::IsUpper((char)oldStr[0]) &&
02649        nsnull != (newStr = nsCRT::strdup(oldStr)))
02650     {
02651         newStr[0] = (PRUnichar) nsCRT::ToLower((char)newStr[0]);
02652         newJSStr = JS_NewUCStringCopyZ(ccx, (const jschar*)newStr);
02653         nsCRT::free(newStr);
02654         if(newJSStr && (set ?
02655              set->FindMember(STRING_TO_JSVAL(newJSStr), &member, &localIface) :
02656                         (JSBool)NS_PTR_TO_INT32(iface->FindMember(STRING_TO_JSVAL(newJSStr)))))
02657         {
02658             // found it!
02659             const char* ifaceName = localIface->GetNameString();
02660             const char* goodName = JS_GetStringBytes(newJSStr);
02661             const char* badName = JS_GetStringBytes(oldJSStr);
02662             char* locationStr = nsnull;
02663 
02664             nsIException* e = nsnull;
02665             nsXPCException::NewException("", NS_OK, nsnull, nsnull, &e);
02666 
02667             if(e)
02668             {
02669                 nsresult rv;
02670                 nsCOMPtr<nsIStackFrame> loc = nsnull;
02671                 rv = e->GetLocation(getter_AddRefs(loc));
02672                 if(NS_SUCCEEDED(rv) && loc) {
02673                     loc->ToString(&locationStr); // failure here leaves it nsnull.
02674                 }
02675             }
02676 
02677             if(locationStr && ifaceName && goodName && badName )
02678             {
02679                 printf("**************************************************\n"
02680                        "ERROR: JS code at [%s]\n"
02681                        "tried to access nonexistent property called\n"
02682                        "\'%s\' on interface of type \'%s\'.\n"
02683                        "That interface does however have a property called\n"
02684                        "\'%s\'. Did you mean to access that lowercase property?\n"
02685                        "Please fix the JS code as appropriate.\n"
02686                        "**************************************************\n",
02687                         locationStr, badName, ifaceName, goodName);
02688             }
02689             if(locationStr)
02690                 nsMemory::Free(locationStr);
02691         }
02692     }
02693 }
02694 #endif
02695 
02696 #ifdef XPC_CHECK_CLASSINFO_CLAIMS
02697 static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper)
02698 {
02699     if(!wrapper || !wrapper->GetClassInfo())
02700         return;
02701 
02702     nsISupports* obj = wrapper->GetIdentityObject();
02703     XPCNativeSet* set = wrapper->GetSet();
02704     PRUint16 count = set->GetInterfaceCount();
02705     for(PRUint16 i = 0; i < count; i++)
02706     {
02707         nsIClassInfo* clsInfo = wrapper->GetClassInfo();
02708         XPCNativeInterface* iface = set->GetInterfaceAt(i);
02709         nsIInterfaceInfo* info = iface->GetInterfaceInfo();
02710         const nsIID* iid;
02711         nsISupports* ptr;
02712 
02713         info->GetIIDShared(&iid);
02714         nsresult rv = obj->QueryInterface(*iid, (void**)&ptr);
02715         if(NS_SUCCEEDED(rv))
02716         {
02717             NS_RELEASE(ptr);
02718             continue;
02719         }
02720 
02721         // Houston, We have a problem...
02722 
02723         char* className = nsnull;
02724         char* contractID = nsnull;
02725         const char* interfaceName;
02726 
02727         info->GetNameShared(&interfaceName);
02728         clsInfo->GetContractID(&contractID);
02729         if(wrapper->GetScriptableInfo())
02730         {
02731             wrapper->GetScriptableInfo()->GetCallback()->
02732                 GetClassName(&className);
02733         }
02734 
02735 
02736         printf("\n!!! Object's nsIClassInfo lies about it's interfaces!!!\n"
02737                "   classname: %s \n"
02738                "   contractid: %s \n"
02739                "   unimplemented interface name: %s\n\n",
02740                className ? className : "<unknown>",
02741                contractID ? contractID : "<unknown>",
02742                interfaceName);
02743 
02744 #ifdef XPC_ASSERT_CLASSINFO_CLAIMS
02745         NS_ERROR("Fix this QueryInterface or nsIClassInfo");
02746 #endif
02747 
02748         if(className)
02749             nsMemory::Free(className);
02750         if(contractID)
02751             nsMemory::Free(contractID);
02752     }
02753 }
02754 #endif
02755 
02756 #ifdef XPC_REPORT_SHADOWED_WRAPPED_NATIVE_MEMBERS
02757 static void DEBUG_PrintShadowObjectInfo(const char* header,
02758                                         XPCNativeSet* set,
02759                                         XPCWrappedNative* wrapper,
02760                                         XPCWrappedNativeProto* proto)
02761 
02762 {
02763     if(header)
02764         printf("%s\n", header);
02765 
02766     printf("   XPCNativeSet @ 0x%p for the class:\n", (void*)set);
02767 
02768     char* className = nsnull;
02769     char* contractID = nsnull;
02770 
02771     nsIClassInfo* clsInfo = proto ? proto->GetClassInfo() : nsnull;
02772     if(clsInfo)
02773         clsInfo->GetContractID(&contractID);
02774 
02775     XPCNativeScriptableInfo* si = wrapper ?
02776             wrapper->GetScriptableInfo() :
02777             proto->GetScriptableInfo();
02778     if(si)
02779         si->GetCallback()->GetClassName(&className);
02780 
02781     printf("   classname: %s \n"
02782            "   contractid: %s \n",
02783            className ? className : "<unknown>",
02784            contractID ? contractID : "<unknown>");
02785 
02786     if(className)
02787         nsMemory::Free(className);
02788     if(contractID)
02789         nsMemory::Free(contractID);
02790 
02791     printf("   claims to implement interfaces:\n");
02792 
02793     PRUint16 count = set->GetInterfaceCount();
02794     for(PRUint16 i = 0; i < count; i++)
02795     {
02796         XPCNativeInterface* iface = set->GetInterfaceAt(i);
02797         nsIInterfaceInfo* info = iface->GetInterfaceInfo();
02798         const char* interfaceName;
02799         info->GetNameShared(&interfaceName);
02800         printf("      %s\n", interfaceName);
02801     }
02802 }
02803 
02804 static void ReportSingleMember(jsval ifaceName,
02805                                jsval memberName)
02806 {
02807     if(JSVAL_IS_STRING(memberName))
02808         printf("%s::%s", JS_GetStringBytes(JSVAL_TO_STRING(ifaceName)),
02809                          JS_GetStringBytes(JSVAL_TO_STRING(memberName)));
02810     else
02811         printf("%s", JS_GetStringBytes(JSVAL_TO_STRING(ifaceName)));
02812 }
02813 
02814 static void ShowHeader(JSBool* printedHeader,
02815                        const char* header,
02816                        XPCNativeSet* set,
02817                        XPCWrappedNative* wrapper,
02818                        XPCWrappedNativeProto* proto)
02819 {
02820     if(!*printedHeader)
02821     {
02822         DEBUG_PrintShadowObjectInfo(header, set, wrapper, proto);
02823         *printedHeader = JS_TRUE;
02824     }
02825 
02826 }
02827 
02828 static void ShowOneShadow(jsval ifaceName1,
02829                           jsval memberName1,
02830                           jsval ifaceName2,
02831                           jsval memberName2)
02832 {
02833     ReportSingleMember(ifaceName1, memberName1);
02834     printf(" shadows ");
02835     ReportSingleMember(ifaceName2, memberName2);
02836     printf("\n");
02837 }
02838 
02839 static void ShowDuplicateInterface(jsval ifaceName)
02840 {
02841     printf(" ! %s appears twice in the nsIClassInfo interface set!\n",
02842            JS_GetStringBytes(JSVAL_TO_STRING(ifaceName)));
02843 }
02844 
02845 static JSBool InterfacesAreRelated(XPCNativeInterface* iface1,
02846                                    XPCNativeInterface* iface2)
02847 {
02848     nsIInterfaceInfo* info1 = iface1->GetInterfaceInfo();
02849     nsIInterfaceInfo* info2 = iface2->GetInterfaceInfo();
02850 
02851     NS_ASSERTION(info1 != info2, "should not have different iface!");
02852 
02853     PRBool match;
02854 
02855     return
02856         (NS_SUCCEEDED(info1->HasAncestor(iface2->GetIID(), &match)) && match) ||
02857         (NS_SUCCEEDED(info2->HasAncestor(iface1->GetIID(), &match)) && match);
02858 }
02859 
02860 static JSBool MembersAreTheSame(XPCNativeInterface* iface1,
02861                                 PRUint16 memberIndex1,
02862                                 XPCNativeInterface* iface2,
02863                                 PRUint16 memberIndex2)
02864 {
02865     nsIInterfaceInfo* info1 = iface1->GetInterfaceInfo();
02866     nsIInterfaceInfo* info2 = iface2->GetInterfaceInfo();
02867 
02868     XPCNativeMember* member1 = iface1->GetMemberAt(memberIndex1);
02869     XPCNativeMember* member2 = iface2->GetMemberAt(memberIndex2);
02870 
02871     PRUint16 index1 = member1->GetIndex();
02872     PRUint16 index2 = member2->GetIndex();
02873 
02874     // If they are both constants, then we'll just be sure that they are equivalent.
02875 
02876     if(member1->IsConstant())
02877     {
02878         if(!member2->IsConstant())
02879             return JS_FALSE;
02880 
02881         const nsXPTConstant* constant1;
02882         const nsXPTConstant* constant2;
02883 
02884         return NS_SUCCEEDED(info1->GetConstant(index1, &constant1)) &&
02885                NS_SUCCEEDED(info2->GetConstant(index2, &constant2)) &&
02886                constant1->GetType() == constant2->GetType() &&
02887                constant1->GetValue() == constant2->GetValue();
02888     }
02889 
02890     // Else we make sure they are of the same 'type' and return true only if
02891     // they are inherited from the same interface.
02892 
02893     if(member1->IsMethod() != member2->IsMethod() ||
02894        member1->IsWritableAttribute() != member2->IsWritableAttribute() ||
02895        member1->IsReadOnlyAttribute() != member2->IsReadOnlyAttribute())
02896     {
02897         return JS_FALSE;
02898     }
02899 
02900     const nsXPTMethodInfo* mi1;
02901     const nsXPTMethodInfo* mi2;
02902 
02903     return NS_SUCCEEDED(info1->GetMethodInfo(index1, &mi1)) &&
02904            NS_SUCCEEDED(info2->GetMethodInfo(index2, &mi2)) &&
02905            mi1 == mi2;
02906 }
02907 
02908 void DEBUG_ReportShadowedMembers(XPCNativeSet* set,
02909                                  XPCWrappedNative* wrapper,
02910                                  XPCWrappedNativeProto* proto)
02911 {
02912     // NOTE: Either wrapper or proto could be null...
02913 
02914     if(!(proto || wrapper) || !set || set->GetInterfaceCount() < 2)
02915         return;
02916 
02917     NS_ASSERTION(proto || wrapper, "bad param!");
02918     XPCJSRuntime* rt = proto ? proto->GetRuntime() : wrapper->GetRuntime();
02919 
02920     // a quicky hack to avoid reporting info for the same set too often
02921     static int nextSeenSet = 0;
02922     static const int MAX_SEEN_SETS = 128;
02923     static XPCNativeSet* SeenSets[MAX_SEEN_SETS];
02924     for(int seen = 0; seen < MAX_SEEN_SETS; seen++)
02925         if(set == SeenSets[seen])
02926             return;
02927     SeenSets[nextSeenSet] = set;
02928 
02929 #ifdef off_DEBUG_jband
02930     static int seenCount = 0;
02931     printf("--- adding SeenSets[%d] = 0x%p\n", nextSeenSet, set);
02932     DEBUG_PrintShadowObjectInfo(nsnull, set, wrapper, proto);
02933 #endif
02934     int localNext = nextSeenSet+1;
02935     nextSeenSet = localNext < MAX_SEEN_SETS ? localNext : 0;
02936 
02937     XPCNativeScriptableInfo* si = wrapper ?
02938             wrapper->GetScriptableInfo() :
02939             proto->GetScriptableInfo();
02940 
02941     // We just want to skip some classes...
02942     if(si)
02943     {
02944         // Add any classnames to skip to this (null terminated) array...
02945         static const char* skipClasses[] = {
02946             "Window",
02947             "HTMLDocument",
02948             "HTMLCollection",
02949             "Event",
02950             "ChromeWindow",
02951             nsnull
02952         };
02953 
02954         static PRBool warned = JS_FALSE;
02955         if(!warned)
02956         {
02957             printf("!!! XPConnect won't warn about Shadowed Members of...\n  ");
02958             for(const char** name = skipClasses; *name; name++)
02959                 printf("%s %s", name == skipClasses ? "" : ",", *name);
02960              printf("\n");
02961             warned = JS_TRUE;
02962         }
02963 
02964         PRBool quit = JS_FALSE;
02965         char* className = nsnull;
02966         si->GetCallback()->GetClassName(&className);
02967         if(className)
02968         {
02969             for(const char** name = skipClasses; *name; name++)
02970             {
02971                 if(!strcmp(*name, className))
02972                 {
02973                     quit = JS_TRUE;
02974                     break;
02975                 }
02976             }
02977             nsMemory::Free(className);
02978         }
02979         if(quit)
02980             return;
02981     }
02982 
02983     const char header[] =
02984         "!!!Object wrapped by XPConnect has members whose names shadow each other!!!";
02985 
02986     JSBool printedHeader = JS_FALSE;
02987 
02988     jsval QIName = rt->GetStringJSVal(XPCJSRuntime::IDX_QUERY_INTERFACE);
02989 
02990     PRUint16 ifaceCount = set->GetInterfaceCount();
02991     PRUint16 i, j, k, m;
02992 
02993     // First look for duplicate interface entries
02994 
02995     for(i = 0; i < ifaceCount; i++)
02996     {
02997         XPCNativeInterface* ifaceOuter = set->GetInterfaceAt(i);
02998         for(k = i+1; k < ifaceCount; k++)
02999         {
03000             XPCNativeInterface* ifaceInner = set->GetInterfaceAt(k);
03001             if(ifaceInner == ifaceOuter)
03002             {
03003                 ShowHeader(&printedHeader, header, set, wrapper, proto);
03004                 ShowDuplicateInterface(ifaceOuter->GetName());
03005             }
03006         }
03007     }
03008 
03009     // Now scan for shadowing names
03010 
03011     for(i = 0; i < ifaceCount; i++)
03012     {
03013         XPCNativeInterface* ifaceOuter = set->GetInterfaceAt(i);
03014         jsval ifaceOuterName = ifaceOuter->GetName();
03015 
03016         PRUint16 memberCountOuter = ifaceOuter->GetMemberCount();
03017         for(j = 0; j < memberCountOuter; j++)
03018         {
03019             XPCNativeMember* memberOuter = ifaceOuter->GetMemberAt(j);
03020             jsval memberOuterName = memberOuter->GetName();
03021 
03022             if(memberOuterName == QIName)
03023                 continue;
03024 
03025             for(k = i+1; k < ifaceCount; k++)
03026             {
03027                 XPCNativeInterface* ifaceInner = set->GetInterfaceAt(k);
03028                 jsval ifaceInnerName = ifaceInner->GetName();
03029 
03030                 // Reported elsewhere.
03031                 if(ifaceInner == ifaceOuter)
03032                     continue;
03033 
03034                 // We consider this not worth reporting because callers will
03035                 // almost certainly be getting what they expect.
03036                 if(InterfacesAreRelated(ifaceInner, ifaceOuter))
03037                     continue;
03038 
03039                 if(ifaceInnerName == memberOuterName)
03040                 {
03041                     ShowHeader(&printedHeader, header, set, wrapper, proto);
03042                     ShowOneShadow(ifaceInnerName, JSVAL_NULL,
03043                                   ifaceOuterName, memberOuterName);
03044                 }
03045 
03046                 PRUint16 memberCountInner = ifaceInner->GetMemberCount();
03047 
03048                 for(m = 0; m < memberCountInner; m++)
03049                 {
03050                     XPCNativeMember* memberInner = ifaceInner->GetMemberAt(m);
03051                     jsval memberInnerName = memberInner->GetName();
03052 
03053                     if(memberInnerName == QIName)
03054                         continue;
03055 
03056                     if(memberOuterName == memberInnerName &&
03057                        !MembersAreTheSame(ifaceOuter, j, ifaceInner, m))
03058 
03059                     {
03060                         ShowHeader(&printedHeader, header, set, wrapper, proto);
03061                         ShowOneShadow(ifaceOuterName, memberOuterName,
03062                                       ifaceInnerName, memberInnerName);
03063                     }
03064                 }
03065             }
03066         }
03067     }
03068 }
03069 #endif
03070 
03071 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
03072 void DEBUG_ReportWrapperThreadSafetyError(XPCCallContext& ccx,
03073                                           const char* msg,
03074                                           const XPCWrappedNative* wrapper)
03075 {
03076     XPCPerThreadData* tls = ccx.GetThreadData();
03077     if(1 != tls->IncrementWrappedNativeThreadsafetyReportDepth())
03078         return;
03079 
03080     printf("---------------------------------------------------------------\n");
03081     printf("!!!!! XPConnect wrapper thread use error...\n");
03082 
03083     char* wrapperDump = wrapper->ToString(ccx);
03084     if(wrapperDump)
03085     {
03086         printf("  %s\n  wrapper: %s\n", msg, wrapperDump);
03087         JS_smprintf_free(wrapperDump);
03088     }
03089     else
03090         printf("  %s\n  wrapper @ 0x%p\n", msg, (void *)wrapper);
03091 
03092     printf("  JS call stack...\n");
03093     xpc_DumpJSStack(ccx, JS_TRUE, JS_TRUE, JS_TRUE);
03094     printf("---------------------------------------------------------------\n");
03095     
03096     tls->ClearWrappedNativeThreadsafetyReportDepth();
03097 }
03098 
03099 void DEBUG_CheckWrapperThreadSafety(const XPCWrappedNative* wrapper)
03100 {
03101     XPCWrappedNativeProto* proto = wrapper->GetProto();
03102     if(proto && proto->ClassIsThreadSafe())
03103         return;
03104 
03105     PRThread* currentThread = PR_GetCurrentThread();
03106 
03107     if(proto && proto->ClassIsMainThreadOnly())
03108     {
03109         if(currentThread != wrapper->gMainThread)
03110         {
03111             XPCCallContext ccx(NATIVE_CALLER);
03112             DEBUG_ReportWrapperThreadSafetyError(ccx,
03113                 "Main Thread Only wrapper accessed on another thread", wrapper);
03114         }
03115     }
03116     else if(currentThread != wrapper->mThread)
03117     {
03118         XPCCallContext ccx(NATIVE_CALLER);
03119         DEBUG_ReportWrapperThreadSafetyError(ccx,
03120             "XPConnect WrappedNative is being accessed on multiple threads but "
03121             "the underlying native xpcom object does not have a "
03122             "nsIClassInfo with the 'THREADSAFE' flag set", wrapper);
03123     }
03124 }
03125 #endif
03126 
03127 NS_IMPL_THREADSAFE_ISUPPORTS1(XPCJSObjectHolder, nsIXPConnectJSObjectHolder)
03128 
03129 NS_IMETHODIMP
03130 XPCJSObjectHolder::GetJSObject(JSObject** aJSObj)
03131 {
03132     NS_PRECONDITION(aJSObj, "bad param");
03133     NS_PRECONDITION(mJSObj, "bad object state");
03134     *aJSObj = mJSObj;
03135     return NS_OK;
03136 }
03137 
03138 XPCJSObjectHolder::XPCJSObjectHolder(JSContext* cx, JSObject* obj)
03139     : mRuntime(JS_GetRuntime(cx)), mJSObj(obj)
03140 {
03141     JS_AddNamedRoot(cx, &mJSObj, "XPCJSObjectHolder::mJSObj");
03142 }
03143 
03144 XPCJSObjectHolder::~XPCJSObjectHolder()
03145 {
03146     JS_RemoveRootRT(mRuntime, &mJSObj);
03147 }
03148 
03149 XPCJSObjectHolder*
03150 XPCJSObjectHolder::newHolder(JSContext* cx, JSObject* obj)
03151 {
03152     if(!cx || !obj)
03153     {
03154         NS_ASSERTION(0, "bad param");
03155         return nsnull;
03156     }
03157     return new XPCJSObjectHolder(cx, obj);
03158 }