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