Commit eee897b0 authored by Jon Coppeard's avatar Jon Coppeard
Browse files

Bug 1412912 - Split out AllocKinds.h and inline definitions in ArenaList.h r=sfink

parent 76606ba9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@

#include <stdint.h>

#include "jstypes.h"

namespace js {

struct JS_PUBLIC_API(TimeBudget)

js/src/gc/AllocKind.h

0 → 100644
+197 −0
Original line number Diff line number Diff line
/* -*- 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/. */

/*
 * GC-internal definition of GC cell kinds.
 */

#ifndef gc_AllocKind_h
#define gc_AllocKind_h

#include "mozilla/ArrayUtils.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/EnumeratedRange.h"

#include <stdint.h>

#include "js/TraceKind.h"

namespace js {
namespace gc {

/* The GC allocation kinds. */
// FIXME: uint8_t would make more sense for the underlying type, but causes
// miscompilations in GCC (fixed in 4.8.5 and 4.9.3). See also bug 1143966.
enum class AllocKind {
    FIRST,
    OBJECT_FIRST = FIRST,
    FUNCTION = FIRST,
    FUNCTION_EXTENDED,
    OBJECT0,
    OBJECT0_BACKGROUND,
    OBJECT2,
    OBJECT2_BACKGROUND,
    OBJECT4,
    OBJECT4_BACKGROUND,
    OBJECT8,
    OBJECT8_BACKGROUND,
    OBJECT12,
    OBJECT12_BACKGROUND,
    OBJECT16,
    OBJECT16_BACKGROUND,
    OBJECT_LIMIT,
    OBJECT_LAST = OBJECT_LIMIT - 1,
    SCRIPT,
    LAZY_SCRIPT,
    SHAPE,
    ACCESSOR_SHAPE,
    BASE_SHAPE,
    OBJECT_GROUP,
    FAT_INLINE_STRING,
    STRING,
    EXTERNAL_STRING,
    FAT_INLINE_ATOM,
    ATOM,
    SYMBOL,
    JITCODE,
    SCOPE,
    REGEXP_SHARED,
    LIMIT,
    LAST = LIMIT - 1
};

// Macro to enumerate the different allocation kinds supplying information about
// the trace kind, C++ type and allocation size.
#define FOR_EACH_OBJECT_ALLOCKIND(D) \
 /* AllocKind              TraceKind      TypeName           SizedType */ \
    D(FUNCTION,            Object,        JSObject,          JSFunction) \
    D(FUNCTION_EXTENDED,   Object,        JSObject,          FunctionExtended) \
    D(OBJECT0,             Object,        JSObject,          JSObject_Slots0) \
    D(OBJECT0_BACKGROUND,  Object,        JSObject,          JSObject_Slots0) \
    D(OBJECT2,             Object,        JSObject,          JSObject_Slots2) \
    D(OBJECT2_BACKGROUND,  Object,        JSObject,          JSObject_Slots2) \
    D(OBJECT4,             Object,        JSObject,          JSObject_Slots4) \
    D(OBJECT4_BACKGROUND,  Object,        JSObject,          JSObject_Slots4) \
    D(OBJECT8,             Object,        JSObject,          JSObject_Slots8) \
    D(OBJECT8_BACKGROUND,  Object,        JSObject,          JSObject_Slots8) \
    D(OBJECT12,            Object,        JSObject,          JSObject_Slots12) \
    D(OBJECT12_BACKGROUND, Object,        JSObject,          JSObject_Slots12) \
    D(OBJECT16,            Object,        JSObject,          JSObject_Slots16) \
    D(OBJECT16_BACKGROUND, Object,        JSObject,          JSObject_Slots16)

#define FOR_EACH_NONOBJECT_ALLOCKIND(D) \
 /* AllocKind              TraceKind      TypeName           SizedType */ \
    D(SCRIPT,              Script,        JSScript,          JSScript) \
    D(LAZY_SCRIPT,         LazyScript,    js::LazyScript,    js::LazyScript) \
    D(SHAPE,               Shape,         js::Shape,         js::Shape) \
    D(ACCESSOR_SHAPE,      Shape,         js::AccessorShape, js::AccessorShape) \
    D(BASE_SHAPE,          BaseShape,     js::BaseShape,     js::BaseShape) \
    D(OBJECT_GROUP,        ObjectGroup,   js::ObjectGroup,   js::ObjectGroup) \
    D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString) \
    D(STRING,              String,        JSString,          JSString) \
    D(EXTERNAL_STRING,     String,        JSExternalString,  JSExternalString) \
    D(FAT_INLINE_ATOM,     String,        js::FatInlineAtom, js::FatInlineAtom) \
    D(ATOM,                String,        js::NormalAtom,    js::NormalAtom) \
    D(SYMBOL,              Symbol,        JS::Symbol,        JS::Symbol) \
    D(JITCODE,             JitCode,       js::jit::JitCode,  js::jit::JitCode) \
    D(SCOPE,               Scope,         js::Scope,         js::Scope) \
    D(REGEXP_SHARED,       RegExpShared,  js::RegExpShared,  js::RegExpShared)

#define FOR_EACH_ALLOCKIND(D) \
    FOR_EACH_OBJECT_ALLOCKIND(D) \
    FOR_EACH_NONOBJECT_ALLOCKIND(D)

static_assert(int(AllocKind::FIRST) == 0, "Various places depend on AllocKind starting at 0, "
                                          "please audit them carefully!");
static_assert(int(AllocKind::OBJECT_FIRST) == 0, "Various places depend on AllocKind::OBJECT_FIRST "
                                                 "being 0, please audit them carefully!");

inline bool
IsAllocKind(AllocKind kind)
{
    return kind >= AllocKind::FIRST && kind <= AllocKind::LIMIT;
}

inline bool
IsValidAllocKind(AllocKind kind)
{
    return kind >= AllocKind::FIRST && kind <= AllocKind::LAST;
}

inline bool
IsObjectAllocKind(AllocKind kind)
{
    return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
}

inline bool
IsShapeAllocKind(AllocKind kind)
{
    return kind == AllocKind::SHAPE || kind == AllocKind::ACCESSOR_SHAPE;
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all alloc kinds.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT))
AllAllocKinds()
{
    return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all object alloc kinds.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT))
ObjectAllocKinds()
{
    return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over alloc kinds from |first| to |limit|, exclusive.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT))
SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT)
{
    MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!");
    MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!");
    return mozilla::MakeEnumeratedRange(first, limit);
}

// AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular alloc kind.
template<typename ValueType> using AllAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;

// ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular object alloc kind.
template<typename ValueType> using ObjectAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;

static inline JS::TraceKind
MapAllocToTraceKind(AllocKind kind)
{
    static const JS::TraceKind map[] = {
#define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType) \
        JS::TraceKind::traceKind,
FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
#undef EXPAND_ELEMENT
    };

    static_assert(MOZ_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT),
                  "AllocKind-to-TraceKind mapping must be in sync");
    return map[size_t(kind)];
}

/*
 * This must be an upper bound, but we do not need the least upper bound, so
 * we just exclude non-background objects.
 */
static const size_t MAX_BACKGROUND_FINALIZE_KINDS =
    size_t(AllocKind::LIMIT) - size_t(AllocKind::OBJECT_LIMIT) / 2;

} /* namespace gc */
} /* namespace js */

#endif /* gc_AllocKind_h */
+353 −0
Original line number Diff line number Diff line
/* -*- 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 gc_ArenaList_inl_h
#define gc_ArenaList_inl_h

#include "gc/ArenaList.h"

#include "gc/Heap.h"

void
js::gc::SortedArenaListSegment::append(Arena* arena)
{
    MOZ_ASSERT(arena);
    MOZ_ASSERT_IF(head, head->getAllocKind() == arena->getAllocKind());
    *tailp = arena;
    tailp = &arena->next;
}

inline
js::gc::ArenaList::ArenaList()
{
    clear();
}

void
js::gc::ArenaList::copy(const ArenaList& other)
{
    other.check();
    head_ = other.head_;
    cursorp_ = other.isCursorAtHead() ? &head_ : other.cursorp_;
    check();
}

inline
js::gc::ArenaList::ArenaList(const ArenaList& other)
{
    copy(other);
}

js::gc::ArenaList&
js::gc::ArenaList::operator=(const ArenaList& other)
{
    copy(other);
    return *this;
}

inline
js::gc::ArenaList::ArenaList(const SortedArenaListSegment& segment)
{
    head_ = segment.head;
    cursorp_ = segment.isEmpty() ? &head_ : segment.tailp;
    check();
}

// This does checking just of |head_| and |cursorp_|.
void
js::gc::ArenaList::check() const
{
#ifdef DEBUG
    // If the list is empty, it must have this form.
    MOZ_ASSERT_IF(!head_, cursorp_ == &head_);

    // If there's an arena following the cursor, it must not be full.
    Arena* cursor = *cursorp_;
    MOZ_ASSERT_IF(cursor, cursor->hasFreeThings());
#endif
}

void
js::gc::ArenaList::clear()
{
    head_ = nullptr;
    cursorp_ = &head_;
    check();
}

js::gc::ArenaList
js::gc::ArenaList::copyAndClear()
{
    ArenaList result = *this;
    clear();
    return result;
}

bool
js::gc::ArenaList::isEmpty() const
{
    check();
    return !head_;
}

js::gc::Arena*
js::gc::ArenaList::head() const
{
    check();
    return head_;
}

bool
js::gc::ArenaList::isCursorAtHead() const
{
    check();
    return cursorp_ == &head_;
}

bool
js::gc::ArenaList::isCursorAtEnd() const
{
    check();
    return !*cursorp_;
}

void
js::gc::ArenaList::moveCursorToEnd()
{
    while (!isCursorAtEnd())
        cursorp_ = &(*cursorp_)->next;
}

js::gc::Arena*
js::gc::ArenaList::arenaAfterCursor() const
{
    check();
    return *cursorp_;
}

js::gc::Arena*
js::gc::ArenaList::takeNextArena()
{
    check();
    Arena* arena = *cursorp_;
    if (!arena)
        return nullptr;
    cursorp_ = &arena->next;
    check();
    return arena;
}

void
js::gc::ArenaList::insertAtCursor(Arena* a)
{
    check();
    a->next = *cursorp_;
    *cursorp_ = a;
    // At this point, the cursor is sitting before |a|. Move it after |a|
    // if necessary.
    if (!a->hasFreeThings())
        cursorp_ = &a->next;
    check();
}

void
js::gc::ArenaList::insertBeforeCursor(Arena* a)
{
    check();
    a->next = *cursorp_;
    *cursorp_ = a;
    cursorp_ = &a->next;
    check();
}

js::gc::ArenaList&
js::gc::ArenaList::insertListWithCursorAtEnd(const ArenaList& other)
{
    check();
    other.check();
    MOZ_ASSERT(other.isCursorAtEnd());
    if (other.isCursorAtHead())
        return *this;
    // Insert the full arenas of |other| after those of |this|.
    *other.cursorp_ = *cursorp_;
    *cursorp_ = other.head_;
    cursorp_ = other.cursorp_;
    check();
    return *this;
}

js::gc::SortedArenaList::SortedArenaList(size_t thingsPerArena)
{
    reset(thingsPerArena);
}

void
js::gc::SortedArenaList::setThingsPerArena(size_t thingsPerArena)
{
    MOZ_ASSERT(thingsPerArena && thingsPerArena <= MaxThingsPerArena);
    thingsPerArena_ = thingsPerArena;
}

void
js::gc::SortedArenaList::reset(size_t thingsPerArena)
{
    setThingsPerArena(thingsPerArena);
    // Initialize the segments.
    for (size_t i = 0; i <= thingsPerArena; ++i)
        segments[i].clear();
}

void
js::gc::SortedArenaList::insertAt(Arena* arena, size_t nfree)
{
    MOZ_ASSERT(nfree <= thingsPerArena_);
    segments[nfree].append(arena);
}

void
js::gc::SortedArenaList::extractEmpty(Arena** empty)
{
    SortedArenaListSegment& segment = segments[thingsPerArena_];
    if (segment.head) {
        *segment.tailp = *empty;
        *empty = segment.head;
        segment.clear();
    }
}

js::gc::ArenaList
js::gc::SortedArenaList::toArenaList()
{
    // Link the non-empty segment tails up to the non-empty segment heads.
    size_t tailIndex = 0;
    for (size_t headIndex = 1; headIndex <= thingsPerArena_; ++headIndex) {
        if (headAt(headIndex)) {
            segments[tailIndex].linkTo(headAt(headIndex));
            tailIndex = headIndex;
        }
    }
    // Point the tail of the final non-empty segment at null. Note that if
    // the list is empty, this will just set segments[0].head to null.
    segments[tailIndex].linkTo(nullptr);
    // Create an ArenaList with head and cursor set to the head and tail of
    // the first segment (if that segment is empty, only the head is used).
    return ArenaList(segments[0]);
}

js::gc::Arena*
js::gc::ArenaLists::getFirstArena(AllocKind thingKind) const
{
    return arenaLists(thingKind).head();
}

js::gc::Arena*
js::gc::ArenaLists::getFirstArenaToSweep(AllocKind thingKind) const
{
    return arenaListsToSweep(thingKind);
}

js::gc::Arena*
js::gc::ArenaLists::getFirstSweptArena(AllocKind thingKind) const
{
    if (thingKind != incrementalSweptArenaKind.ref())
        return nullptr;
    return incrementalSweptArenas.ref().head();
}

js::gc::Arena*
js::gc::ArenaLists::getArenaAfterCursor(AllocKind thingKind) const
{
    return arenaLists(thingKind).arenaAfterCursor();
}

bool
js::gc::ArenaLists::arenaListsAreEmpty() const
{
    for (auto i : AllAllocKinds()) {
        /*
         * The arena cannot be empty if the background finalization is not yet
         * done.
         */
        if (backgroundFinalizeState(i) != BFS_DONE)
            return false;
        if (!arenaLists(i).isEmpty())
            return false;
    }
    return true;
}

void
js::gc::ArenaLists::unmarkAll()
{
    for (auto i : AllAllocKinds()) {
        /* The background finalization must have stopped at this point. */
        MOZ_ASSERT(backgroundFinalizeState(i) == BFS_DONE);
        for (Arena* arena = arenaLists(i).head(); arena; arena = arena->next)
            arena->unmarkAll();
    }
}

bool
js::gc::ArenaLists::doneBackgroundFinalize(AllocKind kind) const
{
    return backgroundFinalizeState(kind) == BFS_DONE;
}

bool
js::gc::ArenaLists::needBackgroundFinalizeWait(AllocKind kind) const
{
    return backgroundFinalizeState(kind) != BFS_DONE;
}

void
js::gc::ArenaLists::purge()
{
    for (auto i : AllAllocKinds())
        freeLists(i) = &placeholder;
}

bool
js::gc::ArenaLists::arenaIsInUse(Arena* arena, AllocKind kind) const
{
    MOZ_ASSERT(arena);
    return arena == freeLists(kind)->getArenaUnchecked();
}

MOZ_ALWAYS_INLINE js::gc::TenuredCell*
js::gc::ArenaLists::allocateFromFreeList(AllocKind thingKind, size_t thingSize)
{
    return freeLists(thingKind)->allocate(thingSize);
}

void
js::gc::ArenaLists::checkEmptyFreeLists()
{
#ifdef DEBUG
    for (auto i : AllAllocKinds())
        checkEmptyFreeList(i);
#endif
}

bool
js::gc::ArenaLists::checkEmptyArenaLists()
{
    bool empty = true;
#ifdef DEBUG
    for (auto i : AllAllocKinds()) {
        if (!checkEmptyArenaList(i))
            empty = false;
    }
#endif
    return empty;
}

void
js::gc::ArenaLists::checkEmptyFreeList(AllocKind kind)
{
    MOZ_ASSERT(freeLists(kind)->isEmpty());
}

#endif // gc_ArenaList_inl_h
+55 −240

File changed.

Preview size limit exceeded, changes collapsed.

+1 −171
Original line number Diff line number Diff line
@@ -11,8 +11,6 @@
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/EnumeratedRange.h"
#include "mozilla/PodOperations.h"

#include <stddef.h>
@@ -24,6 +22,7 @@
#include "jsutil.h"

#include "ds/BitArray.h"
#include "gc/AllocKind.h"
#include "gc/GCEnum.h"
#include "gc/Memory.h"
#include "js/GCAPI.h"
@@ -60,175 +59,6 @@ enum InitialHeap : uint8_t {
    TenuredHeap
};

/* The GC allocation kinds. */
// FIXME: uint8_t would make more sense for the underlying type, but causes
// miscompilations in GCC (fixed in 4.8.5 and 4.9.3). See also bug 1143966.
enum class AllocKind {
    FIRST,
    OBJECT_FIRST = FIRST,
    FUNCTION = FIRST,
    FUNCTION_EXTENDED,
    OBJECT0,
    OBJECT0_BACKGROUND,
    OBJECT2,
    OBJECT2_BACKGROUND,
    OBJECT4,
    OBJECT4_BACKGROUND,
    OBJECT8,
    OBJECT8_BACKGROUND,
    OBJECT12,
    OBJECT12_BACKGROUND,
    OBJECT16,
    OBJECT16_BACKGROUND,
    OBJECT_LIMIT,
    OBJECT_LAST = OBJECT_LIMIT - 1,
    SCRIPT,
    LAZY_SCRIPT,
    SHAPE,
    ACCESSOR_SHAPE,
    BASE_SHAPE,
    OBJECT_GROUP,
    FAT_INLINE_STRING,
    STRING,
    EXTERNAL_STRING,
    FAT_INLINE_ATOM,
    ATOM,
    SYMBOL,
    JITCODE,
    SCOPE,
    REGEXP_SHARED,
    LIMIT,
    LAST = LIMIT - 1
};

// Macro to enumerate the different allocation kinds supplying information about
// the trace kind, C++ type and allocation size.
#define FOR_EACH_OBJECT_ALLOCKIND(D) \
 /* AllocKind              TraceKind      TypeName           SizedType */ \
    D(FUNCTION,            Object,        JSObject,          JSFunction) \
    D(FUNCTION_EXTENDED,   Object,        JSObject,          FunctionExtended) \
    D(OBJECT0,             Object,        JSObject,          JSObject_Slots0) \
    D(OBJECT0_BACKGROUND,  Object,        JSObject,          JSObject_Slots0) \
    D(OBJECT2,             Object,        JSObject,          JSObject_Slots2) \
    D(OBJECT2_BACKGROUND,  Object,        JSObject,          JSObject_Slots2) \
    D(OBJECT4,             Object,        JSObject,          JSObject_Slots4) \
    D(OBJECT4_BACKGROUND,  Object,        JSObject,          JSObject_Slots4) \
    D(OBJECT8,             Object,        JSObject,          JSObject_Slots8) \
    D(OBJECT8_BACKGROUND,  Object,        JSObject,          JSObject_Slots8) \
    D(OBJECT12,            Object,        JSObject,          JSObject_Slots12) \
    D(OBJECT12_BACKGROUND, Object,        JSObject,          JSObject_Slots12) \
    D(OBJECT16,            Object,        JSObject,          JSObject_Slots16) \
    D(OBJECT16_BACKGROUND, Object,        JSObject,          JSObject_Slots16)

#define FOR_EACH_NONOBJECT_ALLOCKIND(D) \
 /* AllocKind              TraceKind      TypeName           SizedType */ \
    D(SCRIPT,              Script,        JSScript,          JSScript) \
    D(LAZY_SCRIPT,         LazyScript,    js::LazyScript,    js::LazyScript) \
    D(SHAPE,               Shape,         js::Shape,         js::Shape) \
    D(ACCESSOR_SHAPE,      Shape,         js::AccessorShape, js::AccessorShape) \
    D(BASE_SHAPE,          BaseShape,     js::BaseShape,     js::BaseShape) \
    D(OBJECT_GROUP,        ObjectGroup,   js::ObjectGroup,   js::ObjectGroup) \
    D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString) \
    D(STRING,              String,        JSString,          JSString) \
    D(EXTERNAL_STRING,     String,        JSExternalString,  JSExternalString) \
    D(FAT_INLINE_ATOM,     String,        js::FatInlineAtom, js::FatInlineAtom) \
    D(ATOM,                String,        js::NormalAtom,    js::NormalAtom) \
    D(SYMBOL,              Symbol,        JS::Symbol,        JS::Symbol) \
    D(JITCODE,             JitCode,       js::jit::JitCode,  js::jit::JitCode) \
    D(SCOPE,               Scope,         js::Scope,         js::Scope) \
    D(REGEXP_SHARED,       RegExpShared,  js::RegExpShared,  js::RegExpShared)

#define FOR_EACH_ALLOCKIND(D) \
    FOR_EACH_OBJECT_ALLOCKIND(D) \
    FOR_EACH_NONOBJECT_ALLOCKIND(D)

static_assert(int(AllocKind::FIRST) == 0, "Various places depend on AllocKind starting at 0, "
                                          "please audit them carefully!");
static_assert(int(AllocKind::OBJECT_FIRST) == 0, "Various places depend on AllocKind::OBJECT_FIRST "
                                                 "being 0, please audit them carefully!");

inline bool
IsAllocKind(AllocKind kind)
{
    return kind >= AllocKind::FIRST && kind <= AllocKind::LIMIT;
}

inline bool
IsValidAllocKind(AllocKind kind)
{
    return kind >= AllocKind::FIRST && kind <= AllocKind::LAST;
}

inline bool
IsObjectAllocKind(AllocKind kind)
{
    return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
}

inline bool
IsShapeAllocKind(AllocKind kind)
{
    return kind == AllocKind::SHAPE || kind == AllocKind::ACCESSOR_SHAPE;
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all alloc kinds.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT))
AllAllocKinds()
{
    return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all object alloc kinds.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT))
ObjectAllocKinds()
{
    return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over alloc kinds from |first| to |limit|, exclusive.
inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT))
SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT)
{
    MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!");
    MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!");
    return mozilla::MakeEnumeratedRange(first, limit);
}

// AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular alloc kind.
template<typename ValueType> using AllAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;

// ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular object alloc kind.
template<typename ValueType> using ObjectAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;

static inline JS::TraceKind
MapAllocToTraceKind(AllocKind kind)
{
    static const JS::TraceKind map[] = {
#define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType) \
        JS::TraceKind::traceKind,
FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
#undef EXPAND_ELEMENT
    };

    static_assert(MOZ_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT),
                  "AllocKind-to-TraceKind mapping must be in sync");
    return map[size_t(kind)];
}

/*
 * This must be an upper bound, but we do not need the least upper bound, so
 * we just exclude non-background objects.
 */
static const size_t MAX_BACKGROUND_FINALIZE_KINDS =
    size_t(AllocKind::LIMIT) - size_t(AllocKind::OBJECT_LIMIT) / 2;

/* Cells are aligned to CellAlignShift, so the largest tagged null pointer is: */
const uintptr_t LargestTaggedNullCellPointer = (1 << CellAlignShift) - 1;

Loading