diff --git a/dom/public/nsIScriptContext.h b/dom/public/nsIScriptContext.h index 296287c28df..ae1cb030ea5 100644 --- a/dom/public/nsIScriptContext.h +++ b/dom/public/nsIScriptContext.h @@ -301,9 +301,14 @@ public: * A GC may be done if "necessary." * This call is necessary if script evaluation is done * without using the EvaluateScript method. + * @param aTerminated If true then call termination function if it was + * previously set. Within DOM this will always be true, but outside + * callers (such as xpconnect) who may do script evaluations nested + * inside DOM script evaluations can pass false to avoid premature + * calls to the termination function. * @return NS_OK if the method is successful */ - NS_IMETHOD ScriptEvaluated(void) = 0; + NS_IMETHOD ScriptEvaluated(PRBool aTerminated) = 0; /** * Let the script context know who its owner is. diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 3f11c4f35b8..20a4037cd16 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -603,7 +603,7 @@ nsJSContext::EvaluateString(const nsAReadableString& aScript, aRetValue.Truncate(); } - ScriptEvaluated(); + ScriptEvaluated(PR_TRUE); // Pop here, after JS_ValueToString and any other possible evaluation. if (NS_FAILED(stack->Pop(nsnull))) @@ -740,7 +740,7 @@ nsJSContext::ExecuteScript(void* aScriptObject, aRetValue->Truncate(); } - ScriptEvaluated(); + ScriptEvaluated(PR_TRUE); // Pop here, after JS_ValueToString and any other possible evaluation. if (NS_FAILED(stack->Pop(nsnull))) @@ -908,7 +908,7 @@ nsJSContext::CallEventHandler(void *aTarget, void *aHandler, PRUint32 argc, ? !JSVAL_IS_BOOLEAN(val) || (aReverseReturnResult ? !JSVAL_TO_BOOLEAN(val) : JSVAL_TO_BOOLEAN(val)) : JS_TRUE; - ScriptEvaluated(); + ScriptEvaluated(PR_TRUE); } if (NS_FAILED(stack->Pop(nsnull))) @@ -1288,9 +1288,9 @@ nsJSContext::GC() } NS_IMETHODIMP -nsJSContext::ScriptEvaluated(void) +nsJSContext::ScriptEvaluated(PRBool aTerminated) { - if (mTerminationFunc) { + if (aTerminated && mTerminationFunc) { (*mTerminationFunc)(mRef); mRef = nsnull; mTerminationFunc = nsnull; diff --git a/dom/src/base/nsJSEnvironment.h b/dom/src/base/nsJSEnvironment.h index 1deb18905a8..74b6b620673 100644 --- a/dom/src/base/nsJSEnvironment.h +++ b/dom/src/base/nsJSEnvironment.h @@ -126,7 +126,7 @@ public: NS_IMETHOD GetNameSpaceManager(nsIScriptNameSpaceManager** aInstancePtr); NS_IMETHOD GetSecurityManager(nsIScriptSecurityManager** aInstancePtr); - NS_IMETHOD ScriptEvaluated(void); + NS_IMETHOD ScriptEvaluated(PRBool aTerminated); NS_IMETHOD SetOwner(nsIScriptContextOwner* owner); NS_IMETHOD GetOwner(nsIScriptContextOwner** owner); NS_IMETHOD SetTerminationFunction(nsScriptTerminationFunc aFunc, diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 5eab356a7b1..2a6d94d0fed 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -43,6 +43,34 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass) // the value of this variable is never used - we use its address as a sentinel static uint32 zero_methods_descriptor; +static inline void DoPreScriptEvaluated(JSContext* cx) +{ +// XXX should we do this? +// JS_BeginRequest(cx); +} + +static inline void DoPostScriptEvaluated(JSContext* cx) +{ +// XXX should we do this? +// JS_EndRequest(cx); + +#ifndef XPCONNECT_STANDALONE + // If this is a DOM JSContext, then notify nsIScriptContext of script + // completion so that it can reset its infinite loop detection mechanism. + // + // XXX We rely on the rule that if any JSContext in our JSRuntime has a + // private set then that private *must* be a pointer to an nsISupports. + + nsISupports *supports = (nsISupports*) JS_GetContextPrivate(cx); + if(supports) + { + nsCOMPtr scx = do_QueryInterface(supports); + if(scx) + scx->ScriptEvaluated(PR_FALSE); + } +#endif /* XPCONNECT_STANDALONE */ +} + // static nsXPCWrappedJSClass* nsXPCWrappedJSClass::GetNewOrUsedClass(XPCJSRuntime* rt, @@ -169,8 +197,10 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSObject* jsobj, REFNSIID aIID if(!OBJ_GET_PROPERTY(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun)) return nsnull; + DoPreScriptEvaluated(cx); + // XXX we should install an error reporter that will sent reports to - // some as yet non-existent JS error console via a service. + // the JS error console service. jsval e; JSBool hadExpection = JS_GetPendingException(cx, &e); @@ -181,6 +211,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSObject* jsobj, REFNSIID aIID jsval args[1] = {OBJECT_TO_JSVAL(id)}; success = JS_CallFunctionValue(cx, jsobj, fun, 1, args, &retval); } + if(success) success = JS_ValueToObject(cx, retval, &retObj); JS_SetErrorReporter(cx, older); @@ -189,6 +220,8 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSObject* jsobj, REFNSIID aIID else JS_ClearPendingException(cx); + DoPostScriptEvaluated(cx); + return success ? retObj : nsnull; } @@ -507,6 +540,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, if(!xpc || !cx || !xpcc || !IsReflectable(methodIndex)) goto pre_call_clean_up; + DoPreScriptEvaluated(cx); + xpcc->SetPendingResult(pending_result); xpcc->SetException(nsnull); xpc->SetPendingException(nsnull); @@ -800,21 +835,14 @@ pre_call_clean_up: { if(NS_FAILED(e_result)) { - // XXX we should send the error string to some as yet - // non-existent JS error console via a service. - // Below is a quick hack to show the error/exception text - // via printf in debug builds only -#ifdef DEBUG static const char line[] = "************************************************************\n"; - static const char disclaimer[] = - "** NOTE: This report will only be printed in DEBUG builds.**\n"; static const char preamble[] = "* Call to xpconnect wrapped JSObject produced this error: *\n"; static const char cant_get_text[] = "FAILED TO GET TEXT FROM EXCEPTION\n"; + printf(line); - printf(disclaimer); printf(preamble); char* text; if(NS_SUCCEEDED(xpc_exception->ToString(&text)) && text) @@ -825,8 +853,8 @@ pre_call_clean_up: } else printf(cant_get_text); - printf(line); -#endif + printf(line); + // Log the exception to the JS Console, so that users can do // something with it. nsCOMPtr consoleService @@ -839,6 +867,7 @@ pre_call_clean_up: rv = xpc_exception->GetData(getter_AddRefs(errorData)); if(NS_SUCCEEDED(rv)) scriptError = do_QueryInterface(errorData); + if(nsnull == scriptError) { // No luck getting one from the exception, so @@ -892,7 +921,6 @@ pre_call_clean_up: } } } - if(nsnull != scriptError) consoleService->LogMessage(scriptError); } @@ -1144,7 +1172,10 @@ done: nsMemory::Free((void*)conditional_iid); if(cx) + { JS_SetErrorReporter(cx, older); + DoPostScriptEvaluated(cx); + } NS_IF_RELEASE(xpc); #ifdef DEBUG_stats_jband