Skip to content

Commit

Permalink
Bug 595243 - Expose debugMode to JSD. Relanding test bustage fixed up…
Browse files Browse the repository at this point in the history
…. r=gal.
  • Loading branch information
sayrer committed Oct 30, 2010
1 parent 577021f commit b246558
Show file tree
Hide file tree
Showing 14 changed files with 198 additions and 58 deletions.
4 changes: 0 additions & 4 deletions dom/base/nsJSEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,10 +993,6 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
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
Expand Down
39 changes: 32 additions & 7 deletions js/jsd/idl/jsdIDebuggerService.idl
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ 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. */
Expand Down Expand Up @@ -216,19 +217,34 @@ interface jsdIDebuggerService : nsISupports
*/
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
Expand Down Expand Up @@ -457,6 +473,15 @@ interface jsdIFilter : nsISupports
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.
*/
Expand Down
7 changes: 1 addition & 6 deletions js/jsd/jsd_scpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,6 @@ jsd_NewScriptHookProc(
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);
Expand All @@ -611,7 +606,7 @@ jsd_NewScriptHookProc(

if( hook )
hook(jsdc, jsdscript, JS_TRUE, hookData);
}
}

void
jsd_DestroyScriptHookProc(
Expand Down
55 changes: 43 additions & 12 deletions js/jsd/jsd_xpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2396,6 +2396,12 @@ jsdService::GetIsOn (PRBool *_rval)

NS_IMETHODIMP
jsdService::On (void)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
{
nsresult rv;

Expand All @@ -2410,18 +2416,32 @@ jsdService::On (void)
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::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::OnForRuntime (JSRuntime *rt)
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 */
Expand Down Expand Up @@ -2471,6 +2491,10 @@ jsdService::OnForRuntime (JSRuntime *rt)
#ifdef DEBUG
printf ("+++ JavaScript debugging hooks installed.\n");
#endif

if (mActivationCallback)
return mActivationCallback->OnDebuggerActivated();

return NS_OK;
}

Expand Down Expand Up @@ -2521,6 +2545,13 @@ jsdService::Off (void)
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;
}

Expand Down Expand Up @@ -2969,7 +3000,7 @@ 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;
Expand Down Expand Up @@ -3013,7 +3044,7 @@ 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;
Expand Down Expand Up @@ -3041,7 +3072,7 @@ 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;
Expand Down Expand Up @@ -3069,7 +3100,7 @@ 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;
Expand Down Expand Up @@ -3097,7 +3128,7 @@ 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;
Expand Down Expand Up @@ -3125,7 +3156,7 @@ 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;
Expand Down Expand Up @@ -3153,7 +3184,7 @@ 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;
Expand Down Expand Up @@ -3181,7 +3212,7 @@ 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;
Expand Down Expand Up @@ -3274,7 +3305,7 @@ jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
if (NS_FAILED(rv))
return rv;

rv = jsds->OnForRuntime(rt);
rv = jsds->ActivateDebugger(rt);
if (NS_FAILED(rv))
return rv;

Expand Down
2 changes: 1 addition & 1 deletion js/jsd/jsd_xpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class jsdService : public jsdIDebuggerService
nsCOMPtr<jsdIExecutionHook> mThrowHook;
nsCOMPtr<jsdICallHook> mTopLevelHook;
nsCOMPtr<jsdICallHook> mFunctionHook;

nsCOMPtr<jsdIActivationCallback> mActivationCallback;
};

#endif /* JSDSERVICE_H___ */
Expand Down
68 changes: 42 additions & 26 deletions js/jsd/test/test_bug507448.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,6 @@

</div>
<pre id="test">
<script type="application/javascript">

/** Test for Bug 507448 **/
function assertArraysEqual(arr1, arr2) {
is(arr1.length, arr2.length, "Lengths not equal");
for (var i = 0 ; i < arr1.length; ++i) {
is(arr1[i], arr2[i], "Element " + i + " not equal");
}
}

// This is somewhat unfortunate: jsd only deals with scripts that have a
// nonzero line number, so we can't just createElement a script here.
// So break the test up into three <script>s, of which the middle one has our test functions.

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1']
.getService(jsdIDebuggerService);
var jsdOn = jsd.isOn;
if (!jsdOn) {
jsd.on();
ok(jsd.isOn, "JSD should be running.");
}
</script>
<script>
function f() {}
function g(a,b) {}
Expand All @@ -50,6 +26,8 @@
}
</script>
<script>
function testJSD() {
ok(jsd.isOn, "JSD needs to be running for this test.");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
assertArraysEqual(jsd.wrapValue(f).script.getParameterNames(), []);
assertArraysEqual(jsd.wrapValue(g).script.getParameterNames(), ["a", "b"]);
Expand All @@ -59,10 +37,48 @@
assertArraysEqual(jsd.wrapValue(manyLocals).script.getParameterNames(),
"abcdefghijklm".split(""));

if (!jsdOn) {
if (!jsdOnAtStart) {
// turn JSD off if it wasn't on when this test started
jsd.off();
ok(!jsd.isOn, "JSD shouldn't be running anymore.");
ok(!jsd.isOn, "JSD shouldn't be running at the end of this test.");
}
SimpleTest.finish();
}
</script>
<script type="application/javascript">

SimpleTest.waitForExplicitFinish();

/** Test for Bug 507448 **/
function assertArraysEqual(arr1, arr2) {
is(arr1.length, arr2.length, "Lengths not equal");
for (var i = 0 ; i < arr1.length; ++i) {
is(arr1[i], arr2[i], "Element " + i + " not equal");
}
}

// This is somewhat unfortunate: jsd only deals with scripts that have a
// nonzero line number, so we can't just createElement a script here.
// So break the test up into three <script>s, of which the middle one has our test functions.

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1']
.getService(jsdIDebuggerService);

var jsdOnAtStart = jsd.isOn;
if (jsdOnAtStart) {
testJSD();
} else {
jsd.asyncOn(
{
debuggerActivated: function() {
testJSD();
}
}
);
}

</script>
</pre>
</body>
Expand Down
3 changes: 3 additions & 0 deletions js/src/jsapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@ JSRuntime::init(uint32 maxbytes)
if (!debuggerLock)
return false;
#endif

debugMode = JS_FALSE;

return propertyTree.init() && js_InitThreads(this);
}

Expand Down
5 changes: 5 additions & 0 deletions js/src/jscntxt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,11 @@ struct JSRuntime {
/* 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 {
Expand Down
2 changes: 1 addition & 1 deletion js/src/jscompartment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ 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);
Expand Down
Loading

0 comments on commit b246558

Please sign in to comment.