Backed out 2 changesets (bug 1305360) for sm(nu) failures a=backout
authorWes Kocher <wkocher@mozilla.com>
Thu, 29 Sep 2016 13:52:09 -0700
changeset 315925 282b5fdbd98b40b96bc8568294fc500aa2f06838
parent 315924 0cc441ce2c8c394767c8f3161fad0047555dbaac
child 315926 bc3137d7d869992394745738791cadfc23a927b2
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1305360
milestone52.0a1
backs outa70dda2a48b40683107eacf133e4ba27cf86dba1
eab2157634632da5e39a037c5b62d7bfa6123c7e
Backed out 2 changesets (bug 1305360) for sm(nu) failures a=backout Backed out changeset a70dda2a48b4 (bug 1305360) Backed out changeset eab215763463 (bug 1305360)
js/src/ds/MemoryProtectionExceptionHandler.cpp
js/src/ds/MemoryProtectionExceptionHandler.h
js/src/ds/PageProtectingVector.h
js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
js/src/jit/x86-shared/BaseAssembler-x86-shared.h
js/src/moz.build
js/src/vm/Initialization.cpp
deleted file mode 100644
--- a/js/src/ds/MemoryProtectionExceptionHandler.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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/. */
-
-#include "ds/MemoryProtectionExceptionHandler.h"
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Atomics.h"
-
-#if defined(XP_WIN)
-# include "jswin.h"
-#elif defined(XP_LINUX)
-# include <signal.h>
-# include <sys/types.h>
-# include <unistd.h>
-#elif defined(XP_DARWIN)
-# include <mach/mach.h>
-#endif
-
-#ifdef ANDROID
-# include <android/log.h>
-#endif
-
-#include "ds/SplayTree.h"
-
-#include "threading/LockGuard.h"
-#include "threading/Mutex.h"
-
-namespace js {
-
-/*
- * A class to store the addresses of the regions recognized as protected
- * by this exception handler. We use a splay tree to store these addresses.
- */
-class ProtectedRegionTree
-{
-    struct Region
-    {
-        uintptr_t first;
-        uintptr_t last;
-
-        Region(uintptr_t addr, size_t size) : first(addr),
-                                              last(addr + (size - 1)) {}
-
-        static int compare(const Region& A, const Region& B) {
-            if (A.last < B.first)
-                return -1;
-            if (A.first > B.last)
-                return 1;
-            return 0;
-        }
-    };
-
-    Mutex lock;
-    LifoAlloc alloc;
-    SplayTree<Region, Region> tree;
-
-  public:
-    ProtectedRegionTree() : alloc(4096),
-                            tree(&alloc) {}
-
-    ~ProtectedRegionTree() { MOZ_ASSERT(tree.empty()); }
-
-    void insert(uintptr_t addr, size_t size) {
-        MOZ_ASSERT(addr && size);
-        LockGuard<Mutex> guard(lock);
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        if (!tree.insert(Region(addr, size)))
-            oomUnsafe.crash("Failed to store allocation ID.");
-    }
-
-    void remove(uintptr_t addr) {
-        MOZ_ASSERT(addr);
-        LockGuard<Mutex> guard(lock);
-        tree.remove(Region(addr, 1));
-    }
-
-    bool isProtected(uintptr_t addr) {
-        if (!addr)
-            return false;
-        LockGuard<Mutex> guard(lock);
-        return tree.maybeLookup(Region(addr, 1));
-    }
-};
-
-static bool sExceptionHandlerInstalled = false;
-
-static ProtectedRegionTree sProtectedRegions;
-
-bool
-MemoryProtectionExceptionHandler::isDisabled()
-{
-    // There isn't currently any reason to disable it.
-    return false;
-}
-
-void
-MemoryProtectionExceptionHandler::addRegion(void* addr, size_t size)
-{
-    if (sExceptionHandlerInstalled)
-        sProtectedRegions.insert(uintptr_t(addr), size);
-}
-
-void
-MemoryProtectionExceptionHandler::removeRegion(void* addr)
-{
-    if (sExceptionHandlerInstalled)
-        sProtectedRegions.remove(uintptr_t(addr));
-}
-
-/* -------------------------------------------------------------------------- */
-
-/*
- * This helper function attempts to replicate the functionality of
- * mozilla::MOZ_ReportCrash() in an async-signal-safe way.
- */
-static MOZ_COLD MOZ_ALWAYS_INLINE void
-ReportCrashIfDebug(const char* aStr)
-    MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
-{
-#ifdef DEBUG
-# if defined(XP_WIN)
-    DWORD bytesWritten;
-    BOOL ret = WriteFile(GetStdHandle(STD_ERROR_HANDLE), aStr,
-                         strlen(aStr) + 1, &bytesWritten, nullptr);
-    ::__debugbreak();
-# elif defined(ANDROID)
-    int ret = __android_log_write(ANDROID_LOG_FATAL, "MOZ_CRASH", aStr);
-# else
-    ssize_t ret = write(STDERR_FILENO, aStr, strlen(aStr) + 1);
-# endif
-    (void)ret; // Ignore failures; we're already crashing anyway.
-#endif
-}
-
-/* -------------------------------------------------------------------------- */
-
-#if defined(XP_WIN)
-
-static void* sVectoredExceptionHandler = nullptr;
-
-/*
- * We can only handle one exception. To guard against races and reentrancy,
- * we set this value the first time we enter the exception handler and never
- * touch it again.
- */
-static mozilla::Atomic<bool> sHandlingException(false);
-
-static long __stdcall
-VectoredExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
-{
-    EXCEPTION_RECORD* ExceptionRecord = ExceptionInfo->ExceptionRecord;
-
-    // We only handle one kind of exception; ignore all others.
-    if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
-        // Make absolutely sure we can only get here once.
-        if (sHandlingException.compareExchange(false, true)) {
-            // Restore the previous handler. We're going to forward to it
-            // anyway, and if we crash while doing so we don't want to hang.
-            MOZ_ALWAYS_TRUE(RemoveVectoredExceptionHandler(sVectoredExceptionHandler));
-
-            // Get the address that the offending code tried to access.
-            uintptr_t address = uintptr_t(ExceptionRecord->ExceptionInformation[1]);
-
-            // If the faulting address is in one of our protected regions, we
-            // want to annotate the crash to make it stand out from the crowd.
-            if (sProtectedRegions.isProtected(address)) {
-                ReportCrashIfDebug("Hit MOZ_CRASH(Tried to access a protected region!)\n");
-                MOZ_CRASH_ANNOTATE("Tried to access a protected region!");
-            }
-        }
-    }
-
-    // Forward to the previous handler which may be a debugger,
-    // the crash reporter or something else entirely.
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-
-bool
-MemoryProtectionExceptionHandler::install()
-{
-    MOZ_ASSERT(!sExceptionHandlerInstalled);
-
-    // If the exception handler is disabled, report success anyway.
-    if (MemoryProtectionExceptionHandler::isDisabled())
-        return true;
-
-    // Install our new exception handler.
-    sVectoredExceptionHandler = AddVectoredExceptionHandler(/* FirstHandler = */ true,
-                                                            VectoredExceptionHandler);
-
-    sExceptionHandlerInstalled = sVectoredExceptionHandler != nullptr;
-    return sExceptionHandlerInstalled;
-}
-
-void
-MemoryProtectionExceptionHandler::uninstall()
-{
-    if (sExceptionHandlerInstalled) {
-        MOZ_ASSERT(!sHandlingException);
-
-        // Restore the previous exception handler.
-        MOZ_ALWAYS_TRUE(RemoveVectoredExceptionHandler(sVectoredExceptionHandler));
-
-        sExceptionHandlerInstalled = false;
-    }
-}
-
-#elif defined(XP_LINUX)
-
-static struct sigaction sPrevSEGVHandler = {};
-
-/*
- * We can only handle one exception. To guard against races and reentrancy,
- * we set this value the first time we enter the exception handler and never
- * touch it again.
- */
-static mozilla::Atomic<bool> sHandlingException(false);
-
-static void
-UnixExceptionHandler(int signum, siginfo_t* info, void* context)
-{
-    // Make absolutely sure we can only get here once.
-    if (sHandlingException.compareExchange(false, true)) {
-        // Restore the previous handler. We're going to forward to it
-        // anyway, and if we crash while doing so we don't want to hang.
-        MOZ_ALWAYS_FALSE(sigaction(SIGSEGV, &sPrevSEGVHandler, nullptr));
-
-        MOZ_ASSERT(signum == SIGSEGV && info->si_signo == SIGSEGV);
-
-        if (info->si_code == SEGV_ACCERR) {
-            // Get the address that the offending code tried to access.
-            uintptr_t address = uintptr_t(info->si_addr);
-
-            // If the faulting address is in one of our protected regions, we
-            // want to annotate the crash to make it stand out from the crowd.
-            if (sProtectedRegions.isProtected(address)) {
-                ReportCrashIfDebug("Hit MOZ_CRASH(Tried to access a protected region!)\n");
-                MOZ_CRASH_ANNOTATE("Tried to access a protected region!");
-            }
-        }
-    }
-
-    // Forward to the previous handler which may be a debugger,
-    // the crash reporter or something else entirely.
-    if (sPrevSEGVHandler.sa_flags & SA_SIGINFO)
-        sPrevSEGVHandler.sa_sigaction(signum, info, context);
-    else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN)
-        raise(signum);
-    else
-        sPrevSEGVHandler.sa_handler(signum);
-}
-
-bool
-MemoryProtectionExceptionHandler::install()
-{
-    MOZ_ASSERT(!sExceptionHandlerInstalled);
-
-    // If the exception handler is disabled, report success anyway.
-    if (MemoryProtectionExceptionHandler::isDisabled())
-        return true;
-
-    // Install our new exception handler and save the previous one.
-    struct sigaction faultHandler = {};
-    faultHandler.sa_flags = SA_SIGINFO;
-    faultHandler.sa_sigaction = UnixExceptionHandler;
-    sigemptyset(&faultHandler.sa_mask);
-    sExceptionHandlerInstalled = !sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler);
-
-    return sExceptionHandlerInstalled;
-}
-
-void
-MemoryProtectionExceptionHandler::uninstall()
-{
-    if (sExceptionHandlerInstalled) {
-        MOZ_ASSERT(!sHandlingException);
-
-        // Restore the previous exception handler.
-        MOZ_ALWAYS_FALSE(sigaction(SIGSEGV, &sPrevSEGVHandler, nullptr));
-
-        sExceptionHandlerInstalled = false;
-    }
-}
-
-#elif defined(XP_DARWIN)
-
-/*
- * The fact that we need to be able to forward to other exception handlers
- * makes this code much more complicated. The forwarding logic and the
- * structures required to make it work are heavily based on the code at
- * www.ravenbrook.com/project/mps/prototype/2013-06-24/machtest/machtest/main.c
- */
-
-/* -------------------------------------------------------------------------- */
-/*                Begin Mach definitions and helper functions                 */
-/* -------------------------------------------------------------------------- */
-
-/*
- * These are the message IDs associated with each exception type.
- * We'll be using sIDRequest64, but we need the others for forwarding.
- */
-static const mach_msg_id_t sIDRequest32 = 2401;
-static const mach_msg_id_t sIDRequestState32 = 2402;
-static const mach_msg_id_t sIDRequestStateIdentity32 = 2403;
-
-static const mach_msg_id_t sIDRequest64 = 2405;
-static const mach_msg_id_t sIDRequestState64 = 2406;
-static const mach_msg_id_t sIDRequestStateIdentity64 = 2407;
-
-/*
- * Each message ID has an associated Mach message structure.
- * We use the preprocessor to make defining them a little less arduous.
- */
-# define REQUEST_HEADER_FIELDS\
-    mach_msg_header_t header;
-
-# define REQUEST_IDENTITY_FIELDS\
-    mach_msg_body_t msgh_body;\
-    mach_msg_port_descriptor_t thread;\
-    mach_msg_port_descriptor_t task;
-
-# define REQUEST_GENERAL_FIELDS(bits)\
-    NDR_record_t NDR;\
-    exception_type_t exception;\
-    mach_msg_type_number_t code_count;\
-    int##bits##_t code[2];
-
-# define REQUEST_STATE_FIELDS\
-    int flavor;\
-    mach_msg_type_number_t old_state_count;\
-    natural_t old_state[THREAD_STATE_MAX];
-
-# define REQUEST_TRAILER_FIELDS\
-    mach_msg_trailer_t trailer;
-
-# define EXCEPTION_REQUEST(bits)\
-    struct ExceptionRequest##bits\
-    {\
-        REQUEST_HEADER_FIELDS\
-        REQUEST_IDENTITY_FIELDS\
-        REQUEST_GENERAL_FIELDS(bits)\
-        REQUEST_TRAILER_FIELDS\
-    };\
-
-# define EXCEPTION_REQUEST_STATE(bits)\
-    struct ExceptionRequestState##bits\
-    {\
-        REQUEST_HEADER_FIELDS\
-        REQUEST_GENERAL_FIELDS(bits)\
-        REQUEST_STATE_FIELDS\
-        REQUEST_TRAILER_FIELDS\
-    };\
-
-# define EXCEPTION_REQUEST_STATE_IDENTITY(bits)\
-    struct ExceptionRequestStateIdentity##bits\
-    {\
-        REQUEST_HEADER_FIELDS\
-        REQUEST_IDENTITY_FIELDS\
-        REQUEST_GENERAL_FIELDS(bits)\
-        REQUEST_STATE_FIELDS\
-        REQUEST_TRAILER_FIELDS\
-    };\
-
-/* This is needed because not all fields are naturally aligned on 64-bit. */
-# ifdef  __MigPackStructs
-#  pragma pack(4)
-# endif
-
-EXCEPTION_REQUEST(32)
-EXCEPTION_REQUEST(64)
-EXCEPTION_REQUEST_STATE(32)
-EXCEPTION_REQUEST_STATE(64)
-EXCEPTION_REQUEST_STATE_IDENTITY(32)
-EXCEPTION_REQUEST_STATE_IDENTITY(64)
-
-/* We use this as a common base when forwarding to the previous handler. */
-union ExceptionRequestUnion {
-    mach_msg_header_t header;
-    ExceptionRequest32 r32;
-    ExceptionRequest64 r64;
-    ExceptionRequestState32 rs32;
-    ExceptionRequestState64 rs64;
-    ExceptionRequestStateIdentity32 rsi32;
-    ExceptionRequestStateIdentity64 rsi64;
-};
-
-/* This isn't really a full Mach message, but it's all we need to send. */
-struct ExceptionReply
-{
-    mach_msg_header_t header;
-    NDR_record_t NDR;
-    kern_return_t RetCode;
-};
-
-# ifdef  __MigPackStructs
-#  pragma pack()
-# endif
-
-# undef EXCEPTION_REQUEST_STATE_IDENTITY
-# undef EXCEPTION_REQUEST_STATE
-# undef EXCEPTION_REQUEST
-# undef REQUEST_STATE_FIELDS
-# undef REQUEST_GENERAL_FIELDS
-# undef REQUEST_IDENTITY_FIELDS
-# undef REQUEST_HEADER_FIELDS
-
-/*
- * The exception handler we're forwarding to may not have the same behavior
- * or thread state flavor as what we're using. These macros help populate
- * the fields of the message we're about to send to the previous handler.
- */
-# define COPY_REQUEST_COMMON(bits, id)\
-    dst.header = src.header;\
-    dst.header.msgh_id = id;\
-    dst.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(dst) - sizeof(dst.trailer));\
-    dst.NDR = src.NDR;\
-    dst.exception = src.exception;\
-    dst.code_count = src.code_count;\
-    dst.code[0] = int##bits##_t(src.code[0]);\
-    dst.code[1] = int##bits##_t(src.code[1]);
-
-# define COPY_REQUEST_IDENTITY\
-    dst.msgh_body = src.msgh_body;\
-    dst.thread = src.thread;\
-    dst.task = src.task;
-
-# define COPY_REQUEST_STATE(flavor, stateCount, state)\
-    mach_msg_size_t stateSize = stateCount * sizeof(natural_t);\
-    dst.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(dst) - sizeof(dst.trailer) -\
-                                                        sizeof(dst.old_state) + stateSize);\
-    dst.flavor = flavor;\
-    dst.old_state_count = stateCount;\
-    memcpy(dst.old_state, state, stateSize);
-
-# define COPY_EXCEPTION_REQUEST(bits)\
-    static void\
-    CopyExceptionRequest##bits(ExceptionRequest64& src,\
-                               ExceptionRequest##bits& dst)\
-    {\
-        COPY_REQUEST_COMMON(bits, sIDRequest##bits)\
-        COPY_REQUEST_IDENTITY\
-    }
-
-# define COPY_EXCEPTION_REQUEST_STATE(bits)\
-    static void\
-    CopyExceptionRequestState##bits(ExceptionRequest64& src,\
-                                    ExceptionRequestState##bits& dst,\
-                                    thread_state_flavor_t flavor,\
-                                    mach_msg_type_number_t stateCount,\
-                                    thread_state_t state)\
-    {\
-        COPY_REQUEST_COMMON(bits, sIDRequestState##bits)\
-        COPY_REQUEST_STATE(flavor, stateCount, state)\
-    }
-
-# define COPY_EXCEPTION_REQUEST_STATE_IDENTITY(bits)\
-    static void\
-    CopyExceptionRequestStateIdentity##bits(ExceptionRequest64& src,\
-                                            ExceptionRequestStateIdentity##bits& dst,\
-                                            thread_state_flavor_t flavor,\
-                                            mach_msg_type_number_t stateCount,\
-                                            thread_state_t state)\
-    {\
-        COPY_REQUEST_COMMON(bits, sIDRequestStateIdentity##bits)\
-        COPY_REQUEST_IDENTITY\
-        COPY_REQUEST_STATE(flavor, stateCount, state)\
-    }
-
-COPY_EXCEPTION_REQUEST(32)
-COPY_EXCEPTION_REQUEST_STATE(32)
-COPY_EXCEPTION_REQUEST_STATE_IDENTITY(32)
-COPY_EXCEPTION_REQUEST(64)
-COPY_EXCEPTION_REQUEST_STATE(64)
-COPY_EXCEPTION_REQUEST_STATE_IDENTITY(64)
-
-# undef COPY_EXCEPTION_REQUEST_STATE_IDENTITY
-# undef COPY_EXCEPTION_REQUEST_STATE
-# undef COPY_EXCEPTION_REQUEST
-# undef COPY_REQUEST_STATE
-# undef COPY_REQUEST_IDENTITY
-# undef COPY_REQUEST_COMMON
-
-/* -------------------------------------------------------------------------- */
-/*                 End Mach definitions and helper functions                  */
-/* -------------------------------------------------------------------------- */
-
-/* Every Mach exception handler is parameterized by these four properties. */
-struct MachExceptionParameters
-{
-    exception_mask_t mask;
-    mach_port_t port;
-    exception_behavior_t behavior;
-    thread_state_flavor_t flavor;
-};
-
-struct ExceptionHandlerState
-{
-    MachExceptionParameters current;
-    MachExceptionParameters previous;
-
-    /* Each Mach exception handler runs in its own thread. */
-    Thread handlerThread;
-};
-
-/* This choice of ID is arbitrary, but must not match our exception ID. */
-static const mach_msg_id_t sIDQuit = 42;
-
-static ExceptionHandlerState sMachExceptionState;
-
-/*
- * The meat of our exception handler. This thread waits for an exception
- * message, annotates the exception if needed, then forwards it to the
- * previously installed handler (which will likely terminate the process).
- */
-static void
-MachExceptionHandler()
-{
-    kern_return_t ret;
-    MachExceptionParameters& current = sMachExceptionState.current;
-    MachExceptionParameters& previous = sMachExceptionState.previous;
-
-    // We use the simplest kind of 64-bit exception message here.
-    ExceptionRequest64 request = {};
-    request.header.msgh_local_port = current.port;
-    request.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(request));
-    ret = mach_msg(&request.header, MACH_RCV_MSG, 0, request.header.msgh_size,
-                   current.port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-
-    // Restore the previous handler. We're going to forward to it
-    // anyway, and if we crash while doing so we don't want to hang.
-    task_set_exception_ports(mach_task_self(), previous.mask, previous.port,
-                             previous.behavior, previous.flavor);
-
-    // If we failed even receiving the message, just give up.
-    if (ret != MACH_MSG_SUCCESS)
-        MOZ_CRASH("MachExceptionHandler: mach_msg failed to receive a message!");
-
-    // Terminate the thread if we're shutting down.
-    if (request.header.msgh_id == sIDQuit)
-        return;
-
-    // The only other valid message ID is the one associated with the
-    // EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES behavior we chose.
-    if (request.header.msgh_id != sIDRequest64)
-        MOZ_CRASH("MachExceptionHandler: Unexpected Message ID!");
-
-    // Make sure we can understand the exception we received.
-    if (request.exception != EXC_BAD_ACCESS || request.code_count != 2)
-        MOZ_CRASH("MachExceptionHandler: Unexpected exception type!");
-
-    // Get the address that the offending code tried to access.
-    uintptr_t address = uintptr_t(request.code[1]);
-
-    // If the faulting address is inside one of our protected regions, we
-    // want to annotate the crash to make it stand out from the crowd.
-    if (sProtectedRegions.isProtected(address)) {
-        ReportCrashIfDebug("Hit MOZ_CRASH(Tried to access a protected region!)\n");
-        MOZ_CRASH_ANNOTATE("Tried to access a protected region!");
-    }
-
-    // Forward to the previous handler which may be a debugger, the unix
-    // signal handler, the crash reporter or something else entirely.
-    if (previous.port != MACH_PORT_NULL) {
-        mach_msg_type_number_t stateCount;
-        thread_state_data_t state;
-        if ((uint32_t(previous.behavior) & ~MACH_EXCEPTION_CODES) != EXCEPTION_DEFAULT) {
-            // If the previous handler requested thread state, get it here.
-            stateCount = THREAD_STATE_MAX;
-            ret = thread_get_state(request.thread.name, previous.flavor, state, &stateCount);
-            if (ret != KERN_SUCCESS)
-                MOZ_CRASH("MachExceptionHandler: Could not get the thread state to forward!");
-        }
-
-        // Depending on the behavior of the previous handler, the forwarded
-        // exception message will have a different set of fields.
-        // Of particular note is that exception handlers that lack
-        // MACH_EXCEPTION_CODES will get 32-bit fields even on 64-bit
-        // systems. It appears that OSX simply truncates these fields.
-        ExceptionRequestUnion forward;
-        switch (uint32_t(previous.behavior)) {
-          case EXCEPTION_DEFAULT:
-             CopyExceptionRequest32(request, forward.r32);
-             break;
-          case EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES:
-             CopyExceptionRequest64(request, forward.r64);
-             break;
-          case EXCEPTION_STATE:
-             CopyExceptionRequestState32(request, forward.rs32,
-                                         previous.flavor, stateCount, state);
-             break;
-          case EXCEPTION_STATE | MACH_EXCEPTION_CODES:
-             CopyExceptionRequestState64(request, forward.rs64,
-                                         previous.flavor, stateCount, state);
-             break;
-          case EXCEPTION_STATE_IDENTITY:
-             CopyExceptionRequestStateIdentity32(request, forward.rsi32,
-                                                 previous.flavor, stateCount, state);
-             break;
-          case EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES:
-             CopyExceptionRequestStateIdentity64(request, forward.rsi64,
-                                                 previous.flavor, stateCount, state);
-             break;
-          default:
-             MOZ_CRASH("MachExceptionHandler: Unknown previous handler behavior!");
-        }
-
-        // Forward the generated message to the old port. The local and remote
-        // port fields *and their rights* are swapped on arrival, so we need to
-        // swap them back first.
-        forward.header.msgh_bits = (request.header.msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
-            MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(request.header.msgh_bits),
-                           MACH_MSGH_BITS_REMOTE(request.header.msgh_bits));
-        forward.header.msgh_local_port = forward.header.msgh_remote_port;
-        forward.header.msgh_remote_port = previous.port;
-        ret = mach_msg(&forward.header, MACH_SEND_MSG, forward.header.msgh_size, 0,
-                       MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-        if (ret != MACH_MSG_SUCCESS)
-            MOZ_CRASH("MachExceptionHandler: Failed to forward to the previous handler!");
-    } else {
-        // There was no previous task-level exception handler, so defer to the
-        // host level one instead. We set the return code to KERN_FAILURE to
-        // indicate that we did not handle the exception.
-        // The reply message ID is always the request ID + 100.
-        ExceptionReply reply = {};
-        reply.header.msgh_bits =
-            MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.header.msgh_bits), 0);
-        reply.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(reply));
-        reply.header.msgh_remote_port = request.header.msgh_remote_port;
-        reply.header.msgh_local_port = MACH_PORT_NULL;
-        reply.header.msgh_id = request.header.msgh_id + 100;
-        reply.NDR = request.NDR;
-        reply.RetCode = KERN_FAILURE;
-        ret = mach_msg(&reply.header, MACH_SEND_MSG, reply.header.msgh_size, 0,
-                       MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-        if (ret != MACH_MSG_SUCCESS)
-            MOZ_CRASH("MachExceptionHandler: Failed to forward to the host level!");
-    }
-}
-
-static void
-TerminateMachExceptionHandlerThread()
-{
-    // Send a simple quit message to the exception handler thread.
-    mach_msg_header_t msg;
-    msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
-    msg.msgh_size = static_cast<mach_msg_size_t>(sizeof(msg));
-    msg.msgh_remote_port = sMachExceptionState.current.port;
-    msg.msgh_local_port = MACH_PORT_NULL;
-    msg.msgh_reserved = 0;
-    msg.msgh_id = sIDQuit;
-    kern_return_t ret = mach_msg(&msg, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
-                                 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-
-    if (ret == MACH_MSG_SUCCESS)
-        sMachExceptionState.handlerThread.join();
-    else
-        MOZ_CRASH("MachExceptionHandler: Handler thread failed to terminate!");
-}
-
-bool
-MemoryProtectionExceptionHandler::install()
-{
-    MOZ_ASSERT(!sExceptionHandlerInstalled);
-
-    // If the exception handler is disabled, report success anyway.
-    if (MemoryProtectionExceptionHandler::isDisabled())
-        return true;
-
-    kern_return_t ret;
-    mach_port_t task = mach_task_self();
-
-    // Allocate a new exception port with receive rights.
-    sMachExceptionState.current = {};
-    MachExceptionParameters& current = sMachExceptionState.current;
-    ret = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &current.port);
-    if (ret != KERN_SUCCESS)
-        return false;
-
-    // Give the new port send rights as well.
-    ret = mach_port_insert_right(task, current.port, current.port, MACH_MSG_TYPE_MAKE_SEND);
-    if (ret != KERN_SUCCESS) {
-        mach_port_deallocate(task, current.port);
-        current = {};
-        return false;
-    }
-
-    // Start the thread that will receive the messages from our exception port.
-    if (!sMachExceptionState.handlerThread.init(MachExceptionHandler)) {
-        mach_port_deallocate(task, current.port);
-        current = {};
-        return false;
-    }
-
-    // Set the other properties of our new exception handler.
-    current.mask = EXC_MASK_BAD_ACCESS;
-    current.behavior = exception_behavior_t(EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES);
-    current.flavor = THREAD_STATE_NONE;
-
-    // Tell the task to use our exception handler, and save the previous one.
-    sMachExceptionState.previous = {};
-    MachExceptionParameters& previous = sMachExceptionState.previous;
-    mach_msg_type_number_t previousCount = 1;
-    ret = task_swap_exception_ports(task, current.mask, current.port, current.behavior,
-                                    current.flavor, &previous.mask, &previousCount,
-                                    &previous.port, &previous.behavior, &previous.flavor);
-    if (ret != KERN_SUCCESS) {
-        TerminateMachExceptionHandlerThread();
-        mach_port_deallocate(task, current.port);
-        previous = {};
-        current = {};
-        return false;
-    }
-
-    // We should have info on the previous exception handler, even if it's null.
-    MOZ_ASSERT(previousCount == 1);
-
-    sExceptionHandlerInstalled = true;
-    return sExceptionHandlerInstalled;
-}
-
-void
-MemoryProtectionExceptionHandler::uninstall()
-{
-    if (sExceptionHandlerInstalled) {
-        mach_port_t task = mach_task_self();
-
-        // Restore the previous exception handler.
-        MachExceptionParameters& previous = sMachExceptionState.previous;
-        task_set_exception_ports(task, previous.mask, previous.port,
-                                 previous.behavior, previous.flavor);
-
-        TerminateMachExceptionHandlerThread();
-
-        // Release the Mach IPC port we used.
-        mach_port_deallocate(task, sMachExceptionState.current.port);
-
-        sMachExceptionState.current = {};
-        sMachExceptionState.previous = {};
-
-        sExceptionHandlerInstalled = false;
-    }
-}
-
-#else
-
-#error "This platform is not supported!"
-
-#endif
-
-} /* namespace js */
deleted file mode 100644
--- a/js/src/ds/MemoryProtectionExceptionHandler.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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/. */
-
-#ifndef ds_MemoryProtectionExceptionHandler_h
-#define ds_MemoryProtectionExceptionHandler_h
-
-namespace js {
-
-/*
- * This structure allows you to annotate crashes resulting from unauthorized
- * access to protected memory in regions of interest, to make them stand out
- * from other heap corruption crashes.
- */
-
-struct MemoryProtectionExceptionHandler
-{
-    /* Installs the exception handler; called early during initialization. */
-    static bool install();
-
-    /* If the exception handler is disabled, it won't be installed. */
-    static bool isDisabled();
-
-    /*
-     * Marks a region of memory as important; if something tries to access this
-     * region in an unauthorized way (e.g. writing to read-only memory),
-     * the resulting crash will be annotated to stand out from other random
-     * heap corruption.
-     */
-    static void addRegion(void* addr, size_t size);
-
-    /* Removes a previously added region. */
-    static void removeRegion(void* addr);
-
-    /* Uninstalls the exception handler; called late during shutdown. */
-    static void uninstall();
-};
-
-} /* namespace js */
-
-#endif /* ds_MemoryProtectionExceptionHandler_h */
--- a/js/src/ds/PageProtectingVector.h
+++ b/js/src/ds/PageProtectingVector.h
@@ -4,17 +4,16 @@
  * 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/. */
 
 #ifndef ds_PageProtectingVector_h
 #define ds_PageProtectingVector_h
 
 #include "mozilla/Vector.h"
 
-#include "ds/MemoryProtectionExceptionHandler.h"
 #include "gc/Memory.h"
 
 namespace js {
 
 /*
  * PageProtectingVector is a vector that can only grow or be cleared, and marks
  * all of its fully used memory pages as read-only. It can be used to detect
  * heap corruption in important buffers, since anything that tries to write
@@ -54,32 +53,23 @@ class PageProtectingVector final
      * the whole page). As a result, if |unprotectedBytes >= pageSize|, we know
      * we can protect at least one more page, and |unprotectedBytes & ~pageMask|
      * is always the number of additional bytes we can protect. Put another way,
      * |offsetToPage + protectedBytes + unprotectedBytes == vector.length()|
      * always holds, and if |protectedBytes != 0| then |unprotectedBytes >= 0|.
      */
     intptr_t unprotectedBytes;
 
-    /*
-     * The size in bytes that a buffer needs to be before its pages will be
-     * protected. This is intended to reduce churn for small vectors while
-     * still offering protection when they grow large enough.
-     */
-    size_t protectionLowerBound;
-
     bool protectionEnabled;
     bool regionUnprotected;
 
     void updateOffsetToPage() {
         unprotectedBytes += offsetToPage;
         offsetToPage = (pageSize - (uintptr_t(vector.begin()) & pageMask)) & pageMask;
         unprotectedBytes -= offsetToPage;
-        protectionEnabled = vector.capacity() >= protectionLowerBound &&
-                            vector.capacity() >= pageSize + offsetToPage;
     }
 
     void protect() {
         MOZ_ASSERT(!regionUnprotected);
         if (protectionEnabled && unprotectedBytes >= intptr_t(pageSize)) {
             size_t toProtect = size_t(unprotectedBytes) & ~pageMask;
             uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage + protectedBytes;
             gc::MakePagesReadOnly(reinterpret_cast<void*>(addr), toProtect);
@@ -96,27 +86,19 @@ class PageProtectingVector final
             gc::UnprotectPages(reinterpret_cast<void*>(addr), protectedBytes);
             unprotectedBytes += protectedBytes;
             protectedBytes = 0;
         }
     }
 
     void protectNewBuffer() {
         updateOffsetToPage();
-        if (protectionEnabled)
-            MemoryProtectionExceptionHandler::addRegion(vector.begin(), vector.capacity());
         protect();
     }
 
-    void unprotectOldBuffer() {
-        if (protectionEnabled)
-            MemoryProtectionExceptionHandler::removeRegion(vector.begin());
-        unprotect();
-    }
-
     bool anyProtected(size_t first, size_t last) {
         return last >= offsetToPage && first < offsetToPage + protectedBytes;
     }
 
     void setContainingRegion(size_t first, size_t last, uintptr_t* addr, size_t* size) {
         if (first < offsetToPage)
             first = offsetToPage;
         if (last > offsetToPage + protectedBytes - 1)
@@ -138,17 +120,17 @@ class PageProtectingVector final
     {
         PageProtectingVector* vector;
 
       public:
         AutoUnprotect() : vector(nullptr) {};
 
         void emplace(PageProtectingVector* holder) {
             vector = holder;
-            vector->unprotectOldBuffer();
+            vector->unprotect();
         }
 
         explicit AutoUnprotect(PageProtectingVector* holder) {
             emplace(holder);
         }
 
         ~AutoUnprotect() {
             if (vector)
@@ -159,32 +141,33 @@ class PageProtectingVector final
   public:
     explicit PageProtectingVector(AllocPolicy policy = AllocPolicy())
       : vector(policy),
         pageSize(gc::SystemPageSize()),
         pageMask(pageSize - 1),
         offsetToPage(0),
         protectedBytes(0),
         unprotectedBytes(0),
-        protectionLowerBound(0),
         protectionEnabled(false),
-        regionUnprotected(false) { protectNewBuffer(); }
+        regionUnprotected(false) { updateOffsetToPage(); }
 
-    ~PageProtectingVector() { unprotectOldBuffer(); }
+    ~PageProtectingVector() { unprotect(); }
 
-    /*
-     * Sets the lower bound on the size, in bytes, that this vector's underlying
-     * capacity has to be before its used pages will be protected.
-     */
-    void setLowerBoundForProtection(size_t bytes) {
-        if (protectionLowerBound != bytes) {
-            unprotectOldBuffer();
-            protectionLowerBound = bytes;
-            protectNewBuffer();
-        }
+    /* Enable protection for the entire buffer. */
+    void enableProtection() {
+        MOZ_ASSERT(!protectionEnabled);
+        protectionEnabled = true;
+        protectNewBuffer();
+    }
+
+    /* Disable protection for the entire buffer. */
+    void disableProtection() {
+        MOZ_ASSERT(protectionEnabled);
+        unprotect();
+        protectionEnabled = false;
     }
 
     /*
      * Disable protection on the smallest number of pages containing
      * both |firstByteOffset| and |lastByteOffset|.
      */
     void unprotectRegion(size_t firstByteOffset, size_t lastByteOffset) {
         MOZ_ASSERT(!regionUnprotected);
--- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
+++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
@@ -82,18 +82,16 @@ namespace jit {
             if (MOZ_UNLIKELY(!m_buffer.append(reinterpret_cast<unsigned char*>(&value), size)))
                 oomDetected();
         }
 
     public:
         AssemblerBuffer()
             : m_oom(false)
         {
-            // Provide memory protection once the buffer starts to get big.
-            m_buffer.setLowerBoundForProtection(32 * 1024);
         }
 
         void ensureSpace(size_t space)
         {
             if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space)))
                 oomDetected();
         }
 
@@ -136,16 +134,19 @@ namespace jit {
             return m_oom;
         }
 
         const unsigned char* buffer() const {
             MOZ_ASSERT(!m_oom);
             return m_buffer.begin();
         }
 
+        void enableBufferProtection() { m_buffer.enableProtection(); }
+        void disableBufferProtection() { m_buffer.disableProtection(); }
+
         void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.unprotectRegion(firstByteOffset, lastByteOffset);
         }
         void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.reprotectRegion(firstByteOffset, lastByteOffset);
         }
 
     protected:
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -3846,16 +3846,19 @@ threeByteOpImmSimd("vblendps", VEX_PD, O
     {
         memcpy(buffer, m_formatter.buffer(), size());
     }
     MOZ_MUST_USE bool appendBuffer(const BaseAssembler& other)
     {
         return m_formatter.append(other.m_formatter.buffer(), other.size());
     }
 
+    void enableBufferProtection() { m_formatter.enableBufferProtection(); }
+    void disableBufferProtection() { m_formatter.disableBufferProtection(); }
+
     void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
         m_formatter.unprotectDataRegion(firstByteOffset, lastByteOffset);
     }
     void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
         m_formatter.reprotectDataRegion(firstByteOffset, lastByteOffset);
     }
 
   protected:
@@ -5124,16 +5127,19 @@ threeByteOpImmSimd("vblendps", VEX_PD, O
         bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
         unsigned char* data() { return m_buffer.data(); }
 
         MOZ_MUST_USE bool append(const unsigned char* values, size_t size)
         {
             return m_buffer.append(values, size);
         }
 
+        void enableBufferProtection() { m_buffer.enableBufferProtection(); }
+        void disableBufferProtection() { m_buffer.disableBufferProtection(); }
+
         void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.unprotectDataRegion(firstByteOffset, lastByteOffset);
         }
         void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) {
             m_buffer.reprotectDataRegion(firstByteOffset, lastByteOffset);
         }
 
     private:
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -189,17 +189,16 @@ UNIFIED_SOURCES += [
     'builtin/SIMD.cpp',
     'builtin/SymbolObject.cpp',
     'builtin/TestingFunctions.cpp',
     'builtin/TypedObject.cpp',
     'builtin/WeakMapObject.cpp',
     'builtin/WeakSetObject.cpp',
     'devtools/sharkctl.cpp',
     'ds/LifoAlloc.cpp',
-    'ds/MemoryProtectionExceptionHandler.cpp',
     'frontend/BytecodeCompiler.cpp',
     'frontend/BytecodeEmitter.cpp',
     'frontend/FoldConstants.cpp',
     'frontend/NameFunctions.cpp',
     'frontend/ParseNode.cpp',
     'frontend/TokenStream.cpp',
     'gc/Allocator.cpp',
     'gc/Barrier.cpp',
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -10,17 +10,16 @@
 
 #include "mozilla/Assertions.h"
 
 #include <ctype.h>
 
 #include "jstypes.h"
 
 #include "builtin/AtomicsObject.h"
-#include "ds/MemoryProtectionExceptionHandler.h"
 #include "gc/Statistics.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/Ion.h"
 #include "js/Utility.h"
 #if ENABLE_INTL_API
 #include "unicode/uclean.h"
 #include "unicode/utypes.h"
 #endif // ENABLE_INTL_API
@@ -96,18 +95,16 @@ JS::detail::InitWithFailureDiagnostic(bo
 
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     RETURN_IF_FAIL(js::oom::InitThreadType());
     js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
 #endif
 
     js::jit::ExecutableAllocator::initStatic();
 
-    MOZ_ALWAYS_TRUE(js::MemoryProtectionExceptionHandler::install());
-
     RETURN_IF_FAIL(js::jit::InitializeIon());
 
     js::DateTimeInfo::init();
 
 #if EXPOSE_INTL_API
     UErrorCode err = U_ZERO_ERROR;
     u_init(&err);
     if (U_FAILURE(err))
@@ -143,18 +140,16 @@ JS_ShutDown(void)
 
     js::DestroyHelperThreadsState();
 
 #ifdef JS_TRACE_LOGGING
     js::DestroyTraceLoggerThreadState();
     js::DestroyTraceLoggerGraphState();
 #endif
 
-    js::MemoryProtectionExceptionHandler::uninstall();
-
     // The only difficult-to-address reason for the restriction that you can't
     // call JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ
     // NowInit initialization code, which uses PR_CallOnce to initialize the
     // PRMJ_Now subsystem.  (For reinitialization to be permitted, we'd need to
     // "reset" the called-once status -- doable, but more trouble than it's
     // worth now.)  Initializing that subsystem from JS_Init eliminates the
     // problem, but initialization can take a comparatively long time (15ms or
     // so), so we really don't want to do it in JS_Init, and we really do want