some fixes pointed out by purify. Tests better verify that wrappers are not leaking

This commit is contained in:
jband%netscape.com 1999-03-02 03:32:42 +00:00
parent 8f30448ae5
commit e569fc7c7f
8 changed files with 143 additions and 160 deletions

View File

@ -1,7 +1,6 @@
/* jband - 02/20/99 - TODO and issues list */
**** TODO ****
- convert some assertions to LOG warnings
- Ports!
- proto object per class?
- Param gc rooting?
@ -12,10 +11,6 @@
- add xpcom JS object and util functions
- reflect IID and CID trees.
- ProgIDs? (mixed in with CID tree or separate?)
- errors
- throw exceptions into JS?
- loosen restrictions re. current cx when calling wrappers across cx boundaries
- Construct objects for 'Components' tree.
**** ISSUES ****
@ -36,3 +31,4 @@
- Listener interface for class and instance create/destroy?
- Issues with shutting down a context?

View File

@ -422,6 +422,8 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
printf(message);
}
extern "C" JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
int main()
{
JSRuntime *rt;
@ -474,6 +476,10 @@ int main()
nsIXPConnectWrappedNative* wrapper;
nsIXPConnectWrappedNative* wrapper2;
nsIXPConnectWrappedNative* fool_wrapper = NULL;
/*
if(NS_SUCCEEDED(xpc->WrapNative(cx, foo, nsITestXPCFoo::IID(), &wrapper)))
*/
@ -484,6 +490,9 @@ int main()
wrapper->GetJSObject(&glob);
JS_DefineFunctions(cx, glob, glob_functions);
nsTestXPCFoo* fool = new nsTestXPCFoo();
xpc->WrapNative(cx, fool, nsITestXPCFoo2::IID(), &fool_wrapper);
if(NS_SUCCEEDED(xpc->WrapNative(cx, foo, nsITestXPCFoo2::IID(), &wrapper2)))
{
JSObject* js_obj;
@ -501,7 +510,8 @@ int main()
nsIXPConnectWrappedNative* echo_wrapper;
JSObject* echo_jsobj;
jsval echo_jsval;
xpc->WrapNative(cx, new MyEcho(), nsIEcho::IID(), &echo_wrapper);
MyEcho* myEcho = new MyEcho();
xpc->WrapNative(cx, myEcho, nsIEcho::IID(), &echo_wrapper);
echo_wrapper->GetJSObject(&echo_jsobj);
echo_jsval = OBJECT_TO_JSVAL(echo_jsobj);
JS_SetProperty(cx, glob, "echo", &echo_jsval);
@ -517,12 +527,12 @@ int main()
if(JS_GetProperty(cx, glob, "bar", &v) && JSVAL_IS_OBJECT(v))
{
JSObject* bar = JSVAL_TO_OBJECT(v);
nsIXPConnectWrappedJS* wrapper;
nsIXPConnectWrappedJS* wrapper3;
if(NS_SUCCEEDED(xpc->WrapJS(cx,
JSVAL_TO_OBJECT(v),
nsITestXPCFoo::IID(), &wrapper)))
nsITestXPCFoo::IID(), &wrapper3)))
{
nsITestXPCFoo* ptr = (nsITestXPCFoo*)wrapper;
nsITestXPCFoo* ptr = (nsITestXPCFoo*)wrapper3;
int result;
JSObject* test_js_obj;
ptr->Test(11, 13, &result);
@ -530,7 +540,7 @@ int main()
nsIXPConnectWrappedJSMethods* methods;
wrapper->QueryInterface(nsIXPConnectWrappedJSMethods::IID(),
wrapper3->QueryInterface(nsIXPConnectWrappedJSMethods::IID(),
(void**) &methods);
methods->GetJSObject(&test_js_obj);
@ -542,14 +552,16 @@ int main()
XPC_DUMP(xpc, 50);
NS_RELEASE(methods);
NS_RELEASE(wrapper);
NS_RELEASE(wrapper3);
}
}
NS_RELEASE(com_obj);
NS_RELEASE(wrapper2);
NS_RELEASE(echo_wrapper);
NS_RELEASE(myEcho);
}
NS_RELEASE(wrapper);
// NS_RELEASE(wrapper);
}
NS_RELEASE(foo);
@ -561,13 +573,34 @@ int main()
// XPC_LOG_ALWAYS((""));
// XPC_DUMP(xpc, 3);
if(glob)
{
JS_DeleteProperty(cx, glob, "foo");
JS_DeleteProperty(cx, glob, "echo");
JS_DeleteProperty(cx, glob, "bar");
JS_DeleteProperty(cx, glob, "foo2");
JS_DeleteProperty(cx, glob, "baz");
JS_DeleteProperty(cx, glob, "baz2");
JS_DeleteProperty(cx, glob, "reciever");
JS_SetGlobalObject(cx, JS_NewObject(cx, &global_class, NULL, NULL));
}
NS_RELEASE(wrapper);
NS_RELEASE(fool_wrapper);
// js_DumpGCHeap = stdout;
JS_GC(cx);
// printf("-----------------------\n");
// JS_GC(cx);
// dump to log test...
// XPC_LOG_ALWAYS((""));
// XPC_LOG_ALWAYS(("after running JS_GC..."));
// XPC_LOG_ALWAYS((""));
// XPC_DUMP(xpc, 3);
XPC_LOG_ALWAYS((""));
XPC_LOG_ALWAYS(("after running JS_GC..."));
XPC_LOG_ALWAYS((""));
XPC_DUMP(xpc, 3);
NS_RELEASE(xpc);
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);

View File

@ -241,6 +241,8 @@ catch(e) {
////////////////////
// check exceptions on can't convert
// XXX this is bad test since null is now convertable.
/*
try {
echo.SetReciever(null);
// print("Can't convert arg to Native ("+out+")- failed");
@ -250,7 +252,7 @@ catch(e) {
// print("Can't convert arg to Native ("+e+") - passed");
print("Can't convert arg to Native - passed");
}
*/
////////////////////
// FailInJSTest
@ -333,5 +335,7 @@ var end_time = new Date().getTime()/1000;
var interval = parseInt(100*(end_time - start_time),10)/100;
print("XPConnect did "+iterations+" iterations in "+interval+ " seconds.");
print(".......................................");
echoJS.SetReciever(null);
echo.SetReciever(null);

View File

@ -20,6 +20,55 @@
#include "xpcprivate.h"
/*
* This is a table driven scheme to determine if the types of the params of the
* given method exclude that method from being reflected via XPConnect.
*
* The table can be appended and modified as requirements change. However...
*
* The table ASSUMES that all the type idenetifiers are contiguous starting
* at ZERO. And, it also ASSUMES that the additional criteria of whether or
* not a give type is reflectable are its use as a pointer and/or 'out' type.
*
* The table has a row for each type and columns for the combinations of
* that type being used as a pointer type and/or as an 'out' param.
*/
#define XPC_MK_BIT(p,o) (1 << (((p)?1:0)+((o)?2:0)))
#define XPC_IS_REFLECTABLE(f, p, o) ((f) & XPC_MK_BIT((p),(o)))
#define XPC_MK_FLAG(np_no,p_no,np_o,p_o) \
((uint8)((np_no) | ((p_no) << 1) | ((np_o) << 2) | ((p_o) << 3)))
/***********************************************************/
#define XPC_FLAG_COUNT nsXPTType::T_INTERFACE_IS+1
/* '1' means 'reflectable'. '0' means 'not reflectable'. */
static uint8 xpc_reflectable_flags[XPC_FLAG_COUNT] = {
/* 'p' stands for 'pointer' and 'o' stands for 'out' */
/* !p&!o, p&!o, !p&o, p&o */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_I8 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_I16 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_I32 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_I64 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_U8 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_U16 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_U32 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_U64 */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_FLOAT */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_DOUBLE */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_BOOL */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_CHAR */
XPC_MK_FLAG( 1 , 1 , 1 , 0 ), /* T_WCHAR */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* T_VOID */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_IID */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* T_BSTR */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_CHAR_STR */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_WCHAR_STR */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_INTERFACE */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ) /* T_INTERFACE_IS */
};
/***********************************************************/
// static
JSBool
XPCConvert::IsMethodReflectable(const nsXPTMethodInfo& info)
@ -31,143 +80,19 @@ XPCConvert::IsMethodReflectable(const nsXPTMethodInfo& info)
{
const nsXPTParamInfo& param = info.GetParam(i);
const nsXPTType& type = param.GetType();
if(param.IsOut())
{
if(type.IsPointer())
{
switch(type.TagPart())
{
case nsXPTType::T_I8 :
case nsXPTType::T_I16 :
case nsXPTType::T_I32 :
case nsXPTType::T_I64 :
case nsXPTType::T_U8 :
case nsXPTType::T_U16 :
case nsXPTType::T_U32 :
case nsXPTType::T_U64 :
case nsXPTType::T_FLOAT :
case nsXPTType::T_DOUBLE :
case nsXPTType::T_BOOL :
case nsXPTType::T_CHAR :
case nsXPTType::T_WCHAR :
case nsXPTType::T_VOID :
uint8 base_type = type.TagPart();
NS_ASSERTION(base_type < XPC_FLAG_COUNT, "BAD TYPE");
if(!XPC_IS_REFLECTABLE(xpc_reflectable_flags[base_type],
type.IsPointer(), param.IsOut()))
return JS_FALSE;
case nsXPTType::T_IID :
continue;
case nsXPTType::T_BSTR :
return JS_FALSE;
case nsXPTType::T_CHAR_STR :
case nsXPTType::T_WCHAR_STR :
case nsXPTType::T_INTERFACE :
case nsXPTType::T_INTERFACE_IS:
continue;
default:
NS_ASSERTION(0, "bad type");
return JS_FALSE;
}
}
else // !(type.IsPointer())
{
switch(type.TagPart())
{
case nsXPTType::T_I8 :
case nsXPTType::T_I16 :
case nsXPTType::T_I32 :
case nsXPTType::T_I64 :
case nsXPTType::T_U8 :
case nsXPTType::T_U16 :
case nsXPTType::T_U32 :
case nsXPTType::T_U64 :
case nsXPTType::T_FLOAT :
case nsXPTType::T_DOUBLE :
case nsXPTType::T_BOOL :
case nsXPTType::T_CHAR :
case nsXPTType::T_WCHAR :
continue;
case nsXPTType::T_VOID :
case nsXPTType::T_IID :
case nsXPTType::T_BSTR :
case nsXPTType::T_CHAR_STR :
case nsXPTType::T_WCHAR_STR :
case nsXPTType::T_INTERFACE :
case nsXPTType::T_INTERFACE_IS:
default:
NS_ASSERTION(0, "bad type");
return JS_FALSE;
}
}
}
else // !(param.IsOut())
{
if(type.IsPointer())
{
switch(type.TagPart())
{
case nsXPTType::T_I8 :
case nsXPTType::T_I16 :
case nsXPTType::T_I32 :
case nsXPTType::T_I64 :
case nsXPTType::T_U8 :
case nsXPTType::T_U16 :
case nsXPTType::T_U32 :
case nsXPTType::T_U64 :
case nsXPTType::T_FLOAT :
case nsXPTType::T_DOUBLE :
case nsXPTType::T_BOOL :
case nsXPTType::T_CHAR :
case nsXPTType::T_WCHAR :
continue;
case nsXPTType::T_VOID :
return JS_FALSE;
case nsXPTType::T_IID :
continue;
case nsXPTType::T_BSTR :
return JS_FALSE;
case nsXPTType::T_CHAR_STR :
case nsXPTType::T_WCHAR_STR :
case nsXPTType::T_INTERFACE :
case nsXPTType::T_INTERFACE_IS:
continue;
default:
NS_ASSERTION(0, "bad type");
return JS_FALSE;
}
}
else // !(type.IsPointer())
{
switch(type.TagPart())
{
case nsXPTType::T_I8 :
case nsXPTType::T_I16 :
case nsXPTType::T_I32 :
case nsXPTType::T_I64 :
case nsXPTType::T_U8 :
case nsXPTType::T_U16 :
case nsXPTType::T_U32 :
case nsXPTType::T_U64 :
case nsXPTType::T_FLOAT :
case nsXPTType::T_DOUBLE :
case nsXPTType::T_BOOL :
case nsXPTType::T_CHAR :
case nsXPTType::T_WCHAR :
continue;
case nsXPTType::T_VOID :
case nsXPTType::T_IID :
case nsXPTType::T_BSTR :
case nsXPTType::T_CHAR_STR :
case nsXPTType::T_WCHAR_STR :
case nsXPTType::T_INTERFACE :
case nsXPTType::T_INTERFACE_IS:
default:
NS_ASSERTION(0, "bad type");
return JS_FALSE;
}
}
}
}
return JS_TRUE;
}
/***************************************************************************/
#define JAM_DOUBLE(cx,v,d) (d=JS_NewDouble(cx,(jsdouble)v),DOUBLE_TO_JSVAL(d))
#define FIT_32(cx,i,d) (INT_FITS_IN_JSVAL(i)?INT_TO_JSVAL(i):JAM_DOUBLE(cx,i,d))
// Win32 can't handle uint64 to double conversion
@ -285,7 +210,10 @@ XPCConvert::NativeData2JS(JSContext* cx, jsval* d, const void* s,
{
nsISupports* iface = *((nsISupports**)s);
if(!iface)
{
*d = JSVAL_NULL;
break;
}
JSObject* aJSObj;
// is this a wrapped JS object?
if(nsXPCWrappedJSClass::IsWrappedJS(iface))
@ -327,6 +255,7 @@ XPCConvert::NativeData2JS(JSContext* cx, jsval* d, const void* s,
return JS_TRUE;
}
/***************************************************************************/
// static
JSBool
XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
@ -339,7 +268,6 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
int32 ti;
uint32 tu;
jsdouble td;
JSBool r;
if(pErr)
*pErr = XPCJSError::BAD_CONVERT_JS;
@ -542,6 +470,12 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
JSObject* obj;
nsISupports* iface = NULL;
if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
{
*((nsISupports**)d) = NULL;
return JS_TRUE;
}
// only wrap JSObjects
if(!JSVAL_IS_OBJECT(s) ||
(!(obj = JSVAL_TO_OBJECT(s))))

View File

@ -74,7 +74,7 @@ nsXPCWrappedJS::Release(void)
}
else
{
NS_RELEASE(mRoot);
mRoot->Release();
}
return 0;
}
@ -362,7 +362,7 @@ nsXPCWrappedJS::DebugDump(int depth)
}
char * iid = GetClass()->GetIID().ToString();
XPC_LOG_ALWAYS(("IID number is %s", iid));
free(iid);
delete iid;
XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x", mClass));
if(mMethods)
XPC_LOG_ALWAYS(("mMethods @ %x with mRefCnt = %d", \

View File

@ -83,9 +83,15 @@ nsXPCWrappedJSClass::nsXPCWrappedJSClass(XPCContext* xpcc, REFNSIID aIID,
{
if(methodCount)
{
if(NULL != (mDescriptors = new uint32[(methodCount/32)+1]))
int wordCount = (methodCount/32)+1;
if(NULL != (mDescriptors = new uint32[wordCount]))
{
for(int i = 0; i < methodCount; i++)
int i;
// init flags to 0;
for(i = wordCount-1; i >= 0; i--)
mDescriptors[i] = 0;
for(i = 0; i < methodCount; i++)
{
const nsXPTMethodInfo* info;
if(NS_SUCCEEDED(mInfo->GetMethodInfo(i, &info)))
@ -525,7 +531,7 @@ nsXPCWrappedJSClass::DebugDump(int depth)
}
char * iid = mIID.ToString();
XPC_LOG_ALWAYS(("IID number is %s", iid));
free(iid);
delete iid;
XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo));
uint16 methodCount = 0;
if(depth)

View File

@ -35,6 +35,8 @@ nsXPCWrappedNative::AddRef(void)
else if(2 == mRefCnt)
JS_AddRoot(mClass->GetXPCContext()->GetJSContext(), &mJSObj);
// XPC_LOG_DEBUG(("+++ AddRef of %x with mJSObj %x and mRefCnt = %d",this,mJSObj, mRefCnt));
return mRefCnt;
}
@ -48,16 +50,24 @@ nsXPCWrappedNative::Release(void)
{
if(mRoot == this)
{
// XPC_LOG_DEBUG(("--- Delete of %x with mJSObj %x and mRefCnt = %d",this,mJSObj, mRefCnt));
NS_DELETEXPCOM(this); // cascaded delete
}
else
{
NS_RELEASE(mRoot);
// XPC_LOG_DEBUG(("--- Release of root %x with mJSObj %x and mRefCnt = %d",this,mJSObj, mRefCnt));
mRoot->Release();
}
return 0;
}
if(1 == mRefCnt)
{
// XPC_LOG_DEBUG(("--- Removing root of %x with mJSObj %x and mRefCnt = %d",this,mJSObj, mRefCnt));
JS_RemoveRoot(mClass->GetXPCContext()->GetJSContext(), &mJSObj);
}
// XPC_LOG_DEBUG(("--- Release of %x with mJSObj %x and mRefCnt = %d",this,mJSObj, mRefCnt));
return mRefCnt;
}
@ -367,7 +377,7 @@ nsXPCWrappedNative::DebugDump(int depth)
XPC_LOG_ALWAYS(("interface name is %s", GetClass()->GetInterfaceName()));
char * iid = GetClass()->GetIID().ToString();
XPC_LOG_ALWAYS(("IID number is %s", iid));
free(iid);
delete iid;
XPC_LOG_ALWAYS(("JSObject @ %x", mJSObj));
XPC_LOG_ALWAYS(("nsXPCWrappedNativeClass @ %x", mClass));
if(GetDynamicScriptable())

View File

@ -1203,7 +1203,7 @@ nsXPCWrappedNativeClass::DebugDump(int depth)
XPC_LOG_ALWAYS(("interface name is %s", GetInterfaceName()));
char * iid = mIID.ToString();
XPC_LOG_ALWAYS(("IID number is %s", iid));
free(iid);
delete iid;
XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo));
if(depth)
{