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',
|
'src/uv.cc',
|
||||||
# headers to make for a more pleasant IDE experience
|
# headers to make for a more pleasant IDE experience
|
||||||
'src/aliased_buffer.h',
|
'src/aliased_buffer.h',
|
||||||
|
'src/aliased_struct.h',
|
||||||
|
'src/aliased_struct-inl.h',
|
||||||
'src/async_wrap.h',
|
'src/async_wrap.h',
|
||||||
'src/async_wrap-inl.h',
|
'src/async_wrap-inl.h',
|
||||||
'src/base_object.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_buffer.h"
|
||||||
|
#include "aliased_struct-inl.h"
|
||||||
#include "debug_utils-inl.h"
|
#include "debug_utils-inl.h"
|
||||||
#include "memory_tracker-inl.h"
|
#include "memory_tracker-inl.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
@ -18,7 +19,6 @@ namespace node {
|
|||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
using v8::ArrayBufferView;
|
using v8::ArrayBufferView;
|
||||||
using v8::BackingStore;
|
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::Float64Array;
|
using v8::Float64Array;
|
||||||
@ -471,6 +471,7 @@ Http2Session::Http2Session(Http2State* http2_state,
|
|||||||
Local<Object> wrap,
|
Local<Object> wrap,
|
||||||
nghttp2_session_type type)
|
nghttp2_session_type type)
|
||||||
: AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
|
: AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
|
||||||
|
js_fields_(http2_state->env()->isolate()),
|
||||||
session_type_(type),
|
session_type_(type),
|
||||||
http2_state_(http2_state) {
|
http2_state_(http2_state) {
|
||||||
MakeWeak();
|
MakeWeak();
|
||||||
@ -518,14 +519,8 @@ Http2Session::Http2Session(Http2State* http2_state,
|
|||||||
outgoing_storage_.reserve(1024);
|
outgoing_storage_.reserve(1024);
|
||||||
outgoing_buffers_.reserve(32);
|
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 =
|
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));
|
USE(wrap->Set(env()->context(), env()->fields_string(), uint8_arr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +531,6 @@ Http2Session::~Http2Session() {
|
|||||||
// current_nghttp2_memory_ check passes.
|
// current_nghttp2_memory_ check passes.
|
||||||
session_.reset();
|
session_.reset();
|
||||||
CHECK_EQ(current_nghttp2_memory_, 0);
|
CHECK_EQ(current_nghttp2_memory_, 0);
|
||||||
js_fields_->~SessionJSFields();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Http2Session::diagnostic_name() const {
|
std::string Http2Session::diagnostic_name() const {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "nghttp2/nghttp2.h"
|
#include "nghttp2/nghttp2.h"
|
||||||
|
|
||||||
|
#include "aliased_struct.h"
|
||||||
#include "node_http2_state.h"
|
#include "node_http2_state.h"
|
||||||
#include "node_http_common.h"
|
#include "node_http_common.h"
|
||||||
#include "node_mem.h"
|
#include "node_mem.h"
|
||||||
@ -823,8 +824,7 @@ class Http2Session : public AsyncWrap,
|
|||||||
Nghttp2SessionPointer session_;
|
Nghttp2SessionPointer session_;
|
||||||
|
|
||||||
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
|
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
|
||||||
SessionJSFields* js_fields_ = nullptr;
|
AliasedStruct<SessionJSFields> js_fields_;
|
||||||
std::shared_ptr<v8::BackingStore> js_fields_store_;
|
|
||||||
|
|
||||||
// The session type: client or server
|
// The session type: client or server
|
||||||
nghttp2_session_type session_type_;
|
nghttp2_session_type session_type_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user