1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* ***** BEGIN LICENSE BLOCK *****
4
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16
* The Original Code is Mozilla Communicator client code, released
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.
25
* John Bandhauer <jband@netscape.com> (original author)
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.
39
* ***** END LICENSE BLOCK ***** */
41
/* Manage the shared info about interfaces for use by wrappedNatives. */
43
#include "xpcprivate.h"
45
/***************************************************************************/
50
XPCNativeMember::GetCallInfo(XPCCallContext& ccx,
52
XPCNativeInterface** pInterface,
53
XPCNativeMember** pMember)
58
// We expect funobj to be a clone, we need the real funobj.
60
fun = (JSFunction*) JS_GetPrivate(ccx, funobj);
61
realFunObj = JS_GetFunctionObject(fun);
66
if(!JS_GetReservedSlot(ccx, realFunObj, 0, &ifaceVal) ||
67
!JS_GetReservedSlot(ccx, realFunObj, 1, &memberVal) ||
68
!JSVAL_IS_INT(ifaceVal) || !JSVAL_IS_INT(memberVal))
73
*pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
74
*pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
80
XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface)
84
const nsXPTConstant* constant;
85
if(NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant)))
88
const nsXPTCMiniVariant& mv = *constant->GetValue();
93
v.type = constant->GetType();
94
memcpy(&v.val, &mv.val, sizeof(mv.val));
98
if(!XPCConvert::NativeData2JS(ccx, &resultVal, &v.val, v.type,
99
nsnull, nsnull, nsnull))
103
XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
112
// This is a method or attribute - we'll be needing a function object
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!
118
JSContext* cx = ccx.GetSafeJSContext();
128
const nsXPTMethodInfo* info;
129
if(NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info)))
132
// Note: ASSUMES that retval is last arg.
133
argc = (intN) info->GetParamCount();
134
if(argc && info->GetParam((uint8)(argc-1)).IsRetval())
138
callback = XPC_WN_CallMethod;
142
if(IsWritableAttribute())
143
flags = JSFUN_GETTER | JSFUN_SETTER;
145
flags = JSFUN_GETTER;
147
callback = XPC_WN_GetterSetter;
150
JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull,
151
iface->GetMemberName(ccx, this));
155
JSObject* funobj = JS_GetFunctionObject(fun);
159
if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(iface))||
160
!JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(this)))
164
XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
165
mVal = OBJECT_TO_JSVAL(funobj);
172
/***************************************************************************/
173
// XPCNativeInterface
177
XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
179
AutoMarkingNativeInterfacePtr iface(ccx);
180
XPCJSRuntime* rt = ccx.GetRuntime();
182
IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
187
XPCAutoLock lock(rt->GetMapLock());
188
iface = map->Find(*iid);
194
nsCOMPtr<nsIInterfaceInfo> info;
195
ccx.GetXPConnect()->GetInfoForIID(iid, getter_AddRefs(info));
199
iface = NewInstance(ccx, info);
204
XPCAutoLock lock(rt->GetMapLock());
205
XPCNativeInterface* iface2 = map->Add(iface);
208
NS_ERROR("failed to add our interface!");
209
DestroyInstance(ccx, rt, iface);
212
else if(iface2 != iface)
214
DestroyInstance(ccx, rt, iface);
224
XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, nsIInterfaceInfo* info)
226
AutoMarkingNativeInterfacePtr iface(ccx);
229
if(NS_FAILED(info->GetIIDShared(&iid)) || !iid)
232
XPCJSRuntime* rt = ccx.GetRuntime();
234
IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
239
XPCAutoLock lock(rt->GetMapLock());
240
iface = map->Find(*iid);
246
iface = NewInstance(ccx, info);
251
XPCAutoLock lock(rt->GetMapLock());
252
XPCNativeInterface* iface2 = map->Add(iface);
255
NS_ERROR("failed to add our interface!");
256
DestroyInstance(ccx, rt, iface);
259
else if(iface2 != iface)
261
DestroyInstance(ccx, rt, iface);
271
XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const char* name)
273
nsCOMPtr<nsIInterfaceInfo> info;
274
ccx.GetXPConnect()->GetInfoForName(name, getter_AddRefs(info));
275
return info ? GetNewOrUsed(ccx, info) : nsnull;
280
XPCNativeInterface::GetISupports(XPCCallContext& ccx)
282
// XXX We should optimize this to cache this common XPCNativeInterface.
283
return GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
288
XPCNativeInterface::NewInstance(XPCCallContext& ccx,
289
nsIInterfaceInfo* aInfo)
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;
297
JSBool failed = JS_FALSE;
299
PRUint16 methodCount;
301
PRUint16 realTotalCount = 0;
302
XPCNativeMember* cur;
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.
315
if(NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
318
if(NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
319
NS_FAILED(aInfo->GetConstantCount(&constCount)))
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
327
if(!nsXPConnect::IsISupportsDescendant(aInfo))
330
totalCount = methodCount + constCount;
332
if(totalCount > MAX_LOCAL_MEMBER_COUNT)
334
members = new XPCNativeMember[totalCount];
340
members = local_members;
343
// NOTE: since getters and setters share a member, we might not use all
344
// of the member objects.
346
for(i = 0; i < methodCount; i++)
348
const nsXPTMethodInfo* info;
349
if(NS_FAILED(aInfo->GetMethodInfo(i, &info)))
355
// don't reflect Addref or Release
359
if(!XPCConvert::IsMethodReflectable(*info))
362
str = JS_InternString(ccx, info->GetName());
365
NS_ASSERTION(0,"bad method name");
369
name = STRING_TO_JSVAL(str);
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();
384
// XXX need better way to find dups
385
// NS_ASSERTION(!LookupMemberByID(name),"duplicate method name");
386
cur = &members[realTotalCount++];
389
cur->SetReadOnlyAttribute(i);
397
for(i = 0; i < constCount; i++)
399
const nsXPTConstant* constant;
400
if(NS_FAILED(aInfo->GetConstant(i, &constant)))
406
str = JS_InternString(ccx, constant->GetName());
409
NS_ASSERTION(0,"bad constant name");
413
name = STRING_TO_JSVAL(str);
415
// XXX need better way to find dups
416
//NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");
418
cur = &members[realTotalCount++];
427
if(NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
428
nsnull == (str = JS_InternString(ccx, bytes)))
432
interfaceName = STRING_TO_JSVAL(str);
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];
444
obj = new(place) XPCNativeInterface(aInfo, interfaceName);
448
obj->mMemberCount = realTotalCount;
449
// copy valid members
451
memcpy(obj->mMembers, members,
452
realTotalCount * sizeof(XPCNativeMember));
456
if(members && members != local_members)
464
XPCNativeInterface::DestroyInstance(JSContext* cx, XPCJSRuntime* rt,
465
XPCNativeInterface* inst)
467
inst->~XPCNativeInterface();
468
delete [] (char*) inst;
472
XPCNativeInterface::GetMemberName(XPCCallContext& ccx,
473
const XPCNativeMember* member) const
475
return JS_GetStringBytes(JSVAL_TO_STRING(member->GetName()));
479
XPCNativeInterface::DebugDump(PRInt16 depth)
483
XPC_LOG_ALWAYS(("XPCNativeInterface @ %x", this));
485
XPC_LOG_ALWAYS(("name is %s", GetNameString()));
486
XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount));
487
XPC_LOG_ALWAYS(("mInfo @ %x", mInfo.get()));
492
/***************************************************************************/
497
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
499
AutoMarkingNativeSetPtr set(ccx);
501
AutoMarkingNativeInterfacePtr iface(ccx);
502
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
506
XPCNativeSetKey key(nsnull, iface, 0);
508
XPCJSRuntime* rt = ccx.GetRuntime();
509
NativeSetMap* map = rt->GetNativeSetMap();
514
XPCAutoLock lock(rt->GetMapLock());
515
set = map->Find(&key);
521
// hacky way to get a XPCNativeInterface** using the AutoPtr
522
XPCNativeInterface* temp[] = {iface};
523
set = NewInstance(ccx, temp, 1);
528
XPCAutoLock lock(rt->GetMapLock());
529
XPCNativeSet* set2 = map->Add(&key, set);
532
NS_ERROR("failed to add our set!");
533
DestroyInstance(set);
538
DestroyInstance(set);
548
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, nsIClassInfo* classInfo)
550
AutoMarkingNativeSetPtr set(ccx);
551
XPCJSRuntime* rt = ccx.GetRuntime();
553
ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
558
XPCAutoLock lock(rt->GetMapLock());
559
set = map->Find(classInfo);
565
nsIID** iidArray = nsnull;
566
XPCNativeInterface** interfaceArray = nsnull;
567
PRUint32 iidCount = 0;
569
if(NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray)))
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.
575
// Make sure these are set correctly...
580
NS_ASSERTION((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array");
582
// !!! from here on we only exit through the 'out' label !!!
586
interfaceArray = new XPCNativeInterface*[iidCount];
590
XPCNativeInterface** currentInterface = interfaceArray;
591
nsIID** currentIID = iidArray;
592
PRUint16 interfaceCount = 0;
594
for(PRUint32 i = 0; i < iidCount; i++)
596
nsIID* iid = *(currentIID++);
598
AutoMarkingNativeInterfacePtr iface(ccx);
599
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
607
*(currentInterface++) = iface;
613
set = NewInstance(ccx, interfaceArray, interfaceCount);
616
NativeSetMap* map2 = rt->GetNativeSetMap();
620
XPCNativeSetKey key(set, nsnull, 0);
623
XPCAutoLock lock(rt->GetMapLock());
624
XPCNativeSet* set2 = map2->Add(&key, set);
627
NS_ERROR("failed to add our set!");
628
DestroyInstance(set);
634
DestroyInstance(set);
641
set = GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
644
set = GetNewOrUsed(ccx, &NS_GET_IID(nsISupports));
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!");
656
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
658
delete [] interfaceArray;
665
XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
668
ClassInfo2NativeSetMap* map;
670
if(nsnull != (rt = nsXPConnect::GetRuntime()) &&
671
nsnull != (map = rt->GetClassInfo2NativeSetMap()))
673
XPCAutoLock lock(rt->GetMapLock());
674
map->Remove(classInfo);
680
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx,
681
XPCNativeSet* otherSet,
682
XPCNativeInterface* newInterface,
685
AutoMarkingNativeSetPtr set(ccx);
686
XPCJSRuntime* rt = ccx.GetRuntime();
687
NativeSetMap* map = rt->GetNativeSetMap();
691
XPCNativeSetKey key(otherSet, newInterface, position);
694
XPCAutoLock lock(rt->GetMapLock());
695
set = map->Find(&key);
702
set = NewInstanceMutate(otherSet, newInterface, position);
704
set = NewInstance(ccx, &newInterface, 1);
710
XPCAutoLock lock(rt->GetMapLock());
711
XPCNativeSet* set2 = map->Add(&key, set);
714
NS_ERROR("failed to add our set!");
715
DestroyInstance(set);
720
DestroyInstance(set);
730
XPCNativeSet::NewInstance(XPCCallContext& ccx,
731
XPCNativeInterface** array,
734
XPCNativeSet* obj = nsnull;
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.
744
XPCNativeInterface* isup = XPCNativeInterface::GetISupports(ccx);
745
PRUint16 slots = count+1;
748
XPCNativeInterface** pcur;
750
for(i = 0, pcur = array; i < count; i++, pcur++)
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);
760
size += (slots - 1) * sizeof(XPCNativeInterface*);
761
void* place = new char[size];
763
obj = new(place) XPCNativeSet();
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
774
for(i = 0; i < count; i++)
776
XPCNativeInterface* cur;
778
if(isup == (cur = *(inp++)))
781
memberCount += cur->GetMemberCount();
783
obj->mMemberCount = memberCount;
784
obj->mInterfaceCount = slots;
792
XPCNativeSet::NewInstanceMutate(XPCNativeSet* otherSet,
793
XPCNativeInterface* newInterface,
796
XPCNativeSet* obj = nsnull;
800
if(otherSet && position > otherSet->mInterfaceCount)
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);
807
size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
808
void* place = new char[size];
810
obj = new(place) XPCNativeSet();
816
obj->mMemberCount = otherSet->GetMemberCount() +
817
newInterface->GetMemberCount();
818
obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
820
XPCNativeInterface** src = otherSet->mInterfaces;
821
XPCNativeInterface** dest = obj->mInterfaces;
822
for(PRUint16 i = 0; i < obj->mInterfaceCount; i++)
825
*dest++ = newInterface;
832
obj->mMemberCount = newInterface->GetMemberCount();
833
obj->mInterfaceCount = 1;
834
obj->mInterfaces[0] = newInterface;
843
XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
845
inst->~XPCNativeSet();
846
delete [] (char*) inst;
850
XPCNativeSet::DebugDump(PRInt16 depth)
854
XPC_LOG_ALWAYS(("XPCNativeSet @ %x", this));
857
XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount));
860
for(PRUint16 i = 0; i < mInterfaceCount; i++)
861
mInterfaces[i]->DebugDump(depth);
863
XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount));