Bug 987666 - Remove the unused dynamic root analysis. r=sfink
authorTerrence Cole <terrence@mozilla.com>
Mon, 24 Mar 2014 18:32:36 -0400
changeset 194372 fbca45e6593052971edb288cda52ce0a12ed959b
parent 194371 cbe388a78f24c244b6dc5bd1a9bfd03b751f0a51
child 194373 db91e5ecb24e6240c6d975d47b2fd5f8da7495b7
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs987666
milestone31.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 987666 - Remove the unused dynamic root analysis. r=sfink
js/public/RootingAPI.h
js/src/assembler/jit/ExecutableAllocatorPosix.cpp
js/src/builtin/Intl.cpp
js/src/builtin/TestingFunctions.cpp
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/gc/GCInternals.h
js/src/gc/Nursery.cpp
js/src/gc/RootMarking.cpp
js/src/gc/Verifier.cpp
js/src/jit/IonCaches.cpp
js/src/jit/IonTypes.h
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi.h
js/src/jsatom.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobjinlines.h
js/src/jspubtd.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/shell/js.cpp
js/src/vm/CharacterEncoding.cpp
js/src/vm/OldDebugAPI.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpStatics.h
js/src/vm/Runtime.h
js/src/vm/Shape-inl.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
js/src/vm/TypedArrayObject.cpp
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -147,21 +147,16 @@ struct PersistentRootedMarker;
 namespace JS {
 
 template <typename T> class Rooted;
 template <typename T> class PersistentRooted;
 
 /* This is exposing internal state of the GC for inlining purposes. */
 JS_FRIEND_API(bool) isGCEnabled();
 
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-extern void
-CheckStackRoots(JSContext *cx);
-#endif
-
 /*
  * JS::NullPtr acts like a nullptr pointer in contexts that require a Handle.
  *
  * Handle provides an implicit constructor for JS::NullPtr so that, given:
  *   foo(Handle<JSObject*> h);
  * callers can simply write:
  *   foo(JS::NullPtr());
  * which avoids creating a Rooted<JSObject*> just to pass nullptr.
@@ -814,25 +809,16 @@ class MOZ_STACK_CLASS Rooted : public js
     bool operator!=(const T &other) const { return ptr != other; }
     bool operator==(const T &other) const { return ptr == other; }
 
   private:
 #ifdef JSGC_TRACK_EXACT_ROOTS
     Rooted<void*> **stack, *prev;
 #endif
 
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-    /* Has the rooting analysis ever scanned this Rooted's stack location? */
-    friend void JS::CheckStackRoots(JSContext*);
-#endif
-
-#ifdef JSGC_ROOT_ANALYSIS
-    bool scanned;
-#endif
-
     /*
      * |ptr| must be the last field in Rooted because the analysis treats all
      * Rooted as Rooted<void*> during the analysis. See bug 829372.
      */
     T ptr;
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
@@ -856,91 +842,16 @@ namespace js {
 template <>
 class RootedBase<JSObject*>
 {
   public:
     template <class U>
     JS::Handle<U*> as() const;
 };
 
-/*
- * Mark a stack location as a root for the rooting analysis, without actually
- * rooting it in release builds. This should only be used for stack locations
- * of GC things that cannot be relocated by a garbage collection, and that
- * are definitely reachable via another path.
- */
-class SkipRoot
-{
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-
-    SkipRoot **stack, *prev;
-    const uint8_t *start;
-    const uint8_t *end;
-
-    template <typename CX, typename T>
-    void init(CX *cx, const T *ptr, size_t count) {
-        SkipRoot **head = &cx->skipGCRooters;
-        this->stack = head;
-        this->prev = *stack;
-        *stack = this;
-        this->start = (const uint8_t *) ptr;
-        this->end = this->start + (sizeof(T) * count);
-    }
-
-  public:
-    ~SkipRoot() {
-        MOZ_ASSERT(*stack == this);
-        *stack = prev;
-    }
-
-    SkipRoot *previous() { return prev; }
-
-    bool contains(const uint8_t *v, size_t len) {
-        return v >= start && v + len <= end;
-    }
-
-#else /* JS_DEBUG && JSGC_ROOT_ANALYSIS */
-
-    template <typename T>
-    void init(js::ContextFriendFields *cx, const T *ptr, size_t count) {}
-
-  public:
-    ~SkipRoot() {
-        // An empty destructor is needed to avoid warnings from clang about
-        // unused local variables of this type.
-    }
-
-#endif /* JS_DEBUG && JSGC_ROOT_ANALYSIS */
-
-    template <typename T>
-    SkipRoot(JSContext *cx, const T *ptr, size_t count = 1
-             MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        init(ContextFriendFields::get(cx), ptr, count);
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    template <typename T>
-    SkipRoot(ContextFriendFields *cx, const T *ptr, size_t count = 1
-             MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        init(cx, ptr, count);
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    template <typename T>
-    SkipRoot(PerThreadData *pt, const T *ptr, size_t count = 1
-             MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        init(PerThreadDataFriendFields::get(pt), ptr, count);
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
 
 /*
  * RootedGeneric<T> allows a class to instantiate its own Rooted type by
  * including the following two methods:
  *
  *    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
  *    void trace(JSTracer *trc);
  *
@@ -953,25 +864,24 @@ class SkipRoot
  * from this pointer to find a vtable containing a type-appropriate trace()
  * method.
  */
 template <typename GCType>
 class JS_PUBLIC_API(RootedGeneric)
 {
   public:
     JS::Rooted<GCType> rooter;
-    SkipRoot skip;
 
     RootedGeneric(js::ContextFriendFields *cx)
-        : rooter(cx), skip(cx, rooter.address())
+        : rooter(cx)
     {
     }
 
     RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
-        : rooter(cx, initial), skip(cx, rooter.address())
+        : rooter(cx, initial)
     {
     }
 
     virtual inline void trace(JSTracer *trc);
 
     operator const GCType&() const { return rooter.get(); }
     GCType operator->() const { return rooter.get(); }
 };
@@ -1282,27 +1192,16 @@ class PersistentRooted : private mozilla
   private:
     T ptr;
 };
 
 } /* namespace JS */
 
 namespace js {
 
-/*
- * Hook for dynamic root analysis. Checks the native stack and poisons
- * references to GC things which have not been rooted.
- */
-inline void MaybeCheckStackRoots(JSContext *cx)
-{
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-    JS::CheckStackRoots(cx);
-#endif
-}
-
 /* Base class for automatic read-only object rooting during compilation. */
 class CompilerRootNode
 {
   protected:
     CompilerRootNode(js::gc::Cell *ptr) : next(nullptr), ptr_(ptr) {}
 
   public:
     void **address() { return (void **)&ptr_; }
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -38,32 +38,25 @@ namespace JSC {
 
 size_t ExecutableAllocator::determinePageSize()
 {
     return getpagesize();
 }
 
 ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
 {
-    void* allocation;
-#ifdef JSGC_ROOT_ANALYSIS
-    do {
-#endif
-        allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
-#ifdef JSGC_ROOT_ANALYSIS
-    } while (allocation && JS::IsPoisonedPtr(allocation));
-#endif
+    void *allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
     if (allocation == MAP_FAILED)
         allocation = NULL;
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
-{ 
+{
     int result = munmap(alloc.pages, alloc.size);
     ASSERT_UNUSED(result, !result);
 }
 
 #if WTF_ENABLE_ASSEMBLER_WX_EXCLUSIVE
 void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
 {
     if (!pageSize)
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -1285,17 +1285,16 @@ NewUNumberFormat(JSContext *cx, HandleOb
     uint32_t uMinimumIntegerDigits = 1;
     uint32_t uMinimumFractionDigits = 0;
     uint32_t uMaximumFractionDigits = 3;
     int32_t uMinimumSignificantDigits = -1;
     int32_t uMaximumSignificantDigits = -1;
     bool uUseGrouping = true;
 
     // Sprinkle appropriate rooting flavor over things the GC might care about.
-    SkipRoot skip(cx, &uCurrency);
     RootedString currency(cx);
 
     // We don't need to look at numberingSystem - it can only be set via
     // the Unicode locale extension and is therefore already set on locale.
 
     if (!JSObject::getProperty(cx, internals, internals, cx->names().style, &value))
         return nullptr;
     JSAutoByteString style(cx, value.toString());
@@ -1778,17 +1777,16 @@ js::intl_patternForSkeleton(JSContext *c
 
     JSAutoByteString locale(cx, args[0].toString());
     if (!locale)
         return false;
     RootedString jsskeleton(cx, args[1].toString());
     const jschar *skeleton = JS_GetStringCharsZ(cx, jsskeleton);
     if (!skeleton)
         return false;
-    SkipRoot skip(cx, &skeleton);
     uint32_t skeletonLen = u_strlen(JSCharToUChar(skeleton));
 
     UErrorCode status = U_ZERO_ERROR;
     UDateTimePatternGenerator *gen = udatpg_open(icuLocale(locale.ptr()), &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
@@ -1840,19 +1838,16 @@ NewUDateFormat(JSContext *cx, HandleObje
         return nullptr;
 
     // UDateFormat options with default values.
     const UChar *uTimeZone = nullptr;
     uint32_t uTimeZoneLength = 0;
     const UChar *uPattern = nullptr;
     uint32_t uPatternLength = 0;
 
-    SkipRoot skipTimeZone(cx, &uTimeZone);
-    SkipRoot skipPattern(cx, &uPattern);
-
     // We don't need to look at calendar and numberingSystem - they can only be
     // set via the Unicode locale extension and are therefore already set on
     // locale.
 
     RootedId id(cx, NameToId(cx->names().timeZone));
     bool hasP;
     if (!JSObject::hasProperty(cx, internals, id, &hasP))
         return nullptr;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -38,23 +38,18 @@ static bool fuzzingSafe = false;
 
 static bool
 GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject info(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
     if (!info)
         return false;
-    RootedValue value(cx);
 
-#ifdef JSGC_ROOT_ANALYSIS
-    value = BooleanValue(true);
-#else
-    value = BooleanValue(false);
-#endif
+    RootedValue value(cx, BooleanValue(false));
     if (!JS_SetProperty(cx, info, "rooting-analysis", value))
         return false;
 
 #ifdef JSGC_USE_EXACT_ROOTING
     value = BooleanValue(true);
 #else
     value = BooleanValue(false);
 #endif
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3254,27 +3254,16 @@ MOZ_ARG_DISABLE_BOOL(gcgenerational,
 [  --disable-gcgenerational Disable generational GC],
     JSGC_GENERATIONAL= ,
     JSGC_GENERATIONAL=1 )
 if test -n "$JSGC_GENERATIONAL"; then
     AC_DEFINE(JSGC_GENERATIONAL)
 fi
 
 dnl ========================================================
-dnl = Perform moving GC stack rooting analysis
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(root-analysis,
-[  --enable-root-analysis  Enable moving GC stack root analysis],
-    JSGC_ROOT_ANALYSIS=1,
-    JSGC_ROOT_ANALYSIS= )
-if test -n "$JSGC_ROOT_ANALYSIS"; then
-    AC_DEFINE(JSGC_ROOT_ANALYSIS)
-fi
-
-dnl ========================================================
 dnl = Use exact stack rooting for GC
 dnl ========================================================
 dnl Use exact rooting by default in all shell builds. The top-level mozilla
 dnl configure.in will configure SpiderMonkey with --disable-exact-rooting as
 dnl needed on a per-platform basis.
 JSGC_USE_EXACT_ROOTING=1
 MOZ_ARG_DISABLE_BOOL(exact-rooting,
 [  --disable-exact-rooting  Enable use of conservative stack scanning for GC],
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -183,17 +183,16 @@ frontend::CompileScript(ExclusiveContext
                         HandleScript evalCaller,
                         const ReadOnlyCompileOptions &options,
                         const jschar *chars, size_t length,
                         JSString *source_ /* = nullptr */,
                         unsigned staticLevel /* = 0 */,
                         SourceCompressionTask *extraSct /* = nullptr */)
 {
     RootedString source(cx, source_);
-    SkipRoot skip(cx, &chars);
 
 #if JS_TRACE_LOGGING
         js::AutoTraceLog logger(js::TraceLogging::defaultLogger(),
                                 js::TraceLogging::PARSER_COMPILE_SCRIPT_START,
                                 js::TraceLogging::PARSER_COMPILE_SCRIPT_STOP,
                                 options);
 #endif
 
@@ -502,17 +501,16 @@ CompileFunctionBody(JSContext *cx, Mutab
         js::AutoTraceLog logger(js::TraceLogging::defaultLogger(),
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_START,
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_STOP,
                                 options);
 #endif
 
     // FIXME: make Function pass in two strings and parse them as arguments and
     // ProgramElements respectively.
-    SkipRoot skip(cx, &chars);
 
     MaybeCallSourceHandler(cx, options, chars, length);
 
     if (!CheckLength(cx, length))
         return false;
 
     RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
     if (!sourceObject)
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -273,20 +273,17 @@ TokenStream::TokenStream(ExclusiveContex
     prevLinebase(nullptr),
     userbuf(cx, base - options.column, length + options.column), // See comment below
     filename(options.filename()),
     displayURL_(nullptr),
     sourceMapURL_(nullptr),
     tokenbuf(cx),
     cx(cx),
     originPrincipals(options.originPrincipals(cx)),
-    strictModeGetter(smg),
-    tokenSkip(cx, &tokens),
-    linebaseSkip(cx, &linebase),
-    prevLinebaseSkip(cx, &prevLinebase)
+    strictModeGetter(smg)
 {
     // The caller must ensure that a reference is held on the supplied principals
     // throughout compilation.
     JS_ASSERT_IF(originPrincipals, originPrincipals->refcount > 0);
 
     // Column numbers are computed as offsets from the current line's base, so the
     // initial line's base must be included in the buffer. linebase and userbuf
     // were adjusted above, and if we are starting tokenization part way through
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -742,18 +742,17 @@ class MOZ_STACK_CLASS TokenStream
     // This is the low-level interface to the JS source code buffer.  It just
     // gets raw chars, basically.  TokenStreams functions are layered on top
     // and do some extra stuff like converting all EOL sequences to '\n',
     // tracking the line number, and setting |flags.isEOF|.  (The "raw" in "raw
     // chars" refers to the lack of EOL sequence normalization.)
     class TokenBuf {
       public:
         TokenBuf(ExclusiveContext *cx, const jschar *buf, size_t length)
-          : base_(buf), limit_(buf + length), ptr(buf),
-            skipBase(cx, &base_), skipLimit(cx, &limit_), skipPtr(cx, &ptr)
+          : base_(buf), limit_(buf + length), ptr(buf)
         { }
 
         bool hasRawChars() const {
             return ptr < limit_;
         }
 
         bool atStart() const {
             return ptr == base_;
@@ -822,19 +821,16 @@ class MOZ_STACK_CLASS TokenStream
         // Finds the next EOL, but stops once 'max' jschars have been scanned
         // (*including* the starting jschar).
         const jschar *findEOLMax(const jschar *p, size_t max);
 
       private:
         const jschar *base_;            // base of buffer
         const jschar *limit_;           // limit for quick bounds check
         const jschar *ptr;              // next char to get
-
-        // We are not yet moving strings
-        SkipRoot skipBase, skipLimit, skipPtr;
     };
 
     TokenKind getTokenInternal(Modifier modifier);
 
     int32_t getChar();
     int32_t getCharIgnoreEOL();
     void ungetChar(int32_t c);
     void ungetCharIgnoreEOL(int32_t c);
@@ -893,25 +889,16 @@ class MOZ_STACK_CLASS TokenStream
     jschar              *sourceMapURL_;     // source map's filename or null
     CharBuffer          tokenbuf;           // current token string buffer
     bool                maybeEOL[256];      // probabilistic EOL lookup table
     bool                maybeStrSpecial[256];   // speeds up string scanning
     uint8_t             isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
     ExclusiveContext    *const cx;
     JSPrincipals        *const originPrincipals;
     StrictModeGetter    *strictModeGetter;  // used to test for strict mode
-
-    // The tokens array stores pointers to JSAtoms. These are rooted by the
-    // atoms table using AutoKeepAtoms in the Parser. This SkipRoot tells the
-    // exact rooting analysis to ignore the atoms in the tokens array.
-    SkipRoot            tokenSkip;
-
-    // Bug 846011
-    SkipRoot            linebaseSkip;
-    SkipRoot            prevLinebaseSkip;
 };
 
 // Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error
 // message have const jschar* type, not const char*.
 #define JSREPORT_UC 0x100
 
 } // namespace frontend
 } // namespace js
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -91,21 +91,16 @@ class IncrementalSafety
         JS_ASSERT(reason_);
         return reason_;
     }
 };
 
 IncrementalSafety
 IsIncrementalGCSafe(JSRuntime *rt);
 
-#ifdef JSGC_ROOT_ANALYSIS
-void *
-GetAddressableGCThing(JSRuntime *rt, uintptr_t w);
-#endif
-
 #ifdef JS_GC_ZEAL
 void
 StartVerifyPreBarriers(JSRuntime *rt);
 
 void
 EndVerifyPreBarriers(JSRuntime *rt);
 
 void
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -47,29 +47,16 @@ bool
 js::Nursery::init()
 {
     JS_ASSERT(start() == 0);
 
     if (!hugeSlots.init())
         return false;
 
     void *heap = MapAlignedPages(runtime(), NurserySize, Alignment);
-#ifdef JSGC_ROOT_ANALYSIS
-    // Our poison pointers are not guaranteed to be invalid on 64-bit
-    // architectures, and often are valid. We can't just reserve the full
-    // poison range, because it might already have been taken up by something
-    // else (shared library, previous allocation). So we'll just loop and
-    // discard poison pointers until we get something valid.
-    //
-    // This leaks all of these poisoned pointers. It would be better if they
-    // were marked as uncommitted, but it's a little complicated to avoid
-    // clobbering pre-existing unrelated mappings.
-    while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize)))
-        heap = MapAlignedPages(runtime(), NurserySize, Alignment);
-#endif
     if (!heap)
         return false;
 
     JSRuntime *rt = runtime();
     rt->gcNurseryStart_ = uintptr_t(heap);
     currentStart_ = start();
     rt->gcNurseryEnd_ = chunk(LastNurseryChunk).end();
     numActiveChunks_ = 1;
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -181,31 +181,16 @@ IsAddressableGCThing(JSRuntime *rt, uint
         *thing = reinterpret_cast<void *>(addr);
     if (arenaHeader)
         *arenaHeader = aheader;
     if (thingKindPtr)
         *thingKindPtr = thingKind;
     return CGCT_VALID;
 }
 
-#ifdef JSGC_ROOT_ANALYSIS
-void *
-js::gc::GetAddressableGCThing(JSRuntime *rt, uintptr_t w)
-{
-    void *thing;
-    ArenaHeader *aheader;
-    AllocKind thingKind;
-    ConservativeGCTest status =
-        IsAddressableGCThing(rt, w, false, &thingKind, &aheader, &thing);
-    if (status != CGCT_VALID)
-        return nullptr;
-    return thing;
-}
-#endif
-
 /*
  * Returns CGCT_VALID and mark it if the w can be a  live GC thing and sets
  * thingKind accordingly. Otherwise returns the reason for rejection.
  */
 static inline ConservativeGCTest
 MarkIfGCThingWord(JSTracer *trc, uintptr_t w)
 {
     void *thing;
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -19,297 +19,16 @@
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace mozilla;
 
-#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-#  if JS_STACK_GROWTH_DIRECTION > 0
-#    error "Root analysis is only supported on a descending stack."
-#  endif
-
-template <typename T>
-bool
-CheckNonAddressThing(uintptr_t *w, Rooted<T> *rootp)
-{
-    return w >= (uintptr_t*)rootp->address() && w < (uintptr_t*)(rootp->address() + 1);
-}
-
-static MOZ_ALWAYS_INLINE bool
-CheckStackRootThing(uintptr_t *w, Rooted<void *> *rootp, ThingRootKind kind)
-{
-    if (kind == THING_ROOT_BINDINGS)
-        return CheckNonAddressThing(w, reinterpret_cast<Rooted<Bindings> *>(rootp));
-
-    if (kind == THING_ROOT_PROPERTY_DESCRIPTOR)
-        return CheckNonAddressThing(w, reinterpret_cast<Rooted<PropertyDescriptor> *>(rootp));
-
-    if (kind == THING_ROOT_VALUE)
-        return CheckNonAddressThing(w, reinterpret_cast<Rooted<Value> *>(rootp));
-
-    return rootp->address() == static_cast<void*>(w);
-}
-
-struct Rooter {
-    Rooted<void*> *rooter;
-    ThingRootKind kind;
-};
-
-static void
-CheckStackRoot(JSRuntime *rt, uintptr_t *w, Rooter *begin, Rooter *end)
-{
-    /* Mark memory as defined for valgrind, as in MarkWordConservatively. */
-#ifdef MOZ_VALGRIND
-    VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
-#endif
-
-    void *thing = GetAddressableGCThing(rt, *w);
-    if (!thing)
-        return;
-
-    /* Don't check atoms as these will never be subject to generational collection. */
-    if (rt->isAtomsZone(static_cast<Cell *>(thing)->tenuredZone()))
-        return;
-
-    /*
-     * Note that |thing| may be in a free list (InFreeList(aheader, thing)),
-     * but we can skip that check because poisoning the pointer can't hurt; the
-     * pointer still cannot be used for a non-gcthing.
-     */
-
-    for (Rooter *p = begin; p != end; p++) {
-        if (CheckStackRootThing(w, p->rooter, p->kind))
-            return;
-    }
-
-    SkipRoot *skip = TlsPerThreadData.get()->skipGCRooters;
-    while (skip) {
-        if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
-            return;
-        skip = skip->previous();
-    }
-    for (ContextIter cx(rt); !cx.done(); cx.next()) {
-        skip = cx->skipGCRooters;
-        while (skip) {
-            if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
-                return;
-            skip = skip->previous();
-        }
-    }
-
-    /*
-     * Only poison the last byte in the word. It is easy to get accidental
-     * collisions when a value that does not occupy a full word is used to
-     * overwrite a now-dead GC thing pointer. In this case we want to avoid
-     * damaging the smaller value.
-     */
-    JS::PoisonPtr(w);
-}
-
-static void
-CheckStackRootsRange(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend)
-{
-    JS_ASSERT(begin <= end);
-    for (uintptr_t *i = begin; i != end; ++i)
-        CheckStackRoot(rt, i, rbegin, rend);
-}
-
-static void
-CheckStackRootsRangeAndSkipJit(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend)
-{
-    /*
-     * Regions of the stack between Ion activiations are marked exactly through
-     * a different mechanism. We need to skip these regions when checking the
-     * stack so that we do not poison IonMonkey's things.
-     */
-    uintptr_t *i = begin;
-
-#if defined(JS_ION)
-    for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
-        uintptr_t *jitMin, *jitEnd;
-        iter.jitStackRange(jitMin, jitEnd);
-
-        uintptr_t *upto = Min(jitMin, end);
-        if (upto > i)
-            CheckStackRootsRange(rt, i, upto, rbegin, rend);
-        else
-            break;
-        i = jitEnd;
-    }
-#endif
-
-    /* The topmost Ion activiation may be beyond our prior top. */
-    if (i < end)
-        CheckStackRootsRange(rt, i, end, rbegin, rend);
-}
-
-static int
-CompareRooters(const void *vpA, const void *vpB)
-{
-    const Rooter *a = static_cast<const Rooter *>(vpA);
-    const Rooter *b = static_cast<const Rooter *>(vpB);
-    // There should be no duplicates, and we wouldn't care about their order anyway.
-    return (a->rooter < b->rooter) ? -1 : 1;
-}
-
-/*
- * In the pathological cases that dominate much of the test case runtime,
- * rooting analysis spends tons of time scanning the stack during a tight-ish
- * loop. Since statically, everything is either rooted or it isn't, these scans
- * are almost certain to be worthless. Detect these cases by checking whether
- * the addresses of the top several rooters in the stack are recurring. Note
- * that there may be more than one CheckRoots call within the loop, so we may
- * alternate between a couple of stacks rather than just repeating the same one
- * over and over, so we need more than a depth-1 memory.
- */
-static bool
-SuppressCheckRoots(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters)
-{
-    static const unsigned int NumStackMemories = 6;
-    static const size_t StackCheckDepth = 10;
-
-    static uint32_t stacks[NumStackMemories];
-    static unsigned int numMemories = 0;
-    static unsigned int oldestMemory = 0;
-
-    // Ugh. Sort the rooters. This should really be an O(n) rank selection
-    // followed by a sort. Interestingly, however, the overall scan goes a bit
-    // *faster* with this sort. Better branch prediction of the later
-    // partitioning pass, perhaps.
-    qsort(rooters.begin(), rooters.length(), sizeof(Rooter), CompareRooters);
-
-    // Forward-declare a variable so its address can be used to mark the
-    // current top of the stack.
-    unsigned int pos;
-
-    // Compute the hash of the current stack.
-    uint32_t hash = HashGeneric(&pos);
-    for (unsigned int i = 0; i < Min(StackCheckDepth, rooters.length()); i++)
-        hash = AddToHash(hash, rooters[rooters.length() - i - 1].rooter);
-
-    // Scan through the remembered stacks to find the current stack.
-    for (pos = 0; pos < numMemories; pos++) {
-        if (stacks[pos] == hash) {
-            // Skip this check. Technically, it is incorrect to not update the
-            // LRU queue position, but it'll cost us at most one extra check
-            // for every time a hot stack falls out of the window.
-            return true;
-        }
-    }
-
-    // Replace the oldest remembered stack with our current stack.
-    stacks[oldestMemory] = hash;
-    oldestMemory = (oldestMemory + 1) % NumStackMemories;
-    if (numMemories < NumStackMemories)
-        numMemories++;
-
-    return false;
-}
-
-static void
-GatherRooters(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters,
-              Rooted<void*> **thingGCRooters,
-              unsigned thingRootKind)
-{
-    Rooted<void*> *rooter = thingGCRooters[thingRootKind];
-    while (rooter) {
-        Rooter r = { rooter, ThingRootKind(thingRootKind) };
-        JS_ALWAYS_TRUE(rooters.append(r));
-        rooter = rooter->previous();
-    }
-}
-
-void
-JS::CheckStackRoots(JSContext *cx)
-{
-    JSRuntime *rt = cx->runtime();
-
-    if (rt->gcZeal_ != ZealStackRootingValue)
-        return;
-
-    // GCs can't happen when analysis/inference/compilation are active.
-    if (cx->compartment()->activeAnalysis)
-        return;
-
-    if (rt->mainThread.suppressGC)
-        return;
-
-    // Can switch to the atoms compartment during analysis.
-    if (IsAtomsCompartment(cx->compartment())) {
-        for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
-            if (c.get()->activeAnalysis)
-                return;
-        }
-    }
-
-    AutoCopyFreeListToArenas copy(rt, WithAtoms);
-
-    ConservativeGCData *cgcd = &rt->conservativeGC;
-    cgcd->recordStackTop();
-
-    JS_ASSERT(cgcd->hasStackToScan());
-    uintptr_t *stackMin, *stackEnd;
-    stackMin = cgcd->nativeStackTop + 1;
-    stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
-    JS_ASSERT(stackMin <= stackEnd);
-
-    // Gather up all of the rooters
-    js::Vector<Rooter, 0, SystemAllocPolicy> rooters;
-    for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-        for (ContextIter cx(rt); !cx.done(); cx.next()) {
-            GatherRooters(rooters, cx->thingGCRooters, i);
-        }
-
-        GatherRooters(rooters, rt->mainThread.thingGCRooters, i);
-    }
-
-    if (SuppressCheckRoots(rooters))
-        return;
-
-    // Truncate stackEnd to just after the address of the youngest
-    // already-scanned rooter on the stack, to avoid re-scanning the rest of
-    // the stack.
-    void *firstScanned = nullptr;
-    for (Rooter *p = rooters.begin(); p != rooters.end(); p++) {
-        if (p->rooter->scanned) {
-            uintptr_t *addr = reinterpret_cast<uintptr_t*>(p->rooter);
-            if (stackEnd > addr) {
-                stackEnd = addr;
-                firstScanned = p->rooter;
-            }
-        }
-    }
-
-    // Partition the stack by the already-scanned start address. Put everything
-    // that needs to be searched at the end of the vector.
-    Rooter *firstToScan = rooters.begin();
-    if (firstScanned) {
-        for (Rooter *p = rooters.begin(); p != rooters.end(); p++) {
-            if (p->rooter >= firstScanned) {
-                Swap(*firstToScan, *p);
-                ++firstToScan;
-            }
-        }
-    }
-
-    CheckStackRootsRangeAndSkipJit(rt, stackMin, stackEnd, firstToScan, rooters.end());
-    CheckStackRootsRange(rt, cgcd->registerSnapshot.words,
-                         ArrayEnd(cgcd->registerSnapshot.words),
-                         firstToScan, rooters.end());
-
-    // Mark all rooters as scanned.
-    for (Rooter *p = rooters.begin(); p != rooters.end(); p++)
-        p->rooter->scanned = true;
-}
-
-#endif /* DEBUG && JS_GC_ZEAL && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */
-
 #ifdef JS_GC_ZEAL
 
 /*
  * Write barrier verification
  *
  * The next few functions are for write barrier verification.
  *
  * The VerifyBarriers function is a shorthand. It checks if a verification phase
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1207,17 +1207,16 @@ GetPropertyIC::tryAttachNative(JSContext
     NativeGetPropCacheability type =
         CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape);
     if (type == CanAttachNone)
         return true;
 
     *emitted = true;
 
     MacroAssembler masm(cx, ion, script_, pc_);
-    SkipRoot skip(cx, &masm);
 
     RepatchStubAppender attacher(*this);
     const char *attachKind;
 
     switch (type) {
       case CanAttachReadSlot:
         GenerateReadSlot(cx, ion, masm, attacher, obj, holder,
                          shape, object(), output());
@@ -2989,17 +2988,16 @@ GetElementIC::attachGetProp(JSContext *c
         return true;
     }
 
     JS_ASSERT(idval.isString());
     JS_ASSERT(idval.toString()->length() == name->length());
 
     Label failures;
     MacroAssembler masm(cx, ion);
-    SkipRoot skip(cx, &masm);
 
     // Ensure the index is a string.
     ValueOperand val = index().reg().valueReg();
     masm.branchTestString(Assembler::NotEqual, val, &failures);
 
     Register scratch = output().valueReg().scratchReg();
     masm.unboxString(val, scratch);
 
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -240,20 +240,17 @@ IsNullOrUndefined(MIRType type)
 }
 
 #ifdef DEBUG
 // Track the pipeline of opcodes which has produced a snapshot.
 #define TRACK_SNAPSHOTS 1
 
 // Make sure registers are not modified between an instruction and
 // its OsiPoint.
-//
-// Skip this check in rooting analysis builds, which poison unrooted
-// pointers on the stack.
-#  if defined(JS_ION) && !defined(JSGC_ROOT_ANALYSIS)
+#  if defined(JS_ION)
 #    define CHECK_OSIPOINT_REGISTERS 1
 #  endif
 #endif
 
 enum {
     ArgType_General = 0x1,
     ArgType_Double  = 0x2,
     ArgType_Float32 = 0x3,
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#if !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING)
+#if !defined(JSGC_USE_EXACT_ROOTING)
 
 #include "jsobj.h"
 
 #include "jsapi-tests/tests.h"
 #include "vm/String.h"
 
 BEGIN_TEST(testConservativeGC)
 {
@@ -80,9 +80,9 @@ BEGIN_TEST(testDerivedValues)
     JS_GC(rt);
   }
 
   CHECK(!memcmp(ch, expected, sizeof(expected)));
   return true;
 }
 END_TEST(testDerivedValues)
 
-#endif /* !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING) */
+#endif /* !defined(JSGC_USE_EXACT_ROOTING) */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -137,22 +137,21 @@ class JS_PUBLIC_API(AutoGCRooter) {
 };
 
 /* AutoValueArray roots an internal fixed-size array of Values. */
 template <size_t N>
 class AutoValueArray : public AutoGCRooter
 {
     const size_t length_;
     Value elements_[N];
-    js::SkipRoot skip_;
 
   public:
     AutoValueArray(JSContext *cx
                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, VALARRAY), length_(N), skip_(cx, elements_, N)
+      : AutoGCRooter(cx, VALARRAY), length_(N)
     {
         /* Always initialize in case we GC before assignment. */
         mozilla::PodArrayZero(elements_);
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     unsigned length() const { return length_; }
     const Value *begin() const { return elements_; }
@@ -171,30 +170,27 @@ class AutoValueArray : public AutoGCRoot
 };
 
 template<class T>
 class AutoVectorRooter : protected AutoGCRooter
 {
     typedef js::Vector<T, 8> VectorImpl;
     VectorImpl vector;
 
-    /* Prevent overwriting of inline elements in vector. */
-    js::SkipRoot vectorRoot;
-
   public:
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
+      : AutoGCRooter(cx, tag), vector(cx)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
+      : AutoGCRooter(cx, tag), vector(cx)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     typedef T ElementType;
     typedef typename VectorImpl::Range Range;
 
     size_t length() const { return vector.length(); }
@@ -1034,20 +1030,16 @@ ToStringSlow(JSContext *cx, JS::HandleVa
 
 namespace JS {
 
 /* ES5 9.3 ToNumber. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, HandleValue v, double *out)
 {
     AssertArgumentsAreSane(cx, v);
-    {
-        js::SkipRoot root(cx, &v);
-        js::MaybeCheckStackRoots(cx);
-    }
 
     if (v.isNumber()) {
         *out = v.toNumber();
         return true;
     }
     return js::ToNumberSlow(cx, v, out);
 }
 
@@ -1112,77 +1104,70 @@ ToUint64Slow(JSContext *cx, JS::HandleVa
 } /* namespace js */
 
 namespace JS {
 
 MOZ_ALWAYS_INLINE bool
 ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out)
 {
     AssertArgumentsAreSane(cx, v);
-    js::MaybeCheckStackRoots(cx);
 
     if (v.isInt32()) {
         *out = uint16_t(v.toInt32());
         return true;
     }
     return js::ToUint16Slow(cx, v, out);
 }
 
 MOZ_ALWAYS_INLINE bool
 ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
 {
     AssertArgumentsAreSane(cx, v);
-    js::MaybeCheckStackRoots(cx);
 
     if (v.isInt32()) {
         *out = v.toInt32();
         return true;
     }
     return js::ToInt32Slow(cx, v, out);
 }
 
 MOZ_ALWAYS_INLINE bool
 ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out)
 {
     AssertArgumentsAreSane(cx, v);
-    js::MaybeCheckStackRoots(cx);
 
     if (v.isInt32()) {
         *out = uint32_t(v.toInt32());
         return true;
     }
     return js::ToUint32Slow(cx, v, out);
 }
 
 MOZ_ALWAYS_INLINE bool
 ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out)
 {
     AssertArgumentsAreSane(cx, v);
-    js::MaybeCheckStackRoots(cx);
 
     if (v.isInt32()) {
         *out = int64_t(v.toInt32());
         return true;
     }
-
     return js::ToInt64Slow(cx, v, out);
 }
 
 MOZ_ALWAYS_INLINE bool
 ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out)
 {
     AssertArgumentsAreSane(cx, v);
-    js::MaybeCheckStackRoots(cx);
 
     if (v.isInt32()) {
         /* Account for sign extension of negatives into the longer 64bit space. */
         *out = uint64_t(int64_t(v.toInt32()));
         return true;
     }
-
     return js::ToUint64Slow(cx, v, out);
 }
 
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, JS::Handle<JS::Value> v);
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -320,17 +320,16 @@ AtomizeAndtake(ExclusiveContext *cx, jsc
     /*
      * If a GC occurs at js_NewStringCopy then |p| will still have the correct
      * hash, allowing us to avoid rehashing it. Even though the hash is
      * unchanged, we need to re-lookup the table position because a last-ditch
      * GC will potentially free some table entries.
      */
     AtomSet& atoms = cx->atoms();
     AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
-    SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
     if (p) {
         JSAtom *atom = p->asPtr();
         p->setTagged(bool(ib));
         js_free(tbchars);
         return atom;
     }
 
     AutoCompartment ac(cx, cx->atomsCompartment());
@@ -372,17 +371,16 @@ AtomizeAndCopyChars(ExclusiveContext *cx
      * unchanged, we need to re-lookup the table position because a last-ditch
      * GC will potentially free some table entries.
      */
 
     AutoLockForExclusiveAccess lock(cx);
 
     AtomSet& atoms = cx->atoms();
     AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
-    SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
     if (p) {
         JSAtom *atom = p->asPtr();
         p->setTagged(bool(ib));
         return atom;
     }
 
     AutoCompartment ac(cx, cx->atomsCompartment());
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -227,17 +227,17 @@ js::DestroyContext(JSContext *cx, Destro
     JSRuntime *rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
 
 #ifdef JS_THREADSAFE
     if (cx->outstandingRequests != 0)
         MOZ_CRASH();
 #endif
 
-#if (defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)) && defined(DEBUG)
+#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
     for (int i = 0; i < THING_ROOT_LIMIT; ++i)
         JS_ASSERT(cx->thingGCRooters[i] == nullptr);
 #endif
 
     if (mode != DCM_NEW_FAILED) {
         if (JSContextCallback cxCallback = rt->cxCallback) {
             /*
              * JSCONTEXT_DESTROY callback is not allowed to fail and must
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -388,22 +388,16 @@ class ExclusiveContext : public ThreadSa
         return runtime_->scriptDataTable();
     }
 
     // Methods specific to any WorkerThread for the context.
     frontend::CompileError &addPendingCompileError();
     void addPendingOverRecursed();
 };
 
-inline void
-MaybeCheckStackRoots(ExclusiveContext *cx)
-{
-    MaybeCheckStackRoots(cx->maybeJSContext());
-}
-
 } /* namespace js */
 
 struct JSContext : public js::ExclusiveContext,
                    public mozilla::LinkedListElement<JSContext>
 {
     explicit JSContext(JSRuntime *rt);
     ~JSContext();
 
@@ -929,17 +923,17 @@ class AutoObjectHashSet : public AutoHas
 };
 
 /* AutoArrayRooter roots an external array of Values. */
 class AutoArrayRooter : private AutoGCRooter
 {
   public:
     AutoArrayRooter(JSContext *cx, size_t len, Value *vec
                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, len), array(vec), skip(cx, array, len)
+      : AutoGCRooter(cx, len), array(vec)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         JS_ASSERT(tag_ >= 0);
     }
 
     void changeLength(size_t newLength) {
         tag_ = ptrdiff_t(newLength);
         JS_ASSERT(tag_ >= 0);
@@ -975,17 +969,16 @@ class AutoArrayRooter : private AutoGCRo
         JS_ASSERT(i < size_t(tag_));
         return HandleValue::fromMarkedLocation(&array[i]);
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
     Value *array;
-    js::SkipRoot skip;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class AutoAssertNoException
 {
 #ifdef DEBUG
     JSContext *cx;
     bool hadException;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -34,22 +34,19 @@ using mozilla::PodArrayZero;
 
 // Required by PerThreadDataFriendFields::getMainThread()
 JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) ==
                  PerThreadDataFriendFields::RuntimeMainThreadOffset);
 
 PerThreadDataFriendFields::PerThreadDataFriendFields()
 {
     PodArrayZero(nativeStackLimit);
-#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
+#if defined(JSGC_USE_EXACT_ROOTING)
     PodArrayZero(thingGCRooters);
 #endif
-#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-    skipGCRooters = nullptr;
-#endif
 }
 
 JS_FRIEND_API(void)
 js::SetSourceHook(JSRuntime *rt, SourceHook *hook)
 {
     rt->sourceHook = hook;
 }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1584,19 +1584,16 @@ FunctionConstructor(JSContext *cx, unsig
     JSLinearString *linear = str->ensureLinear(cx);
     if (!linear)
         return false;
 
     JS::Anchor<JSString *> strAnchor(str);
     const jschar *chars = linear->chars();
     size_t length = linear->length();
 
-    /* Protect inlined chars from root analysis poisoning. */
-    SkipRoot skip(cx, &chars);
-
     /*
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
     JSObject *proto = nullptr;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -741,31 +741,16 @@ ChunkPool::expireAndFree(JSRuntime *rt, 
 {
     FreeChunkList(rt, expire(rt, releaseAll));
 }
 
 /* static */ Chunk *
 Chunk::allocate(JSRuntime *rt)
 {
     Chunk *chunk = AllocChunk(rt);
-
-#ifdef JSGC_ROOT_ANALYSIS
-    // Our poison pointers are not guaranteed to be invalid on 64-bit
-    // architectures, and often are valid. We can't just reserve the full
-    // poison range, because it might already have been taken up by something
-    // else (shared library, previous allocation). So we'll just loop and
-    // discard poison pointers until we get something valid.
-    //
-    // This leaks all of these poisoned pointers. It would be better if they
-    // were marked as uncommitted, but it's a little complicated to avoid
-    // clobbering pre-existing unrelated mappings.
-    while (IsPoisonedPtr(chunk))
-        chunk = AllocChunk(rt);
-#endif
-
     if (!chunk)
         return nullptr;
     chunk->init(rt);
     rt->gcStats.count(gcstats::STAT_NEW_CHUNK);
     return chunk;
 }
 
 /* Must be called with the GC lock taken. */
@@ -4921,20 +4906,16 @@ Collect(JSRuntime *rt, bool incremental,
         return;
 
 #if JS_TRACE_LOGGING
     AutoTraceLog logger(TraceLogging::defaultLogger(),
                         TraceLogging::GC_START,
                         TraceLogging::GC_STOP);
 #endif
 
-    ContextIter cx(rt);
-    if (!cx.done())
-        MaybeCheckStackRoots(cx);
-
 #ifdef JS_GC_ZEAL
     if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason))
         return;
 #endif
 
     JS_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
 
     AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC ||
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -432,18 +432,16 @@ CheckAllocatorState(ThreadSafeContext *c
             js::gc::RunDebugGC(ncx);
 #endif
 
         if (rt->interrupt) {
             // Invoking the interrupt callback can fail and we can't usefully
             // handle that here. Just check in case we need to collect instead.
             js::gc::GCIfNeeded(ncx);
         }
-
-        MaybeCheckStackRoots(ncx);
     }
 
     return true;
 }
 
 template <typename T>
 static inline void
 CheckIncrementalZoneState(ThreadSafeContext *cx, T *t)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3379,27 +3379,17 @@ CheckNewScriptProperties(JSContext *cx, 
         !type->addDefiniteProperties(cx, baseobj) ||
         !initializerList.append(done))
     {
         return;
     }
 
     size_t numBytes = sizeof(TypeNewScript)
                     + (initializerList.length() * sizeof(TypeNewScript::Initializer));
-    TypeNewScript *newScript;
-#ifdef JSGC_ROOT_ANALYSIS
-    // calloc can legitimately return a pointer that appears to be poisoned.
-    void *p;
-    do {
-        p = cx->calloc_(numBytes);
-    } while (IsPoisonedPtr(p));
-    newScript = (TypeNewScript *) p;
-#else
-    newScript = (TypeNewScript *) cx->calloc_(numBytes);
-#endif
+    TypeNewScript *newScript = (TypeNewScript *) cx->calloc_(numBytes);
     if (!newScript)
         return;
 
     new (newScript) TypeNewScript();
 
     type->setAddendum(newScript);
 
     newScript->fun = fun;
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1557,35 +1557,16 @@ js::NonObjectToNumberSlow(ThreadSafeCont
 
 #if defined(_MSC_VER)
 # pragma optimize("g", off)
 #endif
 
 bool
 js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out)
 {
-#ifdef DEBUG
-    /*
-     * MSVC bizarrely miscompiles this, complaining about the first brace below
-     * being unmatched (!).  The error message points at both this opening brace
-     * and at the corresponding SkipRoot constructor.  The error seems to derive
-     * from the presence guard-object macros on the SkipRoot class/constructor,
-     * which seems well in the weeds for an unmatched-brace syntax error.
-     * Otherwise the problem is inscrutable, and I haven't found a workaround.
-     * So for now just disable it when compiling with MSVC -- not ideal, but at
-     * least Windows debug shell builds complete again.
-     */
-#ifndef _MSC_VER
-    {
-        SkipRoot skip(cx, &v);
-        MaybeCheckStackRoots(cx);
-    }
-#endif
-#endif
-
     JS_ASSERT(!v.isNumber());
     goto skip_int_double;
     for (;;) {
         if (v.isNumber()) {
             *out = v.toNumber();
             return true;
         }
 
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -146,20 +146,16 @@ GetDecimalInteger(ExclusiveContext *cx, 
 
 extern bool
 StringToNumber(ThreadSafeContext *cx, JSString *str, double *result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, JS::MutableHandleValue vp)
 {
-#ifdef DEBUG
-    MaybeCheckStackRoots(cx);
-#endif
-
     if (vp.isNumber())
         return true;
     double d;
     extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp);
     if (!ToNumberSlow(cx, vp, &d))
         return false;
 
     vp.setNumber(d);
@@ -228,23 +224,16 @@ IsDefinitelyIndex(const Value &v, uint32
 
     return false;
 }
 
 /* ES5 9.4 ToInteger. */
 static inline bool
 ToInteger(JSContext *cx, HandleValue v, double *dp)
 {
-#ifdef DEBUG
-    {
-        SkipRoot skip(cx, &v);
-        MaybeCheckStackRoots(cx);
-    }
-#endif
-
     if (v.isInt32()) {
         *dp = v.toInt32();
         return true;
     }
     if (v.isDouble()) {
         *dp = v.toDouble();
     } else {
         extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -790,17 +790,17 @@ IsInternalFunctionObject(JSObject *funob
     JSFunction *fun = &funobj->as<JSFunction>();
     return fun->isLambda() && !funobj->getParent();
 }
 
 class AutoPropDescArrayRooter : private AutoGCRooter
 {
   public:
     AutoPropDescArrayRooter(JSContext *cx)
-      : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx), skip(cx, &descriptors)
+      : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
     { }
 
     PropDesc *append() {
         if (!descriptors.append(PropDesc()))
             return nullptr;
         return &descriptors.back();
     }
 
@@ -812,17 +812,16 @@ class AutoPropDescArrayRooter : private 
         JS_ASSERT(i < descriptors.length());
         return descriptors[i];
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
     PropDescArray descriptors;
-    SkipRoot skip;
 };
 
 /*
  * Make an object with the specified prototype. If parent is null, it will
  * default to the prototype's global if the prototype is non-null.
  */
 JSObject *
 NewObjectWithGivenProto(ExclusiveContext *cx, const js::Class *clasp, TaggedProto proto, JSObject *parent,
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -15,17 +15,17 @@
 #include "mozilla/NullPtr.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsprototypes.h"
 #include "jstypes.h"
 
 #include "js/TypeDecls.h"
 
-#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
+#if defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
 # define JSGC_TRACK_EXACT_ROOTS
 #endif
 
 namespace JS {
 
 class AutoIdVector;
 class CallArgs;
 
@@ -264,18 +264,16 @@ namespace js {
 enum ParallelResult { TP_SUCCESS, TP_RETRY_SEQUENTIALLY, TP_RETRY_AFTER_GC, TP_FATAL };
 
 struct ThreadSafeContext;
 struct ForkJoinContext;
 class ExclusiveContext;
 
 class Allocator;
 
-class SkipRoot;
-
 enum ThingRootKind
 {
     THING_ROOT_OBJECT,
     THING_ROOT_SHAPE,
     THING_ROOT_BASE_SHAPE,
     THING_ROOT_TYPE_OBJECT,
     THING_ROOT_STRING,
     THING_ROOT_JIT_CODE,
@@ -338,19 +336,16 @@ struct ContextFriendFields
 
   public:
     explicit ContextFriendFields(JSRuntime *rt)
       : runtime_(rt), compartment_(nullptr), zone_(nullptr), autoGCRooters(nullptr)
     {
 #ifdef JSGC_TRACK_EXACT_ROOTS
         mozilla::PodArrayZero(thingGCRooters);
 #endif
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-        skipGCRooters = nullptr;
-#endif
     }
 
     static const ContextFriendFields *get(const JSContext *cx) {
         return reinterpret_cast<const ContextFriendFields *>(cx);
     }
 
     static ContextFriendFields *get(JSContext *cx) {
         return reinterpret_cast<ContextFriendFields *>(cx);
@@ -359,28 +354,16 @@ struct ContextFriendFields
 #ifdef JSGC_TRACK_EXACT_ROOTS
     /*
      * Stack allocated GC roots for stack GC heap pointers, which may be
      * overwritten if moved during a GC.
      */
     JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
 #endif
 
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-    /*
-     * Stack allocated list of stack locations which hold non-relocatable
-     * GC heap pointers (where the target is rooted somewhere else) or integer
-     * values which may be confused for GC heap pointers. These are used to
-     * suppress false positives which occur when a rooting analysis treats the
-     * location as holding a relocatable pointer, but have no other effect on
-     * GC behavior.
-     */
-    SkipRoot *skipGCRooters;
-#endif
-
     /* Stack of thread-stack-allocated GC roots. */
     JS::AutoGCRooter   *autoGCRooters;
 
     friend JSRuntime *GetRuntime(const JSContext *cx);
     friend JSCompartment *GetContextCompartment(const JSContext *cx);
     friend JS::Zone *GetContextZone(const JSContext *cx);
 };
 
@@ -438,28 +421,16 @@ struct PerThreadDataFriendFields
 #ifdef JSGC_TRACK_EXACT_ROOTS
     /*
      * Stack allocated GC roots for stack GC heap pointers, which may be
      * overwritten if moved during a GC.
      */
     JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
 #endif
 
-#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
-    /*
-     * Stack allocated list of stack locations which hold non-relocatable
-     * GC heap pointers (where the target is rooted somewhere else) or integer
-     * values which may be confused for GC heap pointers. These are used to
-     * suppress false positives which occur when a rooting analysis treats the
-     * location as holding a relocatable pointer, but have no other effect on
-     * GC behavior.
-     */
-    SkipRoot *skipGCRooters;
-#endif
-
     /* Limit pointer for checking native stack consumption. */
     uintptr_t nativeStackLimit[StackKindCount];
 
     static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);
 
     static inline PerThreadDataFriendFields *get(js::PerThreadData *pt) {
         return reinterpret_cast<PerThreadDataFriendFields *>(pt);
     }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2112,17 +2112,16 @@ class RopeBuilder {
 };
 
 namespace {
 
 struct ReplaceData
 {
     ReplaceData(JSContext *cx)
       : str(cx), g(cx), lambda(cx), elembase(cx), repstr(cx),
-        dollarRoot(cx, &dollar), dollarEndRoot(cx, &dollarEnd),
         fig(cx, NullValue()), sb(cx)
     {}
 
     inline void setReplacementString(JSLinearString *string) {
         JS_ASSERT(string);
         lambda = nullptr;
         elembase = nullptr;
         repstr = string;
@@ -2142,18 +2141,16 @@ struct ReplaceData
 
     RootedString       str;            /* 'this' parameter object as a string */
     StringRegExpGuard  g;              /* regexp parameter object and private data */
     RootedObject       lambda;         /* replacement function object or null */
     RootedObject       elembase;       /* object for function(a){return b[a]} replace */
     Rooted<JSLinearString*> repstr; /* replacement string */
     const jschar       *dollar;        /* null or pointer to first $ in repstr */
     const jschar       *dollarEnd;     /* limit pointer for js_strchr_limit */
-    SkipRoot           dollarRoot;     /* XXX prevent dollar from being relocated */
-    SkipRoot           dollarEndRoot;  /* ditto */
     int                leftIndex;      /* left context index in str->chars */
     JSSubString        dollarStr;      /* for "$$" InterpretDollar result */
     bool               calledBack;     /* record whether callback has been called */
     FastInvokeGuard    fig;            /* used for lambda calls, also holds arguments */
     StringBuffer       sb;             /* buffer built during DoMatch */
 };
 
 } /* anonymous namespace */
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -144,23 +144,16 @@ ToStringSlow(ExclusiveContext *cx, typen
  * Convert the given value to a string.  This method includes an inline
  * fast-path for the case where the value is already a string; if the value is
  * known not to be a string, use ToStringSlow instead.
  */
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE JSString *
 ToString(JSContext *cx, JS::HandleValue v)
 {
-#ifdef DEBUG
-    if (allowGC) {
-        SkipRoot skip(cx, &v);
-        MaybeCheckStackRoots(cx);
-    }
-#endif
-
     if (v.isString())
         return v.toString();
     return ToStringSlow<allowGC>(cx, v);
 }
 
 /*
  * This function implements E-262-3 section 9.8, toString. Convert the given
  * value to a string of jschars appended to the given buffer. On error, the
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2715,18 +2715,16 @@ EvalInContext(JSContext *cx, unsigned ar
     if (!JS_ConvertArguments(cx, args, "S / o", str.address(), sobj.address()))
         return false;
 
     size_t srclen;
     const jschar *src = JS_GetStringCharsAndLength(cx, str, &srclen);
     if (!src)
         return false;
 
-    SkipRoot skip(cx, &src);
-
     bool lazy = false;
     if (srclen == 4) {
         if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') {
             lazy = true;
             srclen = 0;
         }
     }
 
--- a/js/src/vm/CharacterEncoding.cpp
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -328,19 +328,16 @@ InflateUTF8StringToBuffer(JSContext *cx,
     return true;
 }
 
 typedef bool (*CountAction)(JSContext *, const UTF8Chars, jschar *, size_t *, bool *isAsciip);
 
 static TwoByteCharsZ
 InflateUTF8StringHelper(JSContext *cx, const UTF8Chars src, CountAction countAction, size_t *outlen)
 {
-    // Malformed UTF8 chars could trigger errors and hence GC.
-    MaybeCheckStackRoots(cx);
-
     *outlen = 0;
 
     bool isAscii;
     if (!countAction(cx, src, /* dst = */ nullptr, outlen, &isAscii))
         return TwoByteCharsZ();
 
     jschar *dst = cx->pod_malloc<jschar>(*outlen + 1);  // +1 for NUL
     if (!dst)
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -1301,19 +1301,16 @@ JSAbstractFramePtr::evaluateInStackFrame
 }
 
 bool
 JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx,
                                            const jschar *chars, unsigned length,
                                            const char *filename, unsigned lineno,
                                            MutableHandleValue rval)
 {
-    /* Protect inlined chars from root analysis poisoning. */
-    SkipRoot skipChars(cx, &chars);
-
     if (!CheckDebugMode(cx))
         return false;
 
     RootedObject scope(cx, scopeChain(cx));
     Rooted<Env*> env(cx, scope);
     if (!env)
         return false;
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -515,19 +515,16 @@ RegExpShared::compileMatchOnlyIfNecessar
         return true;
     return compile(cx, true);
 }
 
 RegExpRunStatus
 RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
                       size_t *lastIndex, MatchPairs &matches)
 {
-    /* Protect inlined chars from root analysis poisoning. */
-    SkipRoot skip(cx, &chars);
-
     /* Compile the code at point-of-use. */
     if (!compileIfNecessary(cx))
         return RegExpRunStatus_Error;
 
     /* Ensure sufficient memory for output vector. */
     if (!matches.initArray(pairCount()))
         return RegExpRunStatus_Error;
 
@@ -571,19 +568,16 @@ RegExpShared::execute(JSContext *cx, con
     *lastIndex = matches[0].limit;
     return RegExpRunStatus_Success;
 }
 
 RegExpRunStatus
 RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length,
                                size_t *lastIndex, MatchPair &match)
 {
-    /* These chars may be inline in a string. See bug 846011. */
-    SkipRoot skipChars(cx, &chars);
-
     /* Compile the code at point-of-use. */
     if (!compileMatchOnlyIfNecessary(cx))
         return RegExpRunStatus_Error;
 
 #ifdef DEBUG
     const size_t origLength = length;
 #endif
     size_t start = *lastIndex;
--- a/js/src/vm/RegExpStatics.h
+++ b/js/src/vm/RegExpStatics.h
@@ -166,17 +166,17 @@ class RegExpStatics
     void getRightContext(JSSubString *out) const;
 };
 
 class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
 {
   public:
     explicit AutoRegExpStaticsBuffer(JSContext *cx
                                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer()), skip(cx, &statics)
+      : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     RegExpStatics& getStatics() { return statics; }
 
   private:
     virtual void trace(JSTracer *trc) {
@@ -190,17 +190,16 @@ class AutoRegExpStaticsBuffer : private 
         }
         if (statics.pendingInput) {
             MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics.pendingInput),
                                 "AutoRegExpStaticsBuffer pendingInput");
         }
     }
 
     RegExpStatics statics;
-    SkipRoot skip;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class PreserveRegExpStatics
 {
     RegExpStatics * const original;
     AutoRegExpStaticsBuffer buffer;
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -136,28 +136,16 @@ typedef Vector<ScriptAndCounts, 0, Syste
 struct ConservativeGCData
 {
     /*
      * The GC scans conservatively between ThreadData::nativeStackBase and
      * nativeStackTop unless the latter is nullptr.
      */
     uintptr_t           *nativeStackTop;
 
-#if defined(JSGC_ROOT_ANALYSIS) && (JS_STACK_GROWTH_DIRECTION < 0)
-    /*
-     * Record old contents of the native stack from the last time there was a
-     * scan, to reduce the overhead involved in repeatedly rescanning the
-     * native stack during root analysis. oldStackData stores words in reverse
-     * order starting at oldStackEnd.
-     */
-    uintptr_t           *oldStackMin, *oldStackEnd;
-    uintptr_t           *oldStackData;
-    size_t              oldStackCapacity; // in sizeof(uintptr_t)
-#endif
-
     union {
         jmp_buf         jmpbuf;
         uintptr_t       words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))];
     } registerSnapshot;
 
     ConservativeGCData() {
         mozilla::PodZero(this);
     }
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -183,18 +183,17 @@ EmptyShape::ensureInitialCustomShape(Exc
     EmptyShape::insertInitialShape(cx, shape, proto);
     return true;
 }
 
 inline
 AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs,
                                      PropertyOp *pgetter_, StrictPropertyOp *psetter_)
   : CustomAutoRooter(cx), attrs(attrs),
-    pgetter(pgetter_), psetter(psetter_),
-    getterRoot(cx, pgetter_), setterRoot(cx, psetter_)
+    pgetter(pgetter_), psetter(psetter_)
 {
     JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter));
     JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter));
 }
 
 inline
 AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
                                                PropertyOp *pgetter, StrictPropertyOp *psetter
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1705,17 +1705,16 @@ EmptyShape::getInitialShape(ExclusiveCon
         return nullptr;
 
     typedef InitialShapeEntry::Lookup Lookup;
     DependentAddPtr<InitialShapeSet>
         p(cx, table, Lookup(clasp, proto, parent, metadata, nfixed, objectFlags));
     if (p)
         return p->shape;
 
-    SkipRoot skip(cx, &p); /* The hash may look like a GC pointer and get poisoned. */
     Rooted<TaggedProto> protoRoot(cx, proto);
     RootedObject parentRoot(cx, parent);
     RootedObject metadataRoot(cx, metadata);
 
     StackBaseShape base(cx, clasp, parent, metadata, objectFlags);
     Rooted<UnownedBaseShape*> nbase(cx, BaseShape::getUnowned(cx, base));
     if (!nbase)
         return nullptr;
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -333,17 +333,17 @@ struct PropDesc {
                   PropDesc *wrappedDesc) const;
 };
 
 class AutoPropDescRooter : private JS::CustomAutoRooter
 {
   public:
     explicit AutoPropDescRooter(JSContext *cx
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : CustomAutoRooter(cx), skip(cx, &propDesc)
+      : CustomAutoRooter(cx)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     PropDesc& getPropDesc() { return propDesc; }
 
     void initFromPropertyDescriptor(Handle<PropertyDescriptor> desc) {
         propDesc.initFromPropertyDescriptor(desc);
@@ -383,17 +383,16 @@ class AutoPropDescRooter : private JS::C
 
     PropertyOp getter() const { return propDesc.getter(); }
     StrictPropertyOp setter() const { return propDesc.setter(); }
 
   private:
     virtual void trace(JSTracer *trc);
 
     PropDesc propDesc;
-    SkipRoot skip;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*
  * Shapes use multiplicative hashing, but specialized to
  * minimize footprint.
  */
 struct ShapeTable {
@@ -1316,17 +1315,16 @@ class AutoRooterGetterSetter
                      PropertyOp *pgetter_, StrictPropertyOp *psetter_);
 
       private:
         virtual void trace(JSTracer *trc);
 
         uint8_t attrs;
         PropertyOp *pgetter;
         StrictPropertyOp *psetter;
-        SkipRoot getterRoot, setterRoot;
     };
 
   public:
     inline AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
                                   PropertyOp *pgetter, StrictPropertyOp *psetter
                                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
 
   private:
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -915,28 +915,26 @@ class TypedArrayObjectTemplate : public 
             return copyFromTypedArray(cx, thisTypedArray, ar, offset);
 
 #ifdef DEBUG
         JSRuntime *runtime = cx->runtime();
         uint64_t gcNumber = runtime->gcNumber;
 #endif
 
         NativeType *dest = static_cast<NativeType*>(thisTypedArray->viewData()) + offset;
-        SkipRoot skipDest(cx, &dest);
 
         if (ar->is<ArrayObject>() && !ar->isIndexed() && ar->getDenseInitializedLength() >= len) {
             JS_ASSERT(ar->as<ArrayObject>().length() == len);
 
             /*
              * The only way the code below can GC is if nativeFromValue fails,
              * but in that case we return false immediately, so we do not need
              * to root |src| and |dest|.
              */
             const Value *src = ar->getDenseElements();
-            SkipRoot skipSrc(cx, &src);
             uint32_t i = 0;
             do {
                 NativeType n;
                 if (!nativeFromValue(cx, src[i], &n))
                     return false;
                 dest[i] = n;
             } while (++i < len);
             JS_ASSERT(runtime->gcNumber == gcNumber);
@@ -1589,17 +1587,16 @@ DataViewObject::write(JSContext *cx, Han
 {
     if (args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_MORE_ARGS_NEEDED, method, "1", "");
         return false;
     }
 
     uint8_t *data;
-    SkipRoot skipData(cx, &data);
     if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
         return false;
 
     NativeType value;
     if (!WebIDLCast(cx, args[1], &value))
         return false;
 
     bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]);