Bug 646660 - fp::pc should work on frames outside the current context (r=luke)
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 12 Apr 2011 13:02:16 -0700
changeset 68529 3dc5d38ba870e48a97a8be2697909f607b765f8e
parent 68528 0c727da2164d061f620015eb11dbf0a4b42c2a84
child 68530 e0f9db5a4fc7ac27673a4eba1bb99b8d34a42421
push id19680
push usercleary@mozilla.com
push dateTue, 26 Apr 2011 17:44:40 +0000
treeherdermozilla-central@28bc239d3d9d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs646660
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 646660 - fp::pc should work on frames outside the current context (r=luke)
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsinterp.cpp
js/src/jsparse.cpp
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -103,39 +103,50 @@
 #   define MAP_ANONYMOUS 0
 #  endif
 # endif
 #endif
 
 using namespace js;
 using namespace js::gc;
 
-#ifdef DEBUG
 JS_REQUIRES_STACK bool
 StackSegment::contains(const JSStackFrame *fp) const
 {
     JS_ASSERT(inContext());
+
+    if (fp < initialFrame)
+        return false;
+
     JSStackFrame *start;
-    JSStackFrame *stop;
     if (isActive()) {
-        JS_ASSERT(cx->hasfp());
+        JS_ASSERT(cx->hasfp() && this == cx->activeSegment());
         start = cx->fp();
-        stop = cx->activeSegment()->initialFrame->prev();
     } else {
         JS_ASSERT(suspendedRegs && suspendedRegs->fp);
         start = suspendedRegs->fp;
-        stop = initialFrame->prev();
     }
-    for (JSStackFrame *f = start; f != stop; f = f->prev()) {
-        if (f == fp)
-            return true;
+
+    if (fp > start)
+        return false;
+
+#ifdef DEBUG
+    bool found = false;
+    JSStackFrame *stop = initialFrame->prev();
+    for (JSStackFrame *f = start; !found && f != stop; f = f->prev()) {
+        if (f == fp) {
+            found = true;
+            break;
+        }
     }
-    return false;
+    JS_ASSERT(found);
+#endif
+
+    return true;
 }
-#endif
 
 JSStackFrame *
 StackSegment::computeNextFrame(JSStackFrame *fp) const
 {
     JS_ASSERT(contains(fp));
     JS_ASSERT(fp != getCurrentFrame());
 
     JSStackFrame *next = getCurrentFrame();
@@ -2016,46 +2027,23 @@ JSContext::generatorFor(JSStackFrame *fp
         if (genStack[i]->liveFrame() == fp)
             return genStack[i];
     }
     JS_NOT_REACHED("no matching generator");
     return NULL;
 }
 
 StackSegment *
-JSContext::containingSegment(const JSStackFrame *target)
+StackSpace::containingSegment(const JSStackFrame *target)
 {
-    /* The context may have nothing running. */
-    StackSegment *seg = currentSegment;
-    if (!seg)
-        return NULL;
-
-    /* The active segments's top frame is cx->regs->fp. */
-    if (regs) {
-        JS_ASSERT(regs->fp);
-        JS_ASSERT(activeSegment() == seg);
-        JSStackFrame *f = regs->fp;
-        JSStackFrame *stop = seg->getInitialFrame()->prev();
-        for (; f != stop; f = f->prev()) {
-            if (f == target)
-                return seg;
-        }
-        seg = seg->getPreviousInContext();
+    for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
+        if (seg->contains(target))
+            return seg;
     }
-
-    /* A suspended segment's top frame is its suspended frame. */
-    for (; seg; seg = seg->getPreviousInContext()) {
-        JSStackFrame *f = seg->getSuspendedFrame();
-        JSStackFrame *stop = seg->getInitialFrame()->prev();
-        for (; f != stop; f = f->prev()) {
-            if (f == target)
-                return seg;
-        }
-    }
-
+    JS_NOT_REACHED("frame not in stack space");
     return NULL;
 }
 
 JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
 #ifdef JS_THREADSAFE
     AutoLockGC lock(this);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -375,19 +375,17 @@ class StackSegment
         return initialVarObj != NULL;
     }
 
     JSObject &getInitialVarObj() const {
         JS_ASSERT(inContext() && initialVarObj);
         return *initialVarObj;
     }
 
-#ifdef DEBUG
     JS_REQUIRES_STACK bool contains(const JSStackFrame *fp) const;
-#endif
 
     JSStackFrame *computeNextFrame(JSStackFrame *fp) const;
 };
 
 static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value);
 JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0);
 
 /* See StackSpace::pushInvokeArgs. */
@@ -678,16 +676,19 @@ class StackSpace
                         JSScript *script, uint32 *flags, InvokeFrameGuard *fg) const;
 
     void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard *fg);
 
     /* These functions are called inside Execute, not Execute clients. */
     bool getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const;
     void pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg);
 
+    /* Get the segment which contains the target frame. */
+    js::StackSegment *containingSegment(const JSStackFrame *target);
+
     /*
      * Since RAII cannot be used for inline frames, callers must manually
      * call pushInlineFrame/popInlineFrame.
      */
     inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
                                         JSFunction *fun, JSScript *script,
                                         uint32 *flags) const;
     inline void pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
@@ -1782,22 +1783,16 @@ struct JSContext
 
   public:
     /* Mark the top segment as suspended, without pushing a new one. */
     void saveActiveSegment();
 
     /* Undoes calls to suspendActiveSegment. */
     void restoreSegment();
 
-    /*
-     * Perform a linear search of all frames in all segments in the given context
-     * for the given frame, returning the segment, if found, and null otherwise.
-     */
-    js::StackSegment *containingSegment(const JSStackFrame *target);
-
     /* Search the call stack for the nearest frame with static level targetLevel. */
     JSStackFrame *findFrameAtLevel(uintN targetLevel) const {
         JSStackFrame *fp = regs->fp;
         while (true) {
             JS_ASSERT(fp && fp->isScriptFrame());
             if (fp->script()->staticLevel == targetLevel)
                 break;
             fp = fp->prev();
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -109,17 +109,17 @@ using namespace js::gc;
 JSObject *const JSStackFrame::sInvalidScopeChain = (JSObject *)0xbeef;
 #endif
 
 jsbytecode *
 JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
 {
     JS_ASSERT_IF(next, next->prev_ == this);
 
-    StackSegment *seg = cx->containingSegment(this);
+    StackSegment *seg = cx->stack().containingSegment(this);
     JSFrameRegs *regs = seg->getCurrentRegs();
     if (regs->fp == this)
         return regs->pc;
 
     if (!next)
         next = seg->computeNextFrame(this);
 
     if (next->flags_ & JSFRAME_HAS_PREVPC)
@@ -939,17 +939,17 @@ Execute(JSContext *cx, JSObject *chain, 
     JSObject *initialVarObj;
     if (prev) {
         JS_ASSERT(chain == &prev->scopeChain());
         frame.fp()->initEvalFrame(cx, script, prev, flags);
 
         /* NB: prev may not be in cx->currentSegment. */
         initialVarObj = (prev == cx->maybefp())
                         ? &prev->varobj(cx)
-                        : &prev->varobj(cx->containingSegment(prev));
+                        : &prev->varobj(cx->stack().containingSegment(prev));
     } else {
         /* The scope chain could be anything, so innerize just in case. */
         JSObject *innerizedChain = chain;
         OBJ_TO_INNER_OBJECT(cx, innerizedChain);
         if (!innerizedChain)
             return false;
 
         /* If we were handed a non-native object, complain bitterly. */
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -185,17 +185,17 @@ JSParseNode::clear()
 
 Parser::Parser(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
   : js::AutoGCRooter(cx, PARSER),
     context(cx),
     aleFreeList(NULL),
     tokenStream(cx),
     principals(NULL),
     callerFrame(cfp),
-    callerVarObj(cfp ? &cfp->varobj(cx->containingSegment(cfp)) : NULL),
+    callerVarObj(cfp ? &cfp->varobj(cx->stack().containingSegment(cfp)) : NULL),
     nodeList(NULL),
     functionCount(0),
     traceListHead(NULL),
     tc(NULL),
     emptyCallShape(NULL),
     keepAtoms(cx->runtime)
 {
     js::PodArrayZero(tempFreeList);