Backed out 2 changesets (bug 1396723) for !ElementAccess::Get(mHead).mPrev assertion failures

Backed out changeset 4f17343164b6 (bug 1396723)
Backed out changeset b744eba9ca78 (bug 1396723)

MozReview-Commit-ID: JbvM6oMxEFl
This commit is contained in:
Phil Ringnalda 2017-09-06 21:39:20 -07:00
Родитель 5921d11c6e
Коммит bc78097d88
6 изменённых файлов: 209 добавлений и 136 удалений

Просмотреть файл

@ -259,7 +259,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
{
friend class Breakpoint;
friend class DebuggerMemory;
friend struct JSRuntime::GlobalObjectWatchersLinkAccess<Debugger>;
friend struct JSRuntime::GlobalObjectWatchersSiblingAccess<Debugger>;
friend class SavedStacks;
friend class ScriptedOnStepHandler;
friend class ScriptedOnPopHandler;
@ -389,17 +389,26 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
// Whether to enable code coverage on the Debuggee.
bool collectCoverageInfo;
template <typename T>
struct DebuggerLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->debuggerLink;
template<typename T>
struct DebuggerSiblingAccess {
static T* GetNext(T* elm) {
return elm->debuggerLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->debuggerLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->debuggerLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->debuggerLink.mPrev = prev;
}
};
// List of all js::Breakpoints in this debugger.
using BreakpointList =
mozilla::DoublyLinkedList<js::Breakpoint,
DebuggerLinkAccess<js::Breakpoint>>;
DebuggerSiblingAccess<js::Breakpoint>>;
BreakpointList breakpoints;
// The set of GC numbers for which one or more of this Debugger's observed
@ -1586,17 +1595,26 @@ class BreakpointSite {
private:
Type type_;
template <typename T>
struct SiteLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->siteLink;
template<typename T>
struct SiteSiblingAccess {
static T* GetNext(T* elm) {
return elm->siteLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->siteLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->siteLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->siteLink.mPrev = prev;
}
};
// List of all js::Breakpoints at this instruction.
using BreakpointList =
mozilla::DoublyLinkedList<js::Breakpoint,
SiteLinkAccess<js::Breakpoint>>;
SiteSiblingAccess<js::Breakpoint>>;
BreakpointList breakpoints;
size_t enabledCount; /* number of breakpoints in the list that are enabled */

Просмотреть файл

@ -582,15 +582,24 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
template <typename T>
struct GlobalObjectWatchersLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->onNewGlobalObjectWatchersLink;
struct GlobalObjectWatchersSiblingAccess {
static T* GetNext(T* elm) {
return elm->onNewGlobalObjectWatchersLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->onNewGlobalObjectWatchersLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->onNewGlobalObjectWatchersLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->onNewGlobalObjectWatchersLink.mPrev = prev;
}
};
using WatchersList =
mozilla::DoublyLinkedList<js::Debugger,
GlobalObjectWatchersLinkAccess<js::Debugger>>;
GlobalObjectWatchersSiblingAccess<js::Debugger>>;
private:
/*
* List of all enabled Debuggers that have onNewGlobalObject handler

Просмотреть файл

@ -0,0 +1,75 @@
/* -*- Mode: C; tab-width: 8; c-basic-offset: 8; indent-tabs-mode: t -*- */
/* vim:set softtabstop=8 shiftwidth=8 noet: */
/*-
* Copyright (C) the Mozilla Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#ifndef linkedlist_h__
#define linkedlist_h__
#include <stddef.h>
struct LinkedList {
LinkedList *next;
LinkedList *prev;
};
/* Convert from LinkedList* to foo*. */
#define LinkedList_Get(e, type, prop) \
(type*)((char*)(e) - offsetof(type, prop))
/* Insert |e| at the beginning of |l|. */
void LinkedList_InsertHead(LinkedList *l, LinkedList *e)
{
e->next = l;
e->prev = l->prev;
e->next->prev = e;
e->prev->next = e;
}
void LinkedList_Remove(LinkedList *e)
{
e->prev->next = e->next;
e->next->prev = e->prev;
e->next = e;
e->prev = e;
}
bool LinkedList_IsEmpty(LinkedList *e)
{
return e->next == e;
}
void LinkedList_Init(LinkedList *e)
{
e->next = e;
e->prev = e;
}
#endif

Просмотреть файл

@ -112,7 +112,6 @@
#include "mozilla/Sprintf.h"
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/DoublyLinkedList.h"
#ifdef ANDROID
#define NO_TLS
@ -253,6 +252,7 @@ typedef long ssize_t;
#endif
#include "mozjemalloc_types.h"
#include "linkedlist.h"
/* Some tools, such as /dev/dsp wrappers, LD_PRELOAD libraries that
* happen to override mmap() and call dlsym() from their overridden
@ -627,7 +627,7 @@ struct arena_chunk_t {
*
* We're currently lazy and don't remove a chunk from this list when
* all its madvised pages are recommitted. */
mozilla::DoublyLinkedListElement<arena_chunk_t> chunks_madvised_elem;
LinkedList chunks_madvised_elem;
#endif
/* Number of dirty pages. */
@ -638,17 +638,6 @@ struct arena_chunk_t {
};
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
#ifdef MALLOC_DOUBLE_PURGE
template<>
struct mozilla::GetDoublyLinkedListElement<arena_chunk_t>
{
static mozilla::DoublyLinkedListElement<arena_chunk_t>& Get(arena_chunk_t* aThis)
{
return aThis->chunks_madvised_elem;
}
};
#endif
struct arena_run_t {
#if defined(MOZ_DEBUG) || defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
uint32_t magic;
@ -720,7 +709,7 @@ struct arena_t {
#ifdef MALLOC_DOUBLE_PURGE
/* Head of a linked list of MADV_FREE'd-page-containing chunks this
* arena manages. */
mozilla::DoublyLinkedList<arena_chunk_t> chunks_madvised;
LinkedList chunks_madvised;
#endif
/*
@ -2710,7 +2699,7 @@ arena_chunk_init(arena_t *arena, arena_chunk_t *chunk, bool zeroed)
&chunk->map[arena_chunk_header_npages]);
#ifdef MALLOC_DOUBLE_PURGE
new (&chunk->chunks_madvised_elem) mozilla::DoublyLinkedListElement<arena_chunk_t>();
LinkedList_Init(&chunk->chunks_madvised_elem);
#endif
}
@ -2727,9 +2716,8 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
}
#ifdef MALLOC_DOUBLE_PURGE
if (arena->chunks_madvised.ElementProbablyInList(arena->spare)) {
arena->chunks_madvised.remove(arena->spare);
}
/* This is safe to do even if arena->spare is not in the list. */
LinkedList_Remove(&arena->spare->chunks_madvised_elem);
#endif
chunk_dealloc((void *)arena->spare, chunksize, ARENA_CHUNK);
@ -2890,10 +2878,8 @@ arena_purge(arena_t *arena, bool all)
if (madvised) {
/* The chunk might already be in the list, but this
* makes sure it's at the front. */
if (arena->chunks_madvised.ElementProbablyInList(chunk)) {
arena->chunks_madvised.remove(chunk);
}
arena->chunks_madvised.pushFront(chunk);
LinkedList_Remove(&chunk->chunks_madvised_elem);
LinkedList_InsertHead(&arena->chunks_madvised, &chunk->chunks_madvised_elem);
}
#endif
}
@ -4037,7 +4023,7 @@ arena_new(arena_t *arena)
/* Initialize chunks. */
arena_chunk_tree_dirty_new(&arena->chunks_dirty);
#ifdef MALLOC_DOUBLE_PURGE
new (&arena->chunks_madvised) mozilla::DoublyLinkedList<arena_chunk_t>();
LinkedList_Init(&arena->chunks_madvised);
#endif
arena->spare = nullptr;
@ -5092,9 +5078,12 @@ hard_purge_arena(arena_t *arena)
{
malloc_spin_lock(&arena->lock);
while (!arena->chunks_madvised.isEmpty()) {
arena_chunk_t *chunk = arena->chunks_madvised.popFront();
while (!LinkedList_IsEmpty(&arena->chunks_madvised)) {
arena_chunk_t *chunk =
LinkedList_Get(arena->chunks_madvised.next,
arena_chunk_t, chunks_madvised_elem);
hard_purge_chunk(chunk);
LinkedList_Remove(&chunk->chunks_madvised_elem);
}
malloc_spin_unlock(&arena->lock);

Просмотреть файл

@ -64,15 +64,31 @@
namespace mozilla {
/**
* Provides access to a next and previous element pointer named |mNext| and
* |mPrev| respectively. This class is the default and will work if the list
* element derives from DoublyLinkedListElement.
*
* Although designed to work with DoublyLinkedListElement this will als work
* with any class that defines |mNext| and |mPrev| members with the correct
* type.
*/
template <typename T>
struct DoublyLinkedSiblingAccess {
static void SetNext(T* aElm, T* aNext) { aElm->mNext = aNext; }
static T* GetNext(T* aElm) { return aElm->mNext; }
static void SetPrev(T* aElm, T* aPrev) { aElm->mPrev = aPrev; }
static T* GetPrev(T* aElm) { return aElm->mPrev; }
};
/**
* Deriving from this will allow T to be inserted into and removed from a
* DoublyLinkedList.
*/
template <typename T>
class DoublyLinkedListElement
struct DoublyLinkedListElement
{
template<typename U, typename E> friend class DoublyLinkedList;
friend T;
friend struct DoublyLinkedSiblingAccess<T>;
T* mNext;
T* mPrev;
@ -80,36 +96,14 @@ public:
DoublyLinkedListElement() : mNext(nullptr), mPrev(nullptr) {}
};
/**
* Provides access to a DoublyLinkedListElement within T.
*
* The default implementation of this template works for types that derive
* from DoublyLinkedListElement, but one can specialize for their class so
* that some appropriate DoublyLinkedListElement reference is returned.
*
* For more complex cases (multiple DoublyLinkedListElements, for example),
* one can define their own trait class and use that as ElementAccess for
* DoublyLinkedList. See TestDoublyLinkedList.cpp for an example.
*/
template <typename T>
struct GetDoublyLinkedListElement
{
static_assert(mozilla::IsBaseOf<DoublyLinkedListElement<T>, T>::value,
"You need your own specialization of GetDoublyLinkedListElement"
" or use a separate Trait.");
static DoublyLinkedListElement<T>& Get(T* aThis)
{
return *aThis;
}
};
/**
* A doubly linked list. |T| is the type of element stored in this list. |T|
* must contain or have access to unique next and previous element pointers.
* The template argument |ElementAccess| provides code to tell this list how to
* get a reference to a DoublyLinkedListElement that may reside anywhere.
* The template argument |SiblingAccess| provides code to tell this list how to
* get and set the next and previous pointers. The actual storage of next/prev
* links may reside anywhere and be encoded in any way.
*/
template <typename T, typename ElementAccess = GetDoublyLinkedListElement<T>>
template <typename T, typename SiblingAccess = DoublyLinkedSiblingAccess<T>>
class DoublyLinkedList final
{
T* mHead;
@ -124,7 +118,7 @@ class DoublyLinkedList final
}
static bool ElementNotInList(T* aElm) {
return !ElementAccess::Get(aElm).mNext && !ElementAccess::Get(aElm).mPrev;
return !SiblingAccess::GetNext(aElm) && !SiblingAccess::GetPrev(aElm);
}
public:
@ -147,7 +141,7 @@ public:
T* operator ->() const { return mCurrent; }
Iterator& operator++() {
mCurrent = ElementAccess::Get(mCurrent).mNext;
mCurrent = SiblingAccess::GetNext(mCurrent);
return *this;
}
@ -158,7 +152,7 @@ public:
}
Iterator& operator--() {
mCurrent = ElementAccess::Get(mCurrent).mPrev;
mCurrent = SiblingAccess::GetPrev(mCurrent);
return *this;
}
@ -206,10 +200,10 @@ public:
MOZ_ASSERT(ElementNotInList(aElm));
MOZ_ASSERT(isStateValid());
ElementAccess::Get(aElm).mNext = mHead;
SiblingAccess::SetNext(aElm, mHead);
if (mHead) {
MOZ_ASSERT(!ElementAccess::Get(mHead).mPrev);
ElementAccess::Get(mHead).mPrev = aElm;
MOZ_ASSERT(!SiblingAccess::GetPrev(mHead));
SiblingAccess::SetPrev(mHead, aElm);
}
mHead = aElm;
@ -227,9 +221,9 @@ public:
MOZ_ASSERT(isStateValid());
T* result = mHead;
mHead = result ? ElementAccess::Get(result).mNext : nullptr;
mHead = result ? SiblingAccess::GetNext(result) : nullptr;
if (mHead) {
ElementAccess::Get(mHead).mPrev = nullptr;
SiblingAccess::SetPrev(mHead, nullptr);
}
if (mTail == result) {
@ -237,8 +231,8 @@ public:
}
if (result) {
ElementAccess::Get(result).mNext = nullptr;
ElementAccess::Get(result).mPrev = nullptr;
SiblingAccess::SetNext(result, nullptr);
SiblingAccess::SetPrev(result, nullptr);
}
return result;
@ -253,11 +247,11 @@ public:
MOZ_ASSERT(ElementNotInList(aElm));
MOZ_ASSERT(isStateValid());
ElementAccess::Get(aElm).mNext = nullptr;
ElementAccess::Get(aElm).mPrev = mTail;
SiblingAccess::SetNext(aElm, nullptr);
SiblingAccess::SetPrev(aElm, mTail);
if (mTail) {
MOZ_ASSERT(!ElementAccess::Get(mTail).mNext);
ElementAccess::Get(mTail).mNext = aElm;
MOZ_ASSERT(!SiblingAccess::GetNext(mTail));
SiblingAccess::SetNext(mTail, aElm);
}
mTail = aElm;
@ -275,9 +269,9 @@ public:
MOZ_ASSERT(isStateValid());
T* result = mTail;
mTail = result ? ElementAccess::Get(result).mPrev : nullptr;
mTail = result ? SiblingAccess::GetPrev(result) : nullptr;
if (mTail) {
ElementAccess::Get(mTail).mNext = nullptr;
SiblingAccess::SetNext(mTail, nullptr);
}
if (mHead == result) {
@ -285,8 +279,8 @@ public:
}
if (result) {
ElementAccess::Get(result).mNext = nullptr;
ElementAccess::Get(result).mPrev = nullptr;
SiblingAccess::SetNext(result, nullptr);
SiblingAccess::SetPrev(result, nullptr);
}
return result;
@ -307,13 +301,13 @@ public:
}
T* after = &(*aIter);
T* before = ElementAccess::Get(after).mPrev;
T* before = SiblingAccess::GetPrev(after);
MOZ_ASSERT(before);
ElementAccess::Get(before).mNext = aElm;
ElementAccess::Get(aElm).mPrev = before;
ElementAccess::Get(aElm).mNext = after;
ElementAccess::Get(after).mPrev = aElm;
SiblingAccess::SetNext(before, aElm);
SiblingAccess::SetPrev(aElm, before);
SiblingAccess::SetNext(aElm, after);
SiblingAccess::SetPrev(after, aElm);
}
/**
@ -321,26 +315,26 @@ public:
*/
void remove(T* aElm) {
MOZ_ASSERT(aElm);
MOZ_ASSERT(ElementAccess::Get(aElm).mNext || ElementAccess::Get(aElm).mPrev ||
MOZ_ASSERT(SiblingAccess::GetNext(aElm) || SiblingAccess::GetPrev(aElm) ||
(aElm == mHead && aElm == mTail),
"Attempted to remove element not in this list");
if (T* prev = ElementAccess::Get(aElm).mPrev) {
ElementAccess::Get(prev).mNext = ElementAccess::Get(aElm).mNext;
if (T* prev = SiblingAccess::GetPrev(aElm)) {
SiblingAccess::SetNext(prev, SiblingAccess::GetNext(aElm));
} else {
MOZ_ASSERT(mHead == aElm);
mHead = ElementAccess::Get(aElm).mNext;
mHead = SiblingAccess::GetNext(aElm);
}
if (T* next = ElementAccess::Get(aElm).mNext) {
ElementAccess::Get(next).mPrev = ElementAccess::Get(aElm).mPrev;
if (T* next = SiblingAccess::GetNext(aElm)) {
SiblingAccess::SetPrev(next, SiblingAccess::GetPrev(aElm));
} else {
MOZ_ASSERT(mTail == aElm);
mTail = ElementAccess::Get(aElm).mPrev;
mTail = SiblingAccess::GetPrev(aElm);
}
ElementAccess::Get(aElm).mNext = nullptr;
ElementAccess::Get(aElm).mPrev = nullptr;
SiblingAccess::SetNext(aElm, nullptr);
SiblingAccess::SetPrev(aElm, nullptr);
}
/**
@ -358,19 +352,6 @@ public:
bool contains(const T& aElm) {
return find(aElm) != Iterator();
}
/**
* Returns whether the given element might be in the list. Note that this
* assumes the element is either in the list or not in the list, and ignores
* the case where the element might be in another list in order to make the
* check fast.
*/
bool ElementProbablyInList(T* aElm) {
if (isEmpty()) {
return false;
}
return !ElementNotInList(aElm);
}
};
} // namespace mozilla

Просмотреть файл

@ -121,31 +121,32 @@ TestDoublyLinkedList()
MOZ_RELEASE_ASSERT(++list.begin() == list.find(four));
}
struct InTwoLists {
explicit InTwoLists(unsigned int aValue) : mValue(aValue) {}
DoublyLinkedListElement<InTwoLists> mListOne;
DoublyLinkedListElement<InTwoLists> mListTwo;
unsigned int mValue;
struct GetListOneTrait {
static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists *aThis) { return aThis->mListOne; }
};
};
namespace mozilla {
template<>
struct GetDoublyLinkedListElement<InTwoLists> {
static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists* aThis) { return aThis->mListTwo; }
};
}
static void
TestCustomAccessor()
{
DoublyLinkedList<InTwoLists, InTwoLists::GetListOneTrait> listOne;
DoublyLinkedList<InTwoLists> listTwo;
struct InTwoLists {
explicit InTwoLists(unsigned int aValue) : mValue(aValue) {}
DoublyLinkedListElement<InTwoLists> mListOne;
DoublyLinkedListElement<InTwoLists> mListTwo;
unsigned int mValue;
};
struct ListOneSiblingAccess {
static void SetNext(InTwoLists* aElm, InTwoLists* aNext) { aElm->mListOne.mNext = aNext; }
static InTwoLists* GetNext(InTwoLists* aElm) { return aElm->mListOne.mNext; }
static void SetPrev(InTwoLists* aElm, InTwoLists* aPrev) { aElm->mListOne.mPrev = aPrev; }
static InTwoLists* GetPrev(InTwoLists* aElm) { return aElm->mListOne.mPrev; }
};
struct ListTwoSiblingAccess {
static void SetNext(InTwoLists* aElm, InTwoLists* aNext) { aElm->mListTwo.mNext = aNext; }
static InTwoLists* GetNext(InTwoLists* aElm) { return aElm->mListTwo.mNext; }
static void SetPrev(InTwoLists* aElm, InTwoLists* aPrev) { aElm->mListTwo.mPrev = aPrev; }
static InTwoLists* GetPrev(InTwoLists* aElm) { return aElm->mListTwo.mPrev; }
};
DoublyLinkedList<InTwoLists, ListOneSiblingAccess> listOne;
DoublyLinkedList<InTwoLists, ListTwoSiblingAccess> listTwo;
InTwoLists one(1);
InTwoLists two(2);