diff options
Diffstat (limited to 'js/src/gc/GCArray.h')
-rw-r--r-- | js/src/gc/GCArray.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/js/src/gc/GCArray.h b/js/src/gc/GCArray.h new file mode 100644 index 0000000000..abd940037d --- /dev/null +++ b/js/src/gc/GCArray.h @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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 js_GCArray_h +#define js_GCArray_h + +#include "mozilla/Assertions.h" + +#include "gc/Barrier.h" +#include "gc/Tracer.h" +#include "js/Value.h" + +namespace js { + +/* + * A fixed size array of |T| for use with GC things. + * + * Must be allocated manually to allow space for the trailing elements + * data. Call bytesRequired to get the required allocation size. + * + * Does not provide any barriers by default. + */ +template <typename T> +class GCArray { + const uint32_t size_; + T elements_[1]; + + public: + explicit GCArray(uint32_t size) : size_(size) { + // The array contents following the first element are not initialized. + } + + uint32_t size() const { return size_; } + + const T& operator[](uint32_t i) const { + MOZ_ASSERT(i < size_); + return elements_[i]; + } + T& operator[](uint32_t i) { + MOZ_ASSERT(i < size_); + return elements_[i]; + } + + const T* begin() const { return elements_; } + T* begin() { return elements_; } + const T* end() const { return elements_ + size_; } + T* end() { return elements_ + size_; } + + void trace(JSTracer* trc) { + TraceRange(trc, size(), begin(), "array element"); + } + + static constexpr ptrdiff_t offsetOfElements() { + return offsetof(GCArray, elements_); + } + + static size_t bytesRequired(size_t size) { + return offsetOfElements() + std::max(size, size_t(1)) * sizeof(T); + } +}; + +/* + * A fixed size array of GC things owned by a GC thing. + * + * Uses the appropriate barriers depending on whether the owner is in the + * nursery or the tenured heap. If the owner cannot be allocated in the nursery + * then this class is not required. + */ +template <typename T> +class GCOwnedArray { + using StorageType = GCArray<PreAndPostBarrierWrapper<T>>; + using TenuredInterface = StorageType; + using NurseryInterface = GCArray<PreBarrierWrapper<T>>; + + StorageType array; + + public: + explicit GCOwnedArray(uint32_t size) : array(size) {} + + uint32_t size() const { return array.size(); } + const T& operator[](uint32_t i) const { return array[i].get(); } + + // Apply |f| to a view of the data with appropriate barriers given |owner|. + template <typename F> + void withOwner(gc::Cell* owner, F&& f) { + if (gc::IsInsideNursery(owner)) { + f(nurseryOwned()); + } else { + f(tenuredOwned()); + } + } + + // For convenience, special case setElement. + void setElement(gc::Cell* owner, uint32_t i, const T& newValue) { + withOwner(owner, [&](auto& self) { self[i] = newValue; }); + } + + void trace(JSTracer* trc) { array.trace(trc); } + + static constexpr ptrdiff_t offsetOfElements() { + return offsetof(GCOwnedArray, array) + StorageType::offsetOfElements(); + } + + static size_t bytesRequired(size_t size) { + return offsetof(GCOwnedArray, array) + StorageType::bytesRequired(size); + } + + private: + TenuredInterface& tenuredOwned() { return array; } + NurseryInterface& nurseryOwned() { + return reinterpret_cast<NurseryInterface&>(array); + } +}; + +} // namespace js + +#endif // js_GCArray_h |