src: add AliasedStruct utility
For http2 (and eventually QUIC) we have a struct that is backed by a v8::BackingStore and exposed to the JavaScript side as an ArrayBuffer and TypedArray. This is similar to AliasedBuffer except that it is fronted by a struct on the C++ side. ```c++ struct foo { uint32_t ex1; uint32_t ex2; }; AliasedStruct<foo> foo_; foo_->ex1 = 1; foo_->ex2 = 2; foo_.GetArrayBuffer(); ``` Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/32778 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
This commit is contained in:
parent
81c03bcebd
commit
cecb08f0c8
2
node.gyp
2
node.gyp
@ -631,6 +631,8 @@
|
||||
'src/uv.cc',
|
||||
# headers to make for a more pleasant IDE experience
|
||||
'src/aliased_buffer.h',
|
||||
'src/aliased_struct.h',
|
||||
'src/aliased_struct-inl.h',
|
||||
'src/async_wrap.h',
|
||||
'src/async_wrap-inl.h',
|
||||
'src/base_object.h',
|
||||
|
54
src/aliased_struct-inl.h
Normal file
54
src/aliased_struct-inl.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef SRC_ALIASED_STRUCT_INL_H_
|
||||
#define SRC_ALIASED_STRUCT_INL_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "aliased_struct.h"
|
||||
#include "v8.h"
|
||||
#include <memory>
|
||||
|
||||
namespace node {
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
AliasedStruct<T>::AliasedStruct(v8::Isolate* isolate, Args&&... args)
|
||||
: isolate_(isolate) {
|
||||
const v8::HandleScope handle_scope(isolate);
|
||||
|
||||
store_ = v8::ArrayBuffer::NewBackingStore(isolate, sizeof(T));
|
||||
ptr_ = new (store_->Data()) T(std::forward<Args>(args)...);
|
||||
DCHECK_NOT_NULL(ptr_);
|
||||
|
||||
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, store_);
|
||||
buffer_ = v8::Global<v8::ArrayBuffer>(isolate, buffer);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AliasedStruct<T>::AliasedStruct(const AliasedStruct& that)
|
||||
: AliasedStruct(that.isolate_, *that) {}
|
||||
|
||||
template <typename T>
|
||||
AliasedStruct<T>& AliasedStruct<T>::operator=(
|
||||
AliasedStruct<T>&& that) noexcept {
|
||||
this->~AliasedStruct();
|
||||
isolate_ = that.isolate_;
|
||||
store_ = that.store_;
|
||||
ptr_ = that.ptr_;
|
||||
|
||||
buffer_ = std::move(that.buffer_);
|
||||
|
||||
that.ptr_ = nullptr;
|
||||
that.store_.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AliasedStruct<T>::~AliasedStruct() {
|
||||
if (ptr_ != nullptr) ptr_->~T();
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_ALIASED_STRUCT_INL_H_
|
63
src/aliased_struct.h
Normal file
63
src/aliased_struct.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef SRC_ALIASED_STRUCT_H_
|
||||
#define SRC_ALIASED_STRUCT_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "node_internals.h"
|
||||
#include "v8.h"
|
||||
#include <memory>
|
||||
|
||||
namespace node {
|
||||
|
||||
// AliasedStruct is a utility that allows uses a V8 Backing Store
|
||||
// to be exposed to the C++/C side as a struct and to the
|
||||
// JavaScript side as an ArrayBuffer to efficiently share
|
||||
// data without marshalling. It is similar in nature to
|
||||
// AliasedBuffer.
|
||||
//
|
||||
// struct Foo { int x; }
|
||||
//
|
||||
// AliasedStruct<Foo> foo;
|
||||
// foo->x = 1;
|
||||
//
|
||||
// Local<ArrayBuffer> ab = foo.GetArrayBuffer();
|
||||
template <typename T>
|
||||
class AliasedStruct final {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit AliasedStruct(v8::Isolate* isolate, Args&&... args);
|
||||
|
||||
inline AliasedStruct(const AliasedStruct& that);
|
||||
|
||||
inline ~AliasedStruct();
|
||||
|
||||
inline AliasedStruct& operator=(AliasedStruct&& that) noexcept;
|
||||
|
||||
v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
|
||||
return buffer_.Get(isolate_);
|
||||
}
|
||||
|
||||
const T* Data() const { return ptr_; }
|
||||
|
||||
T* Data() { return ptr_; }
|
||||
|
||||
const T& operator*() const { return *ptr_; }
|
||||
|
||||
T& operator*() { return *ptr_; }
|
||||
|
||||
const T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator->() { return ptr_; }
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
std::shared_ptr<v8::BackingStore> store_;
|
||||
T* ptr_;
|
||||
v8::Global<v8::ArrayBuffer> buffer_;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_ALIASED_STRUCT_H_
|
@ -1,4 +1,5 @@
|
||||
#include "aliased_buffer.h"
|
||||
#include "aliased_struct-inl.h"
|
||||
#include "debug_utils-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "node.h"
|
||||
@ -18,7 +19,6 @@ namespace node {
|
||||
using v8::Array;
|
||||
using v8::ArrayBuffer;
|
||||
using v8::ArrayBufferView;
|
||||
using v8::BackingStore;
|
||||
using v8::Boolean;
|
||||
using v8::Context;
|
||||
using v8::Float64Array;
|
||||
@ -471,6 +471,7 @@ Http2Session::Http2Session(Http2State* http2_state,
|
||||
Local<Object> wrap,
|
||||
nghttp2_session_type type)
|
||||
: AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
|
||||
js_fields_(http2_state->env()->isolate()),
|
||||
session_type_(type),
|
||||
http2_state_(http2_state) {
|
||||
MakeWeak();
|
||||
@ -518,14 +519,8 @@ Http2Session::Http2Session(Http2State* http2_state,
|
||||
outgoing_storage_.reserve(1024);
|
||||
outgoing_buffers_.reserve(32);
|
||||
|
||||
// Make the js_fields_ property accessible to JS land.
|
||||
js_fields_store_ =
|
||||
ArrayBuffer::NewBackingStore(env()->isolate(), sizeof(SessionJSFields));
|
||||
js_fields_ = new(js_fields_store_->Data()) SessionJSFields;
|
||||
|
||||
Local<ArrayBuffer> ab = ArrayBuffer::New(env()->isolate(), js_fields_store_);
|
||||
Local<Uint8Array> uint8_arr =
|
||||
Uint8Array::New(ab, 0, kSessionUint8FieldCount);
|
||||
Uint8Array::New(js_fields_.GetArrayBuffer(), 0, kSessionUint8FieldCount);
|
||||
USE(wrap->Set(env()->context(), env()->fields_string(), uint8_arr));
|
||||
}
|
||||
|
||||
@ -536,7 +531,6 @@ Http2Session::~Http2Session() {
|
||||
// current_nghttp2_memory_ check passes.
|
||||
session_.reset();
|
||||
CHECK_EQ(current_nghttp2_memory_, 0);
|
||||
js_fields_->~SessionJSFields();
|
||||
}
|
||||
|
||||
std::string Http2Session::diagnostic_name() const {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <cstdint>
|
||||
#include "nghttp2/nghttp2.h"
|
||||
|
||||
#include "aliased_struct.h"
|
||||
#include "node_http2_state.h"
|
||||
#include "node_http_common.h"
|
||||
#include "node_mem.h"
|
||||
@ -823,8 +824,7 @@ class Http2Session : public AsyncWrap,
|
||||
Nghttp2SessionPointer session_;
|
||||
|
||||
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
|
||||
SessionJSFields* js_fields_ = nullptr;
|
||||
std::shared_ptr<v8::BackingStore> js_fields_store_;
|
||||
AliasedStruct<SessionJSFields> js_fields_;
|
||||
|
||||
// The session type: client or server
|
||||
nghttp2_session_type session_type_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user