Skip to content
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

Stop using V8::External #13503

Closed
DemiMarie opened this issue Jun 6, 2017 · 11 comments
Closed

Stop using V8::External #13503

DemiMarie opened this issue Jun 6, 2017 · 11 comments
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. performance Issues and PRs related to the performance of Node.js. v8 engine Issues and PRs related to the V8 dependency.

Comments

@DemiMarie
Copy link

  • Version: v6.10.3

  • Platform:

    Linux localhost.hsd1.tn.comcast.net 4.11.3-300.fc26.x86_64 #1 SMP Thu May 25 18:43:57 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
    
  • Subsystem: Scattered around in C++ code

Node.js uses v8::External in many places. However, these are not efficiently implemented in v8: each of them consists of a full object that contains a pointer. Instead, Node should ensure that each of the pointers is aligned, and use GetAlignedPointerInInternalField/SetAlignedPointerInInternalField instead.

@mscdex mscdex added the v8 engine Issues and PRs related to the V8 dependency. label Jun 6, 2017
@addaleax addaleax added the c++ Issues and PRs that require attention from people who are familiar with C++. label Jun 6, 2017
@addaleax
Copy link
Member

addaleax commented Jun 6, 2017

Mh, looking through the source …

  • env.h & env-inl.h: This should be fine, it’s just creating the object once and there’s not much we can do about these, I think. At least it’s not trivially replaced by using internal fields.
  • inspector_agent.cc: Maybe? This isn’t hot code, and I don’t know off the top of my head what kind of object the inspector object is.
  • node_api.cc: Yes, quite a few of those could probably be pointers. We’d just need to make sure that we keep in mind that pointers provided from userland can’t be assumed to be aligned.
  • node_contextify.cc: The object on which we operate can be passed from userland and doesn’t have any internal fields that would be available for use by us.
  • node_crypto.cc: These can’t be replaced by internal fields either, but I think the methods using them might be dead code (i.e. not used outside of our own tests).
  • node_http_parser.cc, tls_wrap.cc & stream_base-inl.h: Externals are used for passing around C++ objects in JS code; we might be able to get around this by some refactoring.

I wouldn’t expect that anything here has a significant negative performance impact.

@DemiMarie
Copy link
Author

DemiMarie commented Jun 7, 2017 via email

@bnoordhuis
Copy link
Member

I think you mean ObjectTemplate? Instantiating one with NewInstance() isn't much cheaper than External::New(). If anything, it's probably a little slower because it does more.

addaleax added a commit to addaleax/node that referenced this issue Jun 7, 2017
These getters are unused in our source code, untested (apart from a
test checking that the getters themselves do not throw) and are
useless for JS code due to the opaqueness of `v8::External`s.

I can’t really imagine addons depending on this, especially as it’s
undocumented and very niche anyway, but I guess there’s no reason
to not consider this semver-major.

Ref: nodejs#13503
@DemiMarie
Copy link
Author

DemiMarie commented Jun 9, 2017 via email

@bnoordhuis
Copy link
Member

FunctionTemplate doesn't have methods for defining extra slots but I infer you are referring to FunctionTemplate::InstanceTemplate(), which is an ObjectTemplate that controls the shape of instances.

The point stands though that it's probably going to be at least as expensive as an External. Yes, you can do HasInstance checks on instances but that seems like a fairly marginal improvement over Value::IsExternal(). It's not completely without value but neither is it worth spending a lot of effort on.

@DemiMarie
Copy link
Author

The main advantage is to avoid segfault “bugs” by ensuring that bad JS cannot cause a crash in C++.

@jasnell
Copy link
Member

jasnell commented Jun 16, 2017

Just as a point of reference, I should note that I'm currently using V8::External in a couple of ways in the http2 implementation. Specifically:

  • The StreamBase reference on a socket is currently stored in an External via the _external property. This reference is passed in to the http2 impl's native side so that the native node::Http2Session can read data from, and write data to, the StreamBase directly, without bouncing back out to the JS layer each time. That could be refactored, of course, but currently the _external is the only mechanism I have for getting the appropriate pointer.

  • When headers are received, I am wrapping inbound header field names in an external string to avoid unnecessary memcpy'ing. The header data is passed from the nghttp2 library in a persistent buffer that is released when the thing is garbage collected. If I was forced to treat header field values as UTF-8 for backwards compatibility reasons, I would be doing the same with those as it yields a significant performance improvement.

@DemiMarie
Copy link
Author

DemiMarie commented Jun 16, 2017 via email

@jasnell
Copy link
Member

jasnell commented Jun 16, 2017

For the header names, not without adding a memcpy for every header field, which gets expensive very quickly.

@ChALkeR ChALkeR added the performance Issues and PRs related to the performance of Node.js. label Jun 16, 2017
@TimothyGu
Copy link
Member

I'm working on getting rid of Externals in inspector, should be able to put up a PR by tomorrow.

TimothyGu added a commit to TimothyGu/node that referenced this issue Aug 9, 2017
Uses internal fields instead of the less efficient v8::External for
storing the pointer to the C++ object.

Refs: nodejs#13503
TimothyGu added a commit to TimothyGu/node that referenced this issue Sep 28, 2017
- Group all relevant methods/states into a C++ class.
- Uses internal fields instead of the less efficient v8::External for
  storing the pointer to the C++ object.
- Use AsyncWrap to allow instrumenting callback states.

Refs: nodejs#13503
TimothyGu added a commit to TimothyGu/node that referenced this issue Oct 3, 2017
- Group all relevant methods/states into a C++ class.
- Uses internal fields instead of the less efficient v8::External for
  storing the pointer to the C++ object.
- Use AsyncWrap to allow instrumenting callback states.

PR-URL: nodejs#15643
Refs: nodejs#13503
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
addaleax pushed a commit to addaleax/ayo that referenced this issue Oct 4, 2017
- Group all relevant methods/states into a C++ class.
- Uses internal fields instead of the less efficient v8::External for
  storing the pointer to the C++ object.
- Use AsyncWrap to allow instrumenting callback states.

PR-URL: nodejs/node#15643
Refs: nodejs/node#13503
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
TimothyGu added a commit to TimothyGu/node that referenced this issue Oct 22, 2017
- Group all relevant methods/states into a C++ class.
- Uses internal fields instead of the less efficient v8::External for
  storing the pointer to the C++ object.
- Use AsyncWrap to allow instrumenting callback states.

Backport-PR-URL: nodejs#16071
PR-URL: nodejs#15643
Refs: nodejs#13503
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
evanlucas pushed a commit that referenced this issue Oct 23, 2017
- Group all relevant methods/states into a C++ class.
- Uses internal fields instead of the less efficient v8::External for
  storing the pointer to the C++ object.
- Use AsyncWrap to allow instrumenting callback states.

Backport-PR-URL: #16071
PR-URL: #15643
Refs: #13503
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@bnoordhuis
Copy link
Member

This issue has languished and it doesn't look like there is consensus on the suggested changes so I'll go ahead and close it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. performance Issues and PRs related to the performance of Node.js. v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

No branches or pull requests

7 participants