tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Allocator.h (8148B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // SpiderMonkey GC allocation API.
      8 
      9 #ifndef gc_Allocator_h
     10 #define gc_Allocator_h
     11 
     12 #include "gc/AllocKind.h"
     13 #include "gc/GCEnum.h"
     14 #include "js/HeapAPI.h"
     15 #include "js/TypeDecls.h"
     16 
     17 namespace js {
     18 namespace gc {
     19 
     20 class AllocSite;
     21 struct Cell;
     22 class BufferAllocator;
     23 class TenuredCell;
     24 class TenuringTracer;
     25 
     26 // Allocator implementation functions. SpiderMonkey code outside this file
     27 // should use:
     28 //
     29 //     cx->newCell<T>(...)
     30 //
     31 // or optionally:
     32 //
     33 //     cx->newCell<T, AllowGC::NoGC>(...)
     34 //
     35 // `friend` js::gc::CellAllocator in a subtype T of Cell in order to allow it to
     36 // be allocated with cx->newCell<T>(...). The friend declaration will allow
     37 // calling T's constructor.
     38 //
     39 // The parameters will be passed to a type-specific function or constructor. For
     40 // nursery-allocatable types, see e.g. the NewString, NewObject, and NewBigInt
     41 // methods. For all other types, the parameters will be forwarded to the
     42 // constructor.
     43 class CellAllocator {
     44 public:
     45  // This is the entry point for all allocation, though callers should still not
     46  // use this directly. Use cx->newCell<T>(...) instead.
     47  //
     48  // After a successful allocation the caller must fully initialize the thing
     49  // before calling any function that can potentially trigger GC. This will
     50  // ensure that GC tracing never sees junk values stored in the partially
     51  // initialized thing.
     52  template <typename T, AllowGC allowGC = CanGC, typename... Args>
     53  static inline T* NewCell(JSContext* cx, Args&&... args);
     54  friend class BufferAllocator;
     55 
     56 private:
     57  // Allocate a string. Use cx->newCell<T>([heap]).
     58  //
     59  // Use for nursery-allocatable strings. Returns a value cast to the correct
     60  // type. Non-nursery-allocatable strings will go through the fallback
     61  // tenured-only allocation path.
     62  template <typename T, AllowGC allowGC, typename... Args>
     63  static T* NewString(JSContext* cx, Heap heap, Args&&... args);
     64 
     65  template <typename T, AllowGC allowGC>
     66  static T* NewBigInt(JSContext* cx, Heap heap);
     67 
     68  template <typename T, AllowGC allowGC, typename... Args>
     69  static T* NewGetterSetter(JSContext* cx, Heap heap, Args&&... args);
     70 
     71  template <typename T, AllowGC allowGC>
     72  static T* NewObject(JSContext* cx, AllocKind kind, Heap heap,
     73                      const JSClass* clasp, AllocSite* site = nullptr);
     74 
     75  // Allocate all other kinds of GC thing.
     76  template <typename T, AllowGC allowGC, typename... Args>
     77  static T* NewTenuredCell(JSContext* cx, Args&&... args);
     78 
     79  // Allocate a cell in the nursery, unless |heap| is Heap::Tenured or nursery
     80  // allocation is disabled for |traceKind| in the current zone.
     81  template <JS::TraceKind traceKind, AllowGC allowGC>
     82  static void* AllocNurseryOrTenuredCell(JSContext* cx, AllocKind allocKind,
     83                                         size_t thingSize, Heap heap,
     84                                         AllocSite* site);
     85  friend class TenuringTracer;
     86 
     87  template <AllowGC allowGC>
     88  static void* RetryNurseryAlloc(JSContext* cx, JS::TraceKind traceKind,
     89                                 AllocKind allocKind, size_t thingSize,
     90                                 AllocSite* site);
     91  template <AllowGC allowGC>
     92  static void* AllocTenuredCellForNurseryAlloc(JSContext* cx, AllocKind kind);
     93 
     94  // Allocate a cell in the tenured heap.
     95  template <AllowGC allowGC>
     96  static void* AllocTenuredCell(JSContext* cx, AllocKind kind);
     97 
     98  template <AllowGC allowGC>
     99  static void* AllocTenuredCellUnchecked(JS::Zone* zone, AllocKind kind);
    100 
    101  static void* RetryTenuredAlloc(JS::Zone* zone, AllocKind kind);
    102 
    103 #ifdef JS_GC_ZEAL
    104  static AllocSite* MaybeGenerateMissingAllocSite(JSContext* cx,
    105                                                  JS::TraceKind traceKind,
    106                                                  AllocSite* site);
    107 #endif
    108 
    109 #ifdef DEBUG
    110  static void CheckIncrementalZoneState(JS::Zone* zone, void* ptr);
    111 #endif
    112 
    113  static inline Heap CheckedHeap(Heap heap);
    114 };
    115 
    116 // Buffer allocator public API.
    117 
    118 size_t GetGoodAllocSize(size_t requiredBytes);
    119 size_t GetGoodPower2AllocSize(size_t requiredBytes);
    120 size_t GetGoodElementCount(size_t requiredCount, size_t elementSize);
    121 size_t GetGoodPower2ElementCount(size_t requiredCount, size_t elementSize);
    122 void* AllocBuffer(JS::Zone* zone, size_t bytes, bool nurseryOwned);
    123 void* ReallocBuffer(JS::Zone* zone, void* alloc, size_t bytes,
    124                    bool nurseryOwned);
    125 void FreeBuffer(JS::Zone* zone, void* alloc);
    126 
    127 template <typename T, typename... Args>
    128 T* NewBuffer(JS::Zone* zone, size_t bytes, bool nurseryOwned, Args&&... args) {
    129  MOZ_ASSERT(sizeof(T) <= bytes);
    130  void* ptr = AllocBuffer(zone, bytes, nurseryOwned);
    131  if (!ptr) {
    132    return nullptr;
    133  }
    134 
    135  return new (ptr) T(std::forward<Args>(args)...);
    136 }
    137 
    138 // Indicate whether |alloc| is a buffer allocation as opposed to a fixed size GC
    139 // cell. Does not work for malloced memory.
    140 bool IsBufferAlloc(void* alloc);
    141 
    142 #ifdef DEBUG
    143 // Check whether a buffer allocation is part of the specified zone.
    144 bool IsBufferAllocInZone(void* alloc, JS::Zone* zone);
    145 #endif
    146 
    147 bool IsNurseryOwned(JS::Zone* zone, void* alloc);
    148 
    149 size_t GetAllocSize(JS::Zone* zone, const void* alloc);
    150 
    151 // Buffer allocator GC-internal API.
    152 
    153 void* AllocBufferInGC(JS::Zone* zone, size_t bytes, bool nurseryOwned);
    154 bool IsBufferAllocMarkedBlack(JS::Zone* zone, void* alloc);
    155 void TraceBufferEdgeInternal(JSTracer* trc, Cell* owner, void** bufferp,
    156                             const char* name);
    157 void TraceBufferEdgeInternal(JSTracer* trc, JS::Zone* zone, void** bufferp,
    158                             const char* name);
    159 void MarkTenuredBuffer(JS::Zone* zone, void* alloc);
    160 
    161 }  // namespace gc
    162 
    163 // Allow rooting buffers.
    164 
    165 template <typename T>
    166 class MutableHandleBuffer;
    167 
    168 template <typename T>
    169 class BufferHolder {
    170  JS::Zone* zone;
    171  T* buffer;
    172 
    173  friend class MutableHandleBuffer<T>;
    174 
    175 public:
    176  BufferHolder(JS::Zone* zone, T* buffer) : zone(zone), buffer(buffer) {
    177    MOZ_ASSERT_IF(buffer, IsBufferAllocInZone(buffer, zone));
    178  }
    179  inline BufferHolder(JSContext* cx, T* buffer);
    180 
    181  inline void trace(JSTracer* trc);
    182 
    183  T* get() const { return buffer; }
    184  operator T*() const { return get(); }
    185  T* operator->() const { return get(); }
    186  T& operator*() const { return *get(); }
    187 };
    188 
    189 template <typename T>
    190 class RootedBuffer : public JS::Rooted<BufferHolder<T>> {
    191  using Base = JS::Rooted<BufferHolder<T>>;
    192 
    193 public:
    194  RootedBuffer(JSContext* cx, T* buffer)
    195      : Base(cx, BufferHolder<T>(cx, buffer)) {}
    196  T* get() const { return Base::get().get(); }
    197  operator T*() const { return get(); }
    198  T* operator->() const { return get(); }
    199  T& operator*() const { return *get(); }
    200 };
    201 
    202 template <typename T>
    203 class HandleBuffer : public JS::Handle<BufferHolder<T>> {
    204  using Base = JS::Handle<BufferHolder<T>>;
    205 
    206 public:
    207  HandleBuffer(const HandleBuffer& other) : Base(other) {}
    208  MOZ_IMPLICIT HandleBuffer(const RootedBuffer<T>& root) : Base(root) {}
    209  MOZ_IMPLICIT HandleBuffer(JS::MutableHandle<BufferHolder<T>>& handle)
    210      : Base(handle) {}
    211 
    212  T* get() const { return Base::get().get(); }
    213  operator T*() const { return get(); }
    214  T* operator->() const { return get(); }
    215  T& operator*() const { return *get(); }
    216 };
    217 
    218 template <typename T>
    219 class MutableHandleBuffer : public JS::MutableHandle<BufferHolder<T>> {
    220  using Base = JS::MutableHandle<BufferHolder<T>>;
    221 
    222 public:
    223  MutableHandleBuffer(const MutableHandleBuffer& other) : Base(other) {}
    224  MOZ_IMPLICIT MutableHandleBuffer(RootedBuffer<T>* root) : Base(root) {}
    225 
    226  void set(T* buffer) {
    227    BufferHolder<T>& holder = Base::get();
    228    MOZ_ASSERT_IF(buffer, IsBufferAllocInZone(buffer, holder.zone));
    229    holder.buffer = buffer;
    230  }
    231  T* get() const { return Base::get().get(); }
    232  operator T*() const { return get(); }
    233  T* operator->() const { return get(); }
    234  T& operator*() const { return *get(); }
    235 };
    236 
    237 }  // namespace js
    238 
    239 #endif  // gc_Allocator_h