michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=99: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Manage the shared info about interfaces for use by wrappedNatives. */ michael@0: michael@0: #include "xpcprivate.h" michael@0: #include "jswrapper.h" michael@0: #include "nsCxPusher.h" michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/XPTInterfaceInfoManager.h" michael@0: michael@0: using namespace JS; michael@0: using namespace mozilla; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: // XPCNativeMember michael@0: michael@0: // static michael@0: bool michael@0: XPCNativeMember::GetCallInfo(JSObject* funobj, michael@0: XPCNativeInterface** pInterface, michael@0: XPCNativeMember** pMember) michael@0: { michael@0: funobj = js::UncheckedUnwrap(funobj); michael@0: jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0); michael@0: jsval memberVal = js::GetFunctionNativeReserved(funobj, 1); michael@0: michael@0: *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal); michael@0: *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: XPCNativeMember::NewFunctionObject(XPCCallContext& ccx, michael@0: XPCNativeInterface* iface, HandleObject parent, michael@0: jsval* pval) michael@0: { michael@0: MOZ_ASSERT(!IsConstant(), "Only call this if you're sure this is not a constant!"); michael@0: michael@0: return Resolve(ccx, iface, parent, pval); michael@0: } michael@0: michael@0: bool michael@0: XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface, michael@0: HandleObject parent, jsval *vp) michael@0: { michael@0: if (IsConstant()) { michael@0: const nsXPTConstant* constant; michael@0: if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant))) michael@0: return false; michael@0: michael@0: const nsXPTCMiniVariant& mv = *constant->GetValue(); michael@0: michael@0: // XXX Big Hack! michael@0: nsXPTCVariant v; michael@0: v.flags = 0; michael@0: v.type = constant->GetType(); michael@0: memcpy(&v.val, &mv.val, sizeof(mv.val)); michael@0: michael@0: RootedValue resultVal(ccx); michael@0: michael@0: if (!XPCConvert::NativeData2JS(&resultVal, &v.val, v.type, nullptr, nullptr)) michael@0: return false; michael@0: michael@0: *vp = resultVal; michael@0: michael@0: return true; michael@0: } michael@0: // else... michael@0: michael@0: // This is a method or attribute - we'll be needing a function object michael@0: michael@0: int argc; michael@0: JSNative callback; michael@0: michael@0: if (IsMethod()) { michael@0: const nsXPTMethodInfo* info; michael@0: if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info))) michael@0: return false; michael@0: michael@0: // Note: ASSUMES that retval is last arg. michael@0: argc = (int) info->GetParamCount(); michael@0: if (argc && info->GetParam((uint8_t)(argc-1)).IsRetval()) michael@0: argc-- ; michael@0: michael@0: callback = XPC_WN_CallMethod; michael@0: } else { michael@0: argc = 0; michael@0: callback = XPC_WN_GetterSetter; michael@0: } michael@0: michael@0: JSFunction *fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, parent, GetName()); michael@0: if (!fun) michael@0: return false; michael@0: michael@0: JSObject* funobj = JS_GetFunctionObject(fun); michael@0: if (!funobj) michael@0: return false; michael@0: michael@0: js::SetFunctionNativeReserved(funobj, 0, PRIVATE_TO_JSVAL(iface)); michael@0: js::SetFunctionNativeReserved(funobj, 1, PRIVATE_TO_JSVAL(this)); michael@0: michael@0: *vp = OBJECT_TO_JSVAL(funobj); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /***************************************************************************/ michael@0: // XPCNativeInterface michael@0: michael@0: // static michael@0: XPCNativeInterface* michael@0: XPCNativeInterface::GetNewOrUsed(const nsIID* iid) michael@0: { michael@0: AutoJSContext cx; michael@0: AutoMarkingNativeInterfacePtr iface(cx); michael@0: XPCJSRuntime* rt = XPCJSRuntime::Get(); michael@0: michael@0: IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); michael@0: if (!map) michael@0: return nullptr; michael@0: michael@0: iface = map->Find(*iid); michael@0: michael@0: if (iface) michael@0: return iface; michael@0: michael@0: nsCOMPtr info; michael@0: XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(iid, getter_AddRefs(info)); michael@0: if (!info) michael@0: return nullptr; michael@0: michael@0: iface = NewInstance(info); michael@0: if (!iface) michael@0: return nullptr; michael@0: michael@0: XPCNativeInterface* iface2 = map->Add(iface); michael@0: if (!iface2) { michael@0: NS_ERROR("failed to add our interface!"); michael@0: DestroyInstance(iface); michael@0: iface = nullptr; michael@0: } else if (iface2 != iface) { michael@0: DestroyInstance(iface); michael@0: iface = iface2; michael@0: } michael@0: michael@0: return iface; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeInterface* michael@0: XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info) michael@0: { michael@0: AutoJSContext cx; michael@0: AutoMarkingNativeInterfacePtr iface(cx); michael@0: michael@0: const nsIID* iid; michael@0: if (NS_FAILED(info->GetIIDShared(&iid)) || !iid) michael@0: return nullptr; michael@0: michael@0: XPCJSRuntime* rt = XPCJSRuntime::Get(); michael@0: michael@0: IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); michael@0: if (!map) michael@0: return nullptr; michael@0: michael@0: iface = map->Find(*iid); michael@0: michael@0: if (iface) michael@0: return iface; michael@0: michael@0: iface = NewInstance(info); michael@0: if (!iface) michael@0: return nullptr; michael@0: michael@0: XPCNativeInterface* iface2 = map->Add(iface); michael@0: if (!iface2) { michael@0: NS_ERROR("failed to add our interface!"); michael@0: DestroyInstance(iface); michael@0: iface = nullptr; michael@0: } else if (iface2 != iface) { michael@0: DestroyInstance(iface); michael@0: iface = iface2; michael@0: } michael@0: michael@0: return iface; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeInterface* michael@0: XPCNativeInterface::GetNewOrUsed(const char* name) michael@0: { michael@0: nsCOMPtr info; michael@0: XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, getter_AddRefs(info)); michael@0: return info ? GetNewOrUsed(info) : nullptr; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeInterface* michael@0: XPCNativeInterface::GetISupports() michael@0: { michael@0: // XXX We should optimize this to cache this common XPCNativeInterface. michael@0: return GetNewOrUsed(&NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: // static michael@0: XPCNativeInterface* michael@0: XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo) michael@0: { michael@0: AutoJSContext cx; michael@0: static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16; michael@0: XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT]; michael@0: XPCNativeInterface* obj = nullptr; michael@0: XPCNativeMember* members = nullptr; michael@0: michael@0: int i; michael@0: bool failed = false; michael@0: uint16_t constCount; michael@0: uint16_t methodCount; michael@0: uint16_t totalCount; michael@0: uint16_t realTotalCount = 0; michael@0: XPCNativeMember* cur; michael@0: RootedString str(cx); michael@0: RootedId interfaceName(cx); michael@0: michael@0: // XXX Investigate lazy init? This is a problem given the michael@0: // 'placement new' scheme - we need to at least know how big to make michael@0: // the object. We might do a scan of methods to determine needed size, michael@0: // then make our object, but avoid init'ing *any* members until asked? michael@0: // Find out how often we create these objects w/o really looking at michael@0: // (or using) the members. michael@0: michael@0: bool canScript; michael@0: if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript) michael@0: return nullptr; michael@0: michael@0: if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) || michael@0: NS_FAILED(aInfo->GetConstantCount(&constCount))) michael@0: return nullptr; michael@0: michael@0: // If the interface does not have nsISupports in its inheritance chain michael@0: // then we know we can't reflect its methods. However, some interfaces that michael@0: // are used just to reflect constants are declared this way. We need to michael@0: // go ahead and build the thing. But, we'll ignore whatever methods it may michael@0: // have. michael@0: if (!nsXPConnect::IsISupportsDescendant(aInfo)) michael@0: methodCount = 0; michael@0: michael@0: totalCount = methodCount + constCount; michael@0: michael@0: if (totalCount > MAX_LOCAL_MEMBER_COUNT) { michael@0: members = new XPCNativeMember[totalCount]; michael@0: if (!members) michael@0: return nullptr; michael@0: } else { michael@0: members = local_members; michael@0: } michael@0: michael@0: // NOTE: since getters and setters share a member, we might not use all michael@0: // of the member objects. michael@0: michael@0: for (i = 0; i < methodCount; i++) { michael@0: const nsXPTMethodInfo* info; michael@0: if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) { michael@0: failed = true; michael@0: break; michael@0: } michael@0: michael@0: // don't reflect Addref or Release michael@0: if (i == 1 || i == 2) michael@0: continue; michael@0: michael@0: if (!XPCConvert::IsMethodReflectable(*info)) michael@0: continue; michael@0: michael@0: str = JS_InternString(cx, info->GetName()); michael@0: if (!str) { michael@0: NS_ERROR("bad method name"); michael@0: failed = true; michael@0: break; michael@0: } michael@0: jsid name = INTERNED_STRING_TO_JSID(cx, str); michael@0: michael@0: if (info->IsSetter()) { michael@0: MOZ_ASSERT(realTotalCount,"bad setter"); michael@0: // Note: ASSUMES Getter/Setter pairs are next to each other michael@0: // This is a rule of the typelib spec. michael@0: cur = &members[realTotalCount-1]; michael@0: MOZ_ASSERT(cur->GetName() == name,"bad setter"); michael@0: MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter"); michael@0: MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter"); michael@0: cur->SetWritableAttribute(); michael@0: } else { michael@0: // XXX need better way to find dups michael@0: // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name"); michael@0: cur = &members[realTotalCount++]; michael@0: cur->SetName(name); michael@0: if (info->IsGetter()) michael@0: cur->SetReadOnlyAttribute(i); michael@0: else michael@0: cur->SetMethod(i); michael@0: } michael@0: } michael@0: michael@0: if (!failed) { michael@0: for (i = 0; i < constCount; i++) { michael@0: const nsXPTConstant* constant; michael@0: if (NS_FAILED(aInfo->GetConstant(i, &constant))) { michael@0: failed = true; michael@0: break; michael@0: } michael@0: michael@0: str = JS_InternString(cx, constant->GetName()); michael@0: if (!str) { michael@0: NS_ERROR("bad constant name"); michael@0: failed = true; michael@0: break; michael@0: } michael@0: jsid name = INTERNED_STRING_TO_JSID(cx, str); michael@0: michael@0: // XXX need better way to find dups michael@0: //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name"); michael@0: michael@0: cur = &members[realTotalCount++]; michael@0: cur->SetName(name); michael@0: cur->SetConstant(i); michael@0: } michael@0: } michael@0: michael@0: if (!failed) { michael@0: const char* bytes; michael@0: if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes || michael@0: nullptr == (str = JS_InternString(cx, bytes))) { michael@0: failed = true; michael@0: } michael@0: interfaceName = INTERNED_STRING_TO_JSID(cx, str); michael@0: } michael@0: michael@0: if (!failed) { michael@0: // Use placement new to create an object with the right amount of space michael@0: // to hold the members array michael@0: int size = sizeof(XPCNativeInterface); michael@0: if (realTotalCount > 1) michael@0: size += (realTotalCount - 1) * sizeof(XPCNativeMember); michael@0: void* place = new char[size]; michael@0: if (place) michael@0: obj = new(place) XPCNativeInterface(aInfo, interfaceName); michael@0: michael@0: if (obj) { michael@0: obj->mMemberCount = realTotalCount; michael@0: // copy valid members michael@0: if (realTotalCount) michael@0: memcpy(obj->mMembers, members, michael@0: realTotalCount * sizeof(XPCNativeMember)); michael@0: } michael@0: } michael@0: michael@0: if (members && members != local_members) michael@0: delete [] members; michael@0: michael@0: return obj; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst) michael@0: { michael@0: inst->~XPCNativeInterface(); michael@0: delete [] (char*) inst; michael@0: } michael@0: michael@0: size_t michael@0: XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) michael@0: { michael@0: return mallocSizeOf(this); michael@0: } michael@0: michael@0: void michael@0: XPCNativeInterface::DebugDump(int16_t depth) michael@0: { michael@0: #ifdef DEBUG michael@0: depth--; michael@0: XPC_LOG_ALWAYS(("XPCNativeInterface @ %x", this)); michael@0: XPC_LOG_INDENT(); michael@0: XPC_LOG_ALWAYS(("name is %s", GetNameString())); michael@0: XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount)); michael@0: XPC_LOG_ALWAYS(("mInfo @ %x", mInfo.get())); michael@0: XPC_LOG_OUTDENT(); michael@0: #endif michael@0: } michael@0: michael@0: /***************************************************************************/ michael@0: // XPCNativeSet michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::GetNewOrUsed(const nsIID* iid) michael@0: { michael@0: AutoJSContext cx; michael@0: AutoMarkingNativeSetPtr set(cx); michael@0: michael@0: AutoMarkingNativeInterfacePtr iface(cx); michael@0: iface = XPCNativeInterface::GetNewOrUsed(iid); michael@0: if (!iface) michael@0: return nullptr; michael@0: michael@0: XPCNativeSetKey key(nullptr, iface, 0); michael@0: michael@0: XPCJSRuntime* rt = XPCJSRuntime::Get(); michael@0: NativeSetMap* map = rt->GetNativeSetMap(); michael@0: if (!map) michael@0: return nullptr; michael@0: michael@0: set = map->Find(&key); michael@0: michael@0: if (set) michael@0: return set; michael@0: michael@0: // hacky way to get a XPCNativeInterface** using the AutoPtr michael@0: XPCNativeInterface* temp[] = {iface}; michael@0: set = NewInstance(temp, 1); michael@0: if (!set) michael@0: return nullptr; michael@0: michael@0: XPCNativeSet* set2 = map->Add(&key, set); michael@0: if (!set2) { michael@0: NS_ERROR("failed to add our set!"); michael@0: DestroyInstance(set); michael@0: set = nullptr; michael@0: } else if (set2 != set) { michael@0: DestroyInstance(set); michael@0: set = set2; michael@0: } michael@0: michael@0: return set; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo) michael@0: { michael@0: AutoJSContext cx; michael@0: AutoMarkingNativeSetPtr set(cx); michael@0: XPCJSRuntime* rt = XPCJSRuntime::Get(); michael@0: michael@0: ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap(); michael@0: if (!map) michael@0: return nullptr; michael@0: michael@0: set = map->Find(classInfo); michael@0: michael@0: if (set) michael@0: return set; michael@0: michael@0: nsIID** iidArray = nullptr; michael@0: AutoMarkingNativeInterfacePtrArrayPtr interfaceArray(cx); michael@0: uint32_t iidCount = 0; michael@0: michael@0: if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) { michael@0: // Note: I'm making it OK for this call to fail so that one can add michael@0: // nsIClassInfo to classes implemented in script without requiring this michael@0: // method to be implemented. michael@0: michael@0: // Make sure these are set correctly... michael@0: iidArray = nullptr; michael@0: iidCount = 0; michael@0: } michael@0: michael@0: MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array"); michael@0: michael@0: // !!! from here on we only exit through the 'out' label !!! michael@0: michael@0: if (iidCount) { michael@0: AutoMarkingNativeInterfacePtrArrayPtr michael@0: arr(cx, new XPCNativeInterface*[iidCount], iidCount, true); michael@0: michael@0: interfaceArray = arr; michael@0: michael@0: XPCNativeInterface** currentInterface = interfaceArray; michael@0: nsIID** currentIID = iidArray; michael@0: uint16_t interfaceCount = 0; michael@0: michael@0: for (uint32_t i = 0; i < iidCount; i++) { michael@0: nsIID* iid = *(currentIID++); michael@0: if (!iid) { michael@0: NS_ERROR("Null found in classinfo interface list"); michael@0: continue; michael@0: } michael@0: michael@0: XPCNativeInterface* iface = michael@0: XPCNativeInterface::GetNewOrUsed(iid); michael@0: michael@0: if (!iface) { michael@0: // XXX warn here michael@0: continue; michael@0: } michael@0: michael@0: *(currentInterface++) = iface; michael@0: interfaceCount++; michael@0: } michael@0: michael@0: if (interfaceCount) { michael@0: set = NewInstance(interfaceArray, interfaceCount); michael@0: if (set) { michael@0: NativeSetMap* map2 = rt->GetNativeSetMap(); michael@0: if (!map2) michael@0: goto out; michael@0: michael@0: XPCNativeSetKey key(set, nullptr, 0); michael@0: michael@0: XPCNativeSet* set2 = map2->Add(&key, set); michael@0: if (!set2) { michael@0: NS_ERROR("failed to add our set!"); michael@0: DestroyInstance(set); michael@0: set = nullptr; michael@0: goto out; michael@0: } michael@0: if (set2 != set) { michael@0: DestroyInstance(set); michael@0: set = set2; michael@0: } michael@0: } michael@0: } else michael@0: set = GetNewOrUsed(&NS_GET_IID(nsISupports)); michael@0: } else michael@0: set = GetNewOrUsed(&NS_GET_IID(nsISupports)); michael@0: michael@0: if (set) { michael@0: #ifdef DEBUG michael@0: XPCNativeSet* set2 = michael@0: #endif michael@0: map->Add(classInfo, set); michael@0: MOZ_ASSERT(set2, "failed to add our set!"); michael@0: MOZ_ASSERT(set2 == set, "hashtables inconsistent!"); michael@0: } michael@0: michael@0: out: michael@0: if (iidArray) michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray); michael@0: if (interfaceArray) michael@0: delete [] interfaceArray.get(); michael@0: michael@0: return set; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo) michael@0: { michael@0: XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); michael@0: ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap(); michael@0: if (map) michael@0: map->Remove(classInfo); michael@0: } michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::GetNewOrUsed(XPCNativeSet* otherSet, michael@0: XPCNativeInterface* newInterface, michael@0: uint16_t position) michael@0: { michael@0: AutoJSContext cx; michael@0: AutoMarkingNativeSetPtr set(cx); michael@0: XPCJSRuntime* rt = XPCJSRuntime::Get(); michael@0: NativeSetMap* map = rt->GetNativeSetMap(); michael@0: if (!map) michael@0: return nullptr; michael@0: michael@0: XPCNativeSetKey key(otherSet, newInterface, position); michael@0: michael@0: set = map->Find(&key); michael@0: michael@0: if (set) michael@0: return set; michael@0: michael@0: if (otherSet) michael@0: set = NewInstanceMutate(otherSet, newInterface, position); michael@0: else michael@0: set = NewInstance(&newInterface, 1); michael@0: michael@0: if (!set) michael@0: return nullptr; michael@0: michael@0: XPCNativeSet* set2 = map->Add(&key, set); michael@0: if (!set2) { michael@0: NS_ERROR("failed to add our set!"); michael@0: DestroyInstance(set); michael@0: set = nullptr; michael@0: } else if (set2 != set) { michael@0: DestroyInstance(set); michael@0: set = set2; michael@0: } michael@0: michael@0: return set; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet, michael@0: XPCNativeSet* secondSet, michael@0: bool preserveFirstSetOrder) michael@0: { michael@0: // Figure out how many interfaces we'll need in the new set. michael@0: uint32_t uniqueCount = firstSet->mInterfaceCount; michael@0: for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { michael@0: if (!firstSet->HasInterface(secondSet->mInterfaces[i])) michael@0: uniqueCount++; michael@0: } michael@0: michael@0: // If everything in secondSet was a duplicate, we can just use the first michael@0: // set. michael@0: if (uniqueCount == firstSet->mInterfaceCount) michael@0: return firstSet; michael@0: michael@0: // If the secondSet is just a superset of the first, we can use it provided michael@0: // that the caller doesn't care about ordering. michael@0: if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount) michael@0: return secondSet; michael@0: michael@0: // Ok, darn. Now we have to make a new set. michael@0: // michael@0: // It would be faster to just create the new set all at once, but that michael@0: // would involve wrangling with some pretty hairy code - especially since michael@0: // a lot of stuff assumes that sets are created by adding one interface to an michael@0: // existing set. So let's just do the slow and easy thing and hope that the michael@0: // above optimizations handle the common cases. michael@0: XPCNativeSet* currentSet = firstSet; michael@0: for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { michael@0: XPCNativeInterface* iface = secondSet->mInterfaces[i]; michael@0: if (!currentSet->HasInterface(iface)) { michael@0: // Create a new augmented set, inserting this interface at the end. michael@0: uint32_t pos = currentSet->mInterfaceCount; michael@0: currentSet = XPCNativeSet::GetNewOrUsed(currentSet, iface, pos); michael@0: if (!currentSet) michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: // We've got the union set. Hand it back to the caller. michael@0: MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount); michael@0: return currentSet; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::NewInstance(XPCNativeInterface** array, michael@0: uint16_t count) michael@0: { michael@0: XPCNativeSet* obj = nullptr; michael@0: michael@0: if (!array || !count) michael@0: return nullptr; michael@0: michael@0: // We impose the invariant: michael@0: // "All sets have exactly one nsISupports interface and it comes first." michael@0: // This is the place where we impose that rule - even if given inputs michael@0: // that don't exactly follow the rule. michael@0: michael@0: XPCNativeInterface* isup = XPCNativeInterface::GetISupports(); michael@0: uint16_t slots = count+1; michael@0: michael@0: uint16_t i; michael@0: XPCNativeInterface** pcur; michael@0: michael@0: for (i = 0, pcur = array; i < count; i++, pcur++) { michael@0: if (*pcur == isup) michael@0: slots--; michael@0: } michael@0: michael@0: // Use placement new to create an object with the right amount of space michael@0: // to hold the members array michael@0: int size = sizeof(XPCNativeSet); michael@0: if (slots > 1) michael@0: size += (slots - 1) * sizeof(XPCNativeInterface*); michael@0: void* place = new char[size]; michael@0: if (place) michael@0: obj = new(place) XPCNativeSet(); michael@0: michael@0: if (obj) { michael@0: // Stick the nsISupports in front and skip additional nsISupport(s) michael@0: XPCNativeInterface** inp = array; michael@0: XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces; michael@0: uint16_t memberCount = 1; // for the one member in nsISupports michael@0: michael@0: *(outp++) = isup; michael@0: michael@0: for (i = 0; i < count; i++) { michael@0: XPCNativeInterface* cur; michael@0: michael@0: if (isup == (cur = *(inp++))) michael@0: continue; michael@0: *(outp++) = cur; michael@0: memberCount += cur->GetMemberCount(); michael@0: } michael@0: obj->mMemberCount = memberCount; michael@0: obj->mInterfaceCount = slots; michael@0: } michael@0: michael@0: return obj; michael@0: } michael@0: michael@0: // static michael@0: XPCNativeSet* michael@0: XPCNativeSet::NewInstanceMutate(XPCNativeSet* otherSet, michael@0: XPCNativeInterface* newInterface, michael@0: uint16_t position) michael@0: { michael@0: XPCNativeSet* obj = nullptr; michael@0: michael@0: if (!newInterface) michael@0: return nullptr; michael@0: if (otherSet && position > otherSet->mInterfaceCount) michael@0: return nullptr; michael@0: michael@0: // Use placement new to create an object with the right amount of space michael@0: // to hold the members array michael@0: int size = sizeof(XPCNativeSet); michael@0: if (otherSet) michael@0: size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*); michael@0: void* place = new char[size]; michael@0: if (place) michael@0: obj = new(place) XPCNativeSet(); michael@0: michael@0: if (obj) { michael@0: if (otherSet) { michael@0: obj->mMemberCount = otherSet->GetMemberCount() + michael@0: newInterface->GetMemberCount(); michael@0: obj->mInterfaceCount = otherSet->mInterfaceCount + 1; michael@0: michael@0: XPCNativeInterface** src = otherSet->mInterfaces; michael@0: XPCNativeInterface** dest = obj->mInterfaces; michael@0: for (uint16_t i = 0; i < obj->mInterfaceCount; i++) { michael@0: if (i == position) michael@0: *dest++ = newInterface; michael@0: else michael@0: *dest++ = *src++; michael@0: } michael@0: } else { michael@0: obj->mMemberCount = newInterface->GetMemberCount(); michael@0: obj->mInterfaceCount = 1; michael@0: obj->mInterfaces[0] = newInterface; michael@0: } michael@0: } michael@0: michael@0: return obj; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: XPCNativeSet::DestroyInstance(XPCNativeSet* inst) michael@0: { michael@0: inst->~XPCNativeSet(); michael@0: delete [] (char*) inst; michael@0: } michael@0: michael@0: size_t michael@0: XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) michael@0: { michael@0: return mallocSizeOf(this); michael@0: } michael@0: michael@0: void michael@0: XPCNativeSet::DebugDump(int16_t depth) michael@0: { michael@0: #ifdef DEBUG michael@0: depth--; michael@0: XPC_LOG_ALWAYS(("XPCNativeSet @ %x", this)); michael@0: XPC_LOG_INDENT(); michael@0: michael@0: XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount)); michael@0: if (depth) { michael@0: for (uint16_t i = 0; i < mInterfaceCount; i++) michael@0: mInterfaces[i]->DebugDump(depth); michael@0: } michael@0: XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount)); michael@0: XPC_LOG_OUTDENT(); michael@0: #endif michael@0: }