mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-24 21:58:06 +00:00
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:
parent
869a967c81
commit
73855845b3
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user