XPCWrappedNativeInfo.cpp (20663B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Manage the shared info about interfaces for use by wrappedNatives. */ 8 9 #include "xpcprivate.h" 10 #include "XPCMaps.h" 11 #include "js/Wrapper.h" 12 13 #include "mozilla/MemoryReporting.h" 14 #include "mozilla/SourceLocation.h" 15 #include "nsIScriptError.h" 16 #include "nsPrintfCString.h" 17 #include "nsPointerHashKeys.h" 18 19 using namespace JS; 20 using namespace mozilla; 21 22 /***************************************************************************/ 23 24 // XPCNativeMember 25 26 // static 27 bool XPCNativeMember::GetCallInfo(JSObject* funobj, 28 RefPtr<XPCNativeInterface>* pInterface, 29 XPCNativeMember** pMember) { 30 funobj = js::UncheckedUnwrap(funobj); 31 Value memberVal = 32 js::GetFunctionNativeReserved(funobj, XPC_FUNCTION_NATIVE_MEMBER_SLOT); 33 34 *pMember = static_cast<XPCNativeMember*>(memberVal.toPrivate()); 35 *pInterface = (*pMember)->GetInterface(); 36 37 return true; 38 } 39 40 bool XPCNativeMember::NewFunctionObject(XPCCallContext& ccx, 41 XPCNativeInterface* iface, 42 HandleObject parent, Value* pval) { 43 MOZ_ASSERT(!IsConstant(), 44 "Only call this if you're sure this is not a constant!"); 45 46 return Resolve(ccx, iface, parent, pval); 47 } 48 49 bool XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface, 50 HandleObject parent, Value* vp) { 51 MOZ_ASSERT(iface == GetInterface()); 52 if (IsConstant()) { 53 RootedValue resultVal(ccx); 54 nsCString name; 55 if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &resultVal, 56 getter_Copies(name)))) 57 return false; 58 59 *vp = resultVal; 60 61 return true; 62 } 63 // else... 64 65 // This is a method or attribute - we'll be needing a function object 66 67 int argc; 68 JSNative callback; 69 70 if (IsMethod()) { 71 const nsXPTMethodInfo* info; 72 if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info))) { 73 return false; 74 } 75 76 // Note: ASSUMES that retval is last arg. 77 argc = (int)info->ParamCount(); 78 if (info->HasRetval()) { 79 argc--; 80 } 81 82 callback = XPC_WN_CallMethod; 83 } else { 84 argc = 0; 85 callback = XPC_WN_GetterSetter; 86 } 87 88 jsid name = GetName(); 89 JS_MarkCrossZoneId(ccx, name); 90 91 JSFunction* fun; 92 if (name.isString()) { 93 fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, name); 94 } else { 95 fun = js::NewFunctionWithReserved(ccx, callback, argc, 0, nullptr); 96 } 97 if (!fun) { 98 return false; 99 } 100 101 JSObject* funobj = JS_GetFunctionObject(fun); 102 if (!funobj) { 103 return false; 104 } 105 106 js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_NATIVE_MEMBER_SLOT, 107 PrivateValue(this)); 108 js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_PARENT_OBJECT_SLOT, 109 ObjectValue(*parent)); 110 111 vp->setObject(*funobj); 112 113 return true; 114 } 115 116 /***************************************************************************/ 117 // XPCNativeInterface 118 119 XPCNativeInterface::~XPCNativeInterface() { 120 XPCJSRuntime::Get()->GetIID2NativeInterfaceMap()->Remove(this); 121 } 122 123 // static 124 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed( 125 JSContext* cx, const nsIID* iid) { 126 RefPtr<XPCNativeInterface> iface; 127 XPCJSRuntime* rt = XPCJSRuntime::Get(); 128 129 IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); 130 if (!map) { 131 return nullptr; 132 } 133 134 iface = map->Find(*iid); 135 136 if (iface) { 137 return iface.forget(); 138 } 139 140 const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(*iid); 141 if (!info) { 142 return nullptr; 143 } 144 145 return NewInstance(cx, map, info); 146 } 147 148 // static 149 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed( 150 JSContext* cx, const nsXPTInterfaceInfo* info) { 151 RefPtr<XPCNativeInterface> iface; 152 153 XPCJSRuntime* rt = XPCJSRuntime::Get(); 154 155 IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap(); 156 if (!map) { 157 return nullptr; 158 } 159 160 iface = map->Find(info->IID()); 161 162 if (iface) { 163 return iface.forget(); 164 } 165 166 return NewInstance(cx, map, info); 167 } 168 169 // static 170 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed( 171 JSContext* cx, const char* name) { 172 const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name); 173 return info ? GetNewOrUsed(cx, info) : nullptr; 174 } 175 176 // static 177 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetISupports( 178 JSContext* cx) { 179 // XXX We should optimize this to cache this common XPCNativeInterface. 180 return GetNewOrUsed(cx, &NS_GET_IID(nsISupports)); 181 } 182 183 // static 184 already_AddRefed<XPCNativeInterface> XPCNativeInterface::NewInstance( 185 JSContext* cx, IID2NativeInterfaceMap* aMap, 186 const nsXPTInterfaceInfo* aInfo) { 187 // XXX Investigate lazy init? This is a problem given the 188 // 'placement new' scheme - we need to at least know how big to make 189 // the object. We might do a scan of methods to determine needed size, 190 // then make our object, but avoid init'ing *any* members until asked? 191 // Find out how often we create these objects w/o really looking at 192 // (or using) the members. 193 194 if (aInfo->IsMainProcessScriptableOnly() && !XRE_IsParentProcess()) { 195 nsCOMPtr<nsIConsoleService> console( 196 do_GetService(NS_CONSOLESERVICE_CONTRACTID)); 197 if (console) { 198 const char* intfNameChars = aInfo->Name(); 199 nsPrintfCString errorMsg("Use of %s in content process is deprecated.", 200 intfNameChars); 201 202 auto location = JSCallingLocation::Get(cx); 203 nsCOMPtr<nsIScriptError> error( 204 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); 205 error->Init(NS_ConvertUTF8toUTF16(errorMsg), location.FileName(), 206 location.mLine, location.mColumn, nsIScriptError::warningFlag, 207 "chrome javascript"_ns, false /* from private window */, 208 true /* from chrome context */); 209 console->LogMessage(error); 210 } 211 } 212 213 // Make sure the code below does not GC. This means we don't need to trace the 214 // PropertyKeys in the MemberVector, or the XPCNativeInterface we create 215 // before it's added to the map. 216 JS::AutoCheckCannotGC nogc; 217 218 const uint16_t methodCount = aInfo->MethodCount(); 219 const uint16_t constCount = aInfo->ConstantCount(); 220 const uint16_t totalCount = methodCount + constCount; 221 222 using MemberVector = 223 mozilla::Vector<XPCNativeMember, 16, InfallibleAllocPolicy>; 224 MemberVector members; 225 MOZ_ALWAYS_TRUE(members.reserve(totalCount)); 226 227 // NOTE: since getters and setters share a member, we might not use all 228 // of the member objects. 229 230 for (unsigned int i = 0; i < methodCount; i++) { 231 const nsXPTMethodInfo& info = aInfo->Method(i); 232 233 // don't reflect Addref or Release 234 if (i == 1 || i == 2) { 235 continue; 236 } 237 238 if (!info.IsReflectable()) { 239 continue; 240 } 241 242 jsid name; 243 if (!info.GetId(cx, name)) { 244 NS_ERROR("bad method name"); 245 return nullptr; 246 } 247 248 if (info.IsSetter()) { 249 MOZ_ASSERT(!members.empty(), "bad setter"); 250 // Note: ASSUMES Getter/Setter pairs are next to each other 251 // This is a rule of the typelib spec. 252 XPCNativeMember* cur = &members.back(); 253 MOZ_ASSERT(cur->GetName() == name, "bad setter"); 254 MOZ_ASSERT(cur->IsReadOnlyAttribute(), "bad setter"); 255 MOZ_ASSERT(cur->GetIndex() == i - 1, "bad setter"); 256 cur->SetWritableAttribute(); 257 } else { 258 // XXX need better way to find dups 259 // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name"); 260 size_t indexInInterface = members.length(); 261 if (indexInInterface == XPCNativeMember::GetMaxIndexInInterface()) { 262 NS_WARNING("Too many members in interface"); 263 return nullptr; 264 } 265 XPCNativeMember cur; 266 cur.SetName(name); 267 if (info.IsGetter()) { 268 cur.SetReadOnlyAttribute(i); 269 } else { 270 cur.SetMethod(i); 271 } 272 cur.SetIndexInInterface(indexInInterface); 273 members.infallibleAppend(cur); 274 } 275 } 276 277 for (unsigned int i = 0; i < constCount; i++) { 278 RootedValue constant(cx); 279 nsCString namestr; 280 if (NS_FAILED(aInfo->GetConstant(i, &constant, getter_Copies(namestr)))) { 281 return nullptr; 282 } 283 284 RootedString str(cx, JS_AtomizeString(cx, namestr.get())); 285 if (!str) { 286 NS_ERROR("bad constant name"); 287 return nullptr; 288 } 289 jsid name = PropertyKey::NonIntAtom(str); 290 291 // XXX need better way to find dups 292 // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name"); 293 size_t indexInInterface = members.length(); 294 if (indexInInterface == XPCNativeMember::GetMaxIndexInInterface()) { 295 NS_WARNING("Too many members in interface"); 296 return nullptr; 297 } 298 XPCNativeMember cur; 299 cur.SetName(name); 300 cur.SetConstant(i); 301 cur.SetIndexInInterface(indexInInterface); 302 members.infallibleAppend(cur); 303 } 304 305 const char* bytes = aInfo->Name(); 306 if (!bytes) { 307 return nullptr; 308 } 309 RootedString str(cx, JS_AtomizeString(cx, bytes)); 310 if (!str) { 311 return nullptr; 312 } 313 314 RootedId interfaceName(cx, PropertyKey::NonIntAtom(str)); 315 316 // Use placement new to create an object with the right amount of space 317 // to hold the members array 318 size_t size = sizeof(XPCNativeInterface); 319 if (members.length() > 1) { 320 size += (members.length() - 1) * sizeof(XPCNativeMember); 321 } 322 void* place = new char[size]; 323 if (!place) { 324 return nullptr; 325 } 326 327 RefPtr<XPCNativeInterface> obj = 328 new (place) XPCNativeInterface(aInfo, interfaceName); 329 330 obj->mMemberCount = members.length(); 331 // copy valid members 332 if (!members.empty()) { 333 memcpy(obj->mMembers, members.begin(), 334 members.length() * sizeof(XPCNativeMember)); 335 } 336 337 if (!aMap->AddNew(obj)) { 338 NS_ERROR("failed to add our interface!"); 339 return nullptr; 340 } 341 342 return obj.forget(); 343 } 344 345 // static 346 void XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst) { 347 inst->~XPCNativeInterface(); 348 delete[] (char*)inst; 349 } 350 351 size_t XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) { 352 return mallocSizeOf(this); 353 } 354 355 void XPCNativeInterface::Trace(JSTracer* trc) { 356 JS::TraceRoot(trc, &mName, "XPCNativeInterface::mName"); 357 358 for (size_t i = 0; i < mMemberCount; i++) { 359 JS::PropertyKey key = mMembers[i].GetName(); 360 JS::TraceRoot(trc, &key, "XPCNativeInterface::mMembers"); 361 MOZ_ASSERT(mMembers[i].GetName() == key); 362 } 363 } 364 365 void IID2NativeInterfaceMap::Trace(JSTracer* trc) { 366 for (Map::Enum e(mMap); !e.empty(); e.popFront()) { 367 XPCNativeInterface* iface = e.front().value(); 368 iface->Trace(trc); 369 } 370 } 371 372 void XPCNativeInterface::DebugDump(int16_t depth) { 373 #ifdef DEBUG 374 XPC_LOG_ALWAYS(("XPCNativeInterface @ %p", this)); 375 XPC_LOG_INDENT(); 376 XPC_LOG_ALWAYS(("name is %s", GetNameString())); 377 XPC_LOG_ALWAYS(("mInfo @ %p", mInfo)); 378 XPC_LOG_OUTDENT(); 379 #endif 380 } 381 382 /***************************************************************************/ 383 // XPCNativeSetKey 384 385 HashNumber XPCNativeSetKey::Hash() const { 386 HashNumber h = 0; 387 388 if (mBaseSet) { 389 // If we ever start using mCx here, adjust the constructors accordingly. 390 XPCNativeInterface** current = mBaseSet->GetInterfaceArray(); 391 uint16_t count = mBaseSet->GetInterfaceCount(); 392 for (uint16_t i = 0; i < count; i++) { 393 h = AddToHash(h, *(current++)); 394 } 395 } else { 396 // A newly created set will contain nsISupports first... 397 RefPtr<XPCNativeInterface> isupp = XPCNativeInterface::GetISupports(mCx); 398 h = AddToHash(h, isupp.get()); 399 400 // ...but no more than once. 401 if (isupp == mAddition) { 402 return h; 403 } 404 } 405 406 if (mAddition) { 407 h = AddToHash(h, mAddition.get()); 408 } 409 410 return h; 411 } 412 413 /***************************************************************************/ 414 // XPCNativeSet 415 416 XPCNativeSet::~XPCNativeSet() { 417 // Remove |this| before we clear the interfaces to ensure that the 418 // hashtable look up is correct. 419 420 XPCJSRuntime::Get()->GetNativeSetMap()->Remove(this); 421 422 for (int i = 0; i < mInterfaceCount; i++) { 423 NS_RELEASE(mInterfaces[i]); 424 } 425 } 426 427 // static 428 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(JSContext* cx, 429 const nsIID* iid) { 430 RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(cx, iid); 431 if (!iface) { 432 return nullptr; 433 } 434 435 XPCNativeSetKey key(cx, iface); 436 437 XPCJSRuntime* xpcrt = XPCJSRuntime::Get(); 438 NativeSetMap* map = xpcrt->GetNativeSetMap(); 439 if (!map) { 440 return nullptr; 441 } 442 443 RefPtr<XPCNativeSet> set = map->Find(&key); 444 445 if (set) { 446 return set.forget(); 447 } 448 449 set = NewInstance(cx, {std::move(iface)}); 450 if (!set) { 451 return nullptr; 452 } 453 454 if (!map->AddNew(&key, set)) { 455 NS_ERROR("failed to add our set!"); 456 set = nullptr; 457 } 458 459 return set.forget(); 460 } 461 462 // static 463 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed( 464 JSContext* cx, nsIClassInfo* classInfo) { 465 XPCJSRuntime* xpcrt = XPCJSRuntime::Get(); 466 ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap(); 467 if (!map) { 468 return nullptr; 469 } 470 471 RefPtr<XPCNativeSet> set = map->Find(classInfo); 472 473 if (set) { 474 return set.forget(); 475 } 476 477 AutoTArray<nsIID, 4> iids; 478 if (NS_FAILED(classInfo->GetInterfaces(iids))) { 479 // Note: I'm making it OK for this call to fail so that one can add 480 // nsIClassInfo to classes implemented in script without requiring this 481 // method to be implemented. 482 483 // Make sure these are set correctly... 484 iids.Clear(); 485 } 486 487 // Try to look up each IID's XPCNativeInterface object. 488 nsTArray<RefPtr<XPCNativeInterface>> interfaces(iids.Length()); 489 for (auto& iid : iids) { 490 RefPtr<XPCNativeInterface> iface = 491 XPCNativeInterface::GetNewOrUsed(cx, &iid); 492 if (iface) { 493 interfaces.AppendElement(iface.forget()); 494 } 495 } 496 497 // Build a set from the interfaces specified here. 498 if (interfaces.Length() > 0) { 499 set = NewInstance(cx, std::move(interfaces)); 500 if (set) { 501 NativeSetMap* map2 = xpcrt->GetNativeSetMap(); 502 if (!map2) { 503 return set.forget(); 504 } 505 506 XPCNativeSetKey key(set); 507 XPCNativeSet* set2 = map2->Add(&key, set); 508 if (!set2) { 509 NS_ERROR("failed to add our set"); 510 return nullptr; 511 } 512 513 // It is okay to find an existing entry here because 514 // we did not look for one before we called Add(). 515 if (set2 != set) { 516 set = set2; 517 } 518 } 519 } else { 520 set = GetNewOrUsed(cx, &NS_GET_IID(nsISupports)); 521 } 522 523 if (set) { 524 #ifdef DEBUG 525 XPCNativeSet* set2 = 526 #endif 527 map->Add(classInfo, set); 528 MOZ_ASSERT(set2, "failed to add our set!"); 529 MOZ_ASSERT(set2 == set, "hashtables inconsistent!"); 530 } 531 532 return set.forget(); 533 } 534 535 // static 536 void XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo) { 537 XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance(); 538 ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap(); 539 if (map) { 540 map->Remove(classInfo); 541 } 542 } 543 544 // static 545 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed( 546 JSContext* cx, XPCNativeSetKey* key) { 547 NativeSetMap* map = XPCJSRuntime::Get()->GetNativeSetMap(); 548 if (!map) { 549 return nullptr; 550 } 551 552 RefPtr<XPCNativeSet> set = map->Find(key); 553 554 if (set) { 555 return set.forget(); 556 } 557 558 if (key->GetBaseSet()) { 559 set = NewInstanceMutate(key); 560 } else { 561 set = NewInstance(cx, {key->GetAddition()}); 562 } 563 564 if (!set) { 565 return nullptr; 566 } 567 568 if (!map->AddNew(key, set)) { 569 NS_ERROR("failed to add our set!"); 570 set = nullptr; 571 } 572 573 return set.forget(); 574 } 575 576 // static 577 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed( 578 JSContext* cx, XPCNativeSet* firstSet, XPCNativeSet* secondSet, 579 bool preserveFirstSetOrder) { 580 // Figure out how many interfaces we'll need in the new set. 581 uint32_t uniqueCount = firstSet->mInterfaceCount; 582 for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { 583 if (!firstSet->HasInterface(secondSet->mInterfaces[i])) { 584 uniqueCount++; 585 } 586 } 587 588 // If everything in secondSet was a duplicate, we can just use the first 589 // set. 590 if (uniqueCount == firstSet->mInterfaceCount) { 591 return RefPtr<XPCNativeSet>(firstSet).forget(); 592 } 593 594 // If the secondSet is just a superset of the first, we can use it provided 595 // that the caller doesn't care about ordering. 596 if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount) { 597 return RefPtr<XPCNativeSet>(secondSet).forget(); 598 } 599 600 // Ok, darn. Now we have to make a new set. 601 // 602 // It would be faster to just create the new set all at once, but that 603 // would involve wrangling with some pretty hairy code - especially since 604 // a lot of stuff assumes that sets are created by adding one interface to an 605 // existing set. So let's just do the slow and easy thing and hope that the 606 // above optimizations handle the common cases. 607 RefPtr<XPCNativeSet> currentSet = firstSet; 608 for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) { 609 XPCNativeInterface* iface = secondSet->mInterfaces[i]; 610 if (!currentSet->HasInterface(iface)) { 611 // Create a new augmented set, inserting this interface at the end. 612 XPCNativeSetKey key(currentSet, iface); 613 currentSet = XPCNativeSet::GetNewOrUsed(cx, &key); 614 if (!currentSet) { 615 return nullptr; 616 } 617 } 618 } 619 620 // We've got the union set. Hand it back to the caller. 621 MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount); 622 return currentSet.forget(); 623 } 624 625 // static 626 already_AddRefed<XPCNativeSet> XPCNativeSet::NewInstance( 627 JSContext* cx, nsTArray<RefPtr<XPCNativeInterface>>&& array) { 628 if (array.Length() == 0) { 629 return nullptr; 630 } 631 632 // We impose the invariant: 633 // "All sets have exactly one nsISupports interface and it comes first." 634 // This is the place where we impose that rule - even if given inputs 635 // that don't exactly follow the rule. 636 637 RefPtr<XPCNativeInterface> isup = XPCNativeInterface::GetISupports(cx); 638 uint16_t slots = array.Length() + 1; 639 640 for (auto key = array.begin(); key != array.end(); key++) { 641 if (*key == isup) { 642 slots--; 643 } 644 } 645 646 // Use placement new to create an object with the right amount of space 647 // to hold the members array 648 int size = sizeof(XPCNativeSet); 649 if (slots > 1) { 650 size += (slots - 1) * sizeof(XPCNativeInterface*); 651 } 652 void* place = new char[size]; 653 RefPtr<XPCNativeSet> obj = new (place) XPCNativeSet(); 654 655 // Stick the nsISupports in front and skip additional nsISupport(s) 656 XPCNativeInterface** outp = (XPCNativeInterface**)&obj->mInterfaces; 657 658 NS_ADDREF(*(outp++) = isup); 659 660 for (auto key = array.begin(); key != array.end(); key++) { 661 RefPtr<XPCNativeInterface> cur = std::move(*key); 662 if (isup == cur) { 663 continue; 664 } 665 *(outp++) = cur.forget().take(); 666 } 667 obj->mInterfaceCount = slots; 668 669 return obj.forget(); 670 } 671 672 // static 673 already_AddRefed<XPCNativeSet> XPCNativeSet::NewInstanceMutate( 674 XPCNativeSetKey* key) { 675 XPCNativeSet* otherSet = key->GetBaseSet(); 676 XPCNativeInterface* newInterface = key->GetAddition(); 677 678 MOZ_ASSERT(otherSet); 679 680 if (!newInterface) { 681 return nullptr; 682 } 683 684 // Use placement new to create an object with the right amount of space 685 // to hold the members array 686 int size = sizeof(XPCNativeSet); 687 size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*); 688 void* place = new char[size]; 689 RefPtr<XPCNativeSet> obj = new (place) XPCNativeSet(); 690 691 obj->mInterfaceCount = otherSet->mInterfaceCount + 1; 692 693 XPCNativeInterface** src = otherSet->mInterfaces; 694 XPCNativeInterface** dest = obj->mInterfaces; 695 for (uint16_t i = 0; i < otherSet->mInterfaceCount; i++) { 696 NS_ADDREF(*dest++ = *src++); 697 } 698 NS_ADDREF(*dest++ = newInterface); 699 700 return obj.forget(); 701 } 702 703 // static 704 void XPCNativeSet::DestroyInstance(XPCNativeSet* inst) { 705 inst->~XPCNativeSet(); 706 delete[] (char*)inst; 707 } 708 709 size_t XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) { 710 return mallocSizeOf(this); 711 } 712 713 void XPCNativeSet::DebugDump(int16_t depth) { 714 #ifdef DEBUG 715 depth--; 716 XPC_LOG_ALWAYS(("XPCNativeSet @ %p", this)); 717 XPC_LOG_INDENT(); 718 719 XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount)); 720 if (depth) { 721 for (uint16_t i = 0; i < mInterfaceCount; i++) { 722 mInterfaces[i]->DebugDump(depth); 723 } 724 } 725 XPC_LOG_OUTDENT(); 726 #endif 727 }