1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,784 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Manage the shared info about interfaces for use by wrappedNatives. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "jswrapper.h" 1.14 +#include "nsCxPusher.h" 1.15 + 1.16 +#include "mozilla/MemoryReporting.h" 1.17 +#include "mozilla/XPTInterfaceInfoManager.h" 1.18 + 1.19 +using namespace JS; 1.20 +using namespace mozilla; 1.21 + 1.22 +/***************************************************************************/ 1.23 + 1.24 +// XPCNativeMember 1.25 + 1.26 +// static 1.27 +bool 1.28 +XPCNativeMember::GetCallInfo(JSObject* funobj, 1.29 + XPCNativeInterface** pInterface, 1.30 + XPCNativeMember** pMember) 1.31 +{ 1.32 + funobj = js::UncheckedUnwrap(funobj); 1.33 + jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0); 1.34 + jsval memberVal = js::GetFunctionNativeReserved(funobj, 1); 1.35 + 1.36 + *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal); 1.37 + *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal); 1.38 + 1.39 + return true; 1.40 +} 1.41 + 1.42 +bool 1.43 +XPCNativeMember::NewFunctionObject(XPCCallContext& ccx, 1.44 + XPCNativeInterface* iface, HandleObject parent, 1.45 + jsval* pval) 1.46 +{ 1.47 + MOZ_ASSERT(!IsConstant(), "Only call this if you're sure this is not a constant!"); 1.48 + 1.49 + return Resolve(ccx, iface, parent, pval); 1.50 +} 1.51 + 1.52 +bool 1.53 +XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface, 1.54 + HandleObject parent, jsval *vp) 1.55 +{ 1.56 + if (IsConstant()) { 1.57 + const nsXPTConstant* constant; 1.58 + if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant))) 1.59 + return false; 1.60 + 1.61 + const nsXPTCMiniVariant& mv = *constant->GetValue(); 1.62 + 1.63 + // XXX Big Hack! 1.64 + nsXPTCVariant v; 1.65 + v.flags = 0; 1.66 + v.type = constant->GetType(); 1.67 + memcpy(&v.val, &mv.val, sizeof(mv.val)); 1.68 + 1.69 + RootedValue resultVal(ccx); 1.70 + 1.71 + if (!XPCConvert::NativeData2JS(&resultVal, &v.val, v.type, nullptr, nullptr)) 1.72 + return false; 1.73 + 1.74 + *vp = resultVal; 1.75 + 1.76 + return true; 1.77 + } 1.78 + // else... 1.79 + 1.80 + // This is a method or attribute - we'll be needing a function object 1.81 + 1.82 + int argc; 1.83 + JSNative callback; 1.84 + 1.85 + if (IsMethod()) { 1.86 + const nsXPTMethodInfo* info; 1.87 + if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info))) 1.88 + return false; 1.89 + 1.90 + // Note: ASSUMES that retval is last arg. 1.91 + argc = (int) info->GetParamCount(); 1.92 + if (argc && info->GetParam((uint8_t)(argc-1)).IsRetval()) 1.93 + argc-- ; 1.94 + 1.95 + callback = XPC_WN_CallMethod; 1.96 + } else { 1.97 + argc = 0; 1.98 + callback = XPC_WN_GetterSetter; 1.99 + } 1.100 + 1.101 + JSFunction *fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, parent, GetName()); 1.102 + if (!fun) 1.103 + return false; 1.104 + 1.105 + JSObject* funobj = JS_GetFunctionObject(fun); 1.106 + if (!funobj) 1.107 + return false; 1.108 + 1.109 + js::SetFunctionNativeReserved(funobj, 0, PRIVATE_TO_JSVAL(iface)); 1.110 + js::SetFunctionNativeReserved(funobj, 1, PRIVATE_TO_JSVAL(this)); 1.111 + 1.112 + *vp = OBJECT_TO_JSVAL(funobj); 1.113 + 1.114 + return true; 1.115 +} 1.116 + 1.117 +/***************************************************************************/ 1.118 +// XPCNativeInterface 1.119 + 1.120 +// static 1.121 +XPCNativeInterface* 1.122 +XPCNativeInterface::GetNewOrUsed(const nsIID* iid) 1.123 +{ 1.124 + AutoJSContext cx; 1.125 + AutoMarkingNativeInterfacePtr iface(cx); 1.126 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.127 + 1.128 + IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); 1.129 + if (!map) 1.130 + return nullptr; 1.131 + 1.132 + iface = map->Find(*iid); 1.133 + 1.134 + if (iface) 1.135 + return iface; 1.136 + 1.137 + nsCOMPtr<nsIInterfaceInfo> info; 1.138 + XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(iid, getter_AddRefs(info)); 1.139 + if (!info) 1.140 + return nullptr; 1.141 + 1.142 + iface = NewInstance(info); 1.143 + if (!iface) 1.144 + return nullptr; 1.145 + 1.146 + XPCNativeInterface* iface2 = map->Add(iface); 1.147 + if (!iface2) { 1.148 + NS_ERROR("failed to add our interface!"); 1.149 + DestroyInstance(iface); 1.150 + iface = nullptr; 1.151 + } else if (iface2 != iface) { 1.152 + DestroyInstance(iface); 1.153 + iface = iface2; 1.154 + } 1.155 + 1.156 + return iface; 1.157 +} 1.158 + 1.159 +// static 1.160 +XPCNativeInterface* 1.161 +XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info) 1.162 +{ 1.163 + AutoJSContext cx; 1.164 + AutoMarkingNativeInterfacePtr iface(cx); 1.165 + 1.166 + const nsIID* iid; 1.167 + if (NS_FAILED(info->GetIIDShared(&iid)) || !iid) 1.168 + return nullptr; 1.169 + 1.170 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.171 + 1.172 + IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); 1.173 + if (!map) 1.174 + return nullptr; 1.175 + 1.176 + iface = map->Find(*iid); 1.177 + 1.178 + if (iface) 1.179 + return iface; 1.180 + 1.181 + iface = NewInstance(info); 1.182 + if (!iface) 1.183 + return nullptr; 1.184 + 1.185 + XPCNativeInterface* iface2 = map->Add(iface); 1.186 + if (!iface2) { 1.187 + NS_ERROR("failed to add our interface!"); 1.188 + DestroyInstance(iface); 1.189 + iface = nullptr; 1.190 + } else if (iface2 != iface) { 1.191 + DestroyInstance(iface); 1.192 + iface = iface2; 1.193 + } 1.194 + 1.195 + return iface; 1.196 +} 1.197 + 1.198 +// static 1.199 +XPCNativeInterface* 1.200 +XPCNativeInterface::GetNewOrUsed(const char* name) 1.201 +{ 1.202 + nsCOMPtr<nsIInterfaceInfo> info; 1.203 + XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, getter_AddRefs(info)); 1.204 + return info ? GetNewOrUsed(info) : nullptr; 1.205 +} 1.206 + 1.207 +// static 1.208 +XPCNativeInterface* 1.209 +XPCNativeInterface::GetISupports() 1.210 +{ 1.211 + // XXX We should optimize this to cache this common XPCNativeInterface. 1.212 + return GetNewOrUsed(&NS_GET_IID(nsISupports)); 1.213 +} 1.214 + 1.215 +// static 1.216 +XPCNativeInterface* 1.217 +XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo) 1.218 +{ 1.219 + AutoJSContext cx; 1.220 + static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16; 1.221 + XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT]; 1.222 + XPCNativeInterface* obj = nullptr; 1.223 + XPCNativeMember* members = nullptr; 1.224 + 1.225 + int i; 1.226 + bool failed = false; 1.227 + uint16_t constCount; 1.228 + uint16_t methodCount; 1.229 + uint16_t totalCount; 1.230 + uint16_t realTotalCount = 0; 1.231 + XPCNativeMember* cur; 1.232 + RootedString str(cx); 1.233 + RootedId interfaceName(cx); 1.234 + 1.235 + // XXX Investigate lazy init? This is a problem given the 1.236 + // 'placement new' scheme - we need to at least know how big to make 1.237 + // the object. We might do a scan of methods to determine needed size, 1.238 + // then make our object, but avoid init'ing *any* members until asked? 1.239 + // Find out how often we create these objects w/o really looking at 1.240 + // (or using) the members. 1.241 + 1.242 + bool canScript; 1.243 + if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript) 1.244 + return nullptr; 1.245 + 1.246 + if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) || 1.247 + NS_FAILED(aInfo->GetConstantCount(&constCount))) 1.248 + return nullptr; 1.249 + 1.250 + // If the interface does not have nsISupports in its inheritance chain 1.251 + // then we know we can't reflect its methods. However, some interfaces that 1.252 + // are used just to reflect constants are declared this way. We need to 1.253 + // go ahead and build the thing. But, we'll ignore whatever methods it may 1.254 + // have. 1.255 + if (!nsXPConnect::IsISupportsDescendant(aInfo)) 1.256 + methodCount = 0; 1.257 + 1.258 + totalCount = methodCount + constCount; 1.259 + 1.260 + if (totalCount > MAX_LOCAL_MEMBER_COUNT) { 1.261 + members = new XPCNativeMember[totalCount]; 1.262 + if (!members) 1.263 + return nullptr; 1.264 + } else { 1.265 + members = local_members; 1.266 + } 1.267 + 1.268 + // NOTE: since getters and setters share a member, we might not use all 1.269 + // of the member objects. 1.270 + 1.271 + for (i = 0; i < methodCount; i++) { 1.272 + const nsXPTMethodInfo* info; 1.273 + if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) { 1.274 + failed = true; 1.275 + break; 1.276 + } 1.277 + 1.278 + // don't reflect Addref or Release 1.279 + if (i == 1 || i == 2) 1.280 + continue; 1.281 + 1.282 + if (!XPCConvert::IsMethodReflectable(*info)) 1.283 + continue; 1.284 + 1.285 + str = JS_InternString(cx, info->GetName()); 1.286 + if (!str) { 1.287 + NS_ERROR("bad method name"); 1.288 + failed = true; 1.289 + break; 1.290 + } 1.291 + jsid name = INTERNED_STRING_TO_JSID(cx, str); 1.292 + 1.293 + if (info->IsSetter()) { 1.294 + MOZ_ASSERT(realTotalCount,"bad setter"); 1.295 + // Note: ASSUMES Getter/Setter pairs are next to each other 1.296 + // This is a rule of the typelib spec. 1.297 + cur = &members[realTotalCount-1]; 1.298 + MOZ_ASSERT(cur->GetName() == name,"bad setter"); 1.299 + MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter"); 1.300 + MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter"); 1.301 + cur->SetWritableAttribute(); 1.302 + } else { 1.303 + // XXX need better way to find dups 1.304 + // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name"); 1.305 + cur = &members[realTotalCount++]; 1.306 + cur->SetName(name); 1.307 + if (info->IsGetter()) 1.308 + cur->SetReadOnlyAttribute(i); 1.309 + else 1.310 + cur->SetMethod(i); 1.311 + } 1.312 + } 1.313 + 1.314 + if (!failed) { 1.315 + for (i = 0; i < constCount; i++) { 1.316 + const nsXPTConstant* constant; 1.317 + if (NS_FAILED(aInfo->GetConstant(i, &constant))) { 1.318 + failed = true; 1.319 + break; 1.320 + } 1.321 + 1.322 + str = JS_InternString(cx, constant->GetName()); 1.323 + if (!str) { 1.324 + NS_ERROR("bad constant name"); 1.325 + failed = true; 1.326 + break; 1.327 + } 1.328 + jsid name = INTERNED_STRING_TO_JSID(cx, str); 1.329 + 1.330 + // XXX need better way to find dups 1.331 + //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name"); 1.332 + 1.333 + cur = &members[realTotalCount++]; 1.334 + cur->SetName(name); 1.335 + cur->SetConstant(i); 1.336 + } 1.337 + } 1.338 + 1.339 + if (!failed) { 1.340 + const char* bytes; 1.341 + if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes || 1.342 + nullptr == (str = JS_InternString(cx, bytes))) { 1.343 + failed = true; 1.344 + } 1.345 + interfaceName = INTERNED_STRING_TO_JSID(cx, str); 1.346 + } 1.347 + 1.348 + if (!failed) { 1.349 + // Use placement new to create an object with the right amount of space 1.350 + // to hold the members array 1.351 + int size = sizeof(XPCNativeInterface); 1.352 + if (realTotalCount > 1) 1.353 + size += (realTotalCount - 1) * sizeof(XPCNativeMember); 1.354 + void* place = new char[size]; 1.355 + if (place) 1.356 + obj = new(place) XPCNativeInterface(aInfo, interfaceName); 1.357 + 1.358 + if (obj) { 1.359 + obj->mMemberCount = realTotalCount; 1.360 + // copy valid members 1.361 + if (realTotalCount) 1.362 + memcpy(obj->mMembers, members, 1.363 + realTotalCount * sizeof(XPCNativeMember)); 1.364 + } 1.365 + } 1.366 + 1.367 + if (members && members != local_members) 1.368 + delete [] members; 1.369 + 1.370 + return obj; 1.371 +} 1.372 + 1.373 +// static 1.374 +void 1.375 +XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst) 1.376 +{ 1.377 + inst->~XPCNativeInterface(); 1.378 + delete [] (char*) inst; 1.379 +} 1.380 + 1.381 +size_t 1.382 +XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) 1.383 +{ 1.384 + return mallocSizeOf(this); 1.385 +} 1.386 + 1.387 +void 1.388 +XPCNativeInterface::DebugDump(int16_t depth) 1.389 +{ 1.390 +#ifdef DEBUG 1.391 + depth--; 1.392 + XPC_LOG_ALWAYS(("XPCNativeInterface @ %x", this)); 1.393 + XPC_LOG_INDENT(); 1.394 + XPC_LOG_ALWAYS(("name is %s", GetNameString())); 1.395 + XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount)); 1.396 + XPC_LOG_ALWAYS(("mInfo @ %x", mInfo.get())); 1.397 + XPC_LOG_OUTDENT(); 1.398 +#endif 1.399 +} 1.400 + 1.401 +/***************************************************************************/ 1.402 +// XPCNativeSet 1.403 + 1.404 +// static 1.405 +XPCNativeSet* 1.406 +XPCNativeSet::GetNewOrUsed(const nsIID* iid) 1.407 +{ 1.408 + AutoJSContext cx; 1.409 + AutoMarkingNativeSetPtr set(cx); 1.410 + 1.411 + AutoMarkingNativeInterfacePtr iface(cx); 1.412 + iface = XPCNativeInterface::GetNewOrUsed(iid); 1.413 + if (!iface) 1.414 + return nullptr; 1.415 + 1.416 + XPCNativeSetKey key(nullptr, iface, 0); 1.417 + 1.418 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.419 + NativeSetMap* map = rt->GetNativeSetMap(); 1.420 + if (!map) 1.421 + return nullptr; 1.422 + 1.423 + set = map->Find(&key); 1.424 + 1.425 + if (set) 1.426 + return set; 1.427 + 1.428 + // hacky way to get a XPCNativeInterface** using the AutoPtr 1.429 + XPCNativeInterface* temp[] = {iface}; 1.430 + set = NewInstance(temp, 1); 1.431 + if (!set) 1.432 + return nullptr; 1.433 + 1.434 + XPCNativeSet* set2 = map->Add(&key, set); 1.435 + if (!set2) { 1.436 + NS_ERROR("failed to add our set!"); 1.437 + DestroyInstance(set); 1.438 + set = nullptr; 1.439 + } else if (set2 != set) { 1.440 + DestroyInstance(set); 1.441 + set = set2; 1.442 + } 1.443 + 1.444 + return set; 1.445 +} 1.446 + 1.447 +// static 1.448 +XPCNativeSet* 1.449 +XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo) 1.450 +{ 1.451 + AutoJSContext cx; 1.452 + AutoMarkingNativeSetPtr set(cx); 1.453 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.454 + 1.455 + ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap(); 1.456 + if (!map) 1.457 + return nullptr; 1.458 + 1.459 + set = map->Find(classInfo); 1.460 + 1.461 + if (set) 1.462 + return set; 1.463 + 1.464 + nsIID** iidArray = nullptr; 1.465 + AutoMarkingNativeInterfacePtrArrayPtr interfaceArray(cx); 1.466 + uint32_t iidCount = 0; 1.467 + 1.468 + if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) { 1.469 + // Note: I'm making it OK for this call to fail so that one can add 1.470 + // nsIClassInfo to classes implemented in script without requiring this 1.471 + // method to be implemented. 1.472 + 1.473 + // Make sure these are set correctly... 1.474 + iidArray = nullptr; 1.475 + iidCount = 0; 1.476 + } 1.477 + 1.478 + MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array"); 1.479 + 1.480 + // !!! from here on we only exit through the 'out' label !!! 1.481 + 1.482 + if (iidCount) { 1.483 + AutoMarkingNativeInterfacePtrArrayPtr 1.484 + arr(cx, new XPCNativeInterface*[iidCount], iidCount, true); 1.485 + 1.486 + interfaceArray = arr; 1.487 + 1.488 + XPCNativeInterface** currentInterface = interfaceArray; 1.489 + nsIID** currentIID = iidArray; 1.490 + uint16_t interfaceCount = 0; 1.491 + 1.492 + for (uint32_t i = 0; i < iidCount; i++) { 1.493 + nsIID* iid = *(currentIID++); 1.494 + if (!iid) { 1.495 + NS_ERROR("Null found in classinfo interface list"); 1.496 + continue; 1.497 + } 1.498 + 1.499 + XPCNativeInterface* iface = 1.500 + XPCNativeInterface::GetNewOrUsed(iid); 1.501 + 1.502 + if (!iface) { 1.503 + // XXX warn here 1.504 + continue; 1.505 + } 1.506 + 1.507 + *(currentInterface++) = iface; 1.508 + interfaceCount++; 1.509 + } 1.510 + 1.511 + if (interfaceCount) { 1.512 + set = NewInstance(interfaceArray, interfaceCount); 1.513 + if (set) { 1.514 + NativeSetMap* map2 = rt->GetNativeSetMap(); 1.515 + if (!map2) 1.516 + goto out; 1.517 + 1.518 + XPCNativeSetKey key(set, nullptr, 0); 1.519 + 1.520 + XPCNativeSet* set2 = map2->Add(&key, set); 1.521 + if (!set2) { 1.522 + NS_ERROR("failed to add our set!"); 1.523 + DestroyInstance(set); 1.524 + set = nullptr; 1.525 + goto out; 1.526 + } 1.527 + if (set2 != set) { 1.528 + DestroyInstance(set); 1.529 + set = set2; 1.530 + } 1.531 + } 1.532 + } else 1.533 + set = GetNewOrUsed(&NS_GET_IID(nsISupports)); 1.534 + } else 1.535 + set = GetNewOrUsed(&NS_GET_IID(nsISupports)); 1.536 + 1.537 + if (set) { 1.538 +#ifdef DEBUG 1.539 + XPCNativeSet* set2 = 1.540 +#endif 1.541 + map->Add(classInfo, set); 1.542 + MOZ_ASSERT(set2, "failed to add our set!"); 1.543 + MOZ_ASSERT(set2 == set, "hashtables inconsistent!"); 1.544 + } 1.545 + 1.546 +out: 1.547 + if (iidArray) 1.548 + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray); 1.549 + if (interfaceArray) 1.550 + delete [] interfaceArray.get(); 1.551 + 1.552 + return set; 1.553 +} 1.554 + 1.555 +// static 1.556 +void 1.557 +XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo) 1.558 +{ 1.559 + XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); 1.560 + ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap(); 1.561 + if (map) 1.562 + map->Remove(classInfo); 1.563 +} 1.564 + 1.565 +// static 1.566 +XPCNativeSet* 1.567 +XPCNativeSet::GetNewOrUsed(XPCNativeSet* otherSet, 1.568 + XPCNativeInterface* newInterface, 1.569 + uint16_t position) 1.570 +{ 1.571 + AutoJSContext cx; 1.572 + AutoMarkingNativeSetPtr set(cx); 1.573 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.574 + NativeSetMap* map = rt->GetNativeSetMap(); 1.575 + if (!map) 1.576 + return nullptr; 1.577 + 1.578 + XPCNativeSetKey key(otherSet, newInterface, position); 1.579 + 1.580 + set = map->Find(&key); 1.581 + 1.582 + if (set) 1.583 + return set; 1.584 + 1.585 + if (otherSet) 1.586 + set = NewInstanceMutate(otherSet, newInterface, position); 1.587 + else 1.588 + set = NewInstance(&newInterface, 1); 1.589 + 1.590 + if (!set) 1.591 + return nullptr; 1.592 + 1.593 + XPCNativeSet* set2 = map->Add(&key, set); 1.594 + if (!set2) { 1.595 + NS_ERROR("failed to add our set!"); 1.596 + DestroyInstance(set); 1.597 + set = nullptr; 1.598 + } else if (set2 != set) { 1.599 + DestroyInstance(set); 1.600 + set = set2; 1.601 + } 1.602 + 1.603 + return set; 1.604 +} 1.605 + 1.606 +// static 1.607 +XPCNativeSet* 1.608 +XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet, 1.609 + XPCNativeSet* secondSet, 1.610 + bool preserveFirstSetOrder) 1.611 +{ 1.612 + // Figure out how many interfaces we'll need in the new set. 1.613 + uint32_t uniqueCount = firstSet->mInterfaceCount; 1.614 + for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { 1.615 + if (!firstSet->HasInterface(secondSet->mInterfaces[i])) 1.616 + uniqueCount++; 1.617 + } 1.618 + 1.619 + // If everything in secondSet was a duplicate, we can just use the first 1.620 + // set. 1.621 + if (uniqueCount == firstSet->mInterfaceCount) 1.622 + return firstSet; 1.623 + 1.624 + // If the secondSet is just a superset of the first, we can use it provided 1.625 + // that the caller doesn't care about ordering. 1.626 + if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount) 1.627 + return secondSet; 1.628 + 1.629 + // Ok, darn. Now we have to make a new set. 1.630 + // 1.631 + // It would be faster to just create the new set all at once, but that 1.632 + // would involve wrangling with some pretty hairy code - especially since 1.633 + // a lot of stuff assumes that sets are created by adding one interface to an 1.634 + // existing set. So let's just do the slow and easy thing and hope that the 1.635 + // above optimizations handle the common cases. 1.636 + XPCNativeSet* currentSet = firstSet; 1.637 + for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { 1.638 + XPCNativeInterface* iface = secondSet->mInterfaces[i]; 1.639 + if (!currentSet->HasInterface(iface)) { 1.640 + // Create a new augmented set, inserting this interface at the end. 1.641 + uint32_t pos = currentSet->mInterfaceCount; 1.642 + currentSet = XPCNativeSet::GetNewOrUsed(currentSet, iface, pos); 1.643 + if (!currentSet) 1.644 + return nullptr; 1.645 + } 1.646 + } 1.647 + 1.648 + // We've got the union set. Hand it back to the caller. 1.649 + MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount); 1.650 + return currentSet; 1.651 +} 1.652 + 1.653 +// static 1.654 +XPCNativeSet* 1.655 +XPCNativeSet::NewInstance(XPCNativeInterface** array, 1.656 + uint16_t count) 1.657 +{ 1.658 + XPCNativeSet* obj = nullptr; 1.659 + 1.660 + if (!array || !count) 1.661 + return nullptr; 1.662 + 1.663 + // We impose the invariant: 1.664 + // "All sets have exactly one nsISupports interface and it comes first." 1.665 + // This is the place where we impose that rule - even if given inputs 1.666 + // that don't exactly follow the rule. 1.667 + 1.668 + XPCNativeInterface* isup = XPCNativeInterface::GetISupports(); 1.669 + uint16_t slots = count+1; 1.670 + 1.671 + uint16_t i; 1.672 + XPCNativeInterface** pcur; 1.673 + 1.674 + for (i = 0, pcur = array; i < count; i++, pcur++) { 1.675 + if (*pcur == isup) 1.676 + slots--; 1.677 + } 1.678 + 1.679 + // Use placement new to create an object with the right amount of space 1.680 + // to hold the members array 1.681 + int size = sizeof(XPCNativeSet); 1.682 + if (slots > 1) 1.683 + size += (slots - 1) * sizeof(XPCNativeInterface*); 1.684 + void* place = new char[size]; 1.685 + if (place) 1.686 + obj = new(place) XPCNativeSet(); 1.687 + 1.688 + if (obj) { 1.689 + // Stick the nsISupports in front and skip additional nsISupport(s) 1.690 + XPCNativeInterface** inp = array; 1.691 + XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces; 1.692 + uint16_t memberCount = 1; // for the one member in nsISupports 1.693 + 1.694 + *(outp++) = isup; 1.695 + 1.696 + for (i = 0; i < count; i++) { 1.697 + XPCNativeInterface* cur; 1.698 + 1.699 + if (isup == (cur = *(inp++))) 1.700 + continue; 1.701 + *(outp++) = cur; 1.702 + memberCount += cur->GetMemberCount(); 1.703 + } 1.704 + obj->mMemberCount = memberCount; 1.705 + obj->mInterfaceCount = slots; 1.706 + } 1.707 + 1.708 + return obj; 1.709 +} 1.710 + 1.711 +// static 1.712 +XPCNativeSet* 1.713 +XPCNativeSet::NewInstanceMutate(XPCNativeSet* otherSet, 1.714 + XPCNativeInterface* newInterface, 1.715 + uint16_t position) 1.716 +{ 1.717 + XPCNativeSet* obj = nullptr; 1.718 + 1.719 + if (!newInterface) 1.720 + return nullptr; 1.721 + if (otherSet && position > otherSet->mInterfaceCount) 1.722 + return nullptr; 1.723 + 1.724 + // Use placement new to create an object with the right amount of space 1.725 + // to hold the members array 1.726 + int size = sizeof(XPCNativeSet); 1.727 + if (otherSet) 1.728 + size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*); 1.729 + void* place = new char[size]; 1.730 + if (place) 1.731 + obj = new(place) XPCNativeSet(); 1.732 + 1.733 + if (obj) { 1.734 + if (otherSet) { 1.735 + obj->mMemberCount = otherSet->GetMemberCount() + 1.736 + newInterface->GetMemberCount(); 1.737 + obj->mInterfaceCount = otherSet->mInterfaceCount + 1; 1.738 + 1.739 + XPCNativeInterface** src = otherSet->mInterfaces; 1.740 + XPCNativeInterface** dest = obj->mInterfaces; 1.741 + for (uint16_t i = 0; i < obj->mInterfaceCount; i++) { 1.742 + if (i == position) 1.743 + *dest++ = newInterface; 1.744 + else 1.745 + *dest++ = *src++; 1.746 + } 1.747 + } else { 1.748 + obj->mMemberCount = newInterface->GetMemberCount(); 1.749 + obj->mInterfaceCount = 1; 1.750 + obj->mInterfaces[0] = newInterface; 1.751 + } 1.752 + } 1.753 + 1.754 + return obj; 1.755 +} 1.756 + 1.757 +// static 1.758 +void 1.759 +XPCNativeSet::DestroyInstance(XPCNativeSet* inst) 1.760 +{ 1.761 + inst->~XPCNativeSet(); 1.762 + delete [] (char*) inst; 1.763 +} 1.764 + 1.765 +size_t 1.766 +XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) 1.767 +{ 1.768 + return mallocSizeOf(this); 1.769 +} 1.770 + 1.771 +void 1.772 +XPCNativeSet::DebugDump(int16_t depth) 1.773 +{ 1.774 +#ifdef DEBUG 1.775 + depth--; 1.776 + XPC_LOG_ALWAYS(("XPCNativeSet @ %x", this)); 1.777 + XPC_LOG_INDENT(); 1.778 + 1.779 + XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount)); 1.780 + if (depth) { 1.781 + for (uint16_t i = 0; i < mInterfaceCount; i++) 1.782 + mInterfaces[i]->DebugDump(depth); 1.783 + } 1.784 + XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount)); 1.785 + XPC_LOG_OUTDENT(); 1.786 +#endif 1.787 +}