~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/js/src/xpconnect/src/xpcwrappednativeinfo.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

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