GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/aliased_buffer.h Lines: 74 74 100.0 %
Date: 2019-02-13 22:28:58 Branches: 21 38 55.3 %

Line Branch Exec Source
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 "v8.h"
7
#include "util-inl.h"
8
9
namespace node {
10
11
/**
12
 * This class encapsulates the technique of having a native buffer mapped to
13
 * a JS object. Writes to the native buffer can happen efficiently without
14
 * going through JS, and the data is then available to user's via the exposed
15
 * JS object.
16
 *
17
 * While this technique is computationally efficient, it is effectively a
18
 * write to JS program state w/out going through the standard
19
 * (monitored) API. Thus any VM capabilities to detect the modification are
20
 * circumvented.
21
 *
22
 * The encapsulation herein provides a placeholder where such writes can be
23
 * observed. Any notification APIs will be left as a future exercise.
24
 */
25
template <class NativeT, class V8T,
26
          // SFINAE NativeT to be scalar
27
          typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
28
class AliasedBuffer {
29
 public:
30
49146
  AliasedBuffer(v8::Isolate* isolate, const size_t count)
31
      : isolate_(isolate),
32
        count_(count),
33
        byte_offset_(0),
34
98292
        free_buffer_(true) {
35


49146
    CHECK_GT(count, 0);
36
49146
    const v8::HandleScope handle_scope(isolate_);
37
38
49146
    const size_t size_in_bytes = sizeof(NativeT) * count;
39
40
    // allocate native buffer
41
49146
    buffer_ = Calloc<NativeT>(count);
42
43
    // allocate v8 ArrayBuffer
44
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
45
49146
        isolate_, buffer_, size_in_bytes);
46
47
    // allocate v8 TypedArray
48
49146
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
49
98292
    js_array_ = v8::Global<V8T>(isolate, js_array);
50
49146
  }
51
52
  /**
53
   * Create an AliasedBuffer over a sub-region of another aliased buffer.
54
   * The two will share a v8::ArrayBuffer instance &
55
   * a native buffer, but will each read/write to different sections of the
56
   * native buffer.
57
   *
58
   *  Note that byte_offset must by aligned by sizeof(NativeT).
59
   */
60
  // TODO(refack): refactor into a non-owning `AliasedBufferView`
61
10360
  AliasedBuffer(v8::Isolate* isolate,
62
                const size_t byte_offset,
63
                const size_t count,
64
                const AliasedBuffer<uint8_t,
65
                v8::Uint8Array>& backing_buffer)
66
      : isolate_(isolate),
67
        count_(count),
68
        byte_offset_(byte_offset),
69
20720
        free_buffer_(false) {
70
10360
    const v8::HandleScope handle_scope(isolate_);
71
72
10360
    v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
73
74
    // validate that the byte_offset is aligned with sizeof(NativeT)
75

10360
    CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
76
    // validate this fits inside the backing buffer
77

20720
    CHECK_LE(sizeof(NativeT) * count,  ab->ByteLength() - byte_offset);
78
79
10360
    buffer_ = reinterpret_cast<NativeT*>(
80
10360
        const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
81
82
10360
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
83
20720
    js_array_ = v8::Global<V8T>(isolate, js_array);
84
10360
  }
85
86
  AliasedBuffer(const AliasedBuffer& that)
87
      : isolate_(that.isolate_),
88
        count_(that.count_),
89
        byte_offset_(that.byte_offset_),
90
        buffer_(that.buffer_),
91
        free_buffer_(false) {
92
    js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
93
  }
94
95
54722
  ~AliasedBuffer() {
96





54722
    if (free_buffer_ && buffer_ != nullptr) {
97
45098
      free(buffer_);
98
    }
99
54722
    js_array_.Reset();
100
109444
  }
101
102
  AliasedBuffer& operator=(AliasedBuffer&& that) noexcept {
103
    this->~AliasedBuffer();
104
    isolate_ = that.isolate_;
105
    count_ = that.count_;
106
    byte_offset_ = that.byte_offset_;
107
    buffer_ = that.buffer_;
108
    free_buffer_ = that.free_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
  /**
118
   * Helper class that is returned from operator[] to support assignment into
119
   * a specified location.
120
   */
121
  class Reference {
122
   public:
123
35525339
    Reference(AliasedBuffer<NativeT, V8T>* aliased_buffer, size_t index)
124
        : aliased_buffer_(aliased_buffer),
125
35525339
          index_(index) {
126
35525339
    }
127
128
    Reference(const Reference& that)
129
        : aliased_buffer_(that.aliased_buffer_),
130
          index_(that.index_) {
131
    }
132
133
12854763
    inline Reference& operator=(const NativeT& val) {
134
12854763
      aliased_buffer_->SetValue(index_, val);
135
12854764
      return *this;
136
    }
137
138
4833560
    inline Reference& operator=(const Reference& val) {
139
4833560
      return *this = static_cast<NativeT>(val);
140
    }
141
142
20831254
    operator NativeT() const {
143
20831254
      return aliased_buffer_->GetValue(index_);
144
    }
145
146
1746672
    inline Reference& operator+=(const NativeT& val) {
147
1746672
      const NativeT current = aliased_buffer_->GetValue(index_);
148
1746673
      aliased_buffer_->SetValue(index_, current + val);
149
1746673
      return *this;
150
    }
151
152
    inline Reference& operator+=(const Reference& val) {
153
      return this->operator+=(static_cast<NativeT>(val));
154
    }
155
156
92469
    inline Reference& operator-=(const NativeT& val) {
157
92469
      const NativeT current = aliased_buffer_->GetValue(index_);
158
92469
      aliased_buffer_->SetValue(index_, current - val);
159
92469
      return *this;
160
    }
161
162
   private:
163
    AliasedBuffer<NativeT, V8T>* aliased_buffer_;
164
    size_t index_;
165
  };
166
167
  /**
168
   *  Get the underlying v8 TypedArray overlayed on top of the native buffer
169
   */
170
644225
  v8::Local<V8T> GetJSArray() const {
171
1288450
    return js_array_.Get(isolate_);
172
  }
173
174
  /**
175
  *  Get the underlying v8::ArrayBuffer underlying the TypedArray and
176
  *  overlaying the native buffer
177
  */
178
10360
  v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
179
20720
    return GetJSArray()->Buffer();
180
  }
181
182
  /**
183
   *  Get the underlying native buffer. Note that all reads/writes should occur
184
   *  through the GetValue/SetValue/operator[] methods
185
   */
186
10360
  inline const NativeT* GetNativeBuffer() const {
187
10360
    return buffer_;
188
  }
189
190
  /**
191
   *  Synonym for GetBuffer()
192
   */
193
  inline const NativeT* operator * () const {
194
    return GetNativeBuffer();
195
  }
196
197
  /**
198
   *  Set position index to given value.
199
   */
200
22997903
  inline void SetValue(const size_t index, NativeT value) {
201
    DCHECK_LT(index, count_);
202
22997903
    buffer_[index] = value;
203
22997903
  }
204
205
  /**
206
   *  Get value at position index
207
   */
208
25796631
  inline const NativeT GetValue(const size_t index) const {
209
    DCHECK_LT(index, count_);
210
25796631
    return buffer_[index];
211
  }
212
213
  /**
214
   *  Effectively, a synonym for GetValue/SetValue
215
   */
216
35525349
  Reference operator[](size_t index) {
217
35525349
    return Reference(this, index);
218
  }
219
220
3052847
  NativeT operator[](size_t index) const {
221
3052847
    return GetValue(index);
222
  }
223
224
1239809
  size_t Length() const {
225
1239809
    return count_;
226
  }
227
228
  // Should only be used to extend the array.
229
  // Should only be used on an owning array, not one created as a sub array of
230
  // an owning `AliasedBuffer`.
231
8
  void reserve(size_t new_capacity) {
232
    DCHECK_GE(new_capacity, count_);
233
    DCHECK_EQ(byte_offset_, 0);
234
    DCHECK(free_buffer_);
235
8
    const v8::HandleScope handle_scope(isolate_);
236
237
8
    const size_t old_size_in_bytes = sizeof(NativeT) * count_;
238
8
    const size_t new_size_in_bytes = sizeof(NativeT) * new_capacity;
239
240
    // allocate new native buffer
241
8
    NativeT* new_buffer = Calloc<NativeT>(new_capacity);
242
    // copy old content
243
8
    memcpy(new_buffer, buffer_, old_size_in_bytes);
244
245
    // allocate v8 new ArrayBuffer
246
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
247
8
        isolate_, new_buffer, new_size_in_bytes);
248
249
    // allocate v8 TypedArray
250
8
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, new_capacity);
251
252
    // move over old v8 TypedArray
253
24
    js_array_ = std::move(v8::Global<V8T>(isolate_, js_array));
254
255
    // Free old buffer and set new values
256
8
    free(buffer_);
257
8
    buffer_ = new_buffer;
258
8
    count_ = new_capacity;
259
8
  }
260
261
 private:
262
  v8::Isolate* isolate_;
263
  size_t count_;
264
  size_t byte_offset_;
265
  NativeT* buffer_;
266
  v8::Global<V8T> js_array_;
267
  bool free_buffer_;
268
};
269
}  // namespace node
270
271
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
272
273
#endif  // SRC_ALIASED_BUFFER_H_