js/xpconnect/src/XPCWrappedNativeInfo.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* Manage the shared info about interfaces for use by wrappedNatives. */
michael@0 8
michael@0 9 #include "xpcprivate.h"
michael@0 10 #include "jswrapper.h"
michael@0 11 #include "nsCxPusher.h"
michael@0 12
michael@0 13 #include "mozilla/MemoryReporting.h"
michael@0 14 #include "mozilla/XPTInterfaceInfoManager.h"
michael@0 15
michael@0 16 using namespace JS;
michael@0 17 using namespace mozilla;
michael@0 18
michael@0 19 /***************************************************************************/
michael@0 20
michael@0 21 // XPCNativeMember
michael@0 22
michael@0 23 // static
michael@0 24 bool
michael@0 25 XPCNativeMember::GetCallInfo(JSObject* funobj,
michael@0 26 XPCNativeInterface** pInterface,
michael@0 27 XPCNativeMember** pMember)
michael@0 28 {
michael@0 29 funobj = js::UncheckedUnwrap(funobj);
michael@0 30 jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0);
michael@0 31 jsval memberVal = js::GetFunctionNativeReserved(funobj, 1);
michael@0 32
michael@0 33 *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
michael@0 34 *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
michael@0 35
michael@0 36 return true;
michael@0 37 }
michael@0 38
michael@0 39 bool
michael@0 40 XPCNativeMember::NewFunctionObject(XPCCallContext& ccx,
michael@0 41 XPCNativeInterface* iface, HandleObject parent,
michael@0 42 jsval* pval)
michael@0 43 {
michael@0 44 MOZ_ASSERT(!IsConstant(), "Only call this if you're sure this is not a constant!");
michael@0 45
michael@0 46 return Resolve(ccx, iface, parent, pval);
michael@0 47 }
michael@0 48
michael@0 49 bool
michael@0 50 XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
michael@0 51 HandleObject parent, jsval *vp)
michael@0 52 {
michael@0 53 if (IsConstant()) {
michael@0 54 const nsXPTConstant* constant;
michael@0 55 if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant)))
michael@0 56 return false;
michael@0 57
michael@0 58 const nsXPTCMiniVariant& mv = *constant->GetValue();
michael@0 59
michael@0 60 // XXX Big Hack!
michael@0 61 nsXPTCVariant v;
michael@0 62 v.flags = 0;
michael@0 63 v.type = constant->GetType();
michael@0 64 memcpy(&v.val, &mv.val, sizeof(mv.val));
michael@0 65
michael@0 66 RootedValue resultVal(ccx);
michael@0 67
michael@0 68 if (!XPCConvert::NativeData2JS(&resultVal, &v.val, v.type, nullptr, nullptr))
michael@0 69 return false;
michael@0 70
michael@0 71 *vp = resultVal;
michael@0 72
michael@0 73 return true;
michael@0 74 }
michael@0 75 // else...
michael@0 76
michael@0 77 // This is a method or attribute - we'll be needing a function object
michael@0 78
michael@0 79 int argc;
michael@0 80 JSNative callback;
michael@0 81
michael@0 82 if (IsMethod()) {
michael@0 83 const nsXPTMethodInfo* info;
michael@0 84 if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info)))
michael@0 85 return false;
michael@0 86
michael@0 87 // Note: ASSUMES that retval is last arg.
michael@0 88 argc = (int) info->GetParamCount();
michael@0 89 if (argc && info->GetParam((uint8_t)(argc-1)).IsRetval())
michael@0 90 argc-- ;
michael@0 91
michael@0 92 callback = XPC_WN_CallMethod;
michael@0 93 } else {
michael@0 94 argc = 0;
michael@0 95 callback = XPC_WN_GetterSetter;
michael@0 96 }
michael@0 97
michael@0 98 JSFunction *fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, parent, GetName());
michael@0 99 if (!fun)
michael@0 100 return false;
michael@0 101
michael@0 102 JSObject* funobj = JS_GetFunctionObject(fun);
michael@0 103 if (!funobj)
michael@0 104 return false;
michael@0 105
michael@0 106 js::SetFunctionNativeReserved(funobj, 0, PRIVATE_TO_JSVAL(iface));
michael@0 107 js::SetFunctionNativeReserved(funobj, 1, PRIVATE_TO_JSVAL(this));
michael@0 108
michael@0 109 *vp = OBJECT_TO_JSVAL(funobj);
michael@0 110
michael@0 111 return true;
michael@0 112 }
michael@0 113
michael@0 114 /***************************************************************************/
michael@0 115 // XPCNativeInterface
michael@0 116
michael@0 117 // static
michael@0 118 XPCNativeInterface*
michael@0 119 XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
michael@0 120 {
michael@0 121 AutoJSContext cx;
michael@0 122 AutoMarkingNativeInterfacePtr iface(cx);
michael@0 123 XPCJSRuntime* rt = XPCJSRuntime::Get();
michael@0 124
michael@0 125 IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
michael@0 126 if (!map)
michael@0 127 return nullptr;
michael@0 128
michael@0 129 iface = map->Find(*iid);
michael@0 130
michael@0 131 if (iface)
michael@0 132 return iface;
michael@0 133
michael@0 134 nsCOMPtr<nsIInterfaceInfo> info;
michael@0 135 XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(iid, getter_AddRefs(info));
michael@0 136 if (!info)
michael@0 137 return nullptr;
michael@0 138
michael@0 139 iface = NewInstance(info);
michael@0 140 if (!iface)
michael@0 141 return nullptr;
michael@0 142
michael@0 143 XPCNativeInterface* iface2 = map->Add(iface);
michael@0 144 if (!iface2) {
michael@0 145 NS_ERROR("failed to add our interface!");
michael@0 146 DestroyInstance(iface);
michael@0 147 iface = nullptr;
michael@0 148 } else if (iface2 != iface) {
michael@0 149 DestroyInstance(iface);
michael@0 150 iface = iface2;
michael@0 151 }
michael@0 152
michael@0 153 return iface;
michael@0 154 }
michael@0 155
michael@0 156 // static
michael@0 157 XPCNativeInterface*
michael@0 158 XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
michael@0 159 {
michael@0 160 AutoJSContext cx;
michael@0 161 AutoMarkingNativeInterfacePtr iface(cx);
michael@0 162
michael@0 163 const nsIID* iid;
michael@0 164 if (NS_FAILED(info->GetIIDShared(&iid)) || !iid)
michael@0 165 return nullptr;
michael@0 166
michael@0 167 XPCJSRuntime* rt = XPCJSRuntime::Get();
michael@0 168
michael@0 169 IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
michael@0 170 if (!map)
michael@0 171 return nullptr;
michael@0 172
michael@0 173 iface = map->Find(*iid);
michael@0 174
michael@0 175 if (iface)
michael@0 176 return iface;
michael@0 177
michael@0 178 iface = NewInstance(info);
michael@0 179 if (!iface)
michael@0 180 return nullptr;
michael@0 181
michael@0 182 XPCNativeInterface* iface2 = map->Add(iface);
michael@0 183 if (!iface2) {
michael@0 184 NS_ERROR("failed to add our interface!");
michael@0 185 DestroyInstance(iface);
michael@0 186 iface = nullptr;
michael@0 187 } else if (iface2 != iface) {
michael@0 188 DestroyInstance(iface);
michael@0 189 iface = iface2;
michael@0 190 }
michael@0 191
michael@0 192 return iface;
michael@0 193 }
michael@0 194
michael@0 195 // static
michael@0 196 XPCNativeInterface*
michael@0 197 XPCNativeInterface::GetNewOrUsed(const char* name)
michael@0 198 {
michael@0 199 nsCOMPtr<nsIInterfaceInfo> info;
michael@0 200 XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, getter_AddRefs(info));
michael@0 201 return info ? GetNewOrUsed(info) : nullptr;
michael@0 202 }
michael@0 203
michael@0 204 // static
michael@0 205 XPCNativeInterface*
michael@0 206 XPCNativeInterface::GetISupports()
michael@0 207 {
michael@0 208 // XXX We should optimize this to cache this common XPCNativeInterface.
michael@0 209 return GetNewOrUsed(&NS_GET_IID(nsISupports));
michael@0 210 }
michael@0 211
michael@0 212 // static
michael@0 213 XPCNativeInterface*
michael@0 214 XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo)
michael@0 215 {
michael@0 216 AutoJSContext cx;
michael@0 217 static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16;
michael@0 218 XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
michael@0 219 XPCNativeInterface* obj = nullptr;
michael@0 220 XPCNativeMember* members = nullptr;
michael@0 221
michael@0 222 int i;
michael@0 223 bool failed = false;
michael@0 224 uint16_t constCount;
michael@0 225 uint16_t methodCount;
michael@0 226 uint16_t totalCount;
michael@0 227 uint16_t realTotalCount = 0;
michael@0 228 XPCNativeMember* cur;
michael@0 229 RootedString str(cx);
michael@0 230 RootedId interfaceName(cx);
michael@0 231
michael@0 232 // XXX Investigate lazy init? This is a problem given the
michael@0 233 // 'placement new' scheme - we need to at least know how big to make
michael@0 234 // the object. We might do a scan of methods to determine needed size,
michael@0 235 // then make our object, but avoid init'ing *any* members until asked?
michael@0 236 // Find out how often we create these objects w/o really looking at
michael@0 237 // (or using) the members.
michael@0 238
michael@0 239 bool canScript;
michael@0 240 if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
michael@0 241 return nullptr;
michael@0 242
michael@0 243 if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
michael@0 244 NS_FAILED(aInfo->GetConstantCount(&constCount)))
michael@0 245 return nullptr;
michael@0 246
michael@0 247 // If the interface does not have nsISupports in its inheritance chain
michael@0 248 // then we know we can't reflect its methods. However, some interfaces that
michael@0 249 // are used just to reflect constants are declared this way. We need to
michael@0 250 // go ahead and build the thing. But, we'll ignore whatever methods it may
michael@0 251 // have.
michael@0 252 if (!nsXPConnect::IsISupportsDescendant(aInfo))
michael@0 253 methodCount = 0;
michael@0 254
michael@0 255 totalCount = methodCount + constCount;
michael@0 256
michael@0 257 if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
michael@0 258 members = new XPCNativeMember[totalCount];
michael@0 259 if (!members)
michael@0 260 return nullptr;
michael@0 261 } else {
michael@0 262 members = local_members;
michael@0 263 }
michael@0 264
michael@0 265 // NOTE: since getters and setters share a member, we might not use all
michael@0 266 // of the member objects.
michael@0 267
michael@0 268 for (i = 0; i < methodCount; i++) {
michael@0 269 const nsXPTMethodInfo* info;
michael@0 270 if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
michael@0 271 failed = true;
michael@0 272 break;
michael@0 273 }
michael@0 274
michael@0 275 // don't reflect Addref or Release
michael@0 276 if (i == 1 || i == 2)
michael@0 277 continue;
michael@0 278
michael@0 279 if (!XPCConvert::IsMethodReflectable(*info))
michael@0 280 continue;
michael@0 281
michael@0 282 str = JS_InternString(cx, info->GetName());
michael@0 283 if (!str) {
michael@0 284 NS_ERROR("bad method name");
michael@0 285 failed = true;
michael@0 286 break;
michael@0 287 }
michael@0 288 jsid name = INTERNED_STRING_TO_JSID(cx, str);
michael@0 289
michael@0 290 if (info->IsSetter()) {
michael@0 291 MOZ_ASSERT(realTotalCount,"bad setter");
michael@0 292 // Note: ASSUMES Getter/Setter pairs are next to each other
michael@0 293 // This is a rule of the typelib spec.
michael@0 294 cur = &members[realTotalCount-1];
michael@0 295 MOZ_ASSERT(cur->GetName() == name,"bad setter");
michael@0 296 MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter");
michael@0 297 MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter");
michael@0 298 cur->SetWritableAttribute();
michael@0 299 } else {
michael@0 300 // XXX need better way to find dups
michael@0 301 // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name");
michael@0 302 cur = &members[realTotalCount++];
michael@0 303 cur->SetName(name);
michael@0 304 if (info->IsGetter())
michael@0 305 cur->SetReadOnlyAttribute(i);
michael@0 306 else
michael@0 307 cur->SetMethod(i);
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 if (!failed) {
michael@0 312 for (i = 0; i < constCount; i++) {
michael@0 313 const nsXPTConstant* constant;
michael@0 314 if (NS_FAILED(aInfo->GetConstant(i, &constant))) {
michael@0 315 failed = true;
michael@0 316 break;
michael@0 317 }
michael@0 318
michael@0 319 str = JS_InternString(cx, constant->GetName());
michael@0 320 if (!str) {
michael@0 321 NS_ERROR("bad constant name");
michael@0 322 failed = true;
michael@0 323 break;
michael@0 324 }
michael@0 325 jsid name = INTERNED_STRING_TO_JSID(cx, str);
michael@0 326
michael@0 327 // XXX need better way to find dups
michael@0 328 //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name");
michael@0 329
michael@0 330 cur = &members[realTotalCount++];
michael@0 331 cur->SetName(name);
michael@0 332 cur->SetConstant(i);
michael@0 333 }
michael@0 334 }
michael@0 335
michael@0 336 if (!failed) {
michael@0 337 const char* bytes;
michael@0 338 if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
michael@0 339 nullptr == (str = JS_InternString(cx, bytes))) {
michael@0 340 failed = true;
michael@0 341 }
michael@0 342 interfaceName = INTERNED_STRING_TO_JSID(cx, str);
michael@0 343 }
michael@0 344
michael@0 345 if (!failed) {
michael@0 346 // Use placement new to create an object with the right amount of space
michael@0 347 // to hold the members array
michael@0 348 int size = sizeof(XPCNativeInterface);
michael@0 349 if (realTotalCount > 1)
michael@0 350 size += (realTotalCount - 1) * sizeof(XPCNativeMember);
michael@0 351 void* place = new char[size];
michael@0 352 if (place)
michael@0 353 obj = new(place) XPCNativeInterface(aInfo, interfaceName);
michael@0 354
michael@0 355 if (obj) {
michael@0 356 obj->mMemberCount = realTotalCount;
michael@0 357 // copy valid members
michael@0 358 if (realTotalCount)
michael@0 359 memcpy(obj->mMembers, members,
michael@0 360 realTotalCount * sizeof(XPCNativeMember));
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 if (members && members != local_members)
michael@0 365 delete [] members;
michael@0 366
michael@0 367 return obj;
michael@0 368 }
michael@0 369
michael@0 370 // static
michael@0 371 void
michael@0 372 XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst)
michael@0 373 {
michael@0 374 inst->~XPCNativeInterface();
michael@0 375 delete [] (char*) inst;
michael@0 376 }
michael@0 377
michael@0 378 size_t
michael@0 379 XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
michael@0 380 {
michael@0 381 return mallocSizeOf(this);
michael@0 382 }
michael@0 383
michael@0 384 void
michael@0 385 XPCNativeInterface::DebugDump(int16_t depth)
michael@0 386 {
michael@0 387 #ifdef DEBUG
michael@0 388 depth--;
michael@0 389 XPC_LOG_ALWAYS(("XPCNativeInterface @ %x", this));
michael@0 390 XPC_LOG_INDENT();
michael@0 391 XPC_LOG_ALWAYS(("name is %s", GetNameString()));
michael@0 392 XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount));
michael@0 393 XPC_LOG_ALWAYS(("mInfo @ %x", mInfo.get()));
michael@0 394 XPC_LOG_OUTDENT();
michael@0 395 #endif
michael@0 396 }
michael@0 397
michael@0 398 /***************************************************************************/
michael@0 399 // XPCNativeSet
michael@0 400
michael@0 401 // static
michael@0 402 XPCNativeSet*
michael@0 403 XPCNativeSet::GetNewOrUsed(const nsIID* iid)
michael@0 404 {
michael@0 405 AutoJSContext cx;
michael@0 406 AutoMarkingNativeSetPtr set(cx);
michael@0 407
michael@0 408 AutoMarkingNativeInterfacePtr iface(cx);
michael@0 409 iface = XPCNativeInterface::GetNewOrUsed(iid);
michael@0 410 if (!iface)
michael@0 411 return nullptr;
michael@0 412
michael@0 413 XPCNativeSetKey key(nullptr, iface, 0);
michael@0 414
michael@0 415 XPCJSRuntime* rt = XPCJSRuntime::Get();
michael@0 416 NativeSetMap* map = rt->GetNativeSetMap();
michael@0 417 if (!map)
michael@0 418 return nullptr;
michael@0 419
michael@0 420 set = map->Find(&key);
michael@0 421
michael@0 422 if (set)
michael@0 423 return set;
michael@0 424
michael@0 425 // hacky way to get a XPCNativeInterface** using the AutoPtr
michael@0 426 XPCNativeInterface* temp[] = {iface};
michael@0 427 set = NewInstance(temp, 1);
michael@0 428 if (!set)
michael@0 429 return nullptr;
michael@0 430
michael@0 431 XPCNativeSet* set2 = map->Add(&key, set);
michael@0 432 if (!set2) {
michael@0 433 NS_ERROR("failed to add our set!");
michael@0 434 DestroyInstance(set);
michael@0 435 set = nullptr;
michael@0 436 } else if (set2 != set) {
michael@0 437 DestroyInstance(set);
michael@0 438 set = set2;
michael@0 439 }
michael@0 440
michael@0 441 return set;
michael@0 442 }
michael@0 443
michael@0 444 // static
michael@0 445 XPCNativeSet*
michael@0 446 XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
michael@0 447 {
michael@0 448 AutoJSContext cx;
michael@0 449 AutoMarkingNativeSetPtr set(cx);
michael@0 450 XPCJSRuntime* rt = XPCJSRuntime::Get();
michael@0 451
michael@0 452 ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
michael@0 453 if (!map)
michael@0 454 return nullptr;
michael@0 455
michael@0 456 set = map->Find(classInfo);
michael@0 457
michael@0 458 if (set)
michael@0 459 return set;
michael@0 460
michael@0 461 nsIID** iidArray = nullptr;
michael@0 462 AutoMarkingNativeInterfacePtrArrayPtr interfaceArray(cx);
michael@0 463 uint32_t iidCount = 0;
michael@0 464
michael@0 465 if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) {
michael@0 466 // Note: I'm making it OK for this call to fail so that one can add
michael@0 467 // nsIClassInfo to classes implemented in script without requiring this
michael@0 468 // method to be implemented.
michael@0 469
michael@0 470 // Make sure these are set correctly...
michael@0 471 iidArray = nullptr;
michael@0 472 iidCount = 0;
michael@0 473 }
michael@0 474
michael@0 475 MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array");
michael@0 476
michael@0 477 // !!! from here on we only exit through the 'out' label !!!
michael@0 478
michael@0 479 if (iidCount) {
michael@0 480 AutoMarkingNativeInterfacePtrArrayPtr
michael@0 481 arr(cx, new XPCNativeInterface*[iidCount], iidCount, true);
michael@0 482
michael@0 483 interfaceArray = arr;
michael@0 484
michael@0 485 XPCNativeInterface** currentInterface = interfaceArray;
michael@0 486 nsIID** currentIID = iidArray;
michael@0 487 uint16_t interfaceCount = 0;
michael@0 488
michael@0 489 for (uint32_t i = 0; i < iidCount; i++) {
michael@0 490 nsIID* iid = *(currentIID++);
michael@0 491 if (!iid) {
michael@0 492 NS_ERROR("Null found in classinfo interface list");
michael@0 493 continue;
michael@0 494 }
michael@0 495
michael@0 496 XPCNativeInterface* iface =
michael@0 497 XPCNativeInterface::GetNewOrUsed(iid);
michael@0 498
michael@0 499 if (!iface) {
michael@0 500 // XXX warn here
michael@0 501 continue;
michael@0 502 }
michael@0 503
michael@0 504 *(currentInterface++) = iface;
michael@0 505 interfaceCount++;
michael@0 506 }
michael@0 507
michael@0 508 if (interfaceCount) {
michael@0 509 set = NewInstance(interfaceArray, interfaceCount);
michael@0 510 if (set) {
michael@0 511 NativeSetMap* map2 = rt->GetNativeSetMap();
michael@0 512 if (!map2)
michael@0 513 goto out;
michael@0 514
michael@0 515 XPCNativeSetKey key(set, nullptr, 0);
michael@0 516
michael@0 517 XPCNativeSet* set2 = map2->Add(&key, set);
michael@0 518 if (!set2) {
michael@0 519 NS_ERROR("failed to add our set!");
michael@0 520 DestroyInstance(set);
michael@0 521 set = nullptr;
michael@0 522 goto out;
michael@0 523 }
michael@0 524 if (set2 != set) {
michael@0 525 DestroyInstance(set);
michael@0 526 set = set2;
michael@0 527 }
michael@0 528 }
michael@0 529 } else
michael@0 530 set = GetNewOrUsed(&NS_GET_IID(nsISupports));
michael@0 531 } else
michael@0 532 set = GetNewOrUsed(&NS_GET_IID(nsISupports));
michael@0 533
michael@0 534 if (set) {
michael@0 535 #ifdef DEBUG
michael@0 536 XPCNativeSet* set2 =
michael@0 537 #endif
michael@0 538 map->Add(classInfo, set);
michael@0 539 MOZ_ASSERT(set2, "failed to add our set!");
michael@0 540 MOZ_ASSERT(set2 == set, "hashtables inconsistent!");
michael@0 541 }
michael@0 542
michael@0 543 out:
michael@0 544 if (iidArray)
michael@0 545 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
michael@0 546 if (interfaceArray)
michael@0 547 delete [] interfaceArray.get();
michael@0 548
michael@0 549 return set;
michael@0 550 }
michael@0 551
michael@0 552 // static
michael@0 553 void
michael@0 554 XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
michael@0 555 {
michael@0 556 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
michael@0 557 ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
michael@0 558 if (map)
michael@0 559 map->Remove(classInfo);
michael@0 560 }
michael@0 561
michael@0 562 // static
michael@0 563 XPCNativeSet*
michael@0 564 XPCNativeSet::GetNewOrUsed(XPCNativeSet* otherSet,
michael@0 565 XPCNativeInterface* newInterface,
michael@0 566 uint16_t position)
michael@0 567 {
michael@0 568 AutoJSContext cx;
michael@0 569 AutoMarkingNativeSetPtr set(cx);
michael@0 570 XPCJSRuntime* rt = XPCJSRuntime::Get();
michael@0 571 NativeSetMap* map = rt->GetNativeSetMap();
michael@0 572 if (!map)
michael@0 573 return nullptr;
michael@0 574
michael@0 575 XPCNativeSetKey key(otherSet, newInterface, position);
michael@0 576
michael@0 577 set = map->Find(&key);
michael@0 578
michael@0 579 if (set)
michael@0 580 return set;
michael@0 581
michael@0 582 if (otherSet)
michael@0 583 set = NewInstanceMutate(otherSet, newInterface, position);
michael@0 584 else
michael@0 585 set = NewInstance(&newInterface, 1);
michael@0 586
michael@0 587 if (!set)
michael@0 588 return nullptr;
michael@0 589
michael@0 590 XPCNativeSet* set2 = map->Add(&key, set);
michael@0 591 if (!set2) {
michael@0 592 NS_ERROR("failed to add our set!");
michael@0 593 DestroyInstance(set);
michael@0 594 set = nullptr;
michael@0 595 } else if (set2 != set) {
michael@0 596 DestroyInstance(set);
michael@0 597 set = set2;
michael@0 598 }
michael@0 599
michael@0 600 return set;
michael@0 601 }
michael@0 602
michael@0 603 // static
michael@0 604 XPCNativeSet*
michael@0 605 XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
michael@0 606 XPCNativeSet* secondSet,
michael@0 607 bool preserveFirstSetOrder)
michael@0 608 {
michael@0 609 // Figure out how many interfaces we'll need in the new set.
michael@0 610 uint32_t uniqueCount = firstSet->mInterfaceCount;
michael@0 611 for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
michael@0 612 if (!firstSet->HasInterface(secondSet->mInterfaces[i]))
michael@0 613 uniqueCount++;
michael@0 614 }
michael@0 615
michael@0 616 // If everything in secondSet was a duplicate, we can just use the first
michael@0 617 // set.
michael@0 618 if (uniqueCount == firstSet->mInterfaceCount)
michael@0 619 return firstSet;
michael@0 620
michael@0 621 // If the secondSet is just a superset of the first, we can use it provided
michael@0 622 // that the caller doesn't care about ordering.
michael@0 623 if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount)
michael@0 624 return secondSet;
michael@0 625
michael@0 626 // Ok, darn. Now we have to make a new set.
michael@0 627 //
michael@0 628 // It would be faster to just create the new set all at once, but that
michael@0 629 // would involve wrangling with some pretty hairy code - especially since
michael@0 630 // a lot of stuff assumes that sets are created by adding one interface to an
michael@0 631 // existing set. So let's just do the slow and easy thing and hope that the
michael@0 632 // above optimizations handle the common cases.
michael@0 633 XPCNativeSet* currentSet = firstSet;
michael@0 634 for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
michael@0 635 XPCNativeInterface* iface = secondSet->mInterfaces[i];
michael@0 636 if (!currentSet->HasInterface(iface)) {
michael@0 637 // Create a new augmented set, inserting this interface at the end.
michael@0 638 uint32_t pos = currentSet->mInterfaceCount;
michael@0 639 currentSet = XPCNativeSet::GetNewOrUsed(currentSet, iface, pos);
michael@0 640 if (!currentSet)
michael@0 641 return nullptr;
michael@0 642 }
michael@0 643 }
michael@0 644
michael@0 645 // We've got the union set. Hand it back to the caller.
michael@0 646 MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
michael@0 647 return currentSet;
michael@0 648 }
michael@0 649
michael@0 650 // static
michael@0 651 XPCNativeSet*
michael@0 652 XPCNativeSet::NewInstance(XPCNativeInterface** array,
michael@0 653 uint16_t count)
michael@0 654 {
michael@0 655 XPCNativeSet* obj = nullptr;
michael@0 656
michael@0 657 if (!array || !count)
michael@0 658 return nullptr;
michael@0 659
michael@0 660 // We impose the invariant:
michael@0 661 // "All sets have exactly one nsISupports interface and it comes first."
michael@0 662 // This is the place where we impose that rule - even if given inputs
michael@0 663 // that don't exactly follow the rule.
michael@0 664
michael@0 665 XPCNativeInterface* isup = XPCNativeInterface::GetISupports();
michael@0 666 uint16_t slots = count+1;
michael@0 667
michael@0 668 uint16_t i;
michael@0 669 XPCNativeInterface** pcur;
michael@0 670
michael@0 671 for (i = 0, pcur = array; i < count; i++, pcur++) {
michael@0 672 if (*pcur == isup)
michael@0 673 slots--;
michael@0 674 }
michael@0 675
michael@0 676 // Use placement new to create an object with the right amount of space
michael@0 677 // to hold the members array
michael@0 678 int size = sizeof(XPCNativeSet);
michael@0 679 if (slots > 1)
michael@0 680 size += (slots - 1) * sizeof(XPCNativeInterface*);
michael@0 681 void* place = new char[size];
michael@0 682 if (place)
michael@0 683 obj = new(place) XPCNativeSet();
michael@0 684
michael@0 685 if (obj) {
michael@0 686 // Stick the nsISupports in front and skip additional nsISupport(s)
michael@0 687 XPCNativeInterface** inp = array;
michael@0 688 XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces;
michael@0 689 uint16_t memberCount = 1; // for the one member in nsISupports
michael@0 690
michael@0 691 *(outp++) = isup;
michael@0 692
michael@0 693 for (i = 0; i < count; i++) {
michael@0 694 XPCNativeInterface* cur;
michael@0 695
michael@0 696 if (isup == (cur = *(inp++)))
michael@0 697 continue;
michael@0 698 *(outp++) = cur;
michael@0 699 memberCount += cur->GetMemberCount();
michael@0 700 }
michael@0 701 obj->mMemberCount = memberCount;
michael@0 702 obj->mInterfaceCount = slots;
michael@0 703 }
michael@0 704
michael@0 705 return obj;
michael@0 706 }
michael@0 707
michael@0 708 // static
michael@0 709 XPCNativeSet*
michael@0 710 XPCNativeSet::NewInstanceMutate(XPCNativeSet* otherSet,
michael@0 711 XPCNativeInterface* newInterface,
michael@0 712 uint16_t position)
michael@0 713 {
michael@0 714 XPCNativeSet* obj = nullptr;
michael@0 715
michael@0 716 if (!newInterface)
michael@0 717 return nullptr;
michael@0 718 if (otherSet && position > otherSet->mInterfaceCount)
michael@0 719 return nullptr;
michael@0 720
michael@0 721 // Use placement new to create an object with the right amount of space
michael@0 722 // to hold the members array
michael@0 723 int size = sizeof(XPCNativeSet);
michael@0 724 if (otherSet)
michael@0 725 size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
michael@0 726 void* place = new char[size];
michael@0 727 if (place)
michael@0 728 obj = new(place) XPCNativeSet();
michael@0 729
michael@0 730 if (obj) {
michael@0 731 if (otherSet) {
michael@0 732 obj->mMemberCount = otherSet->GetMemberCount() +
michael@0 733 newInterface->GetMemberCount();
michael@0 734 obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
michael@0 735
michael@0 736 XPCNativeInterface** src = otherSet->mInterfaces;
michael@0 737 XPCNativeInterface** dest = obj->mInterfaces;
michael@0 738 for (uint16_t i = 0; i < obj->mInterfaceCount; i++) {
michael@0 739 if (i == position)
michael@0 740 *dest++ = newInterface;
michael@0 741 else
michael@0 742 *dest++ = *src++;
michael@0 743 }
michael@0 744 } else {
michael@0 745 obj->mMemberCount = newInterface->GetMemberCount();
michael@0 746 obj->mInterfaceCount = 1;
michael@0 747 obj->mInterfaces[0] = newInterface;
michael@0 748 }
michael@0 749 }
michael@0 750
michael@0 751 return obj;
michael@0 752 }
michael@0 753
michael@0 754 // static
michael@0 755 void
michael@0 756 XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
michael@0 757 {
michael@0 758 inst->~XPCNativeSet();
michael@0 759 delete [] (char*) inst;
michael@0 760 }
michael@0 761
michael@0 762 size_t
michael@0 763 XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
michael@0 764 {
michael@0 765 return mallocSizeOf(this);
michael@0 766 }
michael@0 767
michael@0 768 void
michael@0 769 XPCNativeSet::DebugDump(int16_t depth)
michael@0 770 {
michael@0 771 #ifdef DEBUG
michael@0 772 depth--;
michael@0 773 XPC_LOG_ALWAYS(("XPCNativeSet @ %x", this));
michael@0 774 XPC_LOG_INDENT();
michael@0 775
michael@0 776 XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount));
michael@0 777 if (depth) {
michael@0 778 for (uint16_t i = 0; i < mInterfaceCount; i++)
michael@0 779 mInterfaces[i]->DebugDump(depth);
michael@0 780 }
michael@0 781 XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount));
michael@0 782 XPC_LOG_OUTDENT();
michael@0 783 #endif
michael@0 784 }

mercurial