Backed out changeset 1070cd7a9da0
authorIgor Bukanov <igor@mir2.org>
Fri, 28 May 2010 14:19:20 +0200
changeset 43205 8609e2cdd335eaba901a4009f629d56f51dc24db
parent 43204 1070cd7a9da034a481e85998a3a40a004d618afc
child 43206 36d81cc1a7de6770632b9cbc24ae65ad820c47e9
push id13641
push userrsayre@mozilla.com
push dateSun, 06 Jun 2010 19:08:23 +0000
treeherdermozilla-central@5b3604a3cfbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a5pre
backs out1070cd7a9da034a481e85998a3a40a004d618afc
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Backed out changeset 1070cd7a9da0
js/src/jsapi-tests/Makefile.in
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi-tests/testIsAboutToBeFinalized.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsstr.cpp
js/src/jstypes.h
js/src/tests/jstests.py
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -43,17 +43,16 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 PROGRAM         = jsapi-tests$(BIN_SUFFIX)
 CPPSRCS = \
   tests.cpp \
   selfTest.cpp \
-  testConservativeGC.cpp \
   testContexts.cpp \
   testDebugger.cpp \
   testDefineGetterSetterNonEnumerable.cpp \
   testDefineProperty.cpp \
   testExtendedEq.cpp \
   testIntString.cpp \
   testIsAboutToBeFinalized.cpp \
   testLookup.cpp \
deleted file mode 100644
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "tests.h"
-#include "jsobj.h"
-#include "jsstr.h"
-
-BEGIN_TEST(testConservativeGC)
-{
-    jsval v1;
-    EVAL("Math.sqrt(42);", &v1);
-    CHECK(JSVAL_IS_DOUBLE(v1));
-    double numCopy = *JSVAL_TO_DOUBLE(v1);
-
-    jsval v2;
-    EVAL("({foo: 'bar'});", &v2);
-    CHECK(JSVAL_IS_OBJECT(v2));
-    JSObject objCopy = *JSVAL_TO_OBJECT(v2);
-
-    jsval v3;
-    EVAL("String(Math.PI);", &v3);
-    CHECK(JSVAL_IS_STRING(v3));
-    JSString strCopy = *JSVAL_TO_STRING(v3);
-
-    jsval tmp;
-    EVAL("Math.sqrt(41);", &tmp);
-    CHECK(JSVAL_IS_DOUBLE(tmp));
-    jsdouble *num2 = JSVAL_TO_DOUBLE(tmp);
-    jsdouble num2Copy = *num2;
-
-    EVAL("({foo2: 'bar2'});", &tmp);
-    CHECK(JSVAL_IS_OBJECT(tmp));
-    JSObject *obj2 = JSVAL_TO_OBJECT(tmp);
-    JSObject obj2Copy = *obj2;
-
-    EVAL("String(Math.sqrt(3));", &tmp);
-    CHECK(JSVAL_IS_STRING(tmp));
-    JSString *str2 = JSVAL_TO_STRING(tmp);
-    JSString str2Copy = *str2;
-
-    tmp = JSVAL_NULL;
-
-    JS_GC(cx);
-
-    EVAL("var a = [];\n"
-         "for (var i = 0; i != 10000; ++i) {\n"
-         "a.push(i + 0.1, [1, 2], String(Math.sqrt(i)));\n"
-         "}", &tmp);
-
-    JS_GC(cx);
-
-    CHECK(numCopy == *JSVAL_TO_DOUBLE(v1));
-    CHECK(!memcmp(&objCopy,  JSVAL_TO_OBJECT(v2), sizeof(objCopy)));
-    CHECK(!memcmp(&strCopy,  JSVAL_TO_STRING(v3), sizeof(strCopy)));
-
-    CHECK(num2Copy == *num2);
-    CHECK(!memcmp(&obj2Copy,  obj2, sizeof(obj2Copy)));
-    CHECK(!memcmp(&str2Copy,  str2, sizeof(str2Copy)));
-
-    return true;
-}
-END_TEST(testConservativeGC)
--- a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp
+++ b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp
@@ -1,81 +1,33 @@
 #include "tests.h"
 #include "jsstr.h"
 
 static JSGCCallback oldGCCallback;
 
 static void **checkPointers;
 static jsuint checkPointersLength;
-static size_t checkPointersStaticStrings;
 
 static JSBool
 TestAboutToBeFinalizedCallback(JSContext *cx, JSGCStatus status)
 {
     if (status == JSGC_MARK_END && checkPointers) {
         for (jsuint i = 0; i != checkPointersLength; ++i) {
             void *p = checkPointers[i];
             JS_ASSERT(p);
             if (JS_IsAboutToBeFinalized(cx, p))
                 checkPointers[i] = NULL;
         }
     }
 
     return !oldGCCallback || oldGCCallback(cx, status);
 }
 
-static JS_NEVER_INLINE size_t
-NativeFrameCleaner()
-{
-    char buffer[1 << 16];
-    memset(buffer, 0, sizeof buffer);
-    size_t count = 0;
-    for (size_t i = 0; i != sizeof buffer; ++i) {
-        if (buffer[i])
-            count++;
-    }
-    return count;
-}
-
 BEGIN_TEST(testIsAboutToBeFinalized_bug528645)
 {
-    /*
-     * Due to the conservative GC we use separated never-inline function to
-     * test rooted elements.
-     */
-    createAndTestRooted();
-    NativeFrameCleaner();
-
-    JS_GC(cx);
-
-    /* Everything is unrooted except unit strings. */
-    for (jsuint i = 0; i != checkPointersLength; ++i) {
-        void *p = checkPointers[i];
-        if (p) {
-            CHECK(JSString::isStatic(p));
-            CHECK(checkPointersStaticStrings != 0);
-            --checkPointersStaticStrings;
-        }
-    }
-    CHECK(checkPointersStaticStrings == 0);
-
-    free(checkPointers);
-    checkPointers = NULL;
-    JS_SetGCCallback(cx, oldGCCallback);
-
-    return true;
-}
-
-JS_NEVER_INLINE bool createAndTestRooted();
-
-END_TEST(testIsAboutToBeFinalized_bug528645)
-
-JS_NEVER_INLINE bool
-cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted()
-{
     jsvalRoot root(cx);
 
     /*
      * Check various types of GC things against JS_IsAboutToBeFinalized.
      * Make sure to include unit and numeric strings to the set.
      */
     EVAL("var x = 1.1; "
          "[x + 0.1, ''+x, 'a', '42', 'something'.substring(1), "
@@ -83,34 +35,55 @@ cls_testIsAboutToBeFinalized_bug528645::
          root.addr());
 
     JSObject *array = JSVAL_TO_OBJECT(root.value());
     JS_ASSERT(JS_IsArrayObject(cx, array));
 
     JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength);
     CHECK(ok);
 
-    checkPointers = (void **) malloc(sizeof(void *) * checkPointersLength);
-    CHECK(checkPointers);
+    void **elems = (void **) malloc(sizeof(void *) * checkPointersLength);
+    CHECK(elems);
 
-    checkPointersStaticStrings = 0;
+    size_t staticStrings = 0;
     for (jsuint i = 0; i != checkPointersLength; ++i) {
         jsval v;
         ok = JS_GetElement(cx, array, i, &v);
         CHECK(ok);
         JS_ASSERT(JSVAL_IS_GCTHING(v));
         JS_ASSERT(!JSVAL_IS_NULL(v));
-        checkPointers[i] = JSVAL_TO_GCTHING(v);
-        if (JSString::isStatic(checkPointers[i]))
-            ++checkPointersStaticStrings;
+        elems[i] = JSVAL_TO_GCTHING(v);
+        if (JSString::isStatic(elems[i]))
+            ++staticStrings;
     }
 
     oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback);
+    checkPointers = elems;
     JS_GC(cx);
 
     /*
      * All GC things are rooted via the root holding the array containing them
      * and TestAboutToBeFinalizedCallback must keep them as is.
      */
     for (jsuint i = 0; i != checkPointersLength; ++i)
         CHECK(checkPointers[i]);
+
+    root = JSVAL_NULL;
+    JS_GC(cx);
+
+    /* Everything is unrooted except unit strings. */
+    for (jsuint i = 0; i != checkPointersLength; ++i) {
+        void *p = checkPointers[i];
+        if (p) {
+            CHECK(JSString::isStatic(p));
+            CHECK(staticStrings != 0);
+            --staticStrings;
+        }
+    }
+    CHECK(staticStrings == 0);
+
+    checkPointers = NULL;
+    JS_SetGCCallback(cx, oldGCCallback);
+    free(elems);
+
+    return true;
 }
-
+END_TEST(testIsAboutToBeFinalized_bug528645)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -837,46 +837,36 @@ JS_YieldRequest(JSContext *cx)
 #endif
 }
 
 JS_PUBLIC_API(jsrefcount)
 JS_SuspendRequest(JSContext *cx)
 {
 #ifdef JS_THREADSAFE
     jsrefcount saveDepth = cx->requestDepth;
-    if (saveDepth == 0)
-        return 0;
-
-    do {
+
+    while (cx->requestDepth) {
         cx->outstandingRequests++;  /* compensate for JS_EndRequest */
         JS_EndRequest(cx);
-    } while (cx->requestDepth);
-
-    JS_THREAD_DATA(cx)->conservativeGC.enable();
-
+    }
     return saveDepth;
 #else
     return 0;
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
 {
 #ifdef JS_THREADSAFE
-    if (saveDepth == 0)
-        return;
-
-    JS_THREAD_DATA(cx)->conservativeGC.disable();
-
-    JS_ASSERT(cx->outstandingRequests != 0);
-    do {
+    JS_ASSERT(!cx->requestDepth);
+    while (--saveDepth >= 0) {
         JS_BeginRequest(cx);
         cx->outstandingRequests--;  /* compensate for JS_BeginRequest */
-    } while (--saveDepth != 0);
+    }
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS_TransferRequest(JSContext *cx, JSContext *another)
 {
     JS_ASSERT(cx != another);
     JS_ASSERT(cx->runtime == another->runtime);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -56,27 +56,27 @@
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
-#include "jsnativestack.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspubtd.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jsstr.h"
 #include "jstracer.h"
+#include "jsnativestack.h"
 
 #include "jscntxtinlines.h"
 
 #ifdef XP_WIN
 # include <windows.h>
 #else
 # include <unistd.h>
 # include <sys/mman.h>
@@ -519,17 +519,16 @@ void
 JSThreadData::finish()
 {
 #ifdef DEBUG
     /* All GC-related things must be already removed at this point. */
     JS_ASSERT(gcFreeLists.isEmpty());
     for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
         JS_ASSERT(!scriptsToGC[i]);
     JS_ASSERT(!localRootStack);
-    JS_ASSERT(conservativeGC.enableCount == 0);
 #endif
 
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 
     js_FinishGSNCache(&gsnCache);
     propertyCache.~PropertyCache();
 #if defined JS_TRACER
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1028,18 +1028,16 @@ struct JSThreadData {
     } dtoaCache;
 
     /* Cached native iterators. */
     JSObject            *cachedNativeIterators[NATIVE_ITER_CACHE_SIZE];
 
     /* Base address of the native stack for the current thread. */
     jsuword             *nativeStackBase;
 
-    js::ConservativeGCThreadData conservativeGC;
-
     bool init();
     void finish();
     void mark(JSTracer *trc);
     void purge(JSContext *cx);
     void purgeGCFreeLists();
 };
 
 #ifdef JS_THREADSAFE
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -805,24 +805,16 @@ GetFinalizableTraceKind(size_t thingKind
 static inline size_t
 GetFinalizableArenaTraceKind(JSGCArenaInfo *ainfo)
 {
     JS_ASSERT(ainfo->list);
     return GetFinalizableTraceKind(ainfo->list->thingKind);
 }
 
 static inline size_t
-GetArenaTraceKind(JSGCArenaInfo *ainfo)
-{
-    if (!ainfo->list)
-        return JSTRACE_DOUBLE;
-    return GetFinalizableArenaTraceKind(ainfo);
-}
-
-static inline size_t
 GetFinalizableThingTraceKind(void *thing)
 {
     JSGCArenaInfo *ainfo = JSGCArenaInfo::fromGCThing(thing);
     return GetFinalizableArenaTraceKind(ainfo);
 }
 
 static void
 InitGCArenaLists(JSRuntime *rt)
@@ -869,17 +861,19 @@ js_GetExternalStringGCType(JSString *str
 
 JS_FRIEND_API(uint32)
 js_GetGCThingTraceKind(void *thing)
 {
     if (JSString::isStatic(thing))
         return JSTRACE_STRING;
 
     JSGCArenaInfo *ainfo = JSGCArenaInfo::fromGCThing(thing);
-    return GetArenaTraceKind(ainfo);
+    if (!ainfo->list)
+        return JSTRACE_DOUBLE;
+    return GetFinalizableArenaTraceKind(ainfo);
 }
 
 JSRuntime *
 js_GetGCThingRuntime(void *thing)
 {
     jsuword chunk = JSGCArena::fromGCThing(thing)->getChunk();
     return JSGCChunkInfo::fromChunk(chunk)->runtime;
 }
@@ -929,415 +923,16 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes
      * (during JS engine start).
      */
     rt->setGCLastBytes(8192);
 
     METER(PodZero(&rt->gcStats));
     return true;
 }
 
-namespace js {
-
-struct GCChunkHasher
-{
-    typedef jsuword Lookup;
-    static HashNumber hash(jsuword chunk) {
-        /*
-         * Strip zeros for better distribution after multiplying by the golden
-         * ratio.
-         */
-        JS_ASSERT(!(chunk & GC_CHUNK_MASK));
-        return HashNumber(chunk >> GC_CHUNK_SHIFT);
-    }
-    static bool match(jsuword k, jsuword l) {
-        JS_ASSERT(!(k & GC_CHUNK_MASK));
-        JS_ASSERT(!(l & GC_CHUNK_MASK));
-        return k == l;
-    }
-};
-
-class ConservativeGCStackMarker {
-  public:
-    ConservativeGCStackMarker(JSTracer *trc);
-
-    ~ConservativeGCStackMarker() {
-#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-        dumpConservativeRoots();
-#endif
-#ifdef JS_GCMETER
-        JSConservativeGCStats *total = &trc->context->runtime->gcStats.conservative;
-        total->words        += stats.words;
-        total->unique       += stats.unique;
-        total->oddaddress   += stats.oddaddress;
-        total->outside      += stats.outside;
-        total->notchunk     += stats.notchunk;
-        total->notarena     += stats.notarena;
-        total->wrongtag     += stats.wrongtag;
-        total->notlive      += stats.notlive;
-        total->gcthings     += stats.gcthings;
-        total->raw          += stats.raw;
-        total->unmarked     += stats.unmarked;
-#endif
-    }
-
-    void markRoots();
-
-  private:
-    void markRange(jsuword *begin, jsuword *end);
-    void markWord(jsuword w);
-
-    JSTracer *trc;
-    jsuword gcthingAddressStart;
-    jsuword gcthingAddressSpan;
-    HashSet<jsuword, GCChunkHasher, SystemAllocPolicy> chunkSet;
-    HashSet<jsuword, DefaultHasher<jsuword>, SystemAllocPolicy> history;
-
-#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
-    JSConservativeGCStats stats;
-
-  public:
-    static void dumpStats(FILE *fp, JSConservativeGCStats *stats);
-
-# define CONSERVATIVE_METER(x)  ((void) (x))
-# define CONSERVATIVE_METER_IF(condition, x) ((void) ((condition) && (x)))
-
-#else
-
-# define CONSERVATIVE_METER(x)                  ((void) 0)
-# define CONSERVATIVE_METER_IF(condition, x)    ((void) 0)
-
-#endif
-
-#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-  private:
-    struct ConservativeRoot { void *thing; uint32 traceKind; };
-    Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
-    const char *dumpFileName;
-
-    void dumpConservativeRoots();
-#endif
-};
-
-ConservativeGCStackMarker::ConservativeGCStackMarker(JSTracer *trc)
-    : trc(trc)
-{
-    /*
-     * If initializing fails because we are out of memory, stack scanning
-     * slows down but is otherwise unaffected.
-     */
-    history.init();
-
-    JSRuntime *rt = trc->context->runtime;
-    jsuword minchunk = 0, maxchunk = 0;
-    bool chunkSetOk = chunkSet.init(rt->gcChunks.length());
-    for (JSGCChunkInfo **i = rt->gcChunks.begin(); i != rt->gcChunks.end(); ++i) {
-        jsuword chunk =(*i)->getChunk();
-        if (chunkSetOk) {
-            JS_ASSERT(!chunkSet.has(chunk));
-            JS_ALWAYS_TRUE(chunkSet.put(chunk));
-        }
-
-        if (minchunk == 0)
-            minchunk = maxchunk = chunk;
-        else if (chunk < minchunk)
-            minchunk = chunk;
-        else if (chunk > maxchunk)
-            maxchunk = chunk;
-    }
-
-    gcthingAddressStart = minchunk;
-    gcthingAddressSpan = (minchunk != 0)
-                         ? maxchunk + GC_MARK_BITMAP_ARRAY_OFFSET
-                         : 0;
-
-#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-    dumpFileName = getenv("JS_DUMP_CONSERVATIVE_GC_ROOTS");
-    memset(&stats, 0, sizeof(stats));
-#endif
-}
-
-#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
-/* static */
-void
-ConservativeGCStackMarker::dumpStats(FILE *fp, JSConservativeGCStats *stats)
-{
-#define ULSTAT(x)       ((unsigned long)(stats->x))
-    fprintf(fp, "CONSERVATIVE STACK SCANNING:\n");
-    fprintf(fp, "      number of stack words: %lu\n", ULSTAT(words));
-    fprintf(fp, "     number of unique words: %lu\n", ULSTAT(unique));
-    fprintf(fp, "      excluded, low bit set: %lu\n", ULSTAT(oddaddress));
-    fprintf(fp, "    not withing chunk range: %lu\n", ULSTAT(outside));
-    fprintf(fp, "        not withing a chunk: %lu\n", ULSTAT(notchunk));
-    fprintf(fp, "       not withing an arena: %lu\n", ULSTAT(notarena));
-    fprintf(fp, "        excluded, wrong tag: %lu\n", ULSTAT(wrongtag));
-    fprintf(fp, "         excluded, not live: %lu\n", ULSTAT(notlive));
-    fprintf(fp, "              things marked: %lu\n", ULSTAT(gcthings));
-    fprintf(fp, "        raw pointers marked: %lu\n", ULSTAT(raw));
-    fprintf(fp, "         conservative roots: %lu\n", ULSTAT(unmarked));
-#undef ULSTAT
-}
-#endif
-
-#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-void
-ConservativeGCStackMarker::dumpConservativeRoots()
-{
-    if (!dumpFileName)
-        return;
-
-    JS_ASSERT(stats.unmarked == conservativeRoots.length());
-
-    FILE *fp = !strcmp(dumpFileName, "stdout") ? stdout
-               : !strcmp(dumpFileName, "stderr") ? stderr
-               : fopen(dumpFileName, "aw");
-    if (!fp) {
-        fprintf(stderr,
-                "Warning: cannot open %s to dump the conservative roots\n",
-                dumpFileName);
-        return;
-    }
-
-    dumpStats(fp, &stats);
-    for (ConservativeRoot *i = conservativeRoots.begin();
-         i != conservativeRoots.end();
-         ++i) {
-        fprintf(fp, "  %p: ", i->thing);
-        switch (i->traceKind) {
-          default:
-            JS_NOT_REACHED("Unknown trace kind");
-
-          case JSTRACE_OBJECT: {
-            JSObject *obj = (JSObject *) i->thing;
-            fprintf(fp, "object %s", obj->getClass()->name);
-            break;
-          }
-          case JSTRACE_STRING: {
-            JSString *str = (JSString *) i->thing;
-            char buf[50];
-            js_PutEscapedString(buf, sizeof buf, str, '"');
-            fprintf(fp, "string %s", buf);
-            break;
-          }
-          case JSTRACE_DOUBLE: {
-            jsdouble *dp = (jsdouble *) i->thing;
-            fprintf(fp, "double %e", *dp);
-            break;
-          }
-# if JS_HAS_XML_SUPPORT
-          case JSTRACE_XML: {
-            JSXML *xml = (JSXML *) i->thing;
-            fprintf(fp, "xml %u", xml->xml_class);
-            break;
-          }
-# endif
-        }
-        fputc('\n', fp);
-    }
-    fputc('\n', fp);
-
-    if (fp != stdout && fp != stderr)
-        fclose(fp);
-}
-#endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */
-
-void
-ConservativeGCStackMarker::markWord(jsuword w)
-{
-#define RETURN(x) do { CONSERVATIVE_METER(stats.x++); return; } while (0)
-
-    JSRuntime *rt = trc->context->runtime;
-
-    CONSERVATIVE_METER(stats.unique++);
-
-    /* If this is an odd addresses or a tagged integer, skip it. */
-    if (w & 1)
-        RETURN(oddaddress);
-
-    /* Strip off the tag bits. */
-    jsuword tag = w & JSVAL_TAGMASK;
-    jsuword p = w & ~(JSVAL_TAGMASK);
-
-    /* Also ignore tagged special values (they never contain pointers). */
-    if (tag == JSVAL_SPECIAL)
-        RETURN(wrongtag);
-
-    /* The remaining pointer must be within the heap boundaries. */
-    if ((p - gcthingAddressStart) >= gcthingAddressSpan)
-        RETURN(outside);
-
-    if ((p & GC_CHUNK_MASK) >= GC_MARK_BITMAP_ARRAY_OFFSET)
-        RETURN(outside);
-
-    jsuword chunk = p & ~GC_CHUNK_MASK;
-    JSGCChunkInfo *ci;
-    if (JS_LIKELY(chunkSet.initialized())) {
-        if (!chunkSet.has(chunk))
-            RETURN(notchunk);
-        ci = JSGCChunkInfo::fromChunk(chunk);
-    } else {
-        ci = JSGCChunkInfo::fromChunk(chunk);
-        for (JSGCChunkInfo **i = rt->gcChunks.begin(); ; ++i) {
-            if (i == rt->gcChunks.end())
-                RETURN(notchunk);
-            if (*i == ci)
-                break;
-        }
-    }
-
-    size_t arenaIndex = (p & GC_CHUNK_MASK) >> GC_ARENA_SHIFT;
-    if (JS_TEST_BIT(ci->getFreeArenaBitmap(), arenaIndex))
-        RETURN(notarena);
-
-    JSGCArena *a = JSGCArena::fromChunkAndIndex(chunk, arenaIndex);
-    JSGCArenaInfo *ainfo = a->getInfo();
-
-    JSGCThing *thing;
-    if (!ainfo->list) { /* doubles */
-        if (tag && tag != JSVAL_DOUBLE)
-            RETURN(wrongtag);
-        JS_STATIC_ASSERT(JSVAL_TAGMASK == 7 && (sizeof(double) - 1) == 7);
-        thing = (JSGCThing *) p;
-    } else {
-        if (tag == JSVAL_DOUBLE)
-            RETURN(wrongtag);
-        jsuword start = a->toPageStart();
-        jsuword offset = p - start;
-        size_t thingSize = ainfo->list->thingSize;
-        p = (start + offset - (offset % thingSize));
-        thing = (JSGCThing *) p;
-
-        /* Make sure the thing is not on the freelist of the arena. */
-        JSGCThing *cursor = ainfo->freeList;
-        while (cursor) {
-            /* If the cursor moves past the thing, its not in the freelist. */
-            if (thing < cursor)
-                break;
-            /* If we find it on the freelist, its dead. */
-            if (thing == cursor)
-                RETURN(notlive);
-            cursor = cursor->link;
-        }
-    }
-
-    CONSERVATIVE_METER(stats.gcthings++);
-    CONSERVATIVE_METER_IF(!tag, stats.raw++);
-
-    /*
-     * We have now a valid pointer, that is either raw or tagged properly.
-     * Since we do not rely on the conservative scanning yet and assume that
-     * all the roots are precisely reported, any unmarked GC things here mean
-     * a leak.
-     */
-    if (IS_GC_MARKING_TRACER(trc)) {
-        if (!js_IsAboutToBeFinalized(thing))
-            return;
-        CONSERVATIVE_METER(stats.unmarked++);
-    }
-
-    uint32 traceKind = GetArenaTraceKind(ainfo);
-#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-    if (IS_GC_MARKING_TRACER(trc) && dumpFileName) {
-        ConservativeRoot root = {thing, traceKind};
-        conservativeRoots.append(root);
-    }
-#endif
-    JS_SET_TRACING_NAME(trc, "machine stack");
-    js_CallGCMarker(trc, thing, traceKind);
-
-#undef RETURN
-}
-
-void
-ConservativeGCStackMarker::markRange(jsuword *begin, jsuword *end)
-{
-    JS_ASSERT(begin <= end);
-    if (history.initialized()) {
-        for (jsuword *i = begin; i != end; ++i) {
-            CONSERVATIVE_METER(stats.words++);
-            jsuword p = *i;
-            if (history.has(p))
-                continue;
-            markWord(p);
-
-            /*
-             * If adding the address to the hash table fails because we are
-             * out of memory, stack scanning slows down but is otherwise
-             * unaffected.
-             */
-            history.put(p);
-        }
-    } else {
-        for (jsuword *i = begin; i != end; ++i)
-            markWord(*i);
-    }
-}
-
-void
-ConservativeGCStackMarker::markRoots()
-{
-    /* Do conservative scanning of the stack. */
-    for (ThreadDataIter i(trc->context->runtime); !i.empty(); i.popFront()) {
-        JSThreadData *td = i.threadData();
-        ConservativeGCThreadData *ctd = &td->conservativeGC;
-        if (ctd->enableCount) {
-#if JS_STACK_GROWTH_DIRECTION > 0
-            JS_ASSERT(td->nativeStackBase <= ctd->nativeStackTop);
-            markRange(td->nativeStackBase, ctd->nativeStackTop);
-#else
-            JS_ASSERT(td->nativeStackBase >= ctd->nativeStackTop + 1);
-            markRange(ctd->nativeStackTop + 1, td->nativeStackBase);
-#endif
-            markRange(ctd->registerSnapshot.words,
-                      JS_ARRAY_END(ctd->registerSnapshot.words));
-        }
-    }
-}
-
-/* static */
-JS_NEVER_INLINE void
-ConservativeGCThreadData::enable(bool knownStackBoundary)
-{
-    /* Update the native stack pointer if it points to a bigger stack. */
-#if JS_STACK_GROWTH_DIRECTION > 0
-# define CMP >
-#else
-# define CMP <
-#endif
-    jsuword dummy;
-    if (knownStackBoundary || enableCount == 0 || &dummy CMP nativeStackTop)
-        nativeStackTop = &dummy;
-#undef CMP
-
-    /* Update the register snapshot with the latest values. */
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4611)
-#endif
-    setjmp(registerSnapshot.jmpbuf);
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-    ++enableCount;
-}
-
-JS_NEVER_INLINE void
-ConservativeGCThreadData::disable()
-{
-    JS_ASSERT(enableCount != 0);
-    --enableCount;
-#ifdef DEBUG
-    if (enableCount == 0)
-        nativeStackTop = NULL;
-#endif
-}
-
-} /* namespace js */
-
-
 #ifdef JS_GCMETER
 
 static void
 UpdateArenaStats(JSGCArenaStats *st, uint32 nlivearenas, uint32 nkilledArenas,
                  uint32 nthings)
 {
     size_t narenas;
 
@@ -1493,18 +1088,16 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
     fprintf(fp, "  thing arenas freed so far: %lu\n", ULSTAT(afree));
     fprintf(fp, "     stack segments scanned: %lu\n", ULSTAT(stackseg));
     fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots));
     fprintf(fp, "reachable closeable objects: %lu\n", ULSTAT(nclose));
     fprintf(fp, "    max reachable closeable: %lu\n", ULSTAT(maxnclose));
     fprintf(fp, "      scheduled close hooks: %lu\n", ULSTAT(closelater));
     fprintf(fp, "  max scheduled close hooks: %lu\n", ULSTAT(maxcloselater));
 
-    ConservativeGCStackMarker::dumpStats(fp, &rt->gcStats.conservative);
-
 #undef UL
 #undef ULSTAT
 #undef PERCENT
 }
 #endif
 
 #ifdef DEBUG
 static void
@@ -2614,44 +2207,37 @@ js_TraceContext(JSTracer *trc, JSContext
     }
 #endif
 }
 
 JS_REQUIRES_STACK void
 js_TraceRuntime(JSTracer *trc)
 {
     JSRuntime *rt = trc->context->runtime;
+    JSContext *iter, *acx;
 
     for (GCRoots::Range r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
         gc_root_traversal(r.front(), trc);
 
     for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront())
         gc_lock_traversal(r.front(), trc);
 
     js_TraceAtomState(trc);
     js_TraceRuntimeNumberState(trc);
     js_MarkTraps(trc);
 
-    JSContext *iter = NULL;
-    while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
+    iter = NULL;
+    while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
         js_TraceContext(trc, acx);
 
     for (ThreadDataIter i(rt); !i.empty(); i.popFront())
         i.threadData()->mark(trc);
 
     if (rt->gcExtraRootsTraceOp)
         rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
-
-    /*
-     * For now we use the conservative stack scanner only in the check mode
-     * and mark conservatively after marking all other roots to detect
-     * conservative leaks.
-     */
-    if (rt->state != JSRTS_LANDING)
-        ConservativeGCStackMarker(trc).markRoots();
 }
 
 void
 js_TriggerGC(JSContext *cx, JSBool gcLocked)
 {
     JSRuntime *rt = cx->runtime;
 
 #ifdef JS_THREADSAFE
@@ -3413,29 +2999,27 @@ LetOtherGCFinish(JSContext *cx)
     cx->thread->gcWaiting = true;
     js_ShareWaitingTitles(cx);
 
     /*
      * Check that we did not release the GC lock above and let the GC to
      * finish before we wait.
      */
     JS_ASSERT(rt->gcThread);
-    JS_THREAD_DATA(cx)->conservativeGC.enable(true);
 
     /*
      * Wait for GC to finish on the other thread, even if requestDebit is 0
      * and even if GC has not started yet because the gcThread is waiting in
      * BeginGCSession. This ensures that js_GC never returns without a full GC
      * cycle happening.
      */
     do {
         JS_AWAIT_GC_DONE(rt);
     } while (rt->gcThread);
 
-    JS_THREAD_DATA(cx)->conservativeGC.disable();
     cx->thread->gcWaiting = false;
     rt->requestCount += requestDebit;
 }
 
 #endif
 
 /*
  * Start a new GC session assuming no GC is running on this or other threads.
@@ -3552,27 +3136,16 @@ GCUntilDone(JSContext *cx, JSGCInvocatio
             return;
     }
 #endif /* JS_THREADSAFE */
 
     BeginGCSession(cx);
 
     METER(rt->gcStats.poke++);
 
-    /*
-     * Do not scan the current thread when on the shutdown or when the
-     * GC is called outside a request.
-     */
-    bool scanGCThreadStack = (rt->state != JSRTS_LANDING)
-#ifndef JS_THREADSAFE
-                             && (rt->gcThread->contextsInRequests != 0)
-#endif
-                             ;
-    if (scanGCThreadStack)
-        JS_THREAD_DATA(cx)->conservativeGC.enable(true);
     bool firstRun = true;
     do {
         rt->gcPoke = false;
 
         AutoUnlockGC unlock(rt);
         if (firstRun) {
             PreGCCleanup(cx, gckind);
             TIMESTAMP(startMark);
@@ -3581,19 +3154,16 @@ GCUntilDone(JSContext *cx, JSGCInvocatio
         GC(cx  GCTIMER_ARG);
 
         // GC again if:
         //   - another thread, not in a request, called js_GC
         //   - js_GC was called recursively
         //   - a finalizer called js_RemoveRoot or js_UnlockGCThingRT.
     } while (rt->gcPoke);
 
-    if (rt->state != JSRTS_LANDING)
-        JS_THREAD_DATA(cx)->conservativeGC.disable();
-
     rt->gcRegenShapes = false;
     rt->setGCLastBytes(rt->gcBytes);
 
     EndGCSession(cx);
 }
 
 /*
  * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -37,19 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_h___
 #define jsgc_h___
 /*
  * JS Garbage Collector.
  */
-#include <setjmp.h>
-
-#include "jstypes.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsdhash.h"
 #include "jsbit.h"
 #include "jsutil.h"
 #include "jstask.h"
 #include "jsvector.h"
 #include "jsversion.h"
@@ -372,19 +369,19 @@ struct JSWeakRoots {
     /* Root for the result of the most recent js_InternalInvoke call. */
     jsval           lastInternalResult;
 
     void mark(JSTracer *trc);
 };
 
 #define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
 
-namespace js {
+#ifdef JS_THREADSAFE
 
-#ifdef JS_THREADSAFE
+namespace js {
 
 /*
  * During the finalization we do not free immediately. Rather we add the
  * corresponding pointers to a buffer which we later release on the
  * background thread.
  *
  * The buffer is implemented as a vector of 64K arrays of pointers, not as a
  * simple vector, to avoid realloc calls during the vector growth and to not
@@ -418,70 +415,29 @@ class BackgroundSweepTask : public JSBac
             *freeCursor++ = ptr;
         else
             replenishAndFreeLater(ptr);
     }
 
     virtual void run();
 };
 
-#endif /* JS_THREADSAFE */
-
-struct ConservativeGCThreadData {
-
-    /*
-     * The GC scans conservatively between JSThreadData::nativeStackBase and
-     * nativeStackTop unless the latter is NULL.
-     */
-    jsuword             *nativeStackTop;
-
-    union {
-        jmp_buf         jmpbuf;
-        jsuword         words[JS_HOWMANY(sizeof(jmp_buf), sizeof(jsuword))];
-    } registerSnapshot;
-
-    size_t              enableCount;
-
-    JS_NEVER_INLINE void enable(bool knownStackBoundary = false);
-    void disable();
-};
-
-} /* namespace js */
-
-#define JS_DUMP_CONSERVATIVE_GC_ROOTS 1
+}
+#endif
 
 extern void
 js_FinalizeStringRT(JSRuntime *rt, JSString *str);
 
 #if defined JS_GCMETER
 const bool JS_WANT_GC_METER_PRINT = true;
 #elif defined DEBUG
 # define JS_GCMETER 1
 const bool JS_WANT_GC_METER_PRINT = false;
 #endif
 
-#if defined JS_GCMETER || defined JS_DUMP_CONSERVATIVE_GC_ROOTS
-
-struct JSConservativeGCStats {
-    uint32  words;      /* number of words on native stacks */
-    uint32  unique;     /* number of unique words */
-    uint32  oddaddress; /* excluded because low bit was set */
-    uint32  outside;    /* not within chunk min/max address range */
-    uint32  notchunk;   /* not within a valid chunk */
-    uint32  notarena;   /* not within non-free arena */
-    uint32  wrongtag;   /* tagged pointer but wrong type */
-    uint32  notlive;    /* gcthing is not allocated */
-    uint32  gcthings;   /* number of live gcthings */
-    uint32  raw;        /* number of raw pointers marked */
-    uint32  unmarked;   /* number of unmarked gc things discovered on the
-                           stack */
-};
-
-#endif
-
 #ifdef JS_GCMETER
 
 struct JSGCArenaStats {
     uint32  alloc;          /* allocation attempts */
     uint32  localalloc;     /* allocations from local lists */
     uint32  retry;          /* allocation retries after running the GC */
     uint32  fail;           /* allocation failures */
     uint32  nthings;        /* live GC things */
@@ -520,18 +476,16 @@ struct JSGCStats {
     uint32  maxcloselater;  /* max number of close hooks scheduled to run */
     uint32  nallarenas;     /* number of all allocated arenas */
     uint32  maxnallarenas;  /* maximum number of all allocated arenas */
     uint32  nchunks;        /* number of allocated chunks */
     uint32  maxnchunks;     /* maximum number of allocated chunks */
 
     JSGCArenaStats  arenaStats[FINALIZE_LIMIT];
     JSGCArenaStats  doubleArenaStats;
-
-    JSConservativeGCStats conservative;
 };
 
 extern JS_FRIEND_API(void)
 js_DumpGCStats(JSRuntime *rt, FILE *fp);
 
 #endif /* JS_GCMETER */
 
 /*
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -5526,17 +5526,17 @@ Utf8ToOneUcs4Char(const uint8 *utf8Buffe
             ucs4Char = OVERLONG_UTF8;
         } else if (ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
             ucs4Char = 0xFFFD;
         }
     }
     return ucs4Char;
 }
 
-#if defined DEBUG || defined JS_DUMP_CONSERVATIVE_GC_ROOTS
+#ifdef DEBUG
 
 JS_FRIEND_API(size_t)
 js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp,
                         JSString *str, uint32 quote)
 {
     const jschar *chars, *charsEnd;
     size_t n;
     const char *escape;
--- a/js/src/jstypes.h
+++ b/js/src/jstypes.h
@@ -199,26 +199,16 @@
 #  define JS_ALWAYS_INLINE   __forceinline
 # elif defined __GNUC__
 #  define JS_ALWAYS_INLINE   __attribute__((always_inline)) JS_INLINE
 # else
 #  define JS_ALWAYS_INLINE   JS_INLINE
 # endif
 #endif
 
-#ifndef JS_NEVER_INLINE
-# if defined _MSC_VER
-#  define JS_NEVER_INLINE __declspec(noinline)
-# elif defined __GNUC__
-#  define JS_NEVER_INLINE __attribute__((noinline))
-# else
-#  define JS_NEVER_INLINE
-# endif
-#endif
-
 #ifdef NS_STATIC_CHECKING
 /*
  * Attributes for static analysis. Functions declared with JS_REQUIRES_STACK
  * always have a valid cx->fp and can access it freely.  Other functions can
  * access cx->fp only after calling a function that "forces" the stack
  * (i.e. lazily instantiates it as needed).
  */
 # define JS_REQUIRES_STACK   __attribute__((user("JS_REQUIRES_STACK")))
--- a/js/src/tests/jstests.py
+++ b/js/src/tests/jstests.py
@@ -144,23 +144,16 @@ class ResultsSink:
     def list(self):
         for label, paths in sorted(self.groups.items()):
             if label == '': continue
 
             print label
             for path in paths:
                 print '    %s'%path
 
-        if OPTIONS.failure_file:
-              failure_file = open(OPTIONS.failure_file, 'w')
-              if not self.all_passed():
-                  for path in self.groups['REGRESSIONS']:
-                      print >> failure_file, path
-              failure_file.close()
-
         suffix = '' if self.finished else ' (partial run -- interrupted by user)'
         if self.all_passed():
             print 'PASS' + suffix
         else:
             print 'FAIL' + suffix
 
     def all_passed(self):
         return 'REGRESSIONS' not in self.groups
@@ -220,18 +213,16 @@ if __name__ == '__main__':
     op.add_option('-g', '--debug', dest='debug', action='store_true',
                   help='run test in debugger')
     op.add_option('--valgrind', dest='valgrind', action='store_true',
                   help='run tests in valgrind')
     op.add_option('--valgrind-args', dest='valgrind_args',
                   help='extra args to pass to valgrind')
     op.add_option('-c', '--check-manifest', dest='check_manifest', action='store_true',
                   help='check for test files not listed in the manifest')
-    op.add_option('--failure-file', dest='failure_file',
-                  help='write tests that have not passed to the given file')
     (OPTIONS, args) = op.parse_args()
     if len(args) < 1:
         if not OPTIONS.check_manifest:
             op.error('missing JS_SHELL argument')
         JS, args = None, []
     else:
         JS, args = args[0], args[1:]
     # Convert to an absolute path so we can run JS from a different directory.