-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
http2, async-wrap: introduce AliasedBuffer class #15077
http2, async-wrap: introduce AliasedBuffer class #15077
Conversation
/cc @jasnell, @addaleax, @mrkmarron. |
src/aliased_buffer.h
Outdated
*/ | ||
inline void SetValue(const int index, NativeT value) { | ||
// if (index >= count_) { | ||
// TODO(@mike-kaufman): Assert? Fail fast? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't clear if I should do anything here. Please let me know if there's existing precedent around such checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHECK
is likely appropriate. /cc @bnoordhuis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a CHECK.
src/aliased_buffer.h
Outdated
*/ | ||
inline const NativeT GetValue(const int index) const { | ||
// if (index >= count_) { | ||
// TODO(@mike-kaufman): Assert? Fail fast? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similiar here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed now with a CHECK.
src/aliased_buffer.h
Outdated
free(this->buffer_); | ||
} | ||
// TODO(@mike-kaufman): what do we do about freeing the | ||
// v8::Global<ArrayBuffer> & the v8::Global<U> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not clear to me if I need to do anything to manage lifecycle of a v8::Global
? Do I need to call reset()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That I'm unsure about. @addaleax or @bnoordhuis may know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Global<>
does need to be reset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. calling .Reset()
on the v8::Global.
@@ -0,0 +1,116 @@ | |||
#ifndef SRC_NODE_HTTP2_STATE_H_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to move most of the stuff here out of node_http2.cc
because http2_state
was forward declaration, and I was seeing a compiler warning about calling delete on a forward declaration. I initially tried to introduce a #include "node_http2.h"
into env.h
, but that was causing cycles.
test/cctest/test_aliased_buffer.cc
Outdated
// v8::MaybeLocal<v8::Number> v3 = v2->ToNumber(); | ||
// v8::Local<v8::Number> v4 = v3.ToLocalChecked(); | ||
// NativeT actualValue = *(reinterpret_cast<NativeT*>(&v4->Value())); | ||
// EXPECT_TRUE((NativeT)(v4->Value()) == oracle[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to validate the value being read from the JS api is the same as the native type value, but I couldn't get this to work. Is there an easy way to do this? Some casting magic I need to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that I'm aware of.
src/aliased_buffer.h
Outdated
|
||
// allocate native buffer | ||
this->buffer_ = reinterpret_cast<NativeT*>( | ||
calloc(count, sizeof(NativeT))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this follow the same pattern as MaybeStackBuffer
... or even make use of that to avoid the calloc
where possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could, but I'm not following why. Can you help me understand your concerns w/ using calloc? I was trying to be consistent w/ original buffers that were alloc'd on heap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency would be the main reason but it's certainly not critical. I don't think the performance difference is going to be enough to worry about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now using node::UncheckedCalloc
. Is using MaybeStackBuffer
still something to investigate?
Very good. I'll give it a thorough review and sign off later but I'd like to get @addaleax, @bnoordhuis and @trevnorris to take a look also |
What kind of performance impact does this have? |
@mscdex - what tests would you suggest I run to measure this? I ran acmeair-nodejs benchmark, comparing my local master (at this commit) with my changes. Results didn't show any meaningful impact: master:
with my change:
Note that intention with this change was to have the I'm happy to run a better set of tests to measure impact here, I just don't know what they are. |
2684ac6
to
7d70f50
Compare
@mscdex ... with regards to performance, it's important just to note that this is largely just a formalization of a pattern we were already using. I wouldn't expect the performance to be much different than what we see currently, tho I do suspect the likelihood of bugs to go way down ;-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch doesn't follow general whitespace and line break rules that the remainder of core follows. I haven't run the linter to see if they violate the current rules, but regardless they should align with what node already uses.
Overall I'm -1 on this change. The abstraction adds more code than it removes, and it substantially adds more complexity. This isn't a pattern that we need to use much, and I'm willing to bet that it's one we won't need to use much in the future.
src/aliased_buffer.h
Outdated
freeBuffer_(true) { | ||
const v8::HandleScope handle_scope(this->isolate_); | ||
|
||
const int sizeInBytes = sizeof(NativeT) * count; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sizeof()
returns a size_t
.
src/aliased_buffer.h
Outdated
|
||
// allocate native buffer | ||
this->buffer_ = reinterpret_cast<NativeT*>( | ||
calloc(count, sizeof(NativeT))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two problems here. 1) please use node::UncheckedCalloc()
instead of using calloc()
directly. 2) You're not checking if this->buffer_ == nullptr
afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @trevnorris, will do. Is there an example of fail-fast behavior when out of memory occurs? e.g., is there a specific error code to return?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I tend to completely forget that we have those Calloc wrappers there.
src/aliased_buffer.h
Outdated
v8::Uint8Array>& backingBuffer) : | ||
isolate_(isolate), | ||
count_(count), | ||
byte_offset_(byte_offset), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A CHECK()
to verify that byte_offset_
is aligned would be helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fwiw, that check isn't strictly necessary because the V8 TypedArray constructor checks it anyway
src/aliased_buffer.h
Outdated
free(this->buffer_); | ||
} | ||
// TODO(@mike-kaufman): what do we do about freeing the | ||
// v8::Global<ArrayBuffer> & the v8::Global<U> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Global<>
does need to be reset.
7d70f50
to
7b33315
Compare
@trevnorris... see here for some of the background leading into this: nodejs/node-chakracore#372 The short version is, the way the code is written now, it causes some headaches for the Chakra folks that this revised method is intended to ease. Given the problem, I think this is the best way to address it but I'd certainly love to have you review and comment on that! :-) |
7b33315
to
f28aa61
Compare
Linter is clean on osx for me. Can you point out specifics? Or is there a style guide I'm missing?
The key thing here is this simplifies cases where we need to observe writes to that program state. e.g., take a look at https://github.com/nodejs/node-chakracore/pull/252/files. The code here to "mark" these writes is scattered around in a way that is prone to breakage & merge conflicts. The Happy to discuss other approaches here if you have ideas. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, would like to make sure @addaleax and @trevnorris are good on it tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, left a few style nits that would bring this a little more in line with our usual style, but nothing blocking :)
src/aliased_buffer.h
Outdated
this->buffer_ = UncheckedCalloc<NativeT>(count); | ||
if (this->buffer_ == nullptr) { | ||
ABORT(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point you might as well use the checked kind of alloc? ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
src/aliased_buffer.h
Outdated
|
||
// allocate v8 ArrayBuffer | ||
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New( | ||
this->isolate_, this->buffer_, sizeInBytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny style nit: 4 spaces indentation for statement continuations (and we don't usually do this->
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added 4 spaces for continuations & removed this->
qualifiers.
src/aliased_buffer.h
Outdated
|
||
// allocate v8 TypedArray | ||
v8::Local<V8T> jsArray = V8T::New(ab, this->byte_offset_, count); | ||
this->jsArray_ = v8::Global<V8T>(isolate, jsArray); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny style nit: snake_case (js_array
, js_array_
) for variables/member fields
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snake cased vars & memebers. LMK if I missed anything.
src/aliased_buffer.h
Outdated
v8::Uint8Array>& backingBuffer) : | ||
isolate_(isolate), | ||
count_(count), | ||
byte_offset_(byte_offset), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fwiw, that check isn't strictly necessary because the V8 TypedArray constructor checks it anyway
src/aliased_buffer.h
Outdated
return *this; | ||
} | ||
|
||
operator NativeT() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be const
, fwiw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/env-inl.h
Outdated
@@ -457,7 +462,8 @@ inline double Environment::trigger_id() { | |||
} | |||
|
|||
inline double Environment::get_init_trigger_id() { | |||
double* uid_fields = async_hooks()->uid_fields(); | |||
AliasedBuffer<double, v8::Float64Array> uid_fields = | |||
async_hooks()->uid_fields(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use a reference (AliasedBuffer<double, v8::Float64Array>&
) instead, right? I think that would allow you to get rid of AliasedBuffer
's copy constructor (and mark that as deleted), which seems like a good idea to me, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, you're right. I'll fix...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/node_http2.cc
Outdated
@@ -149,7 +93,8 @@ ssize_t Http2Session::OnCallbackPadding(size_t frameLen, | |||
Context::Scope context_scope(context); | |||
|
|||
if (object()->Has(context, env()->ongetpadding_string()).FromJust()) { | |||
uint32_t* buffer = env()->http2_state_buffer()->padding_buffer; | |||
AliasedBuffer<uint32_t, v8::Uint32Array> buffer = | |||
env()->http2_state()->padding_buffer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these could be references as well, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
test/cctest/test_aliased_buffer.cc
Outdated
// read through the API | ||
for (size_t i = 0; i < size; i++) { | ||
NativeT v1 = (NativeT)aliasedBuffer[i]; | ||
NativeT v2 = (NativeT)aliasedBuffer.GetValue(i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: Can you use static_cast
for these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed cast, wasn't necessary.
test/cctest/test_aliased_buffer.cc
Outdated
// NativeT actualValue = *(reinterpret_cast<NativeT*>(&v4->Value())); | ||
// EXPECT_TRUE((NativeT)(v4->Value()) == oracle[i]); | ||
// TODO(@mike-kaufman) figure out how to compare the value in the v8 array | ||
// Expect_TRUE(*v.ToLocal() == v8NumberCreateFunction(oracle[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what this code would mean, if I'm honest. Is this code for checking object identity between number values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to validate that the value read through JS APIs was the same value as what was written to the native array. I just never found the right set of APIs and/or casts to make this happen. Was hoping there was something straightforward that I was missing.
test/cctest/test_aliased_buffer.cc
Outdated
EXPECT_TRUE(v2->IsNumber()); | ||
// v8::MaybeLocal<v8::Number> v3 = v2->ToNumber(); | ||
// v8::Local<v8::Number> v4 = v3.ToLocalChecked(); | ||
// NativeT actualValue = *(reinterpret_cast<NativeT*>(&v4->Value())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this could work, you're taking a pointer to a stack-allocated return value and casting it around`.
NativeT actualValue = static_cast<NativeT>(&v4->Value());
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll play around with that...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, got this to work. Think I was seeing seg fault earlier because I didn't pass context
to ToNumber
@trevnorris This pattern solves a real problem, so if you have other solutions, feel free to voice them (but not doing so is kind of unproductive). Also, I would argue that the encapsulation that comes with this does remove complexity; it makes it more obvious to readers that a write to these ArrayBuffers is not just a memory write, but actually changes state for JS. |
d9ca7f4
to
19fa7b6
Compare
Thanks @addaleax for the review! I think I addressed all the feedback & rebased off of master. LMK if I missed anything. I didn't squash in case anyone wants to look at diffs, but I can do that. |
@trevnorris ... I absolutely have to agree with @addaleax on this. This addresses a real problem even if we don't use this pattern extensively. Please reconsider your -1 |
@mike-kaufman Just occurred to me that a proper solution for the |
ping @trevnorris |
src/aliased_buffer.h
Outdated
* Get value at position index | ||
*/ | ||
inline const NativeT GetValue(const size_t index) const { | ||
CHECK_LT(index, count_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@trevnorris I’m pretty sure the reported performance difference is due to this check, it’s the only visible difference in the generated machine code. I’d suggest wrapping it in #if defined(DEBUG) && DEBUG
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
confirmed. that is where the performance hit is coming from. wrapping it sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this and the SetValue check are now in debug-only builds.
src/aliased_buffer.h
Outdated
* Set position index to given value. | ||
*/ | ||
inline void SetValue(const size_t index, NativeT value) { | ||
CHECK_LT(index, count_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(same goes for this one, I assume)
Sorry for the delayed response here, I've been off the grid for the last week or so. I'll address latest feedback shortly.
Short term, in the chakra fork, we'll add some logic in the |
e4c2824
to
3d9f323
Compare
I think I addressed the latest feedback. Please let me know if I missed anything. @jasnell -
I'm happy to do this, but I feel like we're close here? LMK if not the case. |
As long as @trevnorris and @addaleax are happy, I'm good. |
src/aliased_buffer.h
Outdated
buffer_ = reinterpret_cast<NativeT*>( | ||
const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset)); | ||
|
||
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be worth it to assign backing_buffer.GetNativeBuffer()
to a variable at the top, since it's used three times here? (not a blocker)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. (assuming you meant GetArrayBuffer()
).
src/aliased_buffer.h
Outdated
inline const NativeT GetValue(const size_t index) const { | ||
#if defined(DEBUG) && DEBUG | ||
CHECK_LT(index, count_); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit (non-blocking): more common indentation is to have no whitespace before the #if
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
two questions/suggestions, but nothing technically blocking. LGTM.
This change introduces an AliasedBuffer class and updates asytnc-wrap and http2 to use this class. A common technique to optimize performance is to create a native buffer and then map that native buffer to user space via JS array. The runtime can efficiently write to the native buffer without having to route though JS, and the values being written are accessible from user space. While efficient, this technique allows modifications to user space memory w/out going through JS type system APIs, effectively bypassing any monitoring the JS VM has in place to track program state modifications. The result is that monitors have an incorrect view of prorgram state. The AliasedBuffer class provides a future placeholder where this technique can be used, but writes can still be observed. To achieve this, the node-chakra-core fork will add in appropriate tracking logic in the AliasedBuffer's SetValue() method. Going forward, this class can evolve to support more sophisticated mechanisms if necessary.
…r/variable names, adding const, some other stuff...
3d9f323
to
c6508f7
Compare
Fresh CI: https://ci.nodejs.org/job/node-test-commit/12329/ This should be ready. |
Still LGTM |
Great! Thanks @addaleax, @trevnorris, @jasnell! Anything else I need to do here? When can this get merged in? |
If someone else doesn't beat me to it, I'll be merging it in later on this morning. |
Landed in 35a526c |
This change introduces an AliasedBuffer class and updates asytnc-wrap and http2 to use this class. A common technique to optimize performance is to create a native buffer and then map that native buffer to user space via JS array. The runtime can efficiently write to the native buffer without having to route though JS, and the values being written are accessible from user space. While efficient, this technique allows modifications to user space memory w/out going through JS type system APIs, effectively bypassing any monitoring the JS VM has in place to track program state modifications. The result is that monitors have an incorrect view of prorgram state. The AliasedBuffer class provides a future placeholder where this technique can be used, but writes can still be observed. To achieve this, the node-chakra-core fork will add in appropriate tracking logic in the AliasedBuffer's SetValue() method. Going forward, this class can evolve to support more sophisticated mechanisms if necessary. PR-URL: #15077 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This change introduces an AliasedBuffer class and updates asytnc-wrap and http2 to use this class. A common technique to optimize performance is to create a native buffer and then map that native buffer to user space via JS array. The runtime can efficiently write to the native buffer without having to route though JS, and the values being written are accessible from user space. While efficient, this technique allows modifications to user space memory w/out going through JS type system APIs, effectively bypassing any monitoring the JS VM has in place to track program state modifications. The result is that monitors have an incorrect view of prorgram state. The AliasedBuffer class provides a future placeholder where this technique can be used, but writes can still be observed. To achieve this, the node-chakra-core fork will add in appropriate tracking logic in the AliasedBuffer's SetValue() method. Going forward, this class can evolve to support more sophisticated mechanisms if necessary. PR-URL: nodejs/node#15077 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This change introduces an AliasedBuffer class and updates asytnc-wrap and http2 to use this class. A common technique to optimize performance is to create a native buffer and then map that native buffer to user space via JS array. The runtime can efficiently write to the native buffer without having to route though JS, and the values being written are accessible from user space. While efficient, this technique allows modifications to user space memory w/out going through JS type system APIs, effectively bypassing any monitoring the JS VM has in place to track program state modifications. The result is that monitors have an incorrect view of prorgram state. The AliasedBuffer class provides a future placeholder where this technique can be used, but writes can still be observed. To achieve this, the node-chakra-core fork will add in appropriate tracking logic in the AliasedBuffer's SetValue() method. Going forward, this class can evolve to support more sophisticated mechanisms if necessary. PR-URL: #15077 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This change introduces an AliasedBuffer class and updates asytnc-wrap and http2 to use this class. A common technique to optimize performance is to create a native buffer and then map that native buffer to user space via JS array. The runtime can efficiently write to the native buffer without having to route though JS, and the values being written are accessible from user space. While efficient, this technique allows modifications to user space memory w/out going through JS type system APIs, effectively bypassing any monitoring the JS VM has in place to track program state modifications. The result is that monitors have an incorrect view of prorgram state. The AliasedBuffer class provides a future placeholder where this technique can be used, but writes can still be observed. To achieve this, the node-chakra-core fork will add in appropriate tracking logic in the AliasedBuffer's SetValue() method. Going forward, this class can evolve to support more sophisticated mechanisms if necessary. PR-URL: nodejs/node#15077 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This change introduces an
AliasedBuffer
class and updates async-wrapand http2 to use this class.
A common technique to optimize performance is to create a native buffer
and then map that native buffer to user space via JS array. The runtime
can efficiently write to the native buffer without having to route
though JS, and the values being written are accessible from user space.
While efficient, this technique allows modifications to user
space memory w/out going through JS type system APIs, effectively
bypassing any monitoring the JS VM has in place to track program state
modifications. The result is that monitors have an incorrect view
of program state.
The AliasedBuffer class provides a future placeholder where this
technique can be used, but writes can still be observed. To achieve
this, the node-chakra-core fork will add in appropriate tracking logic
in the
AliasedBuffer
'sSetValue()
method. Going forward, this class canevolve to support more sophisticated mechanisms if necessary.
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
async-wrap, http2