--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -988,20 +988,16 @@ nsJSContext::DOMOperationCallback(JSCont
const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
nsCOMPtr<jsdIExecutionHook> jsdHook;
nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
// Check if there's a user for the debugger service that's 'on' for us
if (NS_SUCCEEDED(rv)) {
jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
jsds->GetIsOn(&jsds_IsOn);
- if (jsds_IsOn) { // If this is not true, the next call would start jsd...
- rv = jsds->OnForRuntime(cx->runtime);
- jsds_IsOn = NS_SUCCEEDED(rv);
- }
}
// If there is a debug handler registered for this runtime AND
// ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
// then something useful will be done with our request to debug.
debugPossible = ((jsds_IsOn && (jsdHook != nsnull)) || !jsds_IsOn);
}
#endif
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -67,22 +67,23 @@ interface jsdIExecutionHook;
interface jsdICallHook;
interface jsdIEphemeral;
interface jsdIContext;
interface jsdIStackFrame;
interface jsdIScript;
interface jsdIValue;
interface jsdIObject;
interface jsdIProperty;
+interface jsdIActivationCallback;
/**
* Debugger service. It's not a good idea to have more than one active client of
* the debugger service.
*/
-[scriptable, uuid(dc0a24db-f8ac-4889-80d0-6016545a2dda)]
+[scriptable, uuid(01769775-c77c-47f9-8848-0abbab404215)]
interface jsdIDebuggerService : nsISupports
{
/** Internal use only. */
[noscript] readonly attribute JSDContext JSDContext;
/**
* Called when an error or warning occurs.
*/
@@ -211,29 +212,44 @@ interface jsdIDebuggerService : nsISuppo
/**
* |true| if the debugger service has been turned on. This does not
* necessarily mean another app is actively using the service, as the
* autostart pref may have turned the service on.
*/
readonly attribute boolean isOn;
+
+ /**
+ * Synchronous activation of the debugger is no longer supported,
+ * and will throw an exception.
+ */
+ void on ();
+
/**
* Turn on the debugger. This function should only be called from JavaScript
* code. The debugger will be enabled on the runtime the call is made on,
* as determined by nsIXPCNativeCallContext.
+ *
+ * The debugger will be activated asynchronously, because there can be no JS
+ * on the stack when code is to be re-compiled for debug mode.
*/
- void on ();
+ void asyncOn (in jsdIActivationCallback callback);
+
/**
- * Turn on the debugger for a given runtime.
- *
- * @param rt The runtime you want to debug. You cannot turn the debugger
- * on for multiple runtimes.
+ * Called by nsIXPConnect after it's had a chance to recompile for
+ * debug mode.
*/
- [noscript] void onForRuntime (in JSRuntime rt);
+ [noscript] void activateDebugger(in JSRuntime rt);
+
+ /**
+ * Recompile all active scripts in the runtime for debugMode.
+ */
+ [noscript] void recompileForDebugMode(in JSRuntime rt, in PRBool mode);
+
/**
* Turn the debugger off. This will invalidate all of your jsdIEphemeral
* derived objects, and clear all of your breakpoints. In theory you
* should be able to turn the debugger back on at some later time without
* any problems.
*/
void off ();
@@ -453,16 +469,25 @@ interface jsdIFilter : nsISupports
* Line number for the end of this filter. Line numbers are one based.
* Assigning a 0 to this attribute will tell the debugger to ignore from
* |startLine| to the end of the file.
*/
attribute unsigned long endLine;
};
/**
+ * Notify client code that debugMode has been activated.
+ */
+[scriptable, uuid(6da7f5fb-3a84-4abe-9e23-8b2045960732)]
+interface jsdIActivationCallback : nsISupports
+{
+ void onDebuggerActivated ();
+};
+
+/**
* Pass an instance of one of these to jsdIDebuggerService::enterNestedEventLoop.
*/
[scriptable, uuid(88bea60f-9b5d-4b39-b08b-1c3a278782c6)]
interface jsdINestCallback : nsISupports
{
/**
* This method will be called after pre-nesting work has completed, such
* as pushing the js context and network event queue, but before the new
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -580,21 +580,16 @@ jsd_NewScriptHookProc(
JSD_ScriptHookProc hook;
void* hookData;
JSD_ASSERT_VALID_CONTEXT(jsdc);
if( JSD_IS_DANGEROUS_THREAD(jsdc) )
return;
-#ifdef LIVEWIRE
- if( 1 == lineno )
- jsdlw_PreLoadSource(jsdc, LWDBG_GetCurrentApp(), filename, JS_TRUE );
-#endif
-
JSD_LOCK_SCRIPTS(jsdc);
jsdscript = _newJSDScript(jsdc, cx, script, fun);
JSD_UNLOCK_SCRIPTS(jsdc);
if( ! jsdscript )
return;
#ifdef JSD_DUMP
JSD_LOCK_SCRIPTS(jsdc);
@@ -606,17 +601,17 @@ jsd_NewScriptHookProc(
/* local in case jsdc->scriptHook gets cleared on another thread */
JSD_LOCK();
hook = jsdc->scriptHook;
hookData = jsdc->scriptHookData;
JSD_UNLOCK();
if( hook )
hook(jsdc, jsdscript, JS_TRUE, hookData);
-}
+}
void
jsd_DestroyScriptHookProc(
JSContext *cx,
JSScript *script,
void* callerdata )
{
JSDScript* jsdscript = NULL;
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -2392,41 +2392,61 @@ jsdService::GetIsOn (PRBool *_rval)
{
*_rval = mOn;
return NS_OK;
}
NS_IMETHODIMP
jsdService::On (void)
{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
+{
nsresult rv;
/* get JS things from the CallContext */
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
if (NS_FAILED(rv)) return rv;
nsAXPCNativeCallContext *cc = nsnull;
rv = xpc->GetCurrentNativeCallContext(&cc);
if (NS_FAILED(rv)) return rv;
JSContext *cx;
rv = cc->GetJSContext (&cx);
if (NS_FAILED(rv)) return rv;
+
+ mActivationCallback = activationCallback;
- return OnForRuntime(JS_GetRuntime (cx));
-
+ return xpc->SetDebugModeWhenPossible(PR_TRUE);
}
NS_IMETHODIMP
-jsdService::OnForRuntime (JSRuntime *rt)
+jsdService::RecompileForDebugMode (JSRuntime *rt, JSBool mode) {
+ JSContext *cx;
+ JSContext *iter = NULL;
+
+ while ((cx = JS_ContextIterator (rt, &iter))) {
+ JS_SetDebugMode(cx, mode);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::ActivateDebugger (JSRuntime *rt)
{
if (mOn)
return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
mRuntime = rt;
+ RecompileForDebugMode(rt, JS_TRUE);
if (gLastGCProc == jsds_GCCallbackProc)
/* condition indicates that the callback proc has not been set yet */
gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc);
mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
if (!mCx)
return NS_ERROR_FAILURE;
@@ -2466,16 +2486,20 @@ jsdService::OnForRuntime (JSRuntime *rt)
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
else
JSD_ClearFunctionHook (mCx);
mOn = PR_TRUE;
#ifdef DEBUG
printf ("+++ JavaScript debugging hooks installed.\n");
#endif
+
+ if (mActivationCallback)
+ return mActivationCallback->OnDebuggerActivated();
+
return NS_OK;
}
NS_IMETHODIMP
jsdService::Off (void)
{
if (!mOn)
return NS_OK;
@@ -2516,16 +2540,23 @@ jsdService::Off (void)
mCx = nsnull;
mRuntime = nsnull;
mOn = PR_FALSE;
#ifdef DEBUG
printf ("+++ JavaScript debugging hooks removed.\n");
#endif
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ xpc->SetDebugModeWhenPossible(PR_FALSE);
+
return NS_OK;
}
NS_IMETHODIMP
jsdService::GetPauseDepth(PRUint32 *_rval)
{
NS_ENSURE_ARG_POINTER(_rval);
*_rval = mPauseLevel;
@@ -2964,17 +2995,17 @@ jsdService::ExitNestedEventLoop (PRUint3
/* hook attribute get/set functions */
NS_IMETHODIMP
jsdService::SetErrorHook (jsdIErrorHook *aHook)
{
mErrorHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
else
JSD_SetErrorReporter (mCx, NULL, NULL);
@@ -3008,17 +3039,17 @@ jsdService::GetBreakpointHook (jsdIExecu
}
NS_IMETHODIMP
jsdService::SetDebugHook (jsdIExecutionHook *aHook)
{
mDebugHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
else
JSD_ClearDebugBreakHook (mCx);
@@ -3036,17 +3067,17 @@ jsdService::GetDebugHook (jsdIExecutionH
}
NS_IMETHODIMP
jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
{
mDebuggerHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
else
JSD_ClearDebuggerHook (mCx);
@@ -3064,17 +3095,17 @@ jsdService::GetDebuggerHook (jsdIExecuti
}
NS_IMETHODIMP
jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
{
mInterruptHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
else
JSD_ClearInterruptHook (mCx);
@@ -3092,17 +3123,17 @@ jsdService::GetInterruptHook (jsdIExecut
}
NS_IMETHODIMP
jsdService::SetScriptHook (jsdIScriptHook *aHook)
{
mScriptHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
/* we can't unset it if !aHook, because we still need to see script
* deletes in order to Release the jsdIScripts held in JSDScript
@@ -3120,17 +3151,17 @@ jsdService::GetScriptHook (jsdIScriptHoo
}
NS_IMETHODIMP
jsdService::SetThrowHook (jsdIExecutionHook *aHook)
{
mThrowHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
else
JSD_ClearThrowHook (mCx);
@@ -3148,17 +3179,17 @@ jsdService::GetThrowHook (jsdIExecutionH
}
NS_IMETHODIMP
jsdService::SetTopLevelHook (jsdICallHook *aHook)
{
mTopLevelHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
else
JSD_ClearTopLevelHook (mCx);
@@ -3176,17 +3207,17 @@ jsdService::GetTopLevelHook (jsdICallHoo
}
NS_IMETHODIMP
jsdService::SetFunctionHook (jsdICallHook *aHook)
{
mFunctionHook = aHook;
/* if the debugger isn't initialized, that's all we can do for now. The
- * OnForRuntime() method will do the rest when the coast is clear.
+ * ActivateDebugger() method will do the rest when the coast is clear.
*/
if (!mCx || mPauseLevel)
return NS_OK;
if (aHook)
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
else
JSD_ClearFunctionHook (mCx);
@@ -3269,17 +3300,17 @@ jsdASObserver::Observe (nsISupports *aSu
if (NS_FAILED(rv))
return rv;
JSRuntime *rt;
rts->GetRuntime (&rt);
if (NS_FAILED(rv))
return rv;
- rv = jsds->OnForRuntime(rt);
+ rv = jsds->ActivateDebugger(rt);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}
NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
--- a/js/jsd/jsd_xpc.h
+++ b/js/jsd/jsd_xpc.h
@@ -300,17 +300,17 @@ class jsdService : public jsdIDebuggerSe
nsCOMPtr<jsdIExecutionHook> mBreakpointHook;
nsCOMPtr<jsdIExecutionHook> mDebugHook;
nsCOMPtr<jsdIExecutionHook> mDebuggerHook;
nsCOMPtr<jsdIExecutionHook> mInterruptHook;
nsCOMPtr<jsdIScriptHook> mScriptHook;
nsCOMPtr<jsdIExecutionHook> mThrowHook;
nsCOMPtr<jsdICallHook> mTopLevelHook;
nsCOMPtr<jsdICallHook> mFunctionHook;
-
+ nsCOMPtr<jsdIActivationCallback> mActivationCallback;
};
#endif /* JSDSERVICE_H___ */
/* graveyard */
#if 0
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -648,16 +648,19 @@ JSRuntime::init(uint32 maxbytes)
return false;
stateChange = JS_NEW_CONDVAR(gcLock);
if (!stateChange)
return false;
debuggerLock = JS_NEW_LOCK();
if (!debuggerLock)
return false;
#endif
+
+ debugMode = JS_FALSE;
+
return propertyTree.init() && js_InitThreads(this);
}
JSRuntime::~JSRuntime()
{
#ifdef DEBUG
/* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
if (!JS_CLIST_IS_EMPTY(&contextList)) {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1411,16 +1411,21 @@ struct JSRuntime {
JSString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList;
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
JSDebugHooks globalDebugHooks;
+ /*
+ * Right now, we only support runtime-wide debugging.
+ */
+ JSBool debugMode;
+
#ifdef JS_TRACER
/* True if any debug hooks not supported by the JIT are enabled. */
bool debuggerInhibitsJIT() const {
return (globalDebugHooks.interruptHook ||
globalDebugHooks.callHook);
}
#endif
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,17 +48,17 @@
#include "methodjit/MonoIC.h"
#include "jsgcinlines.h"
using namespace js;
using namespace js::gc;
JSCompartment::JSCompartment(JSRuntime *rt)
- : rt(rt), principals(NULL), data(NULL), marked(false), debugMode(false),
+ : rt(rt), principals(NULL), data(NULL), marked(false), debugMode(rt->debugMode),
anynameObject(NULL), functionNamespaceObject(NULL)
{
JS_INIT_CLIST(&scripts);
}
JSCompartment::~JSCompartment()
{
}
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -103,16 +103,22 @@ IsScriptLive(JSContext *cx, JSScript *sc
for (AllFramesIter i(cx); !i.done(); ++i) {
if (i.fp()->maybeScript() == script)
return true;
}
return false;
}
#endif
+JS_PUBLIC_API(void)
+JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug)
+{
+ rt->debugMode = debug;
+}
+
JS_FRIEND_API(JSBool)
js_SetDebugMode(JSContext *cx, JSBool debug)
{
cx->compartment->debugMode = debug;
#ifdef JS_METHODJIT
for (JSScript *script = (JSScript *)cx->compartment->scripts.next;
&script->links != &cx->compartment->scripts;
script = (JSScript *)script->links.next) {
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -45,16 +45,23 @@
*/
#include "jsapi.h"
#include "jsopcode.h"
#include "jsprvtd.h"
JS_BEGIN_EXTERN_C
/*
+ * Currently, we only support runtime-wide debugging. In the future, we should
+ * be able to support compartment-wide debugging.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug);
+
+/*
* Debug mode is a compartment-wide mode that enables a debugger to attach
* to and interact with running methodjit-ed frames. In particular, it causes
* every function to be compiled as if an eval was present (so eval-in-frame)
* can work, and it ensures that functions can be re-JITed for other debug
* features. In general, it is not safe to interact with frames that were live
* before debug mode was enabled. For this reason, it is also not safe to
* enable debug mode while frames are live.
*/
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -394,17 +394,17 @@ interface nsIXPCFunctionThisTranslator :
%{ C++
// For use with the service manager
// {CB6593E0-F9B2-11d2-BDD6-000064657374}
#define NS_XPCONNECT_CID \
{ 0xcb6593e0, 0xf9b2, 0x11d2, \
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
-[uuid(fb780ace-dced-432b-bb82-8df7d4f919c8)]
+[uuid(c825b64b-d537-4e53-822e-547049aae9c9)]
interface nsIXPConnect : nsISupports
{
%{ C++
NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
%}
/**
* Initializes classes on a global object that has already been created.
@@ -822,9 +822,18 @@ interface nsIXPConnect : nsISupports
nsIXPConnectJSObjectHolder holdObject(in JSContextPtr aJSContext,
in JSObjectPtr aObject);
/**
* Return the caller object of the current call from JS.
*/
[noscript,notxpcom] void getCaller(out JSContextPtr aJSContext,
out JSObjectPtr aObject);
+
+ /**
+ * When we place the browser in JS debug mode, there can't be any
+ * JS on the stack. This is because we currently activate debugMode
+ * on all scripts in the JSRuntime when the debugger is activated.
+ * This method will turn debug mode on or off when the context
+ * stack reaches zero length.
+ */
+ [noscript] void setDebugModeWhenPossible(in PRBool mode);
};
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -56,27 +56,31 @@
#include "nsIURI.h"
#include "jstypedarray.h"
#include "XrayWrapper.h"
#include "WrapperFactory.h"
#include "AccessCheck.h"
+#include "jsdIDebuggerService.h"
+
NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
nsIXPConnect,
nsISupportsWeakReference,
nsIThreadObserver,
nsIJSRuntimeService,
nsIJSContextStack,
nsIThreadJSContextStack)
nsXPConnect* nsXPConnect::gSelf = nsnull;
JSBool nsXPConnect::gOnceAliveNowDead = JS_FALSE;
PRUint32 nsXPConnect::gReportAllJSExceptions = 0;
+JSBool nsXPConnect::gDebugMode = JS_FALSE;
+JSBool nsXPConnect::gDesiredDebugMode = JS_FALSE;
// Global cache of the default script security manager (QI'd to
// nsIScriptSecurityManager)
nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nsnull;
const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1";
const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
@@ -2402,16 +2406,40 @@ nsXPConnect::Peek(JSContext * *_retval)
{
*_retval = nsnull;
return NS_ERROR_FAILURE;
}
return data->GetJSContextStack()->Peek(_retval);
}
+void
+nsXPConnect::CheckForDebugMode(JSRuntime *rt) {
+ if (gDebugMode != gDesiredDebugMode) {
+ nsresult rv;
+ const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
+ nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
+ if (NS_SUCCEEDED(rv)) {
+ if (gDesiredDebugMode == PR_FALSE) {
+ rv = jsds->RecompileForDebugMode(rt, PR_FALSE);
+ } else {
+ rv = jsds->ActivateDebugger(rt);
+ }
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ JS_SetRuntimeDebugMode(rt, gDesiredDebugMode);
+ gDebugMode = gDesiredDebugMode;
+ } else {
+ // if the attempt failed, cancel the debugMode request
+ gDesiredDebugMode = gDebugMode;
+ }
+ }
+}
+
/* JSContext Pop (); */
NS_IMETHODIMP
nsXPConnect::Pop(JSContext * *_retval)
{
XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
if(!data)
{
@@ -2427,16 +2455,25 @@ nsXPConnect::Pop(JSContext * *_retval)
NS_IMETHODIMP
nsXPConnect::Push(JSContext * cx)
{
XPCPerThreadData* data = XPCPerThreadData::GetData(cx);
if(!data)
return NS_ERROR_FAILURE;
+ PRInt32 count;
+ nsresult rv;
+ rv = data->GetJSContextStack()->GetCount(&count);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (count == 0)
+ CheckForDebugMode(mRuntime->GetJSRuntime());
+
return data->GetJSContextStack()->Push(cx);
}
/* attribute JSContext SafeJSContext; */
NS_IMETHODIMP
nsXPConnect::GetSafeJSContext(JSContext * *aSafeJSContext)
{
NS_ASSERTION(aSafeJSContext, "loser!");
@@ -2534,16 +2571,23 @@ nsXPConnect::GetCaller(JSContext **aJSCo
{
XPCCallContext *ccx = XPCPerThreadData::GetData(nsnull)->GetCallContext();
*aJSContext = ccx->GetJSContext();
// Set to the caller in XPC_WN_Helper_{Call,Construct}
*aObj = ccx->GetFlattenedJSObject();
}
+NS_IMETHODIMP
+nsXPConnect::SetDebugModeWhenPossible(PRBool mode)
+{
+ gDesiredDebugMode = mode;
+ return NS_OK;
+}
+
/* These are here to be callable from a debugger */
JS_BEGIN_EXTERN_C
JS_EXPORT_API(void) DumpJSStack()
{
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
if(NS_SUCCEEDED(rv) && xpc)
xpc->DebugDumpJSStack(PR_TRUE, PR_TRUE, PR_FALSE);
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -621,16 +621,19 @@ private:
#ifndef XPCONNECT_STANDALONE
typedef nsBaseHashtable<nsVoidPtrHashKey, nsISupports*, nsISupports*> ScopeSet;
ScopeSet mScopes;
#endif
nsCOMPtr<nsIXPCScriptable> mBackstagePass;
static PRUint32 gReportAllJSExceptions;
+ static JSBool gDebugMode;
+ static JSBool gDesiredDebugMode;
+ static inline void CheckForDebugMode(JSRuntime *rt);
public:
static nsIScriptSecurityManager *gScriptSecurityManager;
};
/***************************************************************************/
class XPCRootSetElem