Bug 602003: add jsd API to query valid script begin and end PCs, r=sayrer,jjb
This commit is contained in:
@@ -1001,6 +1001,17 @@ interface jsdIScript : jsdIEphemeral
|
|||||||
* The |pcmap| argument specifies which pc to source line map to use.
|
* The |pcmap| argument specifies which pc to source line map to use.
|
||||||
*/
|
*/
|
||||||
boolean isLineExecutable (in unsigned long line, in unsigned long pcmap);
|
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.
|
* Set a breakpoint at a PC in this script.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -478,6 +478,12 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
|
|||||||
extern jsuword
|
extern jsuword
|
||||||
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
|
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
|
||||||
|
|
||||||
|
extern jsuword
|
||||||
|
jsd_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript);
|
||||||
|
|
||||||
|
extern jsuword
|
||||||
|
jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript);
|
||||||
|
|
||||||
extern uintN
|
extern uintN
|
||||||
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
|
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
|
||||||
|
|
||||||
|
|||||||
@@ -500,20 +500,22 @@ jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
|
|||||||
jsuword
|
jsuword
|
||||||
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
|
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,
|
return (jsuword) JS_LineNumberToPC(jsdc->dumbContext,
|
||||||
jsdscript->script, line );
|
jsdscript->script, line );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsuword
|
||||||
|
jsd_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript)
|
||||||
|
{
|
||||||
|
return (jsuword) JS_FirstValidPC(jsdc->dumbContext, jsdscript->script );
|
||||||
|
}
|
||||||
|
|
||||||
|
jsuword
|
||||||
|
jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript)
|
||||||
|
{
|
||||||
|
return (jsuword) JS_EndPC(jsdc->dumbContext, jsdscript->script );
|
||||||
|
}
|
||||||
|
|
||||||
uintN
|
uintN
|
||||||
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
|
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -958,7 +958,9 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
|
|||||||
mBaseLineNumber(0),
|
mBaseLineNumber(0),
|
||||||
mLineExtent(0),
|
mLineExtent(0),
|
||||||
mPPLineMap(0),
|
mPPLineMap(0),
|
||||||
mFirstPC(0)
|
mFirstValidPC(0),
|
||||||
|
mFirstPC(0),
|
||||||
|
mEndPC(0)
|
||||||
{
|
{
|
||||||
DEBUG_CREATE ("jsdScript", gScriptCount);
|
DEBUG_CREATE ("jsdScript", gScriptCount);
|
||||||
|
|
||||||
@@ -972,6 +974,8 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
|
|||||||
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
|
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
|
||||||
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
|
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
|
||||||
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
|
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
|
||||||
|
mFirstValidPC = JSD_GetFirstValidPC(mCx, mScript);
|
||||||
|
mEndPC = JSD_GetEndPC(mCx, mScript);
|
||||||
JSD_UnlockScriptSubsystem(mCx);
|
JSD_UnlockScriptSubsystem(mCx);
|
||||||
|
|
||||||
mValid = PR_TRUE;
|
mValid = PR_TRUE;
|
||||||
@@ -1475,6 +1479,22 @@ jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
jsdScript::GetFirstValidPC(PRUint32 *_rval)
|
||||||
|
{
|
||||||
|
ASSERT_VALID_EPHEMERAL;
|
||||||
|
*_rval = PRUint32(mFirstValidPC - mFirstPC);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
jsdScript::GetEndValidPC(PRUint32 *_rval)
|
||||||
|
{
|
||||||
|
ASSERT_VALID_EPHEMERAL;
|
||||||
|
*_rval = PRUint32(mEndPC - mFirstPC);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
jsdScript::SetBreakpoint(PRUint32 aPC)
|
jsdScript::SetBreakpoint(PRUint32 aPC)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ class jsdScript : public jsdIScript
|
|||||||
PRUint32 mBaseLineNumber, mLineExtent;
|
PRUint32 mBaseLineNumber, mLineExtent;
|
||||||
PCMapEntry *mPPLineMap;
|
PCMapEntry *mPPLineMap;
|
||||||
PRUint32 mPCMapSize;
|
PRUint32 mPCMapSize;
|
||||||
jsuword mFirstPC;
|
jsuword mFirstPC; /* address of first PC in script */
|
||||||
|
jsuword mFirstValidPC; /* address of first valid bkpt PC */
|
||||||
|
jsuword mEndPC; /* address of end of script code */
|
||||||
};
|
};
|
||||||
|
|
||||||
PRUint32 jsdScript::LastTag = 0;
|
PRUint32 jsdScript::LastTag = 0;
|
||||||
|
|||||||
@@ -348,6 +348,22 @@ JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
|
|||||||
return jsd_GetClosestPC(jsdc, jsdscript, line);
|
return jsd_GetClosestPC(jsdc, jsdscript, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSD_PUBLIC_API(jsuword)
|
||||||
|
JSD_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript)
|
||||||
|
{
|
||||||
|
JSD_ASSERT_VALID_CONTEXT(jsdc);
|
||||||
|
JSD_ASSERT_VALID_SCRIPT(jsdscript);
|
||||||
|
return jsd_GetFirstValidPC(jsdc, jsdscript);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_PUBLIC_API(uintN)
|
||||||
JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
|
JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -486,6 +486,19 @@ JSD_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
|
|||||||
extern JSD_PUBLIC_API(jsuword)
|
extern JSD_PUBLIC_API(jsuword)
|
||||||
JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
|
JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the first 'Program Counter' value where a breakpoint can be set.
|
||||||
|
*/
|
||||||
|
extern JSD_PUBLIC_API(jsuword)
|
||||||
|
JSD_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
* Get the source line number for a given 'Program Counter' location.
|
||||||
* Returns 0 if no source line information is appropriate (or available) for
|
* Returns 0 if no source line information is appropriate (or available) for
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ MODULE = jsdebug
|
|||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
_TEST_FILES = test_bug507448.html \
|
_TEST_FILES = test_bug507448.html \
|
||||||
|
test_bug602003.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libs:: $(_TEST_FILES)
|
libs:: $(_TEST_FILES)
|
||||||
|
|||||||
62
js/jsd/test/test_bug602003.html
Normal file
62
js/jsd/test/test_bug602003.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=507448
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 602003</title>
|
||||||
|
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507448">Mozilla Bug 507448</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 602003 **/
|
||||||
|
|
||||||
|
// 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 g(a,b) { return a + b }
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
var script = jsd.wrapValue(g).script;
|
||||||
|
|
||||||
|
// Test the script start/end PC APIs.
|
||||||
|
var start = script.getFirstValidPC();
|
||||||
|
var end = script.getEndValidPC();
|
||||||
|
|
||||||
|
// Start PC should be 1 for a function because it starts with JSOP_BEGIN.
|
||||||
|
is(start, 1, "Start PC should be 1");
|
||||||
|
|
||||||
|
// End PC should be something greater than 1, and not huge. Changes
|
||||||
|
// in the bytecode will change this, so we'll just be approximate.
|
||||||
|
ok(1 < end && end < 100, "End PC doesn't seem sane.");
|
||||||
|
|
||||||
|
if (!jsdOn) {
|
||||||
|
jsd.off();
|
||||||
|
ok(!jsd.isOn, "JSD shouldn't be running anymore.");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -475,7 +475,9 @@ AllFramesIter::operator++()
|
|||||||
{
|
{
|
||||||
JS_ASSERT(!done());
|
JS_ASSERT(!done());
|
||||||
if (curfp == curcs->getInitialFrame()) {
|
if (curfp == curcs->getInitialFrame()) {
|
||||||
|
do {
|
||||||
curcs = curcs->getPreviousInMemory();
|
curcs = curcs->getPreviousInMemory();
|
||||||
|
} while (curcs && !curcs->inContext());
|
||||||
curfp = curcs ? curcs->getCurrentFrame() : NULL;
|
curfp = curcs ? curcs->getCurrentFrame() : NULL;
|
||||||
} else {
|
} else {
|
||||||
curfp = curfp->prev();
|
curfp = curfp->prev();
|
||||||
|
|||||||
@@ -235,9 +235,11 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not trap BEGIN, it's a special prologue opcode.
|
if (JSOp(*pc) == JSOP_BEGIN) {
|
||||||
if (JSOp(*pc) == JSOP_BEGIN)
|
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
|
||||||
pc += JSOP_BEGIN_LENGTH;
|
NULL, JSMSG_READ_ONLY, "trap invalid on BEGIN opcode");
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
|
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
|
||||||
junk = NULL;
|
junk = NULL;
|
||||||
@@ -1019,6 +1021,19 @@ JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
|
|||||||
return js_LineNumberToPC(script, lineno);
|
return js_LineNumberToPC(script, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(jsbytecode *)
|
||||||
|
JS_FirstValidPC(JSContext *cx, JSScript *script)
|
||||||
|
{
|
||||||
|
jsbytecode *pc = script->code;
|
||||||
|
return *pc == JSOP_BEGIN ? pc + JSOP_BEGIN_LENGTH : pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(jsbytecode *)
|
||||||
|
JS_EndPC(JSContext *cx, JSScript *script)
|
||||||
|
{
|
||||||
|
return script->code + script->length;
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(uintN)
|
JS_PUBLIC_API(uintN)
|
||||||
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
|
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -159,6 +159,12 @@ JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
|
|||||||
extern JS_PUBLIC_API(jsbytecode *)
|
extern JS_PUBLIC_API(jsbytecode *)
|
||||||
JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno);
|
JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(jsbytecode *)
|
||||||
|
JS_FirstValidPC(JSContext *cx, JSScript *script);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(jsbytecode *)
|
||||||
|
JS_EndPC(JSContext *cx, JSScript *script);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(uintN)
|
extern JS_PUBLIC_API(uintN)
|
||||||
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
|
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user