Skip to content

Commit cecb08f

Browse files
jasnelladdaleax
authored andcommittedApr 14, 2020
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 <[email protected]> PR-URL: nodejs#32778 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]>
1 parent 81c03bc commit cecb08f

File tree

5 files changed

+124
-11
lines changed

5 files changed

+124
-11
lines changed
 

‎node.gyp

+2
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@
631631
'src/uv.cc',
632632
# headers to make for a more pleasant IDE experience
633633
'src/aliased_buffer.h',
634+
'src/aliased_struct.h',
635+
'src/aliased_struct-inl.h',
634636
'src/async_wrap.h',
635637
'src/async_wrap-inl.h',
636638
'src/base_object.h',

‎src/aliased_struct-inl.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef SRC_ALIASED_STRUCT_INL_H_
2+
#define SRC_ALIASED_STRUCT_INL_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "aliased_struct.h"
7+
#include "v8.h"
8+
#include <memory>
9+
10+
namespace node {
11+
12+
template <typename T>
13+
template <typename... Args>
14+
AliasedStruct<T>::AliasedStruct(v8::Isolate* isolate, Args&&... args)
15+
: isolate_(isolate) {
16+
const v8::HandleScope handle_scope(isolate);
17+
18+
store_ = v8::ArrayBuffer::NewBackingStore(isolate, sizeof(T));
19+
ptr_ = new (store_->Data()) T(std::forward<Args>(args)...);
20+
DCHECK_NOT_NULL(ptr_);
21+
22+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, store_);
23+
buffer_ = v8::Global<v8::ArrayBuffer>(isolate, buffer);
24+
}
25+
26+
template <typename T>
27+
AliasedStruct<T>::AliasedStruct(const AliasedStruct& that)
28+
: AliasedStruct(that.isolate_, *that) {}
29+
30+
template <typename T>
31+
AliasedStruct<T>& AliasedStruct<T>::operator=(
32+
AliasedStruct<T>&& that) noexcept {
33+
this->~AliasedStruct();
34+
isolate_ = that.isolate_;
35+
store_ = that.store_;
36+
ptr_ = that.ptr_;
37+
38+
buffer_ = std::move(that.buffer_);
39+
40+
that.ptr_ = nullptr;
41+
that.store_.reset();
42+
return *this;
43+
}
44+
45+
template <typename T>
46+
AliasedStruct<T>::~AliasedStruct() {
47+
if (ptr_ != nullptr) ptr_->~T();
48+
}
49+
50+
} // namespace node
51+
52+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
53+
54+
#endif // SRC_ALIASED_STRUCT_INL_H_

‎src/aliased_struct.h

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef SRC_ALIASED_STRUCT_H_
2+
#define SRC_ALIASED_STRUCT_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "node_internals.h"
7+
#include "v8.h"
8+
#include <memory>
9+
10+
namespace node {
11+
12+
// AliasedStruct is a utility that allows uses a V8 Backing Store
13+
// to be exposed to the C++/C side as a struct and to the
14+
// JavaScript side as an ArrayBuffer to efficiently share
15+
// data without marshalling. It is similar in nature to
16+
// AliasedBuffer.
17+
//
18+
// struct Foo { int x; }
19+
//
20+
// AliasedStruct<Foo> foo;
21+
// foo->x = 1;
22+
//
23+
// Local<ArrayBuffer> ab = foo.GetArrayBuffer();
24+
template <typename T>
25+
class AliasedStruct final {
26+
public:
27+
template <typename... Args>
28+
explicit AliasedStruct(v8::Isolate* isolate, Args&&... args);
29+
30+
inline AliasedStruct(const AliasedStruct& that);
31+
32+
inline ~AliasedStruct();
33+
34+
inline AliasedStruct& operator=(AliasedStruct&& that) noexcept;
35+
36+
v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
37+
return buffer_.Get(isolate_);
38+
}
39+
40+
const T* Data() const { return ptr_; }
41+
42+
T* Data() { return ptr_; }
43+
44+
const T& operator*() const { return *ptr_; }
45+
46+
T& operator*() { return *ptr_; }
47+
48+
const T* operator->() const { return ptr_; }
49+
50+
T* operator->() { return ptr_; }
51+
52+
private:
53+
v8::Isolate* isolate_;
54+
std::shared_ptr<v8::BackingStore> store_;
55+
T* ptr_;
56+
v8::Global<v8::ArrayBuffer> buffer_;
57+
};
58+
59+
} // namespace node
60+
61+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
62+
63+
#endif // SRC_ALIASED_STRUCT_H_

‎src/node_http2.cc

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "aliased_buffer.h"
2+
#include "aliased_struct-inl.h"
23
#include "debug_utils-inl.h"
34
#include "memory_tracker-inl.h"
45
#include "node.h"
@@ -18,7 +19,6 @@ namespace node {
1819
using v8::Array;
1920
using v8::ArrayBuffer;
2021
using v8::ArrayBufferView;
21-
using v8::BackingStore;
2222
using v8::Boolean;
2323
using v8::Context;
2424
using v8::Float64Array;
@@ -471,6 +471,7 @@ Http2Session::Http2Session(Http2State* http2_state,
471471
Local<Object> wrap,
472472
nghttp2_session_type type)
473473
: AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
474+
js_fields_(http2_state->env()->isolate()),
474475
session_type_(type),
475476
http2_state_(http2_state) {
476477
MakeWeak();
@@ -518,14 +519,8 @@ Http2Session::Http2Session(Http2State* http2_state,
518519
outgoing_storage_.reserve(1024);
519520
outgoing_buffers_.reserve(32);
520521

521-
// Make the js_fields_ property accessible to JS land.
522-
js_fields_store_ =
523-
ArrayBuffer::NewBackingStore(env()->isolate(), sizeof(SessionJSFields));
524-
js_fields_ = new(js_fields_store_->Data()) SessionJSFields;
525-
526-
Local<ArrayBuffer> ab = ArrayBuffer::New(env()->isolate(), js_fields_store_);
527522
Local<Uint8Array> uint8_arr =
528-
Uint8Array::New(ab, 0, kSessionUint8FieldCount);
523+
Uint8Array::New(js_fields_.GetArrayBuffer(), 0, kSessionUint8FieldCount);
529524
USE(wrap->Set(env()->context(), env()->fields_string(), uint8_arr));
530525
}
531526

@@ -536,7 +531,6 @@ Http2Session::~Http2Session() {
536531
// current_nghttp2_memory_ check passes.
537532
session_.reset();
538533
CHECK_EQ(current_nghttp2_memory_, 0);
539-
js_fields_->~SessionJSFields();
540534
}
541535

542536
std::string Http2Session::diagnostic_name() const {

‎src/node_http2.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cstdint>
88
#include "nghttp2/nghttp2.h"
99

10+
#include "aliased_struct.h"
1011
#include "node_http2_state.h"
1112
#include "node_http_common.h"
1213
#include "node_mem.h"
@@ -823,8 +824,7 @@ class Http2Session : public AsyncWrap,
823824
Nghttp2SessionPointer session_;
824825

825826
// JS-accessible numeric fields, as indexed by SessionUint8Fields.
826-
SessionJSFields* js_fields_ = nullptr;
827-
std::shared_ptr<v8::BackingStore> js_fields_store_;
827+
AliasedStruct<SessionJSFields> js_fields_;
828828

829829
// The session type: client or server
830830
nghttp2_session_type session_type_;

0 commit comments

Comments
 (0)
Please sign in to comment.