summaryrefslogtreecommitdiffstats
path: root/js/src/gc/GCArray.h
blob: abd940037d13478f2f005e4883e90c9d754f0ede (plain)
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
/* -*- 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