[INFER] Move containingSegment to StackSpace, fix uninitialized field, bug 646660.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 30 Mar 2011 17:24:34 -0700
changeset 74880 ca3aaca8c59083448afb82da0d10cbc41a6e4680
parent 74879 2c9b41f384eaf28a27e2c08c097ca80fc6a12818
child 74881 bc0a254d5c681bab517856f7749ee917ea5807ac
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs646660
milestone2.0b13pre
[INFER] Move containingSegment to StackSpace, fix uninitialized field, bug 646660.
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsinterp.cpp
js/src/jsparse.cpp
js/src/methodjit/Retcon.cpp
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -109,39 +109,48 @@ using namespace js;
 using namespace js::gc;
 
 static const size_t ARENA_HEADER_SIZE_HACK = 40;
 static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
 
 static void
 FreeContext(JSContext *cx);
 
-#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 (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)
-            return true;
+            found = true;
     }
-    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();
@@ -2050,46 +2059,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
@@ -411,19 +411,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. */
@@ -720,16 +718,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,
@@ -1761,22 +1762,16 @@ struct JSContext
     void popSegmentAndFrame();
 
     /* 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
@@ -111,17 +111,17 @@ using namespace js::types;
 JSObject *const JSStackFrame::sInvalidScopeChain = (JSObject *)0xbeef;
 #endif
 
 jsbytecode *
 JSStackFrame::pc(JSContext *cx, JSStackFrame *next, JSInlinedSite **pinlined)
 {
     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) {
         if (pinlined)
             *pinlined = regs->inlined;
         return regs->pc;
     }
 
     if (!next)
@@ -999,17 +999,17 @@ Execute(JSContext *cx, JSObject *chain, 
          * We want to call |prev->varobj()|, but this requires knowing the
          * CallStackSegment of |prev|. If |prev == cx->fp()|, the callstack is
          * simply the context's active callstack, so we can use
          * |prev->varobj(cx)|.  When |prev != cx->fp()|, we need to do a slow
          * linear search. Luckily, this only happens with EvaluateInFrame.
          */
         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
@@ -186,17 +186,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),
     keepAtoms(cx->runtime)
 {
     js::PodArrayZero(tempFreeList);
     setPrincipals(prin);
--- a/js/src/methodjit/Retcon.cpp
+++ b/js/src/methodjit/Retcon.cpp
@@ -330,17 +330,17 @@ ExpandInlineFrames(JSContext *cx, bool a
         return;
     }
 
     for (VMFrame *f = cx->compartment->jaegerCompartment->activeFrame();
          f != NULL;
          f = f->previous) {
 
         if (f->regs.inlined) {
-            StackSegment *seg = cx->containingSegment(f->fp());
+            StackSegment *seg = cx->stack().containingSegment(f->fp());
             JSFrameRegs *regs = seg->getCurrentRegs();
             if (regs->fp == f->fp()) {
                 JS_ASSERT(regs == &f->regs);
                 mjit::Recompiler::expandInlineFrames(cx, f->fp(), f->regs.inlined, NULL, f);
             } else {
                 JSStackFrame *nnext = seg->computeNextFrame(f->fp());
                 mjit::Recompiler::expandInlineFrames(cx, f->fp(), f->regs.inlined, nnext, f);
             }
@@ -441,16 +441,17 @@ Recompiler::recompile()
                 next = fp;
                 continue;
             }
 
             // Remember every frame for each type of JIT'd code.
             PatchableFrame frame;
             frame.fp = fp;
             frame.pc = fp->pc(cx, next);
+            frame.scriptedCall = false;
 
             if (next) {
                 // check for a scripted call returning into the recompiled script.
                 // this misses scanning the entry fp, which cannot return directly
                 // into JIT code.
                 void **addr = next->addressOfNativeReturnAddress();
 
                 if (!*addr) {