bug 115695, rs=brendan, venkman only

netive changes relating to pretty print support, includes...
* remove jsdIPC interface, replaced with ulong offsets from PC 0.
* add |pcmap| parameter to select between sourcetext/prettyprint linemaps (pcToLine, lineToPc, and isLineExecutable.)
* add |functionSource| property to jsdIScript.
* add |tag| to jsdIScript.
* fixed potential jsdIScript leaks.
This commit is contained in:
rginda%netscape.com 2002-01-12 00:56:35 +00:00
parent 869a967c81
commit 73855845b3
7 changed files with 402 additions and 169 deletions

View File

@ -75,6 +75,9 @@ interface jsdIProperty;
[scriptable, uuid(01be7f9a-1dd2-11b2-9d55-aaf919b27c73)]
interface jsdIDebuggerService : nsISupports
{
/** Internal use only. */
[noscript] readonly attribute JSDContext JSDContext;
/**
* Called when a jsdIScript is created or destroyed.
*/
@ -120,7 +123,7 @@ interface jsdIDebuggerService : nsISupports
* autostart pref may have turned the service on.
*/
readonly attribute boolean isOn;
/**
* 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,
@ -183,8 +186,7 @@ interface jsdIDebuggerService : nsISupports
*/
void appendFilter (in jsdIFilter filter);
/**
* Unignore execution hooks which are triggered by a jsdIScript matching
* particular filter.
* Remove a filter.
*
* If |filter| is not present this method throws NS_ERROR_INVALID_ARG.
*
@ -194,16 +196,15 @@ interface jsdIDebuggerService : nsISupports
*/
void removeFilter (in jsdIFilter filter);
/**
* Swaps the positions of the filters passed in.
* Swap position of two filters.
*
* If |filter_a| is not present, this method throws NS_ERROR_INVALID_ARG.
* If |filter_b| is not present, filter_a is replaced by filter_b.
* If |filter_a| == |filter_b|, then the glob and urlPattern properties of
* the filter are reread.
* If |filter_a| == |filter_b|, then filter is refreshed.
*/
void swapFilters (in jsdIFilter filter_a, in jsdIFilter filter_b);
/**
* Enumerate all active filters. This routine refreshes each filter before
* Enumerate registered filters. This routine refreshes each filter before
* passing them on to the enumeration function. Calling this with a null
* |enumerator| is equivilant to jsdIService::refreshFilters.
*
@ -213,13 +214,13 @@ interface jsdIDebuggerService : nsISupports
void enumerateFilters (in jsdIFilterEnumerator enumerator);
/**
* Force the debugger to resync its internal filter cache with the
* actual values in the jsdIFilter objects. To refresh a single filter,
* see jsdIService::swapFilters. This method is equivilant to
* actual values in the jsdIFilter objects. To refresh a single filter
* use jsdIService::swapFilters. This method is equivilant to
* jsdIService::enumerateFilters with a null enumerator.
*/
void refreshFilters ();
/**
* Causes the debugger service to clear its list of filters.
* Clear the list of filters.
*/
void clearFilters();
@ -468,21 +469,6 @@ interface jsdIEphemeral : nsISupports
/* handle objects */
/**
* XXX can't reflect the jsuword pc because it'll change sizes on 64 bit systems,
* but we could represent all pcs as offsets, and store them in ulongs. This
* would allow us to get rid of jsdIPC, and simplify things in some places. The
* only tradeoff would be that scripts with more than 2^32 instructions would
* have pc's we can't represent. If you're script is that large, you need more
* help than the debugger can provide.
*/
[scriptable, uuid(e7c8ea2c-1dd1-11b2-9242-f2768e04e92e)]
interface jsdIPC : nsISupports
{
/** Internal use only. */
[noscript] readonly attribute jsuword pc;
};
/**
* Stack frame objects. These are only valid inside the jsdIExecutionHook which
* gave it to you. After you return from that handler the bottom frame, and any
@ -511,7 +497,7 @@ interface jsdIStackFrame : jsdIEphemeral
/**
* Current program counter in this stack frame.
*/
readonly attribute jsdIPC pc;
readonly attribute unsigned long pc;
/**
* Current line number (using the script's pc to line map.)
*/
@ -556,6 +542,12 @@ interface jsdIScript : jsdIEphemeral
/** Internal use only. */
[noscript] readonly attribute JSDScript JSDScript;
/**
* Tag value guaranteed unique among jsdIScript objects. Useful as a
* hash key in script.
*/
readonly attribute unsigned long tag;
/**
* Filename given for this script when it was compiled.
* This data is copied from the underlying structure when the jsdIScript
@ -571,6 +563,10 @@ interface jsdIScript : jsdIEphemeral
* invalidated.
*/
readonly attribute string functionName;
/**
* Source code for this script, without function declaration.
*/
readonly attribute AString functionSource;
/**
* Line number in source file containing the first line of this script.
* This data is copied from the underlying structure when the jsdIScript
@ -586,27 +582,33 @@ interface jsdIScript : jsdIEphemeral
*/
readonly attribute unsigned long lineExtent;
const unsigned long PCMAP_SOURCETEXT = 1; /* map to actual source text */
const unsigned long PCMAP_PRETTYPRINT = 2; /* map to pretty printed source */
/**
* Get the closest line number to a given PC.
* The |pcmap| argument specifies which pc to source line map to use.
*/
unsigned long pcToLine (in jsdIPC pc);
unsigned long pcToLine (in unsigned long pc, in unsigned long pcmap);
/**
* Get the first PC associated with a line.
* The |pcmap| argument specifies which pc to source line map to use.
*/
jsdIPC lineToPc (in unsigned long line);
unsigned long lineToPc (in unsigned long line, in unsigned long pcmap);
/**
* Determine is a particular line is executable, like checking that
* lineToPc == pcToLine, except in one call.
* The |pcmap| argument specifies which pc to source line map to use.
*/
boolean isLineExecutable (in unsigned long line);
boolean isLineExecutable (in unsigned long line, in unsigned long pcmap);
/**
* Set a breakpoint at a PC in this script.
*/
void setBreakpoint (in jsdIPC pc);
void setBreakpoint (in unsigned long pc);
/**
* Clear a breakpoint at a PC in this script.
*/
void clearBreakpoint (in jsdIPC pc);
void clearBreakpoint (in unsigned long pc);
/**
* Clear all breakpoints set in this script.
*/
@ -646,7 +648,7 @@ interface jsdIValue : jsdIEphemeral
const unsigned long TYPE_BOOLEAN = 0;
/** Value is a primitive number that is too large to fit in an integer. */
const unsigned long TYPE_DOUBLE = 1;
/** Value is a number that fits into an integer. */
/** Value is a primitive number that fits into an integer. */
const unsigned long TYPE_INT = 2;
/** Value is a function. */
const unsigned long TYPE_FUNCTION = 3;

View File

@ -350,6 +350,12 @@ extern JSDScript*
jsd_FindJSDScript(JSDContext* jsdc,
JSScript *script);
extern JSScript *
jsd_GetJSScript (JSDContext *jsdc, JSDScript *script);
extern JSFunction *
jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script);
extern JSDScript*
jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp);

View File

@ -248,6 +248,18 @@ jsd_FindJSDScript( JSDContext* jsdc,
return NULL;
}
JSScript *
jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
{
return script->script;
}
JSFunction *
jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
{
return script->function;
}
JSDScript*
jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
{
@ -336,7 +348,7 @@ jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
#endif
return (jsuword) JS_LineNumberToPC(jsdc->dumbContext,
jsdscript->script, line );
jsdscript->script, line );
}
uintN

View File

@ -34,7 +34,9 @@
*/
#include "jsd_xpc.h"
#include "jsdbgapi.h"
#include "jscntxt.h"
#include "jsfun.h"
#include "nsIXPConnect.h"
#include "nsIGenericFactory.h"
@ -55,6 +57,11 @@
#include "nsIAppShell.h"
#include "nsIJSContextStack.h"
/* XXX
* defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
* script hook. This is a hack to avoid some js engine problems that I havn't
* properly tracked down. I'm lame.
*/
#define CAUTIOUS_SCRIPTHOOK
#ifdef DEBUG_verbose
@ -424,16 +431,17 @@ jsds_NotifyPendingDeadScripts (JSContext *cx)
{
nsCOMPtr<jsdIScriptHook> hook = 0;
gJsds->GetScriptHook (getter_AddRefs(hook));
if (hook)
{
DeadScript *ds;
DeadScript *ds;
#ifdef CAUTIOUS_SCRIPTHOOK
JSRuntime *rt = JS_GetRuntime(cx);
JSRuntime *rt = JS_GetRuntime(cx);
#endif
gJsds->Pause(nsnull);
do {
ds = gDeadScripts;
gJsds->Pause(nsnull);
do {
ds = gDeadScripts;
if (hook)
{
/* tell the user this script has been destroyed */
#ifdef CAUTIOUS_SCRIPTHOOK
JS_DISABLE_GC(rt);
@ -442,19 +450,19 @@ jsds_NotifyPendingDeadScripts (JSContext *cx)
#ifdef CAUTIOUS_SCRIPTHOOK
JS_ENABLE_GC(rt);
#endif
/* get next deleted script */
gDeadScripts = NS_REINTERPRET_CAST(DeadScript *,
PR_NEXT_LINK(&ds->links));
/* take ourselves out of the circular list */
PR_REMOVE_LINK(&ds->links);
/* addref came from the FromPtr call in jsds_ScriptHookProc */
NS_RELEASE(ds->script);
/* free the struct! */
PR_Free(ds);
} while (&gDeadScripts->links != &ds->links);
/* keep going until we catch up with our tail */
gJsds->UnPause(nsnull);
}
}
/* get next deleted script */
gDeadScripts = NS_REINTERPRET_CAST(DeadScript *,
PR_NEXT_LINK(&ds->links));
/* take ourselves out of the circular list */
PR_REMOVE_LINK(&ds->links);
/* addref came from the FromPtr call in jsds_ScriptHookProc */
NS_RELEASE(ds->script);
/* free the struct! */
PR_Free(ds);
} while (&gDeadScripts->links != &ds->links);
/* keep going until we catch up with our tail */
gJsds->UnPause(nsnull);
gDeadScripts = 0;
}
@ -586,12 +594,15 @@ jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
JSRuntime *rt = JS_GetRuntime(cx);
#endif
nsCOMPtr<jsdIScriptHook> hook;
gJsds->GetScriptHook (getter_AddRefs(hook));
if (creating) {
jsdIScriptHook *hook = 0;
gJsds->GetScriptHook (&hook);
if (!hook)
/* a script is being created */
if (!hook) {
/* nobody cares, just exit */
return;
}
nsCOMPtr<jsdIScript> script =
getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
@ -605,41 +616,42 @@ jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
JS_ENABLE_GC(rt);
#endif
} else {
/* a script is being destroyed. even if there is no registered hook
* we'll still need to invalidate the jsdIScript record, in order
* to remove the reference held in the JSDScript private data. */
nsCOMPtr<jsdIScript> jsdis =
NS_STATIC_CAST(jsdIScript *, JSD_GetScriptPrivate(jsdscript));
if (!jsdis)
return;
jsdIScript *jsdis = jsdScript::FromPtr(jsdc, jsdscript);
/* the initial addref is owned by the DeadScript record */
jsdis->Invalidate();
if (!hook)
return;
if (gGCStatus == JSGC_END) {
/* if GC *isn't* running, we can tell the user about the script
* delete now. */
nsCOMPtr<jsdIScriptHook> hook = 0;
gJsds->GetScriptHook (getter_AddRefs(hook));
if (hook) {
#ifdef CAUTIOUS_SCRIPTHOOK
JS_DISABLE_GC(rt);
JS_DISABLE_GC(rt);
#endif
gJsds->Pause(nsnull);
hook->OnScriptDestroyed (jsdis);
gJsds->UnPause(nsnull);
gJsds->Pause(nsnull);
hook->OnScriptDestroyed (jsdis);
gJsds->UnPause(nsnull);
#ifdef CAUTIOUS_SCRIPTHOOK
JS_ENABLE_GC(rt);
JS_ENABLE_GC(rt);
#endif
}
} else {
/* if a GC *is* running, we've got to wait until it's done before
* we can execute any JS, so we queue the notification in a PRCList
* until GC tells us it's done. See jsds_GCCallbackProc(). */
DeadScript *ds = PR_NEW(DeadScript);
if (!ds) {
NS_RELEASE(jsdis);
if (!ds)
return; /* NS_ERROR_OUT_OF_MEMORY */
}
ds->jsdc = jsdc;
ds->script = jsdis;
NS_ADDREF(ds->script);
if (gDeadScripts)
/* if the queue exists, add to it */
PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
@ -649,9 +661,7 @@ jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
gDeadScripts = ds;
}
}
}
}
}
/*******************************************************************************
@ -724,16 +734,6 @@ jsdObject::GetValue(jsdIValue **_rval)
return NS_OK;
}
/* PC */
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdPC, jsdIPC);
NS_IMETHODIMP
jsdPC::GetPc(jsuword *_rval)
{
*_rval = mPC;
return NS_OK;
}
/* Properties */
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral);
@ -837,12 +837,15 @@ jsdProperty::GetVarArgSlot(PRUint32 *_rval)
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral);
jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
mTag(0),
mCx(aCx),
mScript(aScript),
mFileName(0),
mFunctionName(0),
mBaseLineNumber(0),
mLineExtent(0)
mLineExtent(0),
mPPLineMap(0),
mFirstPC(0)
{
DEBUG_CREATE ("jsdScript", gScriptCount);
NS_INIT_ISUPPORTS();
@ -856,6 +859,7 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
JSD_UnlockScriptSubsystem(mCx);
mValid = PR_TRUE;
@ -869,12 +873,123 @@ jsdScript::~jsdScript ()
delete mFileName;
if (mFunctionName)
delete mFunctionName;
if (mPPLineMap)
PR_Free(mPPLineMap);
/* Invalidate() needs to be called to release an owning reference to
* ourselves, so if we got here without being invalidated, something
* has gone wrong with our ref count. */
NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
}
/*
* This method populates a line <-> pc map for a pretty printed version of this
* script. It does this by decompiling, and then recompiling the script. The
* resulting script is scanned for the line map, and then left as GC fodder.
*/
PCMapEntry *
jsdScript::CreatePPLineMap()
{
JSContext *cx = JSD_GetDefaultJSContext (mCx);
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSScript *script;
PRUint32 baseLine;
PRBool scriptOwner = PR_FALSE;
if (fun) {
if (fun->nargs > 8)
return 0;
JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
if (!jsstr)
return 0;
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
"arg5", "arg6", "arg7", "arg8",
"arg9", "arg10", "arg11", "arg12" };
fun = JS_CompileUCFunction (cx, obj, "ppfun", fun->nargs, argnames,
JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr),
"jsd:ppfun", 3);
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
return 0;
baseLine = 3;
} else {
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
"ppscript", 4);
if (!jsstr)
return 0;
script = JS_CompileUCScript (cx, obj,
JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr),
"jsd:ppscript", 1);
if (!script)
return 0;
scriptOwner = PR_TRUE;
baseLine = 1;
}
PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
PRUint32 firstPC = (PRUint32) JS_LineNumberToPC (cx, script, 0);
/* allocate worst case size of map (number of lines in script + 1
* for our 0 record), we'll shrink it with a realloc later. */
mPPLineMap =
NS_STATIC_CAST(PCMapEntry *,
PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
if (mPPLineMap) {
mPCMapSize = 0;
for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) {
PRUint32 pc = (PRUint32) JS_LineNumberToPC (cx, script,
line);
if (line == JS_PCToLineNumber (cx, script, (jsbytecode *)pc)) {
pc -= firstPC;
mPPLineMap[mPCMapSize].line = line;
mPPLineMap[mPCMapSize].pc = pc;
++mPCMapSize;
}
}
if (scriptExtent != mPCMapSize) {
mPPLineMap =
NS_STATIC_CAST(PCMapEntry *,
PR_Realloc(mPPLineMap,
mPCMapSize * sizeof(PCMapEntry)));
}
}
if (scriptOwner)
JS_DestroyScript (cx, script);
return mPPLineMap;
}
PRUint32
jsdScript::PPPcToLine (PRUint32 aPC)
{
if (!mPPLineMap && !CreatePPLineMap())
return 0;
PRUint32 i;
for (i = 1; i < mPCMapSize; ++i) {
if (mPPLineMap[i].pc > aPC)
return mPPLineMap[i - 1].line;
}
return mPPLineMap[mPCMapSize - 1].line;
}
PRUint32
jsdScript::PPLineToPc (PRUint32 aLine)
{
if (!mPPLineMap && !CreatePPLineMap())
return 0;
PRUint32 i;
for (i = 1; i < mPCMapSize; ++i) {
if (mPPLineMap[i].line > aLine)
return mPPLineMap[i - 1].pc;
}
return mPPLineMap[mPCMapSize - 1].pc;
}
NS_IMETHODIMP
@ -893,6 +1008,16 @@ jsdScript::GetJSDScript(JSDScript **_rval)
return NS_OK;
}
NS_IMETHODIMP
jsdScript::GetTag(PRUint32 *_rval)
{
if (!mTag)
mTag = ++jsdScript::LastTag;
*_rval = mTag;
return NS_OK;
}
NS_IMETHODIMP
jsdScript::Invalidate()
{
@ -904,10 +1029,28 @@ jsdScript::Invalidate()
JSD_GetScriptPrivate(mScript));
NS_ASSERTION (script == this, "That's not my script!");
NS_RELEASE(script);
JSD_SetScriptPrivate(mScript, NULL);
return NS_OK;
}
void
jsdScript::InvalidateAll ()
{
JSDContext *cx;
gJsds->GetJSDContext (&cx);
JSDScript *script;
JSDScript *iter = NULL;
JSD_LockScriptSubsystem(cx);
while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
jsdIScript *jsdis = NS_STATIC_CAST(jsdIScript *,
JSD_GetScriptPrivate(script));
if (jsdis)
jsdis->Invalidate();
}
JSD_UnlockScriptSubsystem(cx);
}
NS_IMETHODIMP
jsdScript::GetIsValid(PRBool *_rval)
{
@ -929,6 +1072,30 @@ jsdScript::GetFunctionName(char **_rval)
return NS_OK;
}
NS_IMETHODIMP
jsdScript::GetFunctionSource(nsAString & aFunctionSource)
{
ASSERT_VALID_SCRIPT;
JSContext *cx = JSD_GetDefaultJSContext (mCx);
if (NS_WARN_IF_FALSE(cx, "No default context !?"))
return NS_ERROR_FAILURE;
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSString *jsstr;
if (fun)
{
jsstr = JS_DecompileFunction (cx, fun, 4);
}
else
{
JSScript *script = JSD_GetJSScript (mCx, mScript);
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
}
if (!jsstr)
return NS_ERROR_FAILURE;
aFunctionSource = JS_GetStringChars(jsstr);
return NS_OK;
}
NS_IMETHODIMP
jsdScript::GetBaseLineNumber(PRUint32 *_rval)
{
@ -944,55 +1111,75 @@ jsdScript::GetLineExtent(PRUint32 *_rval)
}
NS_IMETHODIMP
jsdScript::PcToLine(jsdIPC *aPC, PRUint32 *_rval)
jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval)
{
ASSERT_VALID_SCRIPT;
jsuword pc;
aPC->GetPc(&pc);
*_rval = JSD_GetClosestLine (mCx, mScript, pc);
return NS_OK;
}
NS_IMETHODIMP
jsdScript::LineToPc(PRUint32 aLine, jsdIPC **_rval)
{
ASSERT_VALID_SCRIPT;
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
*_rval = jsdPC::FromPtr (pc);
return NS_OK;
}
NS_IMETHODIMP
jsdScript::IsLineExecutable(PRUint32 aLine, PRBool *_rval)
{
ASSERT_VALID_SCRIPT;
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
*_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
return NS_OK;
}
NS_IMETHODIMP
jsdScript::SetBreakpoint(jsdIPC *aPC)
{
ASSERT_VALID_SCRIPT;
jsuword pc;
aPC->GetPc (&pc);
if (aPcmap == PCMAP_SOURCETEXT) {
*_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
} else if (aPcmap == PCMAP_PRETTYPRINT) {
*_rval = PPPcToLine(aPC);
} else {
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
{
ASSERT_VALID_SCRIPT;
if (aPcmap == PCMAP_SOURCETEXT) {
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
*_rval = pc - mFirstPC;
} else if (aPcmap == PCMAP_PRETTYPRINT) {
*_rval = PPLineToPc(aLine);
} else {
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
{
ASSERT_VALID_SCRIPT;
if (aPcmap == PCMAP_SOURCETEXT) {
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
*_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
} else if (aPcmap == PCMAP_PRETTYPRINT) {
if (!mPPLineMap && !CreatePPLineMap())
return NS_ERROR_FAILURE;
*_rval = PR_FALSE;
for (PRUint32 i = 0; i < mPCMapSize; ++i) {
if (mPPLineMap[i].line >= aLine) {
*_rval = (mPPLineMap[i].line == aLine);
break;
}
}
} else {
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
jsdScript::SetBreakpoint(PRUint32 aPC)
{
ASSERT_VALID_SCRIPT;
jsuword pc = mFirstPC + aPC;
JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc,
NS_REINTERPRET_CAST(void *, PRIVATE_TO_JSVAL(NULL)));
return NS_OK;
}
NS_IMETHODIMP
jsdScript::ClearBreakpoint(jsdIPC *aPC)
jsdScript::ClearBreakpoint(PRUint32 aPC)
{
ASSERT_VALID_SCRIPT;
if (!aPC)
return NS_ERROR_INVALID_ARG;
jsuword pc;
aPC->GetPc (&pc);
jsuword pc = mFirstPC + aPC;
JSD_ClearExecutionHook (mCx, mScript, pc);
return NS_OK;
}
@ -1070,12 +1257,17 @@ jsdStackFrame::GetScript(jsdIScript **_rval)
}
NS_IMETHODIMP
jsdStackFrame::GetPc(jsdIPC **_rval)
jsdStackFrame::GetPc(PRUint32 *_rval)
{
ASSERT_VALID_FRAME;
jsuword pc;
pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
*_rval = jsdPC::FromPtr (pc);
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
mStackFrameInfo);
jsuword pcbase = JSD_GetClosestPC(mCx, script, 0);
if (!script)
return NS_ERROR_FAILURE;
jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
*_rval = pc - pcbase;
return NS_OK;
}
@ -1424,6 +1616,13 @@ jsdValue::Refresh()
******************************************************************************/
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService);
NS_IMETHODIMP
jsdService::GetJSDContext(JSDContext **_rval)
{
*_rval = mCx;
return NS_OK;
}
NS_IMETHODIMP
jsdService::GetInitAtStartup (PRBool *_rval)
{
@ -1587,8 +1786,8 @@ jsdService::OnForRuntime (JSRuntime *rt)
*/
if (mThrowHook)
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
if (mScriptHook)
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
/* can't ignore script callbacks, as we need to |Release| the wrapper
* stored in private data when a script is deleted. */
if (mInterruptHook)
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
if (mDebuggerHook)
@ -1635,12 +1834,12 @@ jsdService::Off (void)
JS_SetGCCallbackRT (mRuntime, gLastGCProc);
*/
jsdScript::InvalidateAll();
jsdValue::InvalidateAll();
jsdProperty::InvalidateAll();
ClearAllBreakpoints();
JSD_ClearThrowHook (mCx);
JSD_SetScriptHook (mCx, NULL, NULL);
JSD_ClearInterruptHook (mCx);
JSD_ClearDebuggerHook (mCx);
JSD_ClearDebugBreakHook (mCx);
@ -1720,7 +1919,9 @@ jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
JSD_LockScriptSubsystem(mCx);
while((script = JSD_IterateScripts(mCx, &iter)) != NULL) {
rv = enumerator->EnumerateScript (jsdScript::FromPtr(mCx, script));
nsCOMPtr<jsdIScript> jsdis =
getter_AddRefs(jsdScript::FromPtr(mCx, script));
rv = enumerator->EnumerateScript (jsdis);
if (NS_FAILED(rv))
break;
}
@ -2098,9 +2299,9 @@ jsdService::SetScriptHook (jsdIScriptHook *aHook)
if (aHook)
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
else
JSD_SetScriptHook (mCx, NULL, 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
* private data. */
return NS_OK;
}

View File

@ -48,43 +48,18 @@
struct LiveEphemeral {
/* link in a chain of live values list */
PRCList links;
PRCList links;
jsdIEphemeral *value;
};
struct PCMapEntry {
PRUint32 pc, line;
};
/*******************************************************************************
* reflected jsd data structures
*******************************************************************************/
class jsdPC : public jsdIPC
{
public:
NS_DECL_ISUPPORTS
NS_DECL_JSDIPC
/* you'll normally use use FromPtr() instead of directly constructing one */
jsdPC (jsuword aPC) : mPC(aPC)
{
NS_INIT_ISUPPORTS();
}
static jsdIPC *FromPtr (jsuword aPC)
{
if (!aPC)
return nsnull;
jsdIPC *rv = new jsdPC (aPC);
NS_IF_ADDREF(rv);
return rv;
}
private:
jsdPC(); /* no implementation */
jsdPC(const jsdPC&); /* no implementation */
jsuword mPC;
};
class jsdObject : public jsdIObject
{
public:
@ -183,18 +158,31 @@ class jsdScript : public jsdIScript
return rv;
}
static void InvalidateAll();
private:
static PRUint32 LastTag;
jsdScript(); /* no implementation */
jsdScript (const jsdScript&); /* no implementation */
PCMapEntry* CreatePPLineMap();
PRUint32 PPPcToLine(PRUint32 aPC);
PRUint32 PPLineToPc(PRUint32 aLine);
PRBool mValid;
PRUint32 mTag;
JSDContext *mCx;
JSDScript *mScript;
nsCString *mFileName;
nsCString *mFunctionName;
PRUint32 mBaseLineNumber, mLineExtent;
PCMapEntry *mPPLineMap;
PRUint32 mPCMapSize;
jsuword mFirstPC;
};
PRUint32 jsdScript::LastTag = 0;
class jsdStackFrame : public jsdIStackFrame
{
public:

View File

@ -142,6 +142,18 @@ JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
return jsd_IterateScripts(jsdc, iterp);
}
JSD_PUBLIC_API(JSScript*)
JSD_GetJSScript(JSDContext* jsdc, JSDScript *script)
{
return jsd_GetJSScript(jsdc, script);
}
JSD_PUBLIC_API(JSFunction*)
JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script)
{
return jsd_GetJSFunction (jsdc, script);
}
JSD_PUBLIC_API(void *)
JSD_SetScriptPrivate(JSDScript *jsdscript, void *data)
{

View File

@ -234,6 +234,18 @@ JSD_UnlockScriptSubsystem(JSDContext* jsdc);
extern JSD_PUBLIC_API(JSDScript*)
JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp);
/*
* Get the JSScript for a JSDScript
*/
extern JSD_PUBLIC_API(JSScript*)
JSD_GetJSScript(JSDContext* jsdc, JSDScript *script);
/*
* Get the JSFunction for a JSDScript
*/
extern JSD_PUBLIC_API(JSFunction*)
JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script);
/*
* Set the private data for this script, returns previous value
*/