• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SRC_ALIASED_BUFFER_H_
2 #define SRC_ALIASED_BUFFER_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include <cinttypes>
7 #include "memory_tracker.h"
8 #include "v8.h"
9 
10 namespace node {
11 
12 typedef size_t AliasedBufferIndex;
13 
14 /**
15  * Do not use this class directly when creating instances of it - use the
16  * Aliased*Array defined at the end of this file instead.
17  *
18  * This class encapsulates the technique of having a native buffer mapped to
19  * a JS object. Writes to the native buffer can happen efficiently without
20  * going through JS, and the data is then available to user's via the exposed
21  * JS object.
22  *
23  * While this technique is computationally efficient, it is effectively a
24  * write to JS program state w/out going through the standard
25  * (monitored) API. Thus any VM capabilities to detect the modification are
26  * circumvented.
27  *
28  * The encapsulation herein provides a placeholder where such writes can be
29  * observed. Any notification APIs will be left as a future exercise.
30  */
31 template <class NativeT, class V8T>
32 class AliasedBufferBase : public MemoryRetainer {
33  public:
34   static_assert(std::is_scalar<NativeT>::value);
35 
36   AliasedBufferBase(v8::Isolate* isolate,
37                     const size_t count,
38                     const AliasedBufferIndex* index = nullptr);
39 
40   /**
41    * Create an AliasedBufferBase over a sub-region of another aliased buffer.
42    * The two will share a v8::ArrayBuffer instance &
43    * a native buffer, but will each read/write to different sections of the
44    * native buffer.
45    *
46    *  Note that byte_offset must by aligned by sizeof(NativeT).
47    */
48   // TODO(refack): refactor into a non-owning `AliasedBufferBaseView`
49   AliasedBufferBase(
50       v8::Isolate* isolate,
51       const size_t byte_offset,
52       const size_t count,
53       const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
54       const AliasedBufferIndex* index = nullptr);
55 
56   AliasedBufferBase(const AliasedBufferBase& that);
57 
58   AliasedBufferIndex Serialize(v8::Local<v8::Context> context,
59                                v8::SnapshotCreator* creator);
60 
61   inline void Deserialize(v8::Local<v8::Context> context);
62 
63   AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept;
64 
65   /**
66    * Helper class that is returned from operator[] to support assignment into
67    * a specified location.
68    */
69   class Reference {
70    public:
Reference(AliasedBufferBase<NativeT,V8T> * aliased_buffer,size_t index)71     Reference(AliasedBufferBase<NativeT, V8T>* aliased_buffer, size_t index)
72         : aliased_buffer_(aliased_buffer), index_(index) {}
73 
Reference(const Reference & that)74     Reference(const Reference& that)
75         : aliased_buffer_(that.aliased_buffer_),
76           index_(that.index_) {
77     }
78 
79     inline Reference& operator=(const NativeT& val) {
80       aliased_buffer_->SetValue(index_, val);
81       return *this;
82     }
83 
84     inline Reference& operator=(const Reference& val) {
85       return *this = static_cast<NativeT>(val);
86     }
87 
NativeT()88     operator NativeT() const {
89       return aliased_buffer_->GetValue(index_);
90     }
91 
92     inline Reference& operator+=(const NativeT& val) {
93       const NativeT current = aliased_buffer_->GetValue(index_);
94       aliased_buffer_->SetValue(index_, current + val);
95       return *this;
96     }
97 
98     inline Reference& operator+=(const Reference& val) {
99       return this->operator+=(static_cast<NativeT>(val));
100     }
101 
102     inline Reference& operator-=(const NativeT& val) {
103       const NativeT current = aliased_buffer_->GetValue(index_);
104       aliased_buffer_->SetValue(index_, current - val);
105       return *this;
106     }
107 
108    private:
109     AliasedBufferBase<NativeT, V8T>* aliased_buffer_;
110     size_t index_;
111   };
112 
113   /**
114    *  Get the underlying v8 TypedArray overlayed on top of the native buffer
115    */
116   v8::Local<V8T> GetJSArray() const;
117 
118   void Release();
119 
120   /**
121   *  Get the underlying v8::ArrayBuffer underlying the TypedArray and
122   *  overlaying the native buffer
123   */
124   v8::Local<v8::ArrayBuffer> GetArrayBuffer() const;
125 
126   /**
127    *  Get the underlying native buffer. Note that all reads/writes should occur
128    *  through the GetValue/SetValue/operator[] methods
129    */
130   inline const NativeT* GetNativeBuffer() const;
131 
132   /**
133    *  Synonym for GetBuffer()
134    */
135   inline const NativeT* operator*() const;
136 
137   /**
138    *  Set position index to given value.
139    */
140   inline void SetValue(const size_t index, NativeT value);
141 
142   /**
143    *  Get value at position index
144    */
145   inline const NativeT GetValue(const size_t index) const;
146 
147   /**
148    *  Effectively, a synonym for GetValue/SetValue
149    */
150   Reference operator[](size_t index);
151 
152   NativeT operator[](size_t index) const;
153 
154   size_t Length() const;
155 
156   // Should only be used to extend the array.
157   // Should only be used on an owning array, not one created as a sub array of
158   // an owning `AliasedBufferBase`.
159   void reserve(size_t new_capacity);
160 
161   inline size_t SelfSize() const override;
162 
163   inline const char* MemoryInfoName() const override;
164   inline void MemoryInfo(node::MemoryTracker* tracker) const override;
165 
166  private:
167   v8::Isolate* isolate_ = nullptr;
168   size_t count_ = 0;
169   size_t byte_offset_ = 0;
170   NativeT* buffer_ = nullptr;
171   v8::Global<V8T> js_array_;
172 
173   // Deserialize data
174   const AliasedBufferIndex* index_ = nullptr;
175 };
176 
177 #define ALIASED_BUFFER_LIST(V)                                                 \
178   V(int8_t, Int8Array)                                                         \
179   V(uint8_t, Uint8Array)                                                       \
180   V(int16_t, Int16Array)                                                       \
181   V(uint16_t, Uint16Array)                                                     \
182   V(int32_t, Int32Array)                                                       \
183   V(uint32_t, Uint32Array)                                                     \
184   V(float, Float32Array)                                                       \
185   V(double, Float64Array)                                                      \
186   V(int64_t, BigInt64Array)
187 
188 #define V(NativeT, V8T)                                                        \
189   typedef AliasedBufferBase<NativeT, v8::V8T> Aliased##V8T;
190 ALIASED_BUFFER_LIST(V)
191 #undef V
192 
193 }  // namespace node
194 
195 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
196 
197 #endif  // SRC_ALIASED_BUFFER_H_
198