Skip to content

Commit

Permalink
src: move AliasedBuffer implementation to -inl.h
Browse files Browse the repository at this point in the history
Drive-by: Replace the SFINAE with a static_assert because we don't
have (or need) an implementation for non-scalar AliasedBufferBase
otherwise. Add forward declarations to memory_tracker.h now that
aliased-buffer.h no longer includes util-inl.h.

PR-URL: #46817
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
joyeecheung authored and targos committed Nov 10, 2023
1 parent 04dad9c commit 946f19b
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 168 deletions.
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@
'src/uv.cc',
# headers to make for a more pleasant IDE experience
'src/aliased_buffer.h',
'src/aliased_buffer-inl.h',
'src/aliased_struct.h',
'src/aliased_struct-inl.h',
'src/async_wrap.h',
Expand Down
213 changes: 213 additions & 0 deletions src/aliased_buffer-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#ifndef SRC_ALIASED_BUFFER_INL_H_
#define SRC_ALIASED_BUFFER_INL_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "aliased_buffer.h"
#include "util-inl.h"

namespace node {

typedef size_t AliasedBufferIndex;

template <typename NativeT, typename V8T>
AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
v8::Isolate* isolate, const size_t count, const AliasedBufferIndex* index)
: isolate_(isolate), count_(count), byte_offset_(0), index_(index) {
CHECK_GT(count, 0);
if (index != nullptr) {
// Will be deserialized later.
return;
}
const v8::HandleScope handle_scope(isolate_);
const size_t size_in_bytes =
MultiplyWithOverflowCheck(sizeof(NativeT), count);

// allocate v8 ArrayBuffer
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate_, size_in_bytes);
buffer_ = static_cast<NativeT*>(ab->Data());

// allocate v8 TypedArray
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
js_array_ = v8::Global<V8T>(isolate, js_array);
}

template <typename NativeT, typename V8T>
AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
v8::Isolate* isolate,
const size_t byte_offset,
const size_t count,
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
const AliasedBufferIndex* index)
: isolate_(isolate),
count_(count),
byte_offset_(byte_offset),
index_(index) {
if (index != nullptr) {
// Will be deserialized later.
return;
}
const v8::HandleScope handle_scope(isolate_);
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();

// validate that the byte_offset is aligned with sizeof(NativeT)
CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
// validate this fits inside the backing buffer
CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count),
ab->ByteLength() - byte_offset);

buffer_ = reinterpret_cast<NativeT*>(
const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));

v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
js_array_ = v8::Global<V8T>(isolate, js_array);
}

template <typename NativeT, typename V8T>
AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
const AliasedBufferBase& that)
: isolate_(that.isolate_),
count_(that.count_),
byte_offset_(that.byte_offset_),
buffer_(that.buffer_) {
DCHECK_NULL(index_);
js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
}

template <typename NativeT, typename V8T>
AliasedBufferIndex AliasedBufferBase<NativeT, V8T>::Serialize(
v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
DCHECK_NULL(index_);
return creator->AddData(context, GetJSArray());
}

template <typename NativeT, typename V8T>
inline void AliasedBufferBase<NativeT, V8T>::Deserialize(
v8::Local<v8::Context> context) {
DCHECK_NOT_NULL(index_);
v8::Local<V8T> arr =
context->GetDataFromSnapshotOnce<V8T>(*index_).ToLocalChecked();
// These may not hold true for AliasedBuffers that have grown, so should
// be removed when we expand the snapshot support.
DCHECK_EQ(count_, arr->Length());
DCHECK_EQ(byte_offset_, arr->ByteOffset());
uint8_t* raw = static_cast<uint8_t*>(arr->Buffer()->Data());
buffer_ = reinterpret_cast<NativeT*>(raw + byte_offset_);
js_array_.Reset(isolate_, arr);
index_ = nullptr;
}

template <typename NativeT, typename V8T>
AliasedBufferBase<NativeT, V8T>& AliasedBufferBase<NativeT, V8T>::operator=(
AliasedBufferBase<NativeT, V8T>&& that) noexcept {
DCHECK_NULL(index_);
this->~AliasedBufferBase();
isolate_ = that.isolate_;
count_ = that.count_;
byte_offset_ = that.byte_offset_;
buffer_ = that.buffer_;

js_array_.Reset(isolate_, that.js_array_.Get(isolate_));

that.buffer_ = nullptr;
that.js_array_.Reset();
return *this;
}

template <typename NativeT, typename V8T>
v8::Local<V8T> AliasedBufferBase<NativeT, V8T>::GetJSArray() const {
DCHECK_NULL(index_);
return js_array_.Get(isolate_);
}

template <typename NativeT, typename V8T>
void AliasedBufferBase<NativeT, V8T>::Release() {
DCHECK_NULL(index_);
js_array_.Reset();
}

template <typename NativeT, typename V8T>
v8::Local<v8::ArrayBuffer> AliasedBufferBase<NativeT, V8T>::GetArrayBuffer()
const {
return GetJSArray()->Buffer();
}

template <typename NativeT, typename V8T>
inline const NativeT* AliasedBufferBase<NativeT, V8T>::GetNativeBuffer() const {
DCHECK_NULL(index_);
return buffer_;
}

template <typename NativeT, typename V8T>
inline const NativeT* AliasedBufferBase<NativeT, V8T>::operator*() const {
return GetNativeBuffer();
}

template <typename NativeT, typename V8T>
inline void AliasedBufferBase<NativeT, V8T>::SetValue(const size_t index,
NativeT value) {
DCHECK_LT(index, count_);
DCHECK_NULL(index_);
buffer_[index] = value;
}

template <typename NativeT, typename V8T>
inline const NativeT AliasedBufferBase<NativeT, V8T>::GetValue(
const size_t index) const {
DCHECK_NULL(index_);
DCHECK_LT(index, count_);
return buffer_[index];
}

template <typename NativeT, typename V8T>
typename AliasedBufferBase<NativeT, V8T>::Reference
AliasedBufferBase<NativeT, V8T>::operator[](size_t index) {
DCHECK_NULL(index_);
return Reference(this, index);
}

template <typename NativeT, typename V8T>
NativeT AliasedBufferBase<NativeT, V8T>::operator[](size_t index) const {
return GetValue(index);
}

template <typename NativeT, typename V8T>
size_t AliasedBufferBase<NativeT, V8T>::Length() const {
return count_;
}

template <typename NativeT, typename V8T>
void AliasedBufferBase<NativeT, V8T>::reserve(size_t new_capacity) {
DCHECK_NULL(index_);
DCHECK_GE(new_capacity, count_);
DCHECK_EQ(byte_offset_, 0);
const v8::HandleScope handle_scope(isolate_);

const size_t old_size_in_bytes = sizeof(NativeT) * count_;
const size_t new_size_in_bytes =
MultiplyWithOverflowCheck(sizeof(NativeT), new_capacity);

// allocate v8 new ArrayBuffer
v8::Local<v8::ArrayBuffer> ab =
v8::ArrayBuffer::New(isolate_, new_size_in_bytes);

// allocate new native buffer
NativeT* new_buffer = static_cast<NativeT*>(ab->Data());
// copy old content
memcpy(new_buffer, buffer_, old_size_in_bytes);

// allocate v8 TypedArray
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, new_capacity);

// move over old v8 TypedArray
js_array_ = std::move(v8::Global<V8T>(isolate_, js_array));

buffer_ = new_buffer;
count_ = new_capacity;
}

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_ALIASED_BUFFER_INL_H_

0 comments on commit 946f19b

Please sign in to comment.