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: 68 68 100.0 %
Date: 2019-08-17 22:35:23 Branches: 9 18 50.0 %

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


52153
    CHECK_GT(count, 0);
38
52153
    const v8::HandleScope handle_scope(isolate_);
39
    const size_t size_in_bytes =
40
52153
        MultiplyWithOverflowCheck(sizeof(NativeT), count);
41
42
    // allocate v8 ArrayBuffer
43
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
44
52153
        isolate_, size_in_bytes);
45
52153
    buffer_ = static_cast<NativeT*>(ab->GetContents().Data());
46
47
    // allocate v8 TypedArray
48
52153
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
49
104306
    js_array_ = v8::Global<V8T>(isolate, js_array);
50
52153
  }
51
52
  /**
53
   * Create an AliasedBufferBase 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 `AliasedBufferBaseView`
61
11931
  AliasedBufferBase(
62
      v8::Isolate* isolate,
63
      const size_t byte_offset,
64
      const size_t count,
65
      const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer)
66
11931
      : isolate_(isolate), count_(count), byte_offset_(byte_offset) {
67
11931
    const v8::HandleScope handle_scope(isolate_);
68
69
11931
    v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
70
71
    // validate that the byte_offset is aligned with sizeof(NativeT)
72

11931
    CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
73
    // validate this fits inside the backing buffer
74

23862
    CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count),
75
             ab->ByteLength() - byte_offset);
76
77
11931
    buffer_ = reinterpret_cast<NativeT*>(
78
11931
        const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
79
80
11931
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
81
23862
    js_array_ = v8::Global<V8T>(isolate, js_array);
82
11931
  }
83
84
  AliasedBufferBase(const AliasedBufferBase& that)
85
      : isolate_(that.isolate_),
86
        count_(that.count_),
87
        byte_offset_(that.byte_offset_),
88
        buffer_(that.buffer_) {
89
    js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
90
  }
91
92
  AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept {
93
    this->~AliasedBufferBase();
94
    isolate_ = that.isolate_;
95
    count_ = that.count_;
96
    byte_offset_ = that.byte_offset_;
97
    buffer_ = that.buffer_;
98
99
    js_array_.Reset(isolate_, that.js_array_.Get(isolate_));
100
101
    that.buffer_ = nullptr;
102
    that.js_array_.Reset();
103
    return *this;
104
  }
105
106
  /**
107
   * Helper class that is returned from operator[] to support assignment into
108
   * a specified location.
109
   */
110
  class Reference {
111
   public:
112
35855678
    Reference(AliasedBufferBase<NativeT, V8T>* aliased_buffer, size_t index)
113
35855678
        : aliased_buffer_(aliased_buffer), index_(index) {}
114
115
    Reference(const Reference& that)
116
        : aliased_buffer_(that.aliased_buffer_),
117
          index_(that.index_) {
118
    }
119
120
13504487
    inline Reference& operator=(const NativeT& val) {
121
13504487
      aliased_buffer_->SetValue(index_, val);
122
13504543
      return *this;
123
    }
124
125
4911415
    inline Reference& operator=(const Reference& val) {
126
4911415
      return *this = static_cast<NativeT>(val);
127
    }
128
129
20603291
    operator NativeT() const {
130
20603291
      return aliased_buffer_->GetValue(index_);
131
    }
132
133
1636876
    inline Reference& operator+=(const NativeT& val) {
134
1636876
      const NativeT current = aliased_buffer_->GetValue(index_);
135
1636879
      aliased_buffer_->SetValue(index_, current + val);
136
1636882
      return *this;
137
    }
138
139
    inline Reference& operator+=(const Reference& val) {
140
      return this->operator+=(static_cast<NativeT>(val));
141
    }
142
143
112511
    inline Reference& operator-=(const NativeT& val) {
144
112511
      const NativeT current = aliased_buffer_->GetValue(index_);
145
112511
      aliased_buffer_->SetValue(index_, current - val);
146
112511
      return *this;
147
    }
148
149
   private:
150
    AliasedBufferBase<NativeT, V8T>* aliased_buffer_;
151
    size_t index_;
152
  };
153
154
  /**
155
   *  Get the underlying v8 TypedArray overlayed on top of the native buffer
156
   */
157
263235
  v8::Local<V8T> GetJSArray() const {
158
526470
    return js_array_.Get(isolate_);
159
  }
160
161
  /**
162
  *  Get the underlying v8::ArrayBuffer underlying the TypedArray and
163
  *  overlaying the native buffer
164
  */
165
11931
  v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
166
23862
    return GetJSArray()->Buffer();
167
  }
168
169
  /**
170
   *  Get the underlying native buffer. Note that all reads/writes should occur
171
   *  through the GetValue/SetValue/operator[] methods
172
   */
173
11931
  inline const NativeT* GetNativeBuffer() const {
174
11931
    return buffer_;
175
  }
176
177
  /**
178
   *  Synonym for GetBuffer()
179
   */
180
  inline const NativeT* operator * () const {
181
    return GetNativeBuffer();
182
  }
183
184
  /**
185
   *  Set position index to given value.
186
   */
187
18884238
  inline void SetValue(const size_t index, NativeT value) {
188
    DCHECK_LT(index, count_);
189
18884238
    buffer_[index] = value;
190
18884238
  }
191
192
  /**
193
   *  Get value at position index
194
   */
195
25048569
  inline const NativeT GetValue(const size_t index) const {
196
    DCHECK_LT(index, count_);
197
25048569
    return buffer_[index];
198
  }
199
200
  /**
201
   *  Effectively, a synonym for GetValue/SetValue
202
   */
203
35855422
  Reference operator[](size_t index) {
204
35855422
    return Reference(this, index);
205
  }
206
207
2696266
  NativeT operator[](size_t index) const {
208
2696266
    return GetValue(index);
209
  }
210
211
1264527
  size_t Length() const {
212
1264527
    return count_;
213
  }
214
215
  // Should only be used to extend the array.
216
  // Should only be used on an owning array, not one created as a sub array of
217
  // an owning `AliasedBufferBase`.
218
8
  void reserve(size_t new_capacity) {
219
    DCHECK_GE(new_capacity, count_);
220
    DCHECK_EQ(byte_offset_, 0);
221
8
    const v8::HandleScope handle_scope(isolate_);
222
223
8
    const size_t old_size_in_bytes = sizeof(NativeT) * count_;
224
8
    const size_t new_size_in_bytes = sizeof(NativeT) * new_capacity;
225
226
    // allocate v8 new ArrayBuffer
227
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
228
8
        isolate_, new_size_in_bytes);
229
230
    // allocate new native buffer
231
8
    NativeT* new_buffer = static_cast<NativeT*>(ab->GetContents().Data());
232
    // copy old content
233
8
    memcpy(new_buffer, buffer_, old_size_in_bytes);
234
235
    // allocate v8 TypedArray
236
8
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, new_capacity);
237
238
    // move over old v8 TypedArray
239
24
    js_array_ = std::move(v8::Global<V8T>(isolate_, js_array));
240
241
8
    buffer_ = new_buffer;
242
8
    count_ = new_capacity;
243
8
  }
244
245
 private:
246
  v8::Isolate* isolate_;
247
  size_t count_;
248
  size_t byte_offset_;
249
  NativeT* buffer_;
250
  v8::Global<V8T> js_array_;
251
};
252
253
typedef AliasedBufferBase<int32_t, v8::Int32Array> AliasedInt32Array;
254
typedef AliasedBufferBase<uint8_t, v8::Uint8Array> AliasedUint8Array;
255
typedef AliasedBufferBase<uint32_t, v8::Uint32Array> AliasedUint32Array;
256
typedef AliasedBufferBase<double, v8::Float64Array> AliasedFloat64Array;
257
typedef AliasedBufferBase<uint64_t, v8::BigUint64Array> AliasedBigUint64Array;
258
}  // namespace node
259
260
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
261
262
#endif  // SRC_ALIASED_BUFFER_H_