DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (a461fe03fdb0)

VCS Links

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=4 sw=4 et tw=79 ft=cpp:
 *
 * 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_Nursery_inl_h
#define gc_Nursery_inl_h

#include "gc/Nursery.h"

#include "jscntxt.h"

#include "gc/Heap.h"
#include "gc/RelocationOverlay.h"
#include "gc/Zone.h"
#include "js/TracingAPI.h"
#include "vm/Runtime.h"
#include "vm/SharedMem.h"

template<typename T>
bool
js::Nursery::isInside(const SharedMem<T>& p) const
{
    return isInside(p.unwrap(/*safe - used for value in comparison above*/));
}

MOZ_ALWAYS_INLINE /* static */ bool
js::Nursery::getForwardedPointer(JSObject** ref)
{
    MOZ_ASSERT(ref);
    MOZ_ASSERT(IsInsideNursery(*ref));
    const gc::RelocationOverlay* overlay = reinterpret_cast<const gc::RelocationOverlay*>(*ref);
    if (!overlay->isForwarded())
        return false;
    *ref = static_cast<JSObject*>(overlay->forwardingAddress());
    return true;
}

inline void
js::Nursery::maybeSetForwardingPointer(JSTracer* trc, void* oldData, void* newData, bool direct)
{
    if (trc->isTenuringTracer())
        setForwardingPointerWhileTenuring(oldData, newData, direct);
}

inline void
js::Nursery::setForwardingPointerWhileTenuring(void* oldData, void* newData, bool direct)
{
    if (isInside(oldData))
        setForwardingPointer(oldData, newData, direct);
}

inline void
js::Nursery::setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots, uint32_t nslots)
{
    // Slot arrays always have enough space for a forwarding pointer, since the
    // number of slots is never zero.
    MOZ_ASSERT(nslots > 0);
    setDirectForwardingPointer(oldSlots, newSlots);
}

inline void
js::Nursery::setElementsForwardingPointer(ObjectElements* oldHeader, ObjectElements* newHeader,
                                          uint32_t capacity)
{
    // Only use a direct forwarding pointer if there is enough space for one.
    setForwardingPointer(oldHeader->elements(), newHeader->elements(),
                         capacity > 0);
}

inline void
js::Nursery::setForwardingPointer(void* oldData, void* newData, bool direct)
{
    if (direct) {
        setDirectForwardingPointer(oldData, newData);
        return;
    }

    setIndirectForwardingPointer(oldData, newData);
}

inline void
js::Nursery::setDirectForwardingPointer(void* oldData, void* newData)
{
    MOZ_ASSERT(isInside(oldData));

    // Bug 1196210: If a zero-capacity header lands in the last 2 words of a
    // jemalloc chunk abutting the start of a nursery chunk, the (invalid)
    // newData pointer will appear to be "inside" the nursery.
    MOZ_ASSERT(!isInside(newData) || (uintptr_t(newData) & js::gc::ChunkMask) == 0);

    *reinterpret_cast<void**>(oldData) = newData;
}

namespace js {

// The allocation methods below will not run the garbage collector. If the
// nursery cannot accomodate the allocation, the malloc heap will be used
// instead.

template <typename T>
static inline T*
AllocateObjectBuffer(JSContext* cx, uint32_t count)
{
    size_t nbytes = JS_ROUNDUP(count * sizeof(T), sizeof(Value));
    T* buffer = static_cast<T*>(cx->nursery().allocateBuffer(cx->zone(), nbytes));
    if (!buffer)
        ReportOutOfMemory(cx);
    return buffer;
}

template <typename T>
static inline T*
AllocateObjectBuffer(JSContext* cx, JSObject* obj, uint32_t count)
{
    if (cx->helperThread())
        return cx->zone()->pod_malloc<T>(count);
    size_t nbytes = JS_ROUNDUP(count * sizeof(T), sizeof(Value));
    T* buffer = static_cast<T*>(cx->nursery().allocateBuffer(obj, nbytes));
    if (!buffer)
        ReportOutOfMemory(cx);
    return buffer;
}

// If this returns null then the old buffer will be left alone.
template <typename T>
static inline T*
ReallocateObjectBuffer(JSContext* cx, JSObject* obj, T* oldBuffer,
                       uint32_t oldCount, uint32_t newCount)
{
    if (cx->helperThread())
        return obj->zone()->pod_realloc<T>(oldBuffer, oldCount, newCount);
    T* buffer =  static_cast<T*>(cx->nursery().reallocateBuffer(obj, oldBuffer,
                                                                oldCount * sizeof(T),
                                                                newCount * sizeof(T)));
    if (!buffer)
        ReportOutOfMemory(cx);
    return buffer;
}

static inline void
EvictAllNurseries(JSRuntime* rt, JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY)
{
    rt->gc.evictNursery(reason);
}

} // namespace js

#endif /* gc_Nursery_inl_h */