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: 69 69 100.0 %
Date: 2019-02-26 22:23:30 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 "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
101028
class AliasedBuffer {
29
 public:
30
44592
  AliasedBuffer(v8::Isolate* isolate, const size_t count)
31
      : isolate_(isolate),
32
        count_(count),
33
44592
        byte_offset_(0) {
34


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

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

20692
    CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count),
75
             ab->ByteLength() - byte_offset);
76
77
10346
    buffer_ = reinterpret_cast<NativeT*>(
78
10346
        const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
79
80
10346
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
81
20692
    js_array_ = v8::Global<V8T>(isolate, js_array);
82
10346
  }
83
84
  AliasedBuffer(const AliasedBuffer& 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
  AliasedBuffer& operator=(AliasedBuffer&& that) noexcept {
93
    this->~AliasedBuffer();
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
35533860
    Reference(AliasedBuffer<NativeT, V8T>* aliased_buffer, size_t index)
113
        : aliased_buffer_(aliased_buffer),
114
35533860
          index_(index) {
115
35533860
    }
116
117
    Reference(const Reference& that)
118
        : aliased_buffer_(that.aliased_buffer_),
119
          index_(that.index_) {
120
    }
121
122
12862652
    inline Reference& operator=(const NativeT& val) {
123
12862652
      aliased_buffer_->SetValue(index_, val);
124
12862649
      return *this;
125
    }
126
127
4850500
    inline Reference& operator=(const Reference& val) {
128
4850500
      return *this = static_cast<NativeT>(val);
129
    }
130
131
20833238
    operator NativeT() const {
132
20833238
      return aliased_buffer_->GetValue(index_);
133
    }
134
135
1745238
    inline Reference& operator+=(const NativeT& val) {
136
1745238
      const NativeT current = aliased_buffer_->GetValue(index_);
137
1745238
      aliased_buffer_->SetValue(index_, current + val);
138
1745239
      return *this;
139
    }
140
141
    inline Reference& operator+=(const Reference& val) {
142
      return this->operator+=(static_cast<NativeT>(val));
143
    }
144
145
92541
    inline Reference& operator-=(const NativeT& val) {
146
92541
      const NativeT current = aliased_buffer_->GetValue(index_);
147
92541
      aliased_buffer_->SetValue(index_, current - val);
148
92541
      return *this;
149
    }
150
151
   private:
152
    AliasedBuffer<NativeT, V8T>* aliased_buffer_;
153
    size_t index_;
154
  };
155
156
  /**
157
   *  Get the underlying v8 TypedArray overlayed on top of the native buffer
158
   */
159
240653
  v8::Local<V8T> GetJSArray() const {
160
481307
    return js_array_.Get(isolate_);
161
  }
162
163
  /**
164
  *  Get the underlying v8::ArrayBuffer underlying the TypedArray and
165
  *  overlaying the native buffer
166
  */
167
10346
  v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
168
20692
    return GetJSArray()->Buffer();
169
  }
170
171
  /**
172
   *  Get the underlying native buffer. Note that all reads/writes should occur
173
   *  through the GetValue/SetValue/operator[] methods
174
   */
175
10346
  inline const NativeT* GetNativeBuffer() const {
176
10346
    return buffer_;
177
  }
178
179
  /**
180
   *  Synonym for GetBuffer()
181
   */
182
  inline const NativeT* operator * () const {
183
    return GetNativeBuffer();
184
  }
185
186
  /**
187
   *  Set position index to given value.
188
   */
189
17418568
  inline void SetValue(const size_t index, NativeT value) {
190
    DCHECK_LT(index, count_);
191
17418568
    buffer_[index] = value;
192
17418568
  }
193
194
  /**
195
   *  Get value at position index
196
   */
197
25841460
  inline const NativeT GetValue(const size_t index) const {
198
    DCHECK_LT(index, count_);
199
25841460
    return buffer_[index];
200
  }
201
202
  /**
203
   *  Effectively, a synonym for GetValue/SetValue
204
   */
205
35533854
  Reference operator[](size_t index) {
206
35533854
    return Reference(this, index);
207
  }
208
209
3098022
  NativeT operator[](size_t index) const {
210
3098022
    return GetValue(index);
211
  }
212
213
1243949
  size_t Length() const {
214
1243949
    return count_;
215
  }
216
217
  // Should only be used to extend the array.
218
  // Should only be used on an owning array, not one created as a sub array of
219
  // an owning `AliasedBuffer`.
220
8
  void reserve(size_t new_capacity) {
221
    DCHECK_GE(new_capacity, count_);
222
    DCHECK_EQ(byte_offset_, 0);
223
8
    const v8::HandleScope handle_scope(isolate_);
224
225
8
    const size_t old_size_in_bytes = sizeof(NativeT) * count_;
226
8
    const size_t new_size_in_bytes = sizeof(NativeT) * new_capacity;
227
228
    // allocate v8 new ArrayBuffer
229
    v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
230
8
        isolate_, new_size_in_bytes);
231
232
    // allocate new native buffer
233
8
    NativeT* new_buffer = static_cast<NativeT*>(ab->GetContents().Data());
234
    // copy old content
235
8
    memcpy(new_buffer, buffer_, old_size_in_bytes);
236
237
    // allocate v8 TypedArray
238
8
    v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, new_capacity);
239
240
    // move over old v8 TypedArray
241
24
    js_array_ = std::move(v8::Global<V8T>(isolate_, js_array));
242
243
8
    buffer_ = new_buffer;
244
8
    count_ = new_capacity;
245
8
  }
246
247
 private:
248
  v8::Isolate* isolate_;
249
  size_t count_;
250
  size_t byte_offset_;
251
  NativeT* buffer_;
252
  v8::Global<V8T> js_array_;
253
};
254
}  // namespace node
255
256
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
257
258
#endif  // SRC_ALIASED_BUFFER_H_