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