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 (b6d82b1a6b02)

VCS Links

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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
/* -*- 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 gc_FreeOp_h
#define gc_FreeOp_h

#include "mozilla/Assertions.h"  // MOZ_ASSERT

#include "gc/GCEnum.h"                // js::MemoryUse
#include "jit/ExecutableAllocator.h"  // jit::JitPoisonRangeVector
#include "js/AllocPolicy.h"           // SystemAllocPolicy
#include "js/MemoryFunctions.h"       // JSFreeOp
#include "js/Utility.h"               // AutoEnterOOMUnsafeRegion, js_free
#include "js/Vector.h"                // js::Vector

struct JSRuntime;

namespace js {
namespace gc {
class AutoSetThreadIsPerformingGC;
}  // namespace gc
}  // namespace js

/*
 * A JSFreeOp can do one thing: free memory. For convenience, it has delete_
 * convenience methods that also call destructors.
 *
 * JSFreeOp is passed to finalizers and other sweep-phase hooks so that we do
 * not need to pass a JSContext to those hooks.
 */
class JSFreeOp {
  using Cell = js::gc::Cell;
  using MemoryUse = js::MemoryUse;

  JSRuntime* runtime_;

  // We may accumulate a set of deferred free operations to be performed when
  // the JSFreeOp is destroyed. This only applies to non-default JSFreeOps that
  // are stack allocated and used during GC sweeping.
  js::Vector<void*, 0, js::SystemAllocPolicy> freeLaterList;

  js::jit::JitPoisonRangeVector jitPoisonRanges;

  const bool isDefault;
  bool isCollecting_;

  friend class js::gc::AutoSetThreadIsPerformingGC;

 public:
  explicit JSFreeOp(JSRuntime* maybeRuntime, bool isDefault = false);
  ~JSFreeOp();

  JSRuntime* runtime() const {
    MOZ_ASSERT(runtime_);
    return runtime_;
  }

  bool onMainThread() const { return runtime_ != nullptr; }

  bool maybeOnHelperThread() const {
    // Sometimes background finalization happens on the main thread so
    // runtime_ being null doesn't always mean we are off thread.
    return !runtime_;
  }

  bool isDefaultFreeOp() const { return isDefault; }
  bool isCollecting() const { return isCollecting_; }

  // Deprecated. Where possible, memory should be tracked against the owning GC
  // thing by calling js::AddCellMemory and the memory freed with free_() below.
  void freeUntracked(void* p) { js_free(p); }

  // Free memory associated with a GC thing and update the memory accounting.
  //
  // The memory should have been associated with the GC thing using
  // js::InitReservedSlot or js::InitObjectPrivate, or possibly
  // js::AddCellMemory.
  void free_(Cell* cell, void* p, size_t nbytes, MemoryUse use);

  // Deprecated. Where possible, memory should be tracked against the owning GC
  // thing by calling js::AddCellMemory and the memory freed with freeLater()
  // below.
  void freeUntrackedLater(void* p) { queueForFreeLater(p); }

  // Queue memory that was associated with a GC thing using js::AddCellMemory to
  // be freed when the JSFreeOp is destroyed.
  //
  // This should not be called on the default JSFreeOps returned by
  // JSRuntime/JSContext::defaultFreeOp() since these are not destroyed until
  // the runtime itself is destroyed.
  //
  // This is used to ensure that copy-on-write object elements are not freed
  // until all objects that refer to them have been finalized.
  void freeLater(Cell* cell, void* p, size_t nbytes, MemoryUse use);

  bool appendJitPoisonRange(const js::jit::JitPoisonRange& range) {
    // JSFreeOps other than the defaultFreeOp() are constructed on the stack,
    // and won't hold onto the pointers to free indefinitely.
    MOZ_ASSERT(!isDefaultFreeOp());

    return jitPoisonRanges.append(range);
  }

  // Deprecated. Where possible, memory should be tracked against the owning GC
  // thing by calling js::AddCellMemory and the memory freed with delete_()
  // below.
  template <class T>
  void deleteUntracked(T* p) {
    if (p) {
      p->~T();
      js_free(p);
    }
  }

  // Delete a C++ object that was associated with a GC thing and update the
  // memory accounting. The size is determined by the type T.
  //
  // The memory should have been associated with the GC thing using
  // js::InitReservedSlot or js::InitObjectPrivate, or possibly
  // js::AddCellMemory.
  template <class T>
  void delete_(Cell* cell, T* p, MemoryUse use) {
    delete_(cell, p, sizeof(T), use);
  }

  // Delete a C++ object that was associated with a GC thing and update the
  // memory accounting.
  //
  // The memory should have been associated with the GC thing using
  // js::InitReservedSlot or js::InitObjectPrivate, or possibly
  // js::AddCellMemory.
  template <class T>
  void delete_(Cell* cell, T* p, size_t nbytes, MemoryUse use) {
    if (p) {
      p->~T();
      free_(cell, p, nbytes, use);
    }
  }

  // Release a RefCounted object that was associated with a GC thing and update
  // the memory accounting.
  //
  // The memory should have been associated with the GC thing using
  // js::InitReservedSlot or js::InitObjectPrivate, or possibly
  // js::AddCellMemory.
  //
  // This counts the memory once per association with a GC thing. It's not
  // expected that the same object is associated with more than one GC thing in
  // each zone. If this is the case then some other form of accounting would be
  // more appropriate.
  template <class T>
  void release(Cell* cell, T* p, MemoryUse use) {
    release(cell, p, sizeof(T), use);
  }

  // Release a RefCounted object and that was associated with a GC thing and
  // update the memory accounting.
  //
  // The memory should have been associated with the GC thing using
  // js::InitReservedSlot or js::InitObjectPrivate, or possibly
  // js::AddCellMemory.
  template <class T>
  void release(Cell* cell, T* p, size_t nbytes, MemoryUse use);

  // Update the memory accounting for a GC for memory freed by some other
  // method.
  void removeCellMemory(Cell* cell, size_t nbytes, MemoryUse use);

 private:
  void queueForFreeLater(void* p);
};

#endif  // gc_FreeOp_h