xref: /third_party/node/src/aliased_buffer-inl.h (revision 1cb0ef41)
1#ifndef SRC_ALIASED_BUFFER_INL_H_
2#define SRC_ALIASED_BUFFER_INL_H_
3
4#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6#include "aliased_buffer.h"
7#include "util-inl.h"
8
9namespace node {
10
11typedef size_t AliasedBufferIndex;
12
13template <typename NativeT, typename V8T>
14AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
15    v8::Isolate* isolate, const size_t count, const AliasedBufferIndex* index)
16    : isolate_(isolate), count_(count), byte_offset_(0), index_(index) {
17  CHECK_GT(count, 0);
18  if (index != nullptr) {
19    // Will be deserialized later.
20    return;
21  }
22  const v8::HandleScope handle_scope(isolate_);
23  const size_t size_in_bytes =
24      MultiplyWithOverflowCheck(sizeof(NativeT), count);
25
26  // allocate v8 ArrayBuffer
27  v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate_, size_in_bytes);
28  buffer_ = static_cast<NativeT*>(ab->Data());
29
30  // allocate v8 TypedArray
31  v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
32  js_array_ = v8::Global<V8T>(isolate, js_array);
33}
34
35template <typename NativeT, typename V8T>
36AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
37    v8::Isolate* isolate,
38    const size_t byte_offset,
39    const size_t count,
40    const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
41    const AliasedBufferIndex* index)
42    : isolate_(isolate),
43      count_(count),
44      byte_offset_(byte_offset),
45      index_(index) {
46  if (index != nullptr) {
47    // Will be deserialized later.
48    return;
49  }
50  const v8::HandleScope handle_scope(isolate_);
51  v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
52
53  // validate that the byte_offset is aligned with sizeof(NativeT)
54  CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
55  // validate this fits inside the backing buffer
56  CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count),
57           ab->ByteLength() - byte_offset);
58
59  buffer_ = reinterpret_cast<NativeT*>(
60      const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
61
62  v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
63  js_array_ = v8::Global<V8T>(isolate, js_array);
64}
65
66template <typename NativeT, typename V8T>
67AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
68    const AliasedBufferBase& that)
69    : isolate_(that.isolate_),
70      count_(that.count_),
71      byte_offset_(that.byte_offset_),
72      buffer_(that.buffer_) {
73  DCHECK_NULL(index_);
74  js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
75}
76
77template <typename NativeT, typename V8T>
78AliasedBufferIndex AliasedBufferBase<NativeT, V8T>::Serialize(
79    v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
80  DCHECK_NULL(index_);
81  return creator->AddData(context, GetJSArray());
82}
83
84template <typename NativeT, typename V8T>
85inline void AliasedBufferBase<NativeT, V8T>::Deserialize(
86    v8::Local<v8::Context> context) {
87  DCHECK_NOT_NULL(index_);
88  v8::Local<V8T> arr =
89      context->GetDataFromSnapshotOnce<V8T>(*index_).ToLocalChecked();
90  // These may not hold true for AliasedBuffers that have grown, so should
91  // be removed when we expand the snapshot support.
92  DCHECK_EQ(count_, arr->Length());
93  DCHECK_EQ(byte_offset_, arr->ByteOffset());
94  uint8_t* raw = static_cast<uint8_t*>(arr->Buffer()->Data());
95  buffer_ = reinterpret_cast<NativeT*>(raw + byte_offset_);
96  js_array_.Reset(isolate_, arr);
97  index_ = nullptr;
98}
99
100template <typename NativeT, typename V8T>
101AliasedBufferBase<NativeT, V8T>& AliasedBufferBase<NativeT, V8T>::operator=(
102    AliasedBufferBase<NativeT, V8T>&& that) noexcept {
103  DCHECK_NULL(index_);
104  this->~AliasedBufferBase();
105  isolate_ = that.isolate_;
106  count_ = that.count_;
107  byte_offset_ = that.byte_offset_;
108  buffer_ = that.buffer_;
109
110  js_array_.Reset(isolate_, that.js_array_.Get(isolate_));
111
112  that.buffer_ = nullptr;
113  that.js_array_.Reset();
114  return *this;
115}
116
117template <typename NativeT, typename V8T>
118v8::Local<V8T> AliasedBufferBase<NativeT, V8T>::GetJSArray() const {
119  DCHECK_NULL(index_);
120  return js_array_.Get(isolate_);
121}
122
123template <typename NativeT, typename V8T>
124void AliasedBufferBase<NativeT, V8T>::Release() {
125  DCHECK_NULL(index_);
126  js_array_.Reset();
127}
128
129template <typename NativeT, typename V8T>
130v8::Local<v8::ArrayBuffer> AliasedBufferBase<NativeT, V8T>::GetArrayBuffer()
131    const {
132  return GetJSArray()->Buffer();
133}
134
135template <typename NativeT, typename V8T>
136inline const NativeT* AliasedBufferBase<NativeT, V8T>::GetNativeBuffer() const {
137  DCHECK_NULL(index_);
138  return buffer_;
139}
140
141template <typename NativeT, typename V8T>
142inline const NativeT* AliasedBufferBase<NativeT, V8T>::operator*() const {
143  return GetNativeBuffer();
144}
145
146template <typename NativeT, typename V8T>
147inline void AliasedBufferBase<NativeT, V8T>::SetValue(const size_t index,
148                                                      NativeT value) {
149  DCHECK_LT(index, count_);
150  DCHECK_NULL(index_);
151  buffer_[index] = value;
152}
153
154template <typename NativeT, typename V8T>
155inline const NativeT AliasedBufferBase<NativeT, V8T>::GetValue(
156    const size_t index) const {
157  DCHECK_NULL(index_);
158  DCHECK_LT(index, count_);
159  return buffer_[index];
160}
161
162template <typename NativeT, typename V8T>
163typename AliasedBufferBase<NativeT, V8T>::Reference
164AliasedBufferBase<NativeT, V8T>::operator[](size_t index) {
165  DCHECK_NULL(index_);
166  return Reference(this, index);
167}
168
169template <typename NativeT, typename V8T>
170NativeT AliasedBufferBase<NativeT, V8T>::operator[](size_t index) const {
171  return GetValue(index);
172}
173
174template <typename NativeT, typename V8T>
175size_t AliasedBufferBase<NativeT, V8T>::Length() const {
176  return count_;
177}
178
179template <typename NativeT, typename V8T>
180void AliasedBufferBase<NativeT, V8T>::reserve(size_t new_capacity) {
181  DCHECK_NULL(index_);
182  DCHECK_GE(new_capacity, count_);
183  DCHECK_EQ(byte_offset_, 0);
184  const v8::HandleScope handle_scope(isolate_);
185
186  const size_t old_size_in_bytes = sizeof(NativeT) * count_;
187  const size_t new_size_in_bytes =
188      MultiplyWithOverflowCheck(sizeof(NativeT), new_capacity);
189
190  // allocate v8 new ArrayBuffer
191  v8::Local<v8::ArrayBuffer> ab =
192      v8::ArrayBuffer::New(isolate_, new_size_in_bytes);
193
194  // allocate new native buffer
195  NativeT* new_buffer = static_cast<NativeT*>(ab->Data());
196  // copy old content
197  memcpy(new_buffer, buffer_, old_size_in_bytes);
198
199  // allocate v8 TypedArray
200  v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, new_capacity);
201
202  // move over old v8 TypedArray
203  js_array_ = std::move(v8::Global<V8T>(isolate_, js_array));
204
205  buffer_ = new_buffer;
206  count_ = new_capacity;
207}
208
209template <typename NativeT, typename V8T>
210inline size_t AliasedBufferBase<NativeT, V8T>::SelfSize() const {
211  return sizeof(*this);
212}
213
214#define VM(NativeT, V8T)                                                       \
215  template <>                                                                  \
216  inline const char* AliasedBufferBase<NativeT, v8::V8T>::MemoryInfoName()     \
217      const {                                                                  \
218    return "Aliased" #V8T;                                                     \
219  }                                                                            \
220  template <>                                                                  \
221  inline void AliasedBufferBase<NativeT, v8::V8T>::MemoryInfo(                 \
222      node::MemoryTracker* tracker) const {                                    \
223    tracker->TrackField("js_array", js_array_);                                \
224  }
225ALIASED_BUFFER_LIST(VM)
226#undef VM
227
228}  // namespace node
229
230#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
231
232#endif  // SRC_ALIASED_BUFFER_INL_H_
233