GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/aliased_buffer.h Lines: 85 85 100.0 %
Date: 2019-01-07 12:15:22 Branches: 40 64 62.5 %

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
41092
  AliasedBuffer(v8::Isolate* isolate, const size_t count)
31
      : isolate_(isolate),
32
        count_(count),
33
        byte_offset_(0),
34
82184
        free_buffer_(true) {
35




41092
    CHECK_GT(count, 0);
36
41092
    const v8::HandleScope handle_scope(isolate_);
37
38
41092
    const size_t size_in_bytes = sizeof(NativeT) * count;
39
40
    // allocate native buffer
41
41092
    buffer_ = Calloc<NativeT>(count);
42
43
    // allocate v8 ArrayBuffer
44
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
45
41092
        isolate_, buffer_, size_in_bytes);
46
47
    // allocate v8 TypedArray
48
41092
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
49
82184
    js_array_ = v8::Global<V8T>(isolate, js_array);
50
41092
  }
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
8838
  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
17676
        free_buffer_(false) {
70
8838
    const v8::HandleScope handle_scope(isolate_);
71
72
8838
    v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
73
74
    // validate that the byte_offset is aligned with sizeof(NativeT)
75


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


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








45419
    if (free_buffer_ && buffer_ != nullptr) {
97
37274
      free(buffer_);
98
    }
99
45419
    js_array_.Reset();
100
90838
  }
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
21338284
    Reference(AliasedBuffer<NativeT, V8T>* aliased_buffer, size_t index)
124
        : aliased_buffer_(aliased_buffer),
125
21338284
          index_(index) {
126
21338284
    }
127
128
1
    Reference(const Reference& that)
129
        : aliased_buffer_(that.aliased_buffer_),
130
1
          index_(that.index_) {
131
1
    }
132
133
7606621
    inline Reference& operator=(const NativeT& val) {
134
7606621
      aliased_buffer_->SetValue(index_, val);
135
7606621
      return *this;
136
    }
137
138
2965199
    inline Reference& operator=(const Reference& val) {
139
2965199
      return *this = static_cast<NativeT>(val);
140
    }
141
142
12555378
    operator NativeT() const {
143
12555378
      return aliased_buffer_->GetValue(index_);
144
    }
145
146
1085233
    inline Reference& operator+=(const NativeT& val) {
147
1085233
      const NativeT current = aliased_buffer_->GetValue(index_);
148
1085234
      aliased_buffer_->SetValue(index_, current + val);
149
1085232
      return *this;
150
    }
151
152
1
    inline Reference& operator+=(const Reference& val) {
153
1
      return this->operator+=(static_cast<NativeT>(val));
154
    }
155
156
91183
    inline Reference& operator-=(const NativeT& val) {
157
91183
      const NativeT current = aliased_buffer_->GetValue(index_);
158
91183
      aliased_buffer_->SetValue(index_, current - val);
159
91183
      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
229666
  v8::Local<V8T> GetJSArray() const {
171
459331
    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
8838
  v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
179
17676
    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
8934
  inline const NativeT* GetNativeBuffer() const {
187
8934
    return buffer_;
188
  }
189
190
  /**
191
   *  Synonym for GetBuffer()
192
   */
193
48
  inline const NativeT* operator * () const {
194
48
    return GetNativeBuffer();
195
  }
196
197
  /**
198
   *  Set position index to given value.
199
   */
200
11199864
  inline void SetValue(const size_t index, NativeT value) {
201
    DCHECK_LT(index, count_);
202
11199864
    buffer_[index] = value;
203
11199864
  }
204
205
  /**
206
   *  Get value at position index
207
   */
208
15943439
  inline const NativeT GetValue(const size_t index) const {
209
    DCHECK_LT(index, count_);
210
15943439
    return buffer_[index];
211
  }
212
213
  /**
214
   *  Effectively, a synonym for GetValue/SetValue
215
   */
216
21338279
  Reference operator[](size_t index) {
217
21338279
    return Reference(this, index);
218
  }
219
220
2208597
  NativeT operator[](size_t index) const {
221
2208597
    return GetValue(index);
222
  }
223
224
767310
  size_t Length() const {
225
767310
    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_