Bug 602003: add jsd API to query valid script begin and end PCs, r=sayrer,jjb
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -997,16 +997,27 @@ interface jsdIScript : jsdIEphemeral
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, in unsigned long pcmap);
/**
+ * Get the first valid PC in the script. This will be either
+ * (a) the first bytecode in the script, or (b) the next bytecode
+ * in the script, iff the first bytecode is a JSOP_BEGIN.
+ */
+ unsigned long getFirstValidPC ();
+ /**
+ * Return the last valid PC in the script (i.e., the PC just after
+ * the last bytecode).
+ */
+ unsigned long getEndValidPC ();
+ /**
* Set a breakpoint at a PC in this script.
*/
void setBreakpoint (in unsigned long pc);
/**
* Clear a breakpoint at a PC in this script.
*/
void clearBreakpoint (in unsigned long pc);
/**
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -473,16 +473,19 @@ extern JSBool
jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
extern JSBool
jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata);
extern jsuword
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
+extern jsuword
+jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript);
+
extern uintN
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
extern void
jsd_NewScriptHookProc(
JSContext *cx,
const char *filename, /* URL this script loads from */
uintN lineno, /* line where this script starts */
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -495,30 +495,26 @@ jsd_GetScriptLineExtent(JSDContext* jsdc
if( NOT_SET_YET == (int)jsdscript->lineExtent )
jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script);
return jsdscript->lineExtent;
}
jsuword
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
{
-#ifdef LIVEWIRE
- if( jsdscript && jsdscript->lwscript )
- {
- uintN newline;
- jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
- if( line != newline )
- line = newline;
- }
-#endif
-
return (jsuword) JS_LineNumberToPC(jsdc->dumbContext,
jsdscript->script, line );
}
+jsuword
+jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript)
+{
+ return (jsuword) JS_EndPC(jsdc->dumbContext, jsdscript->script );
+}
+
uintN
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
{
uintN first = jsdscript->lineBase;
uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
uintN line = pc
? JS_PCToLineNumber(jsdc->dumbContext,
jsdscript->script,
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -953,30 +953,32 @@ jsdScript::jsdScript (JSDContext *aCx, J
mTag(0),
mCx(aCx),
mScript(aScript),
mFileName(0),
mFunctionName(0),
mBaseLineNumber(0),
mLineExtent(0),
mPPLineMap(0),
- mFirstPC(0)
+ mFirstPC(0),
+ mEndPC(0)
{
DEBUG_CREATE ("jsdScript", gScriptCount);
if (mScript) {
/* copy the script's information now, so we have it later, when it
* gets destroyed. */
JSD_LockScriptSubsystem(mCx);
mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
mFunctionName =
new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
+ mEndPC = JSD_GetEndPC(mCx, mScript);
JSD_UnlockScriptSubsystem(mCx);
mValid = PR_TRUE;
}
}
jsdScript::~jsdScript ()
{
@@ -1471,16 +1473,35 @@ jsdScript::IsLineExecutable(PRUint32 aLi
} else {
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
+jsdScript::GetFirstValidPC(PRUint32 *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ jsbytecode *pc = (jsbytecode *) mFirstPC;
+ if (*pc == JSOP_BEGIN)
+ ++pc;
+ *_rval = PRUint32(pc);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetEndValidPC(PRUint32 *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = PRUint32(mEndPC);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
jsdScript::SetBreakpoint(PRUint32 aPC)
{
ASSERT_VALID_EPHEMERAL;
jsuword pc = mFirstPC + aPC;
JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
return NS_OK;
}
--- a/js/jsd/jsd_xpc.h
+++ b/js/jsd/jsd_xpc.h
@@ -178,16 +178,17 @@ class jsdScript : public jsdIScript
JSDContext *mCx;
JSDScript *mScript;
nsCString *mFileName;
nsCString *mFunctionName;
PRUint32 mBaseLineNumber, mLineExtent;
PCMapEntry *mPPLineMap;
PRUint32 mPCMapSize;
jsuword mFirstPC;
+ jsuword mEndPC;
};
PRUint32 jsdScript::LastTag = 0;
class jsdContext : public jsdIContext
{
public:
NS_DECL_ISUPPORTS
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -343,16 +343,24 @@ JSD_GetScriptHook(JSDContext* jsdc, JSD_
JSD_PUBLIC_API(jsuword)
JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
{
JSD_ASSERT_VALID_CONTEXT(jsdc);
JSD_ASSERT_VALID_SCRIPT(jsdscript);
return jsd_GetClosestPC(jsdc, jsdscript, line);
}
+JSD_PUBLIC_API(jsuword)
+JSD_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetEndPC(jsdc, jsdscript);
+}
+
JSD_PUBLIC_API(uintN)
JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
{
JSD_ASSERT_VALID_CONTEXT(jsdc);
JSD_ASSERT_VALID_SCRIPT(jsdscript);
return jsd_GetClosestLine(jsdc, jsdscript, pc);
}
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -482,16 +482,23 @@ JSD_GetScriptHook(JSDContext* jsdc, JSD_
* If no code is on the given line, then the returned pc represents the first
* code within the script (if any) after the given line.
* This function can be used to set breakpoints -- see JSD_SetExecutionHook
*/
extern JSD_PUBLIC_API(jsuword)
JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
/*
+* Get the 'Program Counter' value just after the last byte of the script.
+* 0 is returned for invalid scripts.
+*/
+extern JSD_PUBLIC_API(jsuword)
+JSD_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript);
+
+/*
* Get the source line number for a given 'Program Counter' location.
* Returns 0 if no source line information is appropriate (or available) for
* the given pc.
*/
extern JSD_PUBLIC_API(uintN)
JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
/* these are only used in cases where scripts are created outside of JS*/
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -470,17 +470,19 @@ AllFramesIter::AllFramesIter(JSContext *
{
}
AllFramesIter&
AllFramesIter::operator++()
{
JS_ASSERT(!done());
if (curfp == curcs->getInitialFrame()) {
- curcs = curcs->getPreviousInMemory();
+ do {
+ curcs = curcs->getPreviousInMemory();
+ } while (curcs && !curcs->inContext());
curfp = curcs ? curcs->getCurrentFrame() : NULL;
} else {
curfp = curfp->prev();
}
return *this;
}
bool
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -230,19 +230,21 @@ JS_SetTrap(JSContext *cx, JSScript *scri
return JS_FALSE;
if (script == JSScript::emptyScript()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
NULL, JSMSG_READ_ONLY, "empty script");
return JS_FALSE;
}
- // Do not trap BEGIN, it's a special prologue opcode.
- if (JSOp(*pc) == JSOP_BEGIN)
- pc += JSOP_BEGIN_LENGTH;
+ if (JSOp(*pc) == JSOP_BEGIN) {
+ JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
+ NULL, JSMSG_READ_ONLY, "trap invalid on BEGIN opcode");
+ return JS_FALSE;
+ }
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
junk = NULL;
rt = cx->runtime;
DBG_LOCK(rt);
trap = FindTrap(rt, script, pc);
if (trap) {
JS_ASSERT(trap->script == script && trap->pc == pc);
@@ -1014,16 +1016,22 @@ JS_PCToLineNumber(JSContext *cx, JSScrip
}
JS_PUBLIC_API(jsbytecode *)
JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
{
return js_LineNumberToPC(script, lineno);
}
+JS_PUBLIC_API(jsbytecode *)
+JS_EndPC(JSContext *cx, JSScript *script)
+{
+ return script->code + script->length;
+}
+
JS_PUBLIC_API(uintN)
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
{
return fun->nargs;
}
JS_PUBLIC_API(JSBool)
JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -154,16 +154,19 @@ js_WrapWatchedSetter(JSContext *cx, jsid
/************************************************************************/
extern JS_PUBLIC_API(uintN)
JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
extern JS_PUBLIC_API(jsbytecode *)
JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno);
+extern JS_PUBLIC_API(jsbytecode *)
+JS_EndPC(JSContext *cx, JSScript *script);
+
extern JS_PUBLIC_API(uintN)
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
extern JS_PUBLIC_API(JSBool)
JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun);
/*
* N.B. The mark is in the context temp pool and thus the caller must take care