Back to index

lightning-sunbird  0.9+nobinonly
xpcwrappednativeinfo.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 // vim:cindent:ts=8:et:sw=4:
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 /* Manage the shared info about interfaces for use by wrappedNatives. */
00043 
00044 #include "xpcprivate.h"
00045 
00046 /***************************************************************************/
00047 
00048 /*
00049  * Helper that clones JS Function objects along with both of its
00050  * reserved slots.
00051  */
00052 
00053 JSObject *
00054 xpc_CloneJSFunction(XPCCallContext &ccx, JSObject *funobj, JSObject *parent)
00055 {
00056     JSObject *clone = JS_CloneFunctionObject(ccx, funobj, parent);
00057     if(!clone)
00058         return nsnull;
00059 
00060     AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(clone));
00061 
00062     XPCWrappedNativeScope *scope = 
00063         XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
00064 
00065     if (!scope) {
00066         return nsnull;
00067     }
00068 
00069     // Make sure to break the prototype chain to the function object
00070     // we cloned to prevent its scope from leaking into the clones
00071     // scope.
00072     JS_SetPrototype(ccx, clone, scope->GetPrototypeJSFunction());
00073 
00074     // Copy the reserved slots to the clone.
00075     jsval ifaceVal, memberVal;
00076     if(!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) ||
00077        !JS_GetReservedSlot(ccx, funobj, 1, &memberVal))
00078         return nsnull;
00079 
00080     if(!JS_SetReservedSlot(ccx, clone, 0, ifaceVal) ||
00081        !JS_SetReservedSlot(ccx, clone, 1, memberVal))
00082         return nsnull;
00083 
00084     return clone;
00085 }
00086 
00087 // XPCNativeMember
00088 
00089 // static
00090 JSBool
00091 XPCNativeMember::GetCallInfo(XPCCallContext& ccx,
00092                              JSObject* funobj,
00093                              XPCNativeInterface** pInterface,
00094                              XPCNativeMember**    pMember)
00095 {
00096     jsval ifaceVal;
00097     jsval memberVal;
00098 
00099     if(!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) ||
00100        !JS_GetReservedSlot(ccx, funobj, 1, &memberVal) ||
00101        !JSVAL_IS_INT(ifaceVal) || !JSVAL_IS_INT(memberVal))
00102     {
00103         return JS_FALSE;
00104     }
00105 
00106     *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
00107     *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
00108 
00109     return JS_TRUE;
00110 }
00111 
00112 JSBool
00113 XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface)
00114 {
00115     if(IsConstant())
00116     {
00117         const nsXPTConstant* constant;
00118         if(NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant)))
00119             return JS_FALSE;
00120 
00121         const nsXPTCMiniVariant& mv = *constant->GetValue();
00122 
00123         // XXX Big Hack!
00124         nsXPTCVariant v;
00125         v.flags = 0;
00126         v.type = constant->GetType();
00127         memcpy(&v.val, &mv.val, sizeof(mv.val));
00128 
00129         jsval resultVal;
00130 
00131         if(!XPCConvert::NativeData2JS(ccx, &resultVal, &v.val, v.type,
00132                                       nsnull, nsnull, nsnull))
00133             return JS_FALSE;
00134 
00135         {   // scoped lock
00136             XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
00137             mVal = resultVal;
00138             mFlags |= RESOLVED;
00139         }
00140 
00141         return JS_TRUE;
00142     }
00143     // else...
00144 
00145     // This is a method or attribute - we'll be needing a function object
00146 
00147     // We need to use the safe context for this thread because we don't want
00148     // to parent the new (and cached forever!) function object to the current
00149     // JSContext's global object. That would be bad!
00150 
00151     JSContext* cx = ccx.GetSafeJSContext();
00152     if(!cx)
00153         return JS_FALSE;
00154 
00155     intN argc;
00156     intN flags;
00157     JSNative callback;
00158 
00159     if(IsMethod())
00160     {
00161         const nsXPTMethodInfo* info;
00162         if(NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info)))
00163             return JS_FALSE;
00164 
00165         // Note: ASSUMES that retval is last arg.
00166         argc = (intN) info->GetParamCount();
00167         if(argc && info->GetParam((uint8)(argc-1)).IsRetval())
00168             argc-- ;
00169 
00170         flags = 0;
00171         callback = XPC_WN_CallMethod;
00172     }
00173     else
00174     {
00175         if(IsWritableAttribute())
00176             flags = JSFUN_GETTER | JSFUN_SETTER;
00177         else
00178             flags = JSFUN_GETTER;
00179         argc = 0;
00180         callback = XPC_WN_GetterSetter;
00181     }
00182 
00183     JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull,
00184                                      iface->GetMemberName(ccx, this));
00185     if(!fun)
00186         return JS_FALSE;
00187 
00188     JSObject* funobj = JS_GetFunctionObject(fun);
00189     if(!funobj)
00190         return JS_FALSE;
00191 
00192     AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(funobj));
00193 
00194     if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(iface))||
00195        !JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(this)))
00196         return JS_FALSE;
00197 
00198     {   // scoped lock
00199         XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
00200         mVal = OBJECT_TO_JSVAL(funobj);
00201         mFlags |= RESOLVED;
00202     }
00203 
00204     return JS_TRUE;
00205 }
00206 
00207 /***************************************************************************/
00208 // XPCNativeInterface
00209 
00210 // static
00211 XPCNativeInterface*
00212 XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
00213 {
00214     AutoMarkingNativeInterfacePtr iface(ccx);
00215     XPCJSRuntime* rt = ccx.GetRuntime();
00216 
00217     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
00218     if(!map)
00219         return nsnull;
00220 
00221     {   // scoped lock
00222         XPCAutoLock lock(rt->GetMapLock());
00223         iface = map->Find(*iid);
00224     }
00225 
00226     if(iface)
00227         return iface;
00228 
00229     nsCOMPtr<nsIInterfaceInfo> info;
00230     ccx.GetXPConnect()->GetInfoForIID(iid, getter_AddRefs(info));
00231     if(!info)
00232         return nsnull;
00233 
00234     iface = NewInstance(ccx, info);
00235     if(!iface)
00236         return nsnull;
00237 
00238     {   // scoped lock
00239         XPCAutoLock lock(rt->GetMapLock());
00240         XPCNativeInterface* iface2 = map->Add(iface);
00241         if(!iface2)
00242         {
00243             NS_ERROR("failed to add our interface!");
00244             DestroyInstance(ccx, rt, iface);
00245             iface = nsnull;
00246         }
00247         else if(iface2 != iface)
00248         {
00249             DestroyInstance(ccx, rt, iface);
00250             iface = iface2;
00251         }
00252     }
00253 
00254     return iface;
00255 }
00256 
00257 // static
00258 XPCNativeInterface*
00259 XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, nsIInterfaceInfo* info)
00260 {
00261     AutoMarkingNativeInterfacePtr iface(ccx);
00262 
00263     const nsIID* iid;
00264     if(NS_FAILED(info->GetIIDShared(&iid)) || !iid)
00265         return nsnull;
00266 
00267     XPCJSRuntime* rt = ccx.GetRuntime();
00268 
00269     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
00270     if(!map)
00271         return nsnull;
00272 
00273     {   // scoped lock
00274         XPCAutoLock lock(rt->GetMapLock());
00275         iface = map->Find(*iid);
00276     }
00277 
00278     if(iface)
00279         return iface;
00280 
00281     iface = NewInstance(ccx, info);
00282     if(!iface)
00283         return nsnull;
00284 
00285     {   // scoped lock
00286         XPCAutoLock lock(rt->GetMapLock());
00287         XPCNativeInterface* iface2 = map->Add(iface);
00288         if(!iface2)
00289         {
00290             NS_ERROR("failed to add our interface!");
00291             DestroyInstance(ccx, rt, iface);
00292             iface = nsnull;
00293         }
00294         else if(iface2 != iface)
00295         {
00296             DestroyInstance(ccx, rt, iface);
00297             iface = iface2;
00298         }
00299     }
00300 
00301     return iface;
00302 }
00303 
00304 // static
00305 XPCNativeInterface*
00306 XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const char* name)
00307 {
00308     nsCOMPtr<nsIInterfaceInfo> info;
00309     ccx.GetXPConnect()->GetInfoForName(name, getter_AddRefs(info));
00310     return info ? GetNewOrUsed(ccx, info) : nsnull;
00311 }
00312 
00313 // static
00314 XPCNativeInterface*
00315 XPCNativeInterface::GetISupports(XPCCallContext& ccx)
00316 {
00317     // XXX We should optimize this to cache this common XPCNativeInterface.
00318     return GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
00319 }
00320 
00321 // static
00322 XPCNativeInterface*
00323 XPCNativeInterface::NewInstance(XPCCallContext& ccx,
00324                                 nsIInterfaceInfo* aInfo)
00325 {
00326     static const PRUint16 MAX_LOCAL_MEMBER_COUNT = 16;
00327     XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
00328     XPCNativeInterface* obj = nsnull;
00329     XPCNativeMember* members = nsnull;
00330 
00331     int i;
00332     JSBool failed = JS_FALSE;
00333     PRUint16 constCount;
00334     PRUint16 methodCount;
00335     PRUint16 totalCount;
00336     PRUint16 realTotalCount = 0;
00337     XPCNativeMember* cur;
00338     JSString*  str;
00339     jsval name;
00340     jsval interfaceName;
00341 
00342     // XXX Investigate lazy init? This is a problem given the
00343     // 'placement new' scheme - we need to at least know how big to make
00344     // the object. We might do a scan of methods to determine needed size,
00345     // then make our object, but avoid init'ing *any* members until asked?
00346     // Find out how often we create these objects w/o really looking at
00347     // (or using) the members.
00348 
00349     PRBool canScript;
00350     if(NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
00351         return nsnull;
00352 
00353     if(NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
00354        NS_FAILED(aInfo->GetConstantCount(&constCount)))
00355         return nsnull;
00356 
00357     // If the interface does not have nsISupports in its inheritance chain
00358     // then we know we can't reflect its methods. However, some interfaces that
00359     // are used just to reflect constants are declared this way. We need to
00360     // go ahead and build the thing. But, we'll ignore whatever methods it may
00361     // have.
00362     if(!nsXPConnect::IsISupportsDescendant(aInfo))
00363         methodCount = 0;
00364 
00365     totalCount = methodCount + constCount;
00366 
00367     if(totalCount > MAX_LOCAL_MEMBER_COUNT)
00368     {
00369         members = new XPCNativeMember[totalCount];
00370         if(!members)
00371             return nsnull;
00372     }
00373     else
00374     {
00375         members = local_members;
00376     }
00377 
00378     // NOTE: since getters and setters share a member, we might not use all
00379     // of the member objects.
00380 
00381     for(i = 0; i < methodCount; i++)
00382     {
00383         const nsXPTMethodInfo* info;
00384         if(NS_FAILED(aInfo->GetMethodInfo(i, &info)))
00385         {
00386             failed = JS_TRUE;
00387             break;
00388         }
00389 
00390         // don't reflect Addref or Release
00391         if(i == 1 || i == 2)
00392             continue;
00393 
00394         if(!XPCConvert::IsMethodReflectable(*info))
00395             continue;
00396 
00397         str = JS_InternString(ccx, info->GetName());
00398         if(!str)
00399         {
00400             NS_ASSERTION(0,"bad method name");
00401             failed = JS_TRUE;
00402             break;
00403         }
00404         name = STRING_TO_JSVAL(str);
00405 
00406         if(info->IsSetter())
00407         {
00408             NS_ASSERTION(realTotalCount,"bad setter");
00409             // Note: ASSUMES Getter/Setter pairs are next to each other
00410             // This is a rule of the typelib spec.
00411             cur = &members[realTotalCount-1];
00412             NS_ASSERTION(cur->GetName() == name,"bad setter");
00413             NS_ASSERTION(cur->IsReadOnlyAttribute(),"bad setter");
00414             NS_ASSERTION(cur->GetIndex() == i-1,"bad setter");
00415             cur->SetWritableAttribute();
00416         }
00417         else
00418         {
00419             // XXX need better way to find dups
00420             // NS_ASSERTION(!LookupMemberByID(name),"duplicate method name");
00421             cur = &members[realTotalCount++];
00422             cur->SetName(name);
00423             if(info->IsGetter())
00424                 cur->SetReadOnlyAttribute(i);
00425             else
00426                 cur->SetMethod(i);
00427         }
00428     }
00429 
00430     if(!failed)
00431     {
00432         for(i = 0; i < constCount; i++)
00433         {
00434             const nsXPTConstant* constant;
00435             if(NS_FAILED(aInfo->GetConstant(i, &constant)))
00436             {
00437                 failed = JS_TRUE;
00438                 break;
00439             }
00440 
00441             str = JS_InternString(ccx, constant->GetName());
00442             if(!str)
00443             {
00444                 NS_ASSERTION(0,"bad constant name");
00445                 failed = JS_TRUE;
00446                 break;
00447             }
00448             name = STRING_TO_JSVAL(str);
00449 
00450             // XXX need better way to find dups
00451             //NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");
00452 
00453             cur = &members[realTotalCount++];
00454             cur->SetName(name);
00455             cur->SetConstant(i);
00456         }
00457     }
00458 
00459     if(!failed)
00460     {
00461         const char* bytes;
00462         if(NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
00463            nsnull == (str = JS_InternString(ccx, bytes)))
00464         {
00465             failed = JS_TRUE;
00466         }
00467         interfaceName = STRING_TO_JSVAL(str);
00468     }
00469 
00470     if(!failed)
00471     {
00472         // Use placement new to create an object with the right amount of space
00473         // to hold the members array
00474         int size = sizeof(XPCNativeInterface);
00475         if(realTotalCount > 1)
00476             size += (realTotalCount - 1) * sizeof(XPCNativeMember);
00477         void* place = new char[size];
00478         if(place)
00479             obj = new(place) XPCNativeInterface(aInfo, interfaceName);
00480 
00481         if(obj)
00482         {
00483             obj->mMemberCount = realTotalCount;
00484             // copy valid members
00485             if(realTotalCount)
00486                 memcpy(obj->mMembers, members,
00487                        realTotalCount * sizeof(XPCNativeMember));
00488         }
00489     }
00490 
00491     if(members && members != local_members)
00492         delete [] members;
00493 
00494     return obj;
00495 }
00496 
00497 // static
00498 void
00499 XPCNativeInterface::DestroyInstance(JSContext* cx, XPCJSRuntime* rt,
00500                                     XPCNativeInterface* inst)
00501 {
00502     inst->~XPCNativeInterface();
00503     delete [] (char*) inst;
00504 }
00505 
00506 const char*
00507 XPCNativeInterface::GetMemberName(XPCCallContext& ccx,
00508                                   const XPCNativeMember* member) const
00509 {
00510     return JS_GetStringBytes(JSVAL_TO_STRING(member->GetName()));
00511 }
00512 
00513 void
00514 XPCNativeInterface::DebugDump(PRInt16 depth)
00515 {
00516 #ifdef DEBUG
00517     depth--;
00518     XPC_LOG_ALWAYS(("XPCNativeInterface @ %x", this));
00519         XPC_LOG_INDENT();
00520         XPC_LOG_ALWAYS(("name is %s", GetNameString()));
00521         XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount));
00522         XPC_LOG_ALWAYS(("mInfo @ %x", mInfo.get()));
00523         XPC_LOG_OUTDENT();
00524 #endif
00525 }
00526 
00527 /***************************************************************************/
00528 // XPCNativeSet
00529 
00530 // static
00531 XPCNativeSet*
00532 XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
00533 {
00534     AutoMarkingNativeSetPtr set(ccx);
00535 
00536     AutoMarkingNativeInterfacePtr iface(ccx);
00537     iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
00538     if(!iface)
00539         return nsnull;
00540 
00541     XPCNativeSetKey key(nsnull, iface, 0);
00542 
00543     XPCJSRuntime* rt = ccx.GetRuntime();
00544     NativeSetMap* map = rt->GetNativeSetMap();
00545     if(!map)
00546         return nsnull;
00547 
00548     {   // scoped lock
00549         XPCAutoLock lock(rt->GetMapLock());
00550         set = map->Find(&key);
00551     }
00552 
00553     if(set)
00554         return set;
00555 
00556     // hacky way to get a XPCNativeInterface** using the AutoPtr
00557     XPCNativeInterface* temp[] = {iface}; 
00558     set = NewInstance(ccx, temp, 1);
00559     if(!set)
00560         return nsnull;
00561 
00562     {   // scoped lock
00563         XPCAutoLock lock(rt->GetMapLock());
00564         XPCNativeSet* set2 = map->Add(&key, set);
00565         if(!set2)
00566         {
00567             NS_ERROR("failed to add our set!");
00568             DestroyInstance(set);
00569             set = nsnull;
00570         }
00571         else if(set2 != set)
00572         {
00573             DestroyInstance(set);
00574             set = set2;
00575         }
00576     }
00577 
00578     return set;
00579 }
00580 
00581 // static
00582 XPCNativeSet*
00583 XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, nsIClassInfo* classInfo)
00584 {
00585     AutoMarkingNativeSetPtr set(ccx);
00586     XPCJSRuntime* rt = ccx.GetRuntime();
00587 
00588     ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
00589     if(!map)
00590         return nsnull;
00591 
00592     {   // scoped lock
00593         XPCAutoLock lock(rt->GetMapLock());
00594         set = map->Find(classInfo);
00595     }
00596 
00597     if(set)
00598         return set;
00599 
00600     nsIID** iidArray = nsnull;
00601     AutoMarkingNativeInterfacePtrArrayPtr interfaceArray(ccx);
00602     PRUint32 iidCount = 0;
00603 
00604     if(NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray)))
00605     {
00606         // Note: I'm making it OK for this call to fail so that one can add
00607         // nsIClassInfo to classes implemented in script without requiring this
00608         // method to be implemented.
00609 
00610         // Make sure these are set correctly...
00611         iidArray = nsnull;
00612         iidCount = 0;
00613     }
00614 
00615     NS_ASSERTION((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array");
00616 
00617     // !!! from here on we only exit through the 'out' label !!!
00618 
00619     if(iidCount)
00620     {
00621         AutoMarkingNativeInterfacePtrArrayPtr
00622             arr(ccx, new XPCNativeInterface*[iidCount], iidCount, PR_TRUE);
00623         if (!arr)
00624             goto out;
00625 
00626         interfaceArray = arr;
00627 
00628         XPCNativeInterface** currentInterface = interfaceArray;
00629         nsIID**              currentIID = iidArray;
00630         PRUint16             interfaceCount = 0;
00631 
00632         for(PRUint32 i = 0; i < iidCount; i++)
00633         {
00634             nsIID* iid = *(currentIID++);
00635             if (!iid) {
00636                 NS_ERROR("Null found in classinfo interface list");
00637                 continue;
00638             }
00639 
00640             XPCNativeInterface* iface =
00641                 XPCNativeInterface::GetNewOrUsed(ccx, iid);
00642 
00643             if(!iface)
00644             {
00645                 // XXX warn here
00646                 continue;
00647             }
00648 
00649             *(currentInterface++) = iface;
00650             interfaceCount++;
00651         }
00652 
00653         if(interfaceCount)
00654         {
00655             set = NewInstance(ccx, interfaceArray, interfaceCount);
00656             if(set)
00657             {
00658                 NativeSetMap* map2 = rt->GetNativeSetMap();
00659                 if(!map2)
00660                     goto out;
00661 
00662                 XPCNativeSetKey key(set, nsnull, 0);
00663 
00664                 {   // scoped lock
00665                     XPCAutoLock lock(rt->GetMapLock());
00666                     XPCNativeSet* set2 = map2->Add(&key, set);
00667                     if(!set2)
00668                     {
00669                         NS_ERROR("failed to add our set!");
00670                         DestroyInstance(set);
00671                         set = nsnull;
00672                         goto out;
00673                     }
00674                     if(set2 != set)
00675                     {
00676                         DestroyInstance(set);
00677                         set = set2;
00678                     }
00679                 }
00680             }
00681         }
00682         else
00683             set = GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
00684     }
00685     else
00686         set = GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
00687 
00688     if(set)
00689     {   // scoped lock
00690         XPCAutoLock lock(rt->GetMapLock());
00691         XPCNativeSet* set2 = map->Add(classInfo, set);
00692         NS_ASSERTION(set2, "failed to add our set!");
00693         NS_ASSERTION(set2 == set, "hashtables inconsistent!");
00694     }
00695 
00696 out:
00697     if(iidArray)
00698         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
00699     if(interfaceArray)
00700         delete [] interfaceArray.get();
00701 
00702     return set;
00703 }
00704 
00705 // static 
00706 void 
00707 XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
00708 {
00709     XPCJSRuntime* rt;
00710     ClassInfo2NativeSetMap* map;
00711     
00712     if(nsnull != (rt = nsXPConnect::GetRuntime()) && 
00713        nsnull != (map = rt->GetClassInfo2NativeSetMap()))
00714     {   // scoped lock
00715         XPCAutoLock lock(rt->GetMapLock());
00716         map->Remove(classInfo);
00717     }
00718 }
00719 
00720 // static
00721 XPCNativeSet*
00722 XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx,
00723                            XPCNativeSet* otherSet,
00724                            XPCNativeInterface* newInterface,
00725                            PRUint16 position)
00726 {
00727     AutoMarkingNativeSetPtr set(ccx);
00728     XPCJSRuntime* rt = ccx.GetRuntime();
00729     NativeSetMap* map = rt->GetNativeSetMap();
00730     if(!map)
00731         return nsnull;
00732 
00733     XPCNativeSetKey key(otherSet, newInterface, position);
00734 
00735     {   // scoped lock
00736         XPCAutoLock lock(rt->GetMapLock());
00737         set = map->Find(&key);
00738     }
00739 
00740     if(set)
00741         return set;
00742 
00743     if(otherSet)
00744         set = NewInstanceMutate(otherSet, newInterface, position);
00745     else
00746         set = NewInstance(ccx, &newInterface, 1);
00747 
00748     if(!set)
00749         return nsnull;
00750 
00751     {   // scoped lock
00752         XPCAutoLock lock(rt->GetMapLock());
00753         XPCNativeSet* set2 = map->Add(&key, set);
00754         if(!set2)
00755         {
00756             NS_ERROR("failed to add our set!");
00757             DestroyInstance(set);
00758             set = nsnull;
00759         }
00760         else if(set2 != set)
00761         {
00762             DestroyInstance(set);
00763             set = set2;
00764         }
00765     }
00766 
00767     return set;
00768 }
00769 
00770 // static
00771 XPCNativeSet*
00772 XPCNativeSet::NewInstance(XPCCallContext& ccx,
00773                           XPCNativeInterface** array,
00774                           PRUint16 count)
00775 {
00776     XPCNativeSet* obj = nsnull;
00777 
00778     if(!array || !count)
00779         return nsnull;
00780 
00781     // We impose the invariant:
00782     // "All sets have exactly one nsISupports interface and it comes first."
00783     // This is the place where we impose that rule - even if given inputs
00784     // that don't exactly follow the rule.
00785 
00786     XPCNativeInterface* isup = XPCNativeInterface::GetISupports(ccx);
00787     PRUint16 slots = count+1;
00788 
00789     PRUint16 i;
00790     XPCNativeInterface** pcur;
00791 
00792     for(i = 0, pcur = array; i < count; i++, pcur++)
00793     {
00794         if(*pcur == isup)
00795             slots--;
00796     }
00797 
00798     // Use placement new to create an object with the right amount of space
00799     // to hold the members array
00800     int size = sizeof(XPCNativeSet);
00801     if(slots > 1)
00802         size += (slots - 1) * sizeof(XPCNativeInterface*);
00803     void* place = new char[size];
00804     if(place)
00805         obj = new(place) XPCNativeSet();
00806 
00807     if(obj)
00808     {
00809         // Stick the nsISupports in front and skip additional nsISupport(s)
00810         XPCNativeInterface** inp = array;
00811         XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces;
00812         PRUint16 memberCount = 1;   // for the one member in nsISupports
00813 
00814         *(outp++) = isup;
00815 
00816         for(i = 0; i < count; i++)
00817         {
00818             XPCNativeInterface* cur;
00819 
00820             if(isup == (cur = *(inp++)))
00821                 continue;
00822             *(outp++) = cur;
00823             memberCount += cur->GetMemberCount();
00824         }
00825         obj->mMemberCount = memberCount;
00826         obj->mInterfaceCount = slots;
00827     }
00828 
00829     return obj;
00830 }
00831 
00832 // static
00833 XPCNativeSet*
00834 XPCNativeSet::NewInstanceMutate(XPCNativeSet*       otherSet,
00835                                 XPCNativeInterface* newInterface,
00836                                 PRUint16            position)
00837 {
00838     XPCNativeSet* obj = nsnull;
00839 
00840     if(!newInterface)
00841         return nsnull;
00842     if(otherSet && position > otherSet->mInterfaceCount)
00843         return nsnull;
00844 
00845     // Use placement new to create an object with the right amount of space
00846     // to hold the members array
00847     int size = sizeof(XPCNativeSet);
00848     if(otherSet)
00849         size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
00850     void* place = new char[size];
00851     if(place)
00852         obj = new(place) XPCNativeSet();
00853 
00854     if(obj)
00855     {
00856         if(otherSet)
00857         {
00858             obj->mMemberCount = otherSet->GetMemberCount() +
00859                                 newInterface->GetMemberCount();
00860             obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
00861 
00862             XPCNativeInterface** src = otherSet->mInterfaces;
00863             XPCNativeInterface** dest = obj->mInterfaces;
00864             for(PRUint16 i = 0; i < obj->mInterfaceCount; i++)
00865             {
00866                 if(i == position)
00867                     *dest++ = newInterface;
00868                 else
00869                     *dest++ = *src++;
00870             }
00871         }
00872         else
00873         {
00874             obj->mMemberCount = newInterface->GetMemberCount();
00875             obj->mInterfaceCount = 1;
00876             obj->mInterfaces[0] = newInterface;
00877         }
00878     }
00879 
00880     return obj;
00881 }
00882 
00883 // static
00884 void
00885 XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
00886 {
00887     inst->~XPCNativeSet();
00888     delete [] (char*) inst;
00889 }
00890 
00891 void
00892 XPCNativeSet::DebugDump(PRInt16 depth)
00893 {
00894 #ifdef DEBUG
00895     depth--;
00896     XPC_LOG_ALWAYS(("XPCNativeSet @ %x", this));
00897         XPC_LOG_INDENT();
00898 
00899         XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount));
00900         if(depth)
00901         {
00902             for(PRUint16 i = 0; i < mInterfaceCount; i++)
00903                 mInterfaces[i]->DebugDump(depth);
00904         }
00905         XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount));
00906         XPC_LOG_OUTDENT();
00907 #endif
00908 }