adding code to throw exceptions into JS with customizable messages

This commit is contained in:
jband%netscape.com 1999-02-28 01:41:20 +00:00
Родитель f672d26a46
Коммит 88cc0c3a6e
13 изменённых файлов: 343 добавлений и 23 удалений

Просмотреть файл

@ -42,6 +42,7 @@ CPPSRCS= \
xpclog.cpp \
xpcmaps.cpp \
xpcnsid.cpp \
xpcthrower.cpp \
xpcwrappedjs.cpp \
xpcwrappedjsclass.cpp \
xpcwrappednative.cpp \

Просмотреть файл

@ -1,6 +1,6 @@
/* jband - 02/20/99 - TODO and issues list */
**** ISSUES ****
**** TODO ****
- convert some assertions to LOG warnings
- Ports!
- proto object per class?
@ -16,6 +16,7 @@
- throw exceptions into JS?
- loosen restrictions re. current cx when calling wrappers across cx boundaries
- Construct objects for 'Components' tree.
**** ISSUES ****

Просмотреть файл

@ -43,6 +43,7 @@ OBJS= \
.\$(OBJDIR)\xpcconvert.obj \
.\$(OBJDIR)\xpcmaps.obj \
.\$(OBJDIR)\xpcnsid.obj \
.\$(OBJDIR)\xpcthrower.obj \
.\$(OBJDIR)\xpcwrappedjs.obj \
.\$(OBJDIR)\xpcwrappedjsclass.obj \
.\$(OBJDIR)\xpcwrappednative.obj \

Просмотреть файл

@ -135,6 +135,8 @@ public:
char** p15,
uint16** p16) = 0;
NS_IMETHOD MethodWithNative(int p1, void* p2) = 0;
NS_IMETHOD ReturnCode(int code) = 0;
};
/***************************************************************************/

Просмотреть файл

@ -46,7 +46,8 @@ nsXPConnect::GetXPConnect()
if(mSelf && (!mSelf->mContextMap ||
!mSelf->mAllocator ||
!mSelf->mArbitraryScriptable ||
!mSelf->mInterfaceInfoManager))
!mSelf->mInterfaceInfoManager ||
!mSelf->mThrower))
NS_RELEASE(mSelf);
}
if(mSelf)
@ -105,11 +106,27 @@ nsXPConnect::GetContext(JSContext* cx, nsXPConnect* xpc /*= NULL*/)
return xpcc;
}
// static
XPCJSThrower*
nsXPConnect::GetJSThrower(nsXPConnect* xpc /*= NULL */)
{
XPCJSThrower* thrower;
nsXPConnect* xpcl = xpc;
if(!xpcl && !(xpcl = GetXPConnect()))
return NULL;
thrower = xpcl->mThrower;
if(!xpc)
NS_RELEASE(xpcl);
return thrower;
}
nsXPConnect::nsXPConnect()
: mContextMap(NULL),
mAllocator(NULL),
mArbitraryScriptable(NULL),
mInterfaceInfoManager(NULL)
mInterfaceInfoManager(NULL),
mThrower(NULL)
{
NS_INIT_REFCNT();
NS_ADDREF_THIS();
@ -124,6 +141,7 @@ nsXPConnect::nsXPConnect()
// XXX later this will be a service
mInterfaceInfoManager = XPT_GetInterfaceInfoManager();
mThrower = new XPCJSThrower(JS_TRUE);
}
nsXPConnect::~nsXPConnect()
@ -137,7 +155,8 @@ nsXPConnect::~nsXPConnect()
// XXX later this will be a service
if(mInterfaceInfoManager)
NS_RELEASE(mInterfaceInfoManager);
if(mThrower)
delete mThrower;
mSelf = NULL;
}

Просмотреть файл

@ -46,7 +46,8 @@ static NS_DEFINE_IID(kAllocatorCID, NS_ALLOCATOR_CID);
static void RegAllocator()
{
nsRepository::RegisterComponent(kAllocatorCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE);
nsRepository::RegisterComponent(kAllocatorCID, NULL, NULL, XPCOM_DLL,
PR_FALSE, PR_FALSE);
}
@ -204,6 +205,8 @@ public:
uint16** p16);
NS_IMETHOD MethodWithNative(int p1, void* p2);
NS_IMETHOD ReturnCode(int code);
MyEcho();
private:
nsIEcho* mReciever;
@ -333,6 +336,12 @@ MyEcho::MethodWithNative(int p1, void* p2)
return NS_OK;
}
NS_IMETHODIMP
MyEcho::ReturnCode(int code)
{
return (nsresult) code;
}
/***************************************************************************/
FILE *gOutFile = NULL;

Просмотреть файл

@ -206,6 +206,24 @@ for(i = 0; i < 16; i++) {
if(all_ok)
print("SendInOutManyTypes - passed");
////////////////////
// ReturnCode
try {
echo.ReturnCode(0);
print("ReturnCode(0) - passed");
}
catch(e) {
print("ReturnCode(0) exception text: "+e+" - failed");
}
try {
echo.ReturnCode(-1);
print("ReturnCode(-1) - failed");
}
catch(e) {
print("ReturnCode(-1) exception text: "+e+" - passed");
}
print(".......................................");
print("simple speed tests...");
@ -221,6 +239,7 @@ echoJS.SetReciever = function(r) {this.r = r;};
echoJS.SendOneString = function(str) {if(this.r)this.r.SendOneString(str)};
echoJS.SimpleCallNoEcho = function(){}
/*********************************************/
/*********************************************/
print("\nEcho.SimpleCallNoEcho (just makes call with no params and no callback)");

35
js/src/xpconnect/xpc.msg Normal file
Просмотреть файл

@ -0,0 +1,35 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* Error Message definitions. */
/*
* The format here is the same as that in js/src/js.msg
* However, arguments are not supported. And, the error->exception
* mapping is not appropriate here. So, the arg count and exception id
* columns are left with zero values.
*
* Also, the idetifiers here are read in as members of an anonymous enum in
* the class XPCJSError rather than at the top level as in JS.
*/
MSG_DEF(NOT_AN_ERROR, 0, 0, 0, "<Error #0 is reserved>")
MSG_DEF(NOT_ENOUGH_ARGS, 1, 0, 0, "Not enough arguments")
MSG_DEF(NEED_OUT_OBJECT, 2, 0, 0, "'Out' argument must be an object")
MSG_DEF(CANT_SET_OUT_VAL, 3, 0, 0, "Can not set 'value' property of 'out' argument")
MSG_DEF(NATIVE_RETURNED_FAILURE, 4, 0, 0, "Component returned failure code:")

Просмотреть файл

@ -36,5 +36,7 @@ class nsXPCWrappedNative;
class nsXPCWrappedJSClass;
class nsXPCWrappedNativeClass;
class nsXPCWrappedJSMethods;
class XPCJSThrower;
class XPCNativeMemberDescriptor;
#endif /* xpcforwards_h___ */

Просмотреть файл

@ -33,6 +33,7 @@
#include "nsIXPCScriptable.h"
#include "jsapi.h"
#include "jshash.h"
#include "jsprf.h"
#include "xpt_cpp.h"
#include "xpcforwards.h"
#include "xpcvariant.h"
@ -77,6 +78,7 @@ public:
static nsIAllocator* GetAllocator(nsXPConnect* xpc = NULL);
static nsIInterfaceInfoManager* GetInterfaceInfoManager(nsXPConnect* xpc = NULL);
static XPCContext* GetContext(JSContext* cx, nsXPConnect* xpc = NULL);
static XPCJSThrower* GetJSThrower(nsXPConnect* xpc = NULL);
JSContext2XPCContextMap* GetContextMap() {return mContextMap;}
nsIXPCScriptable* GetArbitraryScriptable() {return mArbitraryScriptable;}
@ -93,6 +95,7 @@ private:
nsIAllocator* mAllocator;
nsIXPCScriptable* mArbitraryScriptable;
nsIInterfaceInfoManager* mInterfaceInfoManager;
XPCJSThrower* mThrower;
};
/***************************************************************************/
@ -141,6 +144,60 @@ private:
IID2WrappedNativeClassMap* mWrappedNativeClassMap;
};
/***************************************************************************/
// code for throwing exceptions into JS
struct XPCJSErrorFormatString
{
const char *format;
/* uintN argCount; */
};
struct XPCJSError
{
enum {
#define MSG_DEF(name, number, count, exception, format) \
name = number,
#include "xpc.msg"
#undef MSG_DEF
LIMIT
};
};
class XPCJSThrower
{
public:
void ThrowBadResultException(JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
nsresult result);
void ThrowBadParamException(uintN errNum,
JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
uintN paramNum);
void ThrowException(uintN errNum,
JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc);
XPCJSThrower(JSBool Verbose = JS_FALSE);
~XPCJSThrower();
private:
void Verbosify(nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
char** psz, PRBool own);
private:
static XPCJSErrorFormatString default_formats[XPCJSError::LIMIT+1];
XPCJSErrorFormatString* mFormats;
JSBool mVerbose;
};
/***************************************************************************/
// this interfaces exists so we can refcount nsXPCWrappedJSClass
@ -330,6 +387,7 @@ public:
REFNSIID GetIID() const {return mIID;}
const char* GetInterfaceName();
const char* GetMemberName(const XPCNativeMemberDescriptor* desc) const;
nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;}
XPCContext* GetXPCContext() const {return mXPCContext;}
JSContext* GetJSContext() const {return mXPCContext->GetJSContext();}
@ -357,23 +415,26 @@ public:
const XPCNativeMemberDescriptor* desc,
jsval* vp);
JSBool CallWrappedMethod(nsXPCWrappedNative* wrapper,
JSBool CallWrappedMethod(JSContext* cx,
nsXPCWrappedNative* wrapper,
const XPCNativeMemberDescriptor* desc,
JSBool isAttributeSet,
uintN argc, jsval *argv, jsval *vp);
JSBool GetAttributeAsJSVal(nsXPCWrappedNative* wrapper,
JSBool GetAttributeAsJSVal(JSContext* cx,
nsXPCWrappedNative* wrapper,
const XPCNativeMemberDescriptor* desc,
jsval* vp)
{
return CallWrappedMethod(wrapper, desc, JS_FALSE, 0, NULL, vp);
return CallWrappedMethod(cx, wrapper, desc, JS_FALSE, 0, NULL, vp);
}
JSBool SetAttributeFromJSVal(nsXPCWrappedNative* wrapper,
JSBool SetAttributeFromJSVal(JSContext* cx,
nsXPCWrappedNative* wrapper,
const XPCNativeMemberDescriptor* desc,
jsval* vp)
{
return CallWrappedMethod(wrapper, desc, JS_TRUE, 1, vp, NULL);
return CallWrappedMethod(cx, wrapper, desc, JS_TRUE, 1, vp, NULL);
}
JSObject* GetInvokeFunObj(const XPCNativeMemberDescriptor* desc);
@ -394,9 +455,27 @@ private:
nsXPCWrappedNativeClass(XPCContext* xpcc, REFNSIID aIID,
nsIInterfaceInfo* aInfo);
const char* GetMemberName(const XPCNativeMemberDescriptor* desc) const;
void ReportError(const XPCNativeMemberDescriptor* desc, const char* msg);
void ThrowBadResultException(JSContext* cx,
const XPCNativeMemberDescriptor* desc,
nsresult result)
{nsXPConnect::GetJSThrower()->
ThrowBadResultException(cx, this, desc, result);}
void ThrowBadParamException(uintN errNum,
JSContext* cx,
const XPCNativeMemberDescriptor* desc,
uintN paramNum)
{nsXPConnect::GetJSThrower()->
ThrowBadParamException(errNum, cx, this, desc, paramNum);}
void ThrowException(uintN errNum,
JSContext* cx,
const XPCNativeMemberDescriptor* desc)
{nsXPConnect::GetJSThrower()->
ThrowException(errNum, cx, this, desc);}
JSBool BuildMemberDescriptors();
void DestroyMemberDescriptors();

Просмотреть файл

@ -0,0 +1,136 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* Code for throwing errors into JavaScript. */
#include "xpcprivate.h"
XPCJSErrorFormatString XPCJSThrower::default_formats[] = {
#define MSG_DEF(name, number, count, exception, format) \
{ format/*, count*/ } ,
#include "xpc.msg"
#undef MSG_DEF
{ NULL/*, 0*/ }
};
XPCJSThrower::XPCJSThrower(JSBool Verbose /*= JS_FALSE*/)
: mFormats(default_formats), mVerbose(Verbose) {}
XPCJSThrower::~XPCJSThrower() {}
void
XPCJSThrower::Verbosify(nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
char** psz, PRBool own)
{
char* sz = JS_smprintf("%s [%s.%s]",
*psz,
clazz->GetInterfaceName(),
clazz->GetMemberName(desc));
if(own)
JS_smprintf_free(*psz);
*psz = sz;
}
void
XPCJSThrower::ThrowBadResultException(JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
nsresult result)
{
char* sz;
const char* format;
JSString* str = NULL;
format = mFormats[XPCJSError::NATIVE_RETURNED_FAILURE].format;
sz = JS_smprintf("%s %x", format, result);
if(sz && mVerbose)
Verbosify(clazz, desc, &sz, PR_TRUE);
if(sz)
{
str = JS_NewStringCopyZ(cx, sz);
JS_smprintf_free(sz);
}
if(str)
JS_SetPendingException(cx, STRING_TO_JSVAL(str));
else
JS_ReportOutOfMemory(cx);
}
void
XPCJSThrower::ThrowBadParamException(uintN errNum,
JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc,
uintN paramNum)
{
char* sz;
const char* format;
JSString* str = NULL;
format = mFormats[errNum].format;
sz = JS_smprintf("%s arg %d", format, paramNum);
if(sz && mVerbose)
Verbosify(clazz, desc, &sz, PR_TRUE);
if(sz)
{
str = JS_NewStringCopyZ(cx, sz);
JS_smprintf_free(sz);
}
if(str)
JS_SetPendingException(cx, STRING_TO_JSVAL(str));
else
JS_ReportOutOfMemory(cx);
}
void
XPCJSThrower::ThrowException(uintN errNum,
JSContext* cx,
nsXPCWrappedNativeClass* clazz,
const XPCNativeMemberDescriptor* desc)
{
char* sz;
const char* format;
JSString* str = NULL;
format = mFormats[errNum].format;
sz = (char*) format;
if(sz && mVerbose)
Verbosify(clazz, desc, &sz, PR_FALSE);
if(sz)
{
str = JS_NewStringCopyZ(cx, sz);
if(sz != format)
JS_smprintf_free(sz);
}
if(str)
JS_SetPendingException(cx, STRING_TO_JSVAL(str));
else
JS_ReportOutOfMemory(cx);
}

Просмотреть файл

@ -343,13 +343,25 @@ void
nsXPCWrappedNativeClass::ReportError(const XPCNativeMemberDescriptor* desc,
const char* msg)
{
JSContext* cx = GetJSContext();
char* sz = JS_smprintf("'%s' accessing '%s' of '%s'",
msg, GetMemberName(desc), GetInterfaceName());
if(sz)
{
JSString* str = JS_NewStringCopyZ(cx, sz);
if(str)
JS_SetPendingException(cx, STRING_TO_JSVAL(str));
JS_smprintf_free(sz);
}
/*
JS_ReportError(GetJSContext(), "'%s' accessing '%s' of '%s'",
msg, GetMemberName(desc), GetInterfaceName());
*/
}
JSBool
nsXPCWrappedNativeClass::CallWrappedMethod(nsXPCWrappedNative* wrapper,
nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx,
nsXPCWrappedNative* wrapper,
const XPCNativeMemberDescriptor* desc,
JSBool isAttributeSet,
uintN argc, jsval *argv, jsval *vp)
@ -360,7 +372,6 @@ nsXPCWrappedNativeClass::CallWrappedMethod(nsXPCWrappedNative* wrapper,
JSBool retval = JS_FALSE;
nsXPCVariant* dispatchParams = NULL;
JSContext* cx = GetJSContext();
uint8 i;
const nsXPTMethodInfo* info;
uint8 requiredArgs;
@ -505,8 +516,7 @@ nsXPCWrappedNativeClass::CallWrappedMethod(nsXPCWrappedNative* wrapper,
if(NS_FAILED(invokeResult))
{
// XXX this (and others!) should throw rather than report error
ReportError(desc, "XPCOM object returned failure");
ThrowBadResultException(cx, desc, invokeResult);
goto done;
}
@ -617,7 +627,7 @@ WrappedNative_CallMethod(JSContext *cx, JSObject *obj,
if(!desc || !desc->IsMethod())
return JS_FALSE;
return clazz->CallWrappedMethod(wrapper, desc, JS_FALSE, argc, argv, vp);
return clazz->CallWrappedMethod(cx, wrapper, desc, JS_FALSE, argc, argv, vp);
}
JSObject*
@ -685,7 +695,7 @@ WrappedNative_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
return JS_TRUE;
}
else // attribute
return clazz->GetAttributeAsJSVal(wrapper, desc, vp);
return clazz->GetAttributeAsJSVal(cx, wrapper, desc, vp);
}
else
{
@ -719,7 +729,7 @@ WrappedNative_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if(desc)
{
if(desc->IsWritableAttribute())
return clazz->SetAttributeFromJSVal(wrapper, desc, vp);
return clazz->SetAttributeFromJSVal(cx, wrapper, desc, vp);
else
return JS_TRUE; // fail silently
}
@ -1197,6 +1207,7 @@ nsXPCWrappedNativeClass::GetWrappedNativeOfJSObject(JSContext* cx,
return NULL;
}
/***************************************************************************/
NS_IMETHODIMP

Просмотреть файл

@ -211,7 +211,11 @@ XPTParamDescriptor nsIEcho_MethodWithNativeParams[2] = {
{XPT_PD_IN, {XPT_TDP_POINTER|TD_VOID,0}}
};
XPTMethodDescriptor nsIEchoMethods[9] = {
XPTParamDescriptor nsIEcho_ReturnCodeParams[1] = {
{XPT_PD_IN, {TD_INT32,0}}
};
XPTMethodDescriptor nsIEchoMethods[10] = {
{0, "SetReciever", 1, nsIEcho_SetRecieverParams, ResultParam},
{0, "SendOneString", 1, nsIEcho_SendOneStringParams, ResultParam},
{0, "In2OutOneInt", 2, nsIEcho_In2OutOneIntParams, ResultParam},
@ -220,11 +224,12 @@ XPTMethodDescriptor nsIEchoMethods[9] = {
{0, "SimpleCallNoEcho", 0, NULL, ResultParam},
{0, "SendManyTypes", 16, nsIEcho_SendManyTypesParams, ResultParam},
{0, "SendInOutManyTypes", 16, nsIEcho_SendInOutManyTypesParams, ResultParam},
{0, "MethodWithNative", 2, nsIEcho_MethodWithNativeParams, ResultParam}
{0, "MethodWithNative", 2, nsIEcho_MethodWithNativeParams, ResultParam},
{0, "ReturnCode", 1, nsIEcho_ReturnCodeParams, ResultParam}
};
XPTInterfaceDescriptor nsIEchoInterfaceDescriptor =
{NULL, 9, nsIEchoMethods, 0, NULL};
{NULL, 10, nsIEchoMethods, 0, NULL};
/***************/