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