GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — http2,async-wrap: introduce AliasedBuffer class · nodejs/node@a32c8a5

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • node.gyp
  • src
    • aliased_buffer.h
    • async-wrap.cc
    • env-inl.h
    • env.h
    • node_http2.cc
    • node_http2.h
    • node_http2_state.h
  • test/cctest
    • node_test_fixture.cc
    • node_test_fixture.h
    • test_aliased_buffer.cc
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎node.gyp‎

Copy file name to clipboardExpand all lines: node.gyp
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@
228228
'src/util.cc',
229229
'src/uv.cc',
230230
# headers to make for a more pleasant IDE experience
231+
'src/aliased_buffer.h',
231232
'src/async-wrap.h',
232233
'src/async-wrap-inl.h',
233234
'src/base-object.h',
@@ -246,6 +247,7 @@
246247
'src/node_constants.h',
247248
'src/node_debug_options.h',
248249
'src/node_http2.h',
250+
'src/node_http2_state.h',
249251
'src/node_internals.h',
250252
'src/node_javascript.h',
251253
'src/node_mutex.h',
@@ -650,6 +652,8 @@
650652
'sources': [
651653
'src/node_platform.cc',
652654
'src/node_platform.h',
655+
'test/cctest/node_test_fixture.cc',
656+
'test/cctest/test_aliased_buffer.cc',
653657
'test/cctest/test_base64.cc',
654658
'test/cctest/test_environment.cc',
655659
'test/cctest/test_util.cc',
Collapse file

‎src/aliased_buffer.h‎

Copy file name to clipboard
+200Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
2+
#ifndef SRC_ALIASED_BUFFER_H_
3+
#define SRC_ALIASED_BUFFER_H_
4+
5+
#include "v8.h"
6+
#include "util.h"
7+
#include "util-inl.h"
8+
9+
namespace node {
10+
11+
/**
12+
* This class encapsulates the technique of having a native buffer mapped to
13+
* a JS object. Writes to the native buffer can happen efficiently without
14+
* going through JS, and the data is then available to user's via the exposed
15+
* JS object.
16+
*
17+
* While this technique is computationaly efficient, it is effectively a
18+
* write to JS program state w/out going through the standard
19+
* (monitored) API. Thus any VM capabilities to detect the modification are
20+
* circumvented.
21+
*
22+
* The encapsulation herein provides a placeholder where such writes can be
23+
* observed. Any notification APIs will be left as a future exercise.
24+
*/
25+
template <class NativeT, class V8T>
26+
class AliasedBuffer {
27+
public:
28+
AliasedBuffer(v8::Isolate* isolate, const size_t count)
29+
: isolate_(isolate),
30+
count_(count),
31+
byte_offset_(0),
32+
free_buffer_(true) {
33+
CHECK_GT(count, 0);
34+
const v8::HandleScope handle_scope(isolate_);
35+
36+
const size_t sizeInBytes = sizeof(NativeT) * count;
37+
38+
// allocate native buffer
39+
buffer_ = Calloc<NativeT>(count);
40+
41+
// allocate v8 ArrayBuffer
42+
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
43+
isolate_, buffer_, sizeInBytes);
44+
45+
// allocate v8 TypedArray
46+
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
47+
js_array_ = v8::Global<V8T>(isolate, js_array);
48+
}
49+
50+
/**
51+
* Create an AliasedBuffer over a sub-region of another aliased buffer.
52+
* The two will share a v8::ArrayBuffer instance &
53+
* a native buffer, but will each read/write to different sections of the
54+
* native buffer.
55+
*
56+
* Note that byte_offset must by aligned by sizeof(NativeT).
57+
*/
58+
AliasedBuffer(v8::Isolate* isolate,
59+
const size_t byte_offset,
60+
const size_t count,
61+
const AliasedBuffer<uint8_t,
62+
v8::Uint8Array>& backing_buffer)
63+
: isolate_(isolate),
64+
count_(count),
65+
byte_offset_(byte_offset),
66+
free_buffer_(false) {
67+
const v8::HandleScope handle_scope(isolate_);
68+
69+
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
70+
71+
// validate that the byte_offset is aligned with sizeof(NativeT)
72+
CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
73+
// validate this fits inside the backing buffer
74+
CHECK_LE(sizeof(NativeT) * count, ab->ByteLength() - byte_offset);
75+
76+
buffer_ = reinterpret_cast<NativeT*>(
77+
const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
78+
79+
v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
80+
js_array_ = v8::Global<V8T>(isolate, js_array);
81+
}
82+
83+
AliasedBuffer(const AliasedBuffer& that)
84+
: isolate_(that.isolate_),
85+
count_(that.count_),
86+
byte_offset_(that.byte_offset_),
87+
buffer_(that.buffer_),
88+
free_buffer_(false) {
89+
js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
90+
}
91+
92+
~AliasedBuffer() {
93+
if (free_buffer_ && buffer_ != nullptr) {
94+
free(buffer_);
95+
}
96+
js_array_.Reset();
97+
}
98+
99+
/**
100+
* Helper class that is returned from operator[] to support assignment into
101+
* a specified location.
102+
*/
103+
class Reference {
104+
public:
105+
Reference(AliasedBuffer<NativeT, V8T>* aliased_buffer, size_t index)
106+
: aliased_buffer_(aliased_buffer),
107+
index_(index) {
108+
}
109+
110+
Reference(const Reference& that)
111+
: aliased_buffer_(that.aliased_buffer_),
112+
index_(that.index_) {
113+
}
114+
115+
inline Reference& operator=(const NativeT &val) {
116+
aliased_buffer_->SetValue(index_, val);
117+
return *this;
118+
}
119+
120+
operator NativeT() const {
121+
return aliased_buffer_->GetValue(index_);
122+
}
123+
124+
private:
125+
AliasedBuffer<NativeT, V8T>* aliased_buffer_;
126+
size_t index_;
127+
};
128+
129+
/**
130+
* Get the underlying v8 TypedArray overlayed on top of the native buffer
131+
*/
132+
v8::Local<V8T> GetJSArray() const {
133+
return js_array_.Get(isolate_);
134+
}
135+
136+
/**
137+
* Get the underlying v8::ArrayBuffer underlying the TypedArray and
138+
* overlaying the native buffer
139+
*/
140+
v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
141+
return GetJSArray()->Buffer();
142+
}
143+
144+
/**
145+
* Get the underlying native buffer. Note that all reads/writes should occur
146+
* through the GetValue/SetValue/operator[] methods
147+
*/
148+
inline const NativeT* GetNativeBuffer() const {
149+
return buffer_;
150+
}
151+
152+
/**
153+
* Synonym for GetBuffer()
154+
*/
155+
inline const NativeT* operator * () const {
156+
return GetNativeBuffer();
157+
}
158+
159+
/**
160+
* Set position index to given value.
161+
*/
162+
inline void SetValue(const size_t index, NativeT value) {
163+
#if defined(DEBUG) && DEBUG
164+
CHECK_LT(index, count_);
165+
#endif
166+
buffer_[index] = value;
167+
}
168+
169+
/**
170+
* Get value at position index
171+
*/
172+
inline const NativeT GetValue(const size_t index) const {
173+
#if defined(DEBUG) && DEBUG
174+
CHECK_LT(index, count_);
175+
#endif
176+
return buffer_[index];
177+
}
178+
179+
/**
180+
* Effectively, a synonym for GetValue/SetValue
181+
*/
182+
Reference operator[](size_t index) {
183+
return Reference(this, index);
184+
}
185+
186+
NativeT operator[](size_t index) const {
187+
return GetValue(index);
188+
}
189+
190+
private:
191+
v8::Isolate* const isolate_;
192+
size_t count_;
193+
size_t byte_offset_;
194+
NativeT* buffer_;
195+
v8::Global<V8T> js_array_;
196+
bool free_buffer_;
197+
};
198+
} // namespace node
199+
200+
#endif // SRC_ALIASED_BUFFER_H_
Collapse file

‎src/async-wrap.cc‎

Copy file name to clipboardExpand all lines: src/async-wrap.cc
+2-14Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include "v8-profiler.h"
3232

3333
using v8::Array;
34-
using v8::ArrayBuffer;
3534
using v8::Context;
3635
using v8::Float64Array;
3736
using v8::Function;
@@ -53,7 +52,6 @@ using v8::RetainedObjectInfo;
5352
using v8::String;
5453
using v8::Symbol;
5554
using v8::TryCatch;
56-
using v8::Uint32Array;
5755
using v8::Undefined;
5856
using v8::Value;
5957

@@ -476,13 +474,9 @@ void AsyncWrap::Initialize(Local<Object> target,
476474
// callbacks waiting to be called on a particular event. It can then be
477475
// incremented/decremented from JS quickly to communicate to C++ if there are
478476
// any callbacks waiting to be called.
479-
uint32_t* fields_ptr = env->async_hooks()->fields();
480-
int fields_count = env->async_hooks()->fields_count();
481-
Local<ArrayBuffer> fields_ab =
482-
ArrayBuffer::New(isolate, fields_ptr, fields_count * sizeof(*fields_ptr));
483477
FORCE_SET_TARGET_FIELD(target,
484478
"async_hook_fields",
485-
Uint32Array::New(fields_ab, 0, fields_count));
479+
env->async_hooks()->fields().GetJSArray());
486480

487481
// The following v8::Float64Array has 5 fields. These fields are shared in
488482
// this way to allow JS and C++ to read/write each value as quickly as
@@ -493,15 +487,9 @@ void AsyncWrap::Initialize(Local<Object> target,
493487
// kInitTriggerId: Write the id of the resource responsible for a handle's
494488
// creation just before calling the new handle's constructor. After the new
495489
// handle is constructed kInitTriggerId is set back to 0.
496-
double* uid_fields_ptr = env->async_hooks()->uid_fields();
497-
int uid_fields_count = env->async_hooks()->uid_fields_count();
498-
Local<ArrayBuffer> uid_fields_ab = ArrayBuffer::New(
499-
isolate,
500-
uid_fields_ptr,
501-
uid_fields_count * sizeof(*uid_fields_ptr));
502490
FORCE_SET_TARGET_FIELD(target,
503491
"async_uid_fields",
504-
Float64Array::New(uid_fields_ab, 0, uid_fields_count));
492+
env->async_hooks()->uid_fields().GetJSArray());
505493

506494
Local<Object> constants = Object::New(isolate);
507495
#define SET_HOOKS_CONSTANT(name) \
Collapse file

‎src/env-inl.h‎

Copy file name to clipboardExpand all lines: src/env-inl.h
+19-13Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
2626

27+
#include "aliased_buffer.h"
2728
#include "env.h"
2829
#include "node.h"
2930
#include "util.h"
@@ -82,8 +83,8 @@ inline uint32_t* IsolateData::zero_fill_field() const {
8283

8384
inline Environment::AsyncHooks::AsyncHooks(v8::Isolate* isolate)
8485
: isolate_(isolate),
85-
fields_(),
86-
uid_fields_() {
86+
fields_(isolate, kFieldsCount),
87+
uid_fields_(isolate, kUidFieldsCount) {
8788
v8::HandleScope handle_scope(isolate_);
8889

8990
// kAsyncUidCntr should start at 1 because that'll be the id the execution
@@ -105,15 +106,17 @@ inline Environment::AsyncHooks::AsyncHooks(v8::Isolate* isolate)
105106
#undef V
106107
}
107108

108-
inline uint32_t* Environment::AsyncHooks::fields() {
109+
inline AliasedBuffer<uint32_t, v8::Uint32Array>&
110+
Environment::AsyncHooks::fields() {
109111
return fields_;
110112
}
111113

112114
inline int Environment::AsyncHooks::fields_count() const {
113115
return kFieldsCount;
114116
}
115117

116-
inline double* Environment::AsyncHooks::uid_fields() {
118+
inline AliasedBuffer<double, v8::Float64Array>&
119+
Environment::AsyncHooks::uid_fields() {
117120
return uid_fields_;
118121
}
119122

@@ -147,7 +150,7 @@ inline bool Environment::AsyncHooks::pop_ids(double async_id) {
147150
fprintf(stderr,
148151
"Error: async hook stack has become corrupted ("
149152
"actual: %.f, expected: %.f)\n",
150-
uid_fields_[kCurrentAsyncId],
153+
uid_fields_.GetValue(kCurrentAsyncId),
151154
async_id);
152155
Environment* env = Environment::GetCurrent(isolate_);
153156
DumpBacktrace(stderr);
@@ -326,7 +329,7 @@ inline Environment::~Environment() {
326329
delete[] heap_statistics_buffer_;
327330
delete[] heap_space_statistics_buffer_;
328331
delete[] http_parser_buffer_;
329-
free(http2_state_buffer_);
332+
delete http2_state_;
330333
free(performance_state_);
331334
}
332335

@@ -425,7 +428,9 @@ inline std::vector<double>* Environment::destroy_ids_list() {
425428
}
426429

427430
inline double Environment::new_async_id() {
428-
return ++async_hooks()->uid_fields()[AsyncHooks::kAsyncUidCntr];
431+
async_hooks()->uid_fields()[AsyncHooks::kAsyncUidCntr] =
432+
async_hooks()->uid_fields()[AsyncHooks::kAsyncUidCntr] + 1;
433+
return async_hooks()->uid_fields()[AsyncHooks::kAsyncUidCntr];
429434
}
430435

431436
inline double Environment::current_async_id() {
@@ -437,7 +442,8 @@ inline double Environment::trigger_id() {
437442
}
438443

439444
inline double Environment::get_init_trigger_id() {
440-
double* uid_fields = async_hooks()->uid_fields();
445+
AliasedBuffer<double, v8::Float64Array>& uid_fields =
446+
async_hooks()->uid_fields();
441447
double tid = uid_fields[AsyncHooks::kInitTriggerId];
442448
uid_fields[AsyncHooks::kInitTriggerId] = 0;
443449
if (tid <= 0) tid = current_async_id();
@@ -477,13 +483,13 @@ inline void Environment::set_http_parser_buffer(char* buffer) {
477483
http_parser_buffer_ = buffer;
478484
}
479485

480-
inline http2::http2_state* Environment::http2_state_buffer() const {
481-
return http2_state_buffer_;
486+
inline http2::http2_state* Environment::http2_state() const {
487+
return http2_state_;
482488
}
483489

484-
inline void Environment::set_http2_state_buffer(http2::http2_state* buffer) {
485-
CHECK_EQ(http2_state_buffer_, nullptr); // Should be set only once.
486-
http2_state_buffer_ = buffer;
490+
inline void Environment::set_http2_state(http2::http2_state* buffer) {
491+
CHECK_EQ(http2_state_, nullptr); // Should be set only once.
492+
http2_state_ = buffer;
487493
}
488494

489495
inline double* Environment::fs_stats_field_array() const {

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.