Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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>
  • Loading branch information
jasnell committed Apr 11, 2020
commit 63c95030179e8b583d02b0f75fb0b29af2dfbd1b
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@
'src/uv.cc',
# headers to make for a more pleasant IDE experience
'src/aliased_buffer.h',
'src/aliased_struct.h',
'src/async_wrap.h',
'src/async_wrap-inl.h',
'src/base_object.h',
Expand Down
73 changes: 73 additions & 0 deletions src/aliased_struct.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#ifndef SRC_ALIASED_STRUCT_H_
#define SRC_ALIASED_STRUCT_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Comment thread
jasnell marked this conversation as resolved.

#include "node_internals.h"
#include "v8.h"
#include <memory>

namespace node {

template <typename T,
typename = std::enable_if_t<std::is_object<T>::value>>
Comment thread
jasnell marked this conversation as resolved.
Outdated
class AliasedStruct {
public:
explicit AliasedStruct(v8::Isolate* isolate) : isolate_(isolate) {
const v8::HandleScope handle_scope(isolate);

store_ = v8::ArrayBuffer::NewBackingStore(isolate, sizeof(T));
ptr_ = new (store_->Data()) T;
Comment thread
jasnell marked this conversation as resolved.
Outdated
DCHECK_NOT_NULL(ptr_);

v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, store_);
buffer_ = v8::Global<v8::ArrayBuffer>(isolate, buffer);
}

AliasedStruct(const AliasedStruct& that)
Comment thread
jasnell marked this conversation as resolved.
Outdated
: isolate_(that.isolate_),
store_(that.store_),
ptr_(that.ptr_) {
buffer_ = v8::Global<v8::ArrayBuffer>(that.isolate_, that.GetArrayBuffer());
Comment thread
jasnell marked this conversation as resolved.
Outdated
}

~AliasedStruct() {
if (ptr_ != nullptr) ptr_->~T();
}

AliasedStruct& operator=(AliasedStruct&& that) noexcept {
Comment thread
jasnell marked this conversation as resolved.
Outdated
this->~AliasedStruct();
isolate_ = that.isolate_;
store_ = that.store_;
ptr_ = that.ptr_;

buffer_.Reset(isolate_, that.buffer_.Get(isolate_));
Comment thread
jasnell marked this conversation as resolved.
Outdated

that.ptr_ = nullptr;
that.store_.reset();
that.buffer_.Reset();
Comment thread
jasnell marked this conversation as resolved.
Outdated
return *this;
}

v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
return buffer_.Get(isolate_);
}

T* Data() const { return ptr_; }

T* operator*() const { return ptr_; }

T* operator->() const { return ptr_; }
Comment thread
jasnell marked this conversation as resolved.
Outdated

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_
11 changes: 2 additions & 9 deletions src/node_http2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ namespace node {
using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
using v8::Boolean;
using v8::Context;
using v8::Float64Array;
Expand Down Expand Up @@ -471,6 +470,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();
Expand Down Expand Up @@ -518,14 +518,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));
}

Expand All @@ -536,7 +530,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 {
Expand Down
4 changes: 2 additions & 2 deletions src/node_http2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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_;
Expand Down