Bug 20786. Use function object, rather than function, as the thing which is executed, ensuring that the correct bindings are used when the function is shared across several contexts. This checkin is really brendan@mozilla.org; I'm just landing the code.

This commit is contained in:
waterson%netscape.com 1999-12-05 07:29:25 +00:00
parent 6461895004
commit ec2655c506
8 changed files with 59 additions and 53 deletions

View File

@ -133,29 +133,42 @@ public:
/**
* Compile the event handler named by atom aName, with function body aBody
* into a function returned on success via *aFunction. Bind the lowercase
* into a function object returned if ok via *aFunObj. Bind the lowercase
* ASCII name to the function in scope aObj, or in the context's global if
* aObj is null.
*
* @param aObj an object telling the scope in which to bind the compiled
* event handler function, or nsnull to use a default scope
* event handler function.
* @param aName an nsIAtom pointer naming the function; it must be lowercase
* and ASCII, and should not be longer than 63 chars. This bound on
* length is enforced only by assertions, so caveat caller!
* @param aBody the event handler function's body
* @param aFunction the out parameter in which a void pointer to the compiled
* function is returned on success; may be null, meaning "don't care"
* @param aFunObj the out parameter in which a void pointer to the compiled
* function object is returned on success; may be null, meaning the
* caller doesn't care.
*
* @return NS_OK if the function body was valid and got compiled
*/
NS_IMETHOD CompileEventHandler(void *aObj,
nsIAtom *aName,
const nsString& aBody,
void** aFunction) = 0;
void** aFunObj) = 0;
NS_IMETHOD CallFunction(void *aObj, void *aFunction,
PRUint32 argc, void *argv,
PRBool *aBoolResult) = 0;
/**
* Call the function object with given args and return its boolean result,
* or true if the result isn't boolean.
*
* @param aObj an object telling the scope in which to bind the compiled
* event handler function.
* @param aFunObj function object (function and static scope) to invoke.
* @param argc actual argument count; length of argv
* @param argv vector of arguments; length is argc
* @param aBoolResult out parameter returning boolean function result, or
* true if the result was not boolean.
**/
NS_IMETHOD CallFunctionObject(void *aObj, void *aFunObj,
PRUint32 argc, void *argv,
PRBool *aBoolResult) = 0;
/**
* Bind an already-compiled event handler function to a name in the given
@ -167,13 +180,13 @@ public:
* @param aName an nsIAtom pointer naming the function; it must be lowercase
* and ASCII, and should not be longer than 63 chars. This bound on
* length is enforced only by assertions, so caveat caller!
* @param aFunction the function to name, created by an earlier call to
* @param aFunObj the function object to name, created by an earlier call to
* CompileEventHandler
* @return NS_OK if the function was successfully bound to the name
*/
NS_IMETHOD BindCompiledEventHandler(void *aObj,
nsIAtom *aName,
void *aFunction) = 0;
void *aFunObj) = 0;
/**
* Set the default scripting language version for this context, which must

View File

@ -1853,9 +1853,8 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout)
lateness = PR_IntervalToMilliseconds(lateness);
timeout->argv[timeout->argc] = INT_TO_JSVAL((jsint)lateness);
PRBool aBoolResult;
JSFunction* fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(timeout->funobj));
rv = mContext->CallFunction(mScriptObject, fun,
timeout->argc + 1, timeout->argv,
rv = mContext->CallFunctionObject(mScriptObject, timeout->funobj,
timeout->argc + 1, timeout->argv,
&aBoolResult);
}
if (NS_FAILED(rv)) {

View File

@ -471,7 +471,7 @@ AtomToEventHandlerName(nsIAtom *aName, char *charName, PRUint32 charNameSize)
NS_IMETHODIMP
nsJSContext::CompileEventHandler(void *aObj, nsIAtom *aName, const nsString& aBody,
void** aFunction)
void** aFunObj)
{
JSPrincipals *jsprin = nsnull;
@ -502,14 +502,14 @@ nsJSContext::CompileEventHandler(void *aObj, nsIAtom *aName, const nsString& aBo
JSPRINCIPALS_DROP(mContext, jsprin);
if (!fun)
return NS_ERROR_FAILURE;
if (aFunction)
*aFunction = (void*) fun;
if (aFunObj)
*aFunObj = (void*) JS_GetFunctionObject(fun);
return NS_OK;
}
NS_IMETHODIMP
nsJSContext::CallFunction(void *aObj, void *aFunction, PRUint32 argc,
void *argv, PRBool *aBoolResult)
nsJSContext::CallFunctionObject(void *aObj, void *aFunObj, PRUint32 argc,
void *argv, PRBool *aBoolResult)
{
// This one's a lot easier than EvaluateString because we don't have to
// hassle with principals: they're already compiled into the JS function.
@ -519,8 +519,11 @@ nsJSContext::CallFunction(void *aObj, void *aFunction, PRUint32 argc,
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
jsval funval = OBJECT_TO_JSVAL(aFunObj);
JSFunction* fun = JS_ValueToFunction(mContext, funval);
PRBool ok;
rv = securityManager->CanExecuteFunction((JSFunction *)aFunction, &ok);
rv = securityManager->CanExecuteFunction(fun, &ok);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
@ -533,8 +536,8 @@ nsJSContext::CallFunction(void *aObj, void *aFunction, PRUint32 argc,
jsval val;
if (ok) {
ok = JS_CallFunction(mContext, (JSObject *)aObj, (JSFunction *)aFunction,
argc, (jsval *)argv, &val);
ok = JS_CallFunctionValue(mContext, (JSObject *)aObj, funval,
argc, (jsval *)argv, &val);
}
*aBoolResult = ok
? !JSVAL_IS_BOOLEAN(val) || JSVAL_TO_BOOLEAN(val)
@ -549,17 +552,13 @@ nsJSContext::CallFunction(void *aObj, void *aFunction, PRUint32 argc,
}
NS_IMETHODIMP
nsJSContext::BindCompiledEventHandler(void *aObj, nsIAtom *aName, void *aFunction)
nsJSContext::BindCompiledEventHandler(void *aObj, nsIAtom *aName, void *aFunObj)
{
char charName[64];
AtomToEventHandlerName(aName, charName, sizeof charName);
JSObject *funobj = JS_GetFunctionObject((JSFunction *)aFunction);
if (!funobj)
return NS_ERROR_UNEXPECTED;
if (!::JS_DefineProperty(mContext, (JSObject *)aObj, charName,
OBJECT_TO_JSVAL(funobj), nsnull, nsnull,
OBJECT_TO_JSVAL(aFunObj), nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
return NS_ERROR_FAILURE;
}

View File

@ -82,13 +82,13 @@ public:
NS_IMETHOD CompileEventHandler(void *aObj,
nsIAtom *aName,
const nsString& aBody,
void** aFunction);
NS_IMETHOD CallFunction(void *aObj, void *aFunction,
PRUint32 argc, void *argv,
PRBool *aBoolResult);
void** aFunObj);
NS_IMETHOD CallFunctionObject(void *aObj, void *aFunObj,
PRUint32 argc, void *argv,
PRBool *aBoolResult);
NS_IMETHOD BindCompiledEventHandler(void *aObj,
nsIAtom *aName,
void *aFunction);
void *aFunObj);
NS_IMETHOD SetDefaultLanguageVersion(const char* aVersion);
NS_IMETHOD_(nsIScriptGlobalObject*) GetGlobalObject();
NS_IMETHOD_(void*) GetNativeContext();

View File

@ -184,7 +184,7 @@ nsJSUtils::nsLookupGlobalName(nsISupports* aSupports,
nsresult result;
if (JSVAL_IS_STRING(aId)) {
JSString* jsstring = JS_ValueToString(aContext, aId);
JSString* jsstring = JSVAL_TO_STRING(aId);
nsAutoString name(JS_GetStringChars(jsstring));
nsIScriptNameSpaceManager* manager;
nsIScriptContext* scriptContext = (nsIScriptContext*)JS_GetContextPrivate(aContext);
@ -441,11 +441,10 @@ nsJSUtils::nsConvertJSValToFunc(nsIDOMEventListener** aListener,
*aListener = nsnull;
}
else if (JSVAL_IS_OBJECT(aValue)) {
JSFunction* jsfun = JS_ValueToFunction(aContext, aValue);
if (jsfun){
if (JS_TypeOfValue(aContext, aValue) == JSTYPE_FUNCTION){
nsIScriptContext* scriptContext = (nsIScriptContext*)JS_GetContextPrivate(aContext);
if (NS_OK == NS_NewScriptEventListener(aListener, scriptContext, (void*)aObj, (void*)jsfun)) {
if (NS_OK == NS_NewScriptEventListener(aListener, scriptContext, (void*)aObj, (void*)JSVAL_TO_OBJECT(aValue))) {
return JS_TRUE;
}
else {
@ -454,7 +453,7 @@ nsJSUtils::nsConvertJSValToFunc(nsIDOMEventListener** aListener,
}
}
else {
JS_ReportError(aContext, "Parameter isn't a object");
JS_ReportError(aContext, "Parameter isn't a callable object");
return JS_FALSE;
}
}
@ -513,7 +512,7 @@ nsJSUtils::nsGlobalResolve(JSContext* aContext,
jsval val;
if (JSVAL_IS_STRING(aId)) {
JSString* jsstring = JS_ValueToString(aContext, aId);
JSString* jsstring = JSVAL_TO_STRING(aId);
nsAutoString name(JS_GetStringChars(jsstring));
nsIScriptNameSpaceManager* manager;
nsIScriptContext* scriptContext = (nsIScriptContext*)JS_GetContextPrivate(aContext);

View File

@ -23,6 +23,7 @@
#include "nsString.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "jsapi.h"
static NS_DEFINE_IID(kIScriptEventListenerIID, NS_ISCRIPTEVENTLISTENER_IID);
static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID);
@ -31,12 +32,12 @@ static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
/*
* nsJSDOMEventListener implementation
*/
nsJSDOMEventListener::nsJSDOMEventListener(JSContext *aContext, JSObject *aObj, JSFunction *aFun)
nsJSDOMEventListener::nsJSDOMEventListener(JSContext *aContext, JSObject *aScopeObj, JSObject *aFunObj)
{
NS_INIT_REFCNT();
mContext = aContext;
mJSObj = aObj;
mJSFun = aFun;
mScopeObj = aScopeObj;
mFunObj = aFunObj;
}
nsJSDOMEventListener::~nsJSDOMEventListener()
@ -82,7 +83,7 @@ nsresult nsJSDOMEventListener::HandleEvent(nsIDOMEvent* aEvent)
argv[0] = OBJECT_TO_JSVAL(eventObj);
PRBool jsBoolResult;
if (NS_FAILED(mScriptCX->CallFunction(mJSObj, mJSFun, 1, argv, &jsBoolResult))) {
if (NS_FAILED(mScriptCX->CallFunctionObject(mScopeObj, mFunObj, 1, argv, &jsBoolResult))) {
return NS_ERROR_FAILURE;
}
return jsBoolResult ? NS_OK : NS_ERROR_FAILURE;
@ -97,11 +98,11 @@ nsresult nsJSDOMEventListener::CheckIfEqual(nsIScriptEventListener *aListener)
* Factory functions
*/
extern "C" NS_DOM nsresult NS_NewScriptEventListener(nsIDOMEventListener ** aInstancePtrResult, nsIScriptContext *aContext, void* aObj, void *aFun)
extern "C" NS_DOM nsresult NS_NewScriptEventListener(nsIDOMEventListener ** aInstancePtrResult, nsIScriptContext *aContext, void* aScopeObj, void *aFunObj)
{
JSContext *mCX = (JSContext*)aContext->GetNativeContext();
nsJSDOMEventListener* it = new nsJSDOMEventListener(mCX, (JSObject*)aObj, (JSFunction*)aFun);
nsJSDOMEventListener* it = new nsJSDOMEventListener(mCX, (JSObject*)aScopeObj, (JSObject*)aFunObj);
if (NULL == it) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -31,7 +31,7 @@
//nsIDOMMouseListener interface
class nsJSDOMEventListener : public nsIDOMEventListener, public nsIScriptEventListener {
public:
nsJSDOMEventListener(JSContext *aContext, JSObject *aObj, JSFunction *aFun);
nsJSDOMEventListener(JSContext *aContext, JSObject *aScopeObj, JSObject *aFunObj);
virtual ~nsJSDOMEventListener();
NS_DECL_ISUPPORTS
@ -44,8 +44,8 @@ public:
protected:
JSContext *mContext;
JSObject *mJSObj;
JSFunction *mJSFun;
JSObject *mScopeObj;
JSObject *mFunObj;
};

View File

@ -124,13 +124,8 @@ nsresult nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
}
argv[0] = OBJECT_TO_JSVAL(eventObj);
JSFunction *jsFun = JS_ValueToFunction(cx, funval);
PRBool jsBoolResult;
if (!jsFun)
{
return NS_ERROR_FAILURE;
}
result = mContext->CallFunction(obj, jsFun, 1, argv, &jsBoolResult);
result = mContext->CallFunctionObject(obj, (void*) JSVAL_TO_OBJECT(funval), 1, argv, &jsBoolResult);
if (NS_FAILED(result)) {
return result;
}