Backed out changeset 2bdf648e7015
authorDavid Anderson <danderson@mozilla.com>
Fri, 15 Oct 2010 15:21:51 -0700
changeset 56031 77794568b4898dc2b4f7757c05af9e2a58d2a30c
parent 56026 2bdf648e701581ddc3c867ae8ba6039b2c3483ae
child 56032 11ddd5d7c3570836a0d019fb2a258915b4549a06
push idunknown
push userunknown
push dateunknown
milestone2.0b8pre
backs out2bdf648e701581ddc3c867ae8ba6039b2c3483ae
Backed out changeset 2bdf648e7015
js/jsd/idl/jsdIDebuggerService.idl
js/jsd/jsd.h
js/jsd/jsd_scpt.c
js/jsd/jsd_xpc.cpp
js/jsd/jsd_xpc.h
js/jsd/jsdebug.c
js/jsd/jsdebug.h
js/jsd/test/Makefile.in
js/jsd/test/test_bug602003.html
js/src/jscntxt.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
--- 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,22 @@ 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_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript);
+
+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,32 @@ 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_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
 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,34 @@ jsdScript::jsdScript (JSDContext *aCx, J
                                                              mTag(0),
                                                              mCx(aCx),
                                                              mScript(aScript),
                                                              mFileName(0), 
                                                              mFunctionName(0),
                                                              mBaseLineNumber(0),
                                                              mLineExtent(0),
                                                              mPPLineMap(0),
-                                                             mFirstPC(0)
+                                                             mFirstValidPC(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);
+        mFirstValidPC = JSD_GetFirstValidPC(mCx, mScript);
+        mEndPC = JSD_GetEndPC(mCx, mScript);
         JSD_UnlockScriptSubsystem(mCx);
         
         mValid = PR_TRUE;
     }
 }
 
 jsdScript::~jsdScript () 
 {
@@ -1471,16 +1475,32 @@ jsdScript::IsLineExecutable(PRUint32 aLi
     } else {
         return NS_ERROR_INVALID_ARG;
     }
     
     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
 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
@@ -177,17 +177,19 @@ class jsdScript : public jsdIScript
     PRUint32    mTag;
     JSDContext *mCx;
     JSDScript  *mScript;
     nsCString  *mFileName;
     nsCString  *mFunctionName;
     PRUint32    mBaseLineNumber, mLineExtent;
     PCMapEntry *mPPLineMap;
     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;
 
 class jsdContext : public jsdIContext
 {
   public:
     NS_DECL_ISUPPORTS
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -343,16 +343,32 @@ 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_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_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,29 @@ 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 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.
 * 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/jsd/test/Makefile.in
+++ b/js/jsd/test/Makefile.in
@@ -43,12 +43,13 @@ relativesrcdir  = js/jsd/test
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = jsdebug
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = 	test_bug507448.html \
+                test_bug602003.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/js/jsd/test/test_bug602003.html
@@ -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>
--- 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,29 @@ 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_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_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,22 @@ 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_FirstValidPC(JSContext *cx, JSScript *script);
+
+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