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 
9 namespace node {
10 
11 typedef size_t AliasedBufferIndex;
12 
13 template <typename NativeT, typename V8T>
AliasedBufferBase( v8::Isolate* isolate, const size_t count, const AliasedBufferIndex* index)14 AliasedBufferBase<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 
35 template <typename NativeT, typename V8T>
AliasedBufferBase( v8::Isolate* isolate, const size_t byte_offset, const size_t count, const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer, const AliasedBufferIndex* index)36 AliasedBufferBase<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 
66 template <typename NativeT, typename V8T>
AliasedBufferBase( const AliasedBufferBase& that)67 AliasedBufferBase<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 
77 template <typename NativeT, typename V8T>
Serialize( v8::Local<v8::Context> context, v8::SnapshotCreator* creator)78 AliasedBufferIndex 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 
84 template <typename NativeT, typename V8T>
Deserialize( v8::Local<v8::Context> context)85 inline 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 
100 template <typename NativeT, typename V8T>
101 AliasedBufferBase<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 
117 template <typename NativeT, typename V8T>
GetJSArray() const118 v8::Local<V8T> AliasedBufferBase<NativeT, V8T>::GetJSArray() const {
119   DCHECK_NULL(index_);
120   return js_array_.Get(isolate_);
121 }
122 
123 template <typename NativeT, typename V8T>
Release()124 void AliasedBufferBase<NativeT, V8T>::Release() {
125   DCHECK_NULL(index_);
126   js_array_.Reset();
127 }
128 
129 template <typename NativeT, typename V8T>
GetArrayBuffer() const130 v8::Local<v8::ArrayBuffer> AliasedBufferBase<NativeT, V8T>::GetArrayBuffer()
131     const {
132   return GetJSArray()->Buffer();
133 }
134 
135 template <typename NativeT, typename V8T>
GetNativeBuffer() const136 inline const NativeT* AliasedBufferBase<NativeT, V8T>::GetNativeBuffer() const {
137   DCHECK_NULL(index_);
138   return buffer_;
139 }
140 
141 template <typename NativeT, typename V8T>
operator *() const142 inline const NativeT* AliasedBufferBase<NativeT, V8T>::operator*() const {
143   return GetNativeBuffer();
144 }
145 
146 template <typename NativeT, typename V8T>
SetValue(const size_t index, NativeT value)147 inline 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 
154 template <typename NativeT, typename V8T>
GetValue( const size_t index) const155 inline 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 
162 template <typename NativeT, typename V8T>
163 typename AliasedBufferBase<NativeT, V8T>::Reference
operator [](size_t index)164 AliasedBufferBase<NativeT, V8T>::operator[](size_t index) {
165   DCHECK_NULL(index_);
166   return Reference(this, index);
167 }
168 
169 template <typename NativeT, typename V8T>
operator [](size_t index) const170 NativeT AliasedBufferBase<NativeT, V8T>::operator[](size_t index) const {
171   return GetValue(index);
172 }
173 
174 template <typename NativeT, typename V8T>
Length() const175 size_t AliasedBufferBase<NativeT, V8T>::Length() const {
176   return count_;
177 }
178 
179 template <typename NativeT, typename V8T>
reserve(size_t new_capacity)180 void 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 
209 template <typename NativeT, typename V8T>
SelfSize() const210 inline 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   }
225 ALIASED_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